添加物体角度调整功能,新增角度修正窗口及相关逻辑
This commit is contained in:
parent
b6dd1ca61b
commit
ca503c0448
@ -235,6 +235,9 @@
|
||||
<Compile Include="src\UI\WPF\Views\EditCoordinatesWindow.xaml.cs">
|
||||
<DependentUpon>EditCoordinatesWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="src\UI\WPF\Views\EditRotationWindow.xaml.cs">
|
||||
<DependentUpon>EditRotationWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="src\UI\WPF\Views\HoistingHeightDialog.xaml.cs">
|
||||
<DependentUpon>HoistingHeightDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -295,6 +298,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="src\UI\WPF\Views\EditRotationWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="src\UI\WPF\Views\ModelSettingsView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@ -97,6 +97,9 @@ namespace NavisworksTransport.Core.Animation
|
||||
private List<ModelItem> _manualCollisionTargets = new List<ModelItem>();
|
||||
private bool _manualCollisionOverrideEnabled = false;
|
||||
|
||||
// === 角度修正 ===
|
||||
private double _objectRotationCorrection = 0.0; // 物体角度修正值(度,顺时针)
|
||||
|
||||
// === 碰撞排除列表缓存管理(从LogisticsAnimationManager迁移)===
|
||||
private ModelItem _currentCachedAnimationObject;
|
||||
private List<ModelItem> _cachedExclusionList;
|
||||
@ -385,16 +388,9 @@ namespace NavisworksTransport.Core.Animation
|
||||
_originalCenter = animatedObject.BoundingBox().Center;
|
||||
_currentPosition = new Point3D(_originalCenter.X, _originalCenter.Y, animatedObject.BoundingBox().Min.Z);
|
||||
|
||||
// 对于虚拟车辆,重置 _currentYaw 为 0,因为虚拟车辆刚创建时已经被重置为单位变换
|
||||
// 对于普通物体,保持原始朝向
|
||||
if (_isVirtualVehicle)
|
||||
{
|
||||
_currentYaw = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
|
||||
}
|
||||
// 统一逻辑:从当前 Transform 中提取实际朝向(无论虚拟车辆还是普通物体)
|
||||
_currentYaw = ModelItemTransformHelper.GetYawFromTransform(_originalTransform);
|
||||
LogManager.Debug($"[MoveVehicleToPathStart初始化] 当前实际yaw={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
}
|
||||
|
||||
if (pathPoints != null)
|
||||
@ -412,6 +408,8 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 计算朝向(使用前两个路径点的方向)
|
||||
double pathDirectionYaw = Math.Atan2(_pathPoints[1].Y - _pathPoints[0].Y, _pathPoints[1].X - _pathPoints[0].X);
|
||||
double yaw;
|
||||
|
||||
LogManager.Info($"[移动到起点] 路径方向yaw: {pathDirectionYaw * 180 / Math.PI:F2}度, 角度修正: {_objectRotationCorrection:F1}度");
|
||||
|
||||
// 根据路径类型调整朝向
|
||||
if (_route?.PathType == PathType.Hoisting)
|
||||
@ -427,6 +425,14 @@ namespace NavisworksTransport.Core.Animation
|
||||
LogManager.Debug($"[移动到起点] 地面/空轨路径使用路径方向: {yaw * 180 / Math.PI:F2}度");
|
||||
}
|
||||
|
||||
// 应用角度修正值(顺时针,转换为弧度)
|
||||
if (_objectRotationCorrection != 0.0)
|
||||
{
|
||||
double correctionRad = _objectRotationCorrection * Math.PI / 180.0;
|
||||
yaw += correctionRad;
|
||||
LogManager.Debug($"[移动到起点] 应用角度修正: {_objectRotationCorrection:F1}°, 修正后yaw: {yaw * 180 / Math.PI:F2}度");
|
||||
}
|
||||
|
||||
// 根据路径类型调整起点位置
|
||||
Point3D startPosition = _pathPoints[0];
|
||||
if (_route?.PathType == PathType.Hoisting)
|
||||
@ -730,6 +736,12 @@ namespace NavisworksTransport.Core.Animation
|
||||
Collisions = new List<CollisionResult>()
|
||||
};
|
||||
|
||||
// 记录第一帧的角度(用于调试)
|
||||
if (i == 0)
|
||||
{
|
||||
LogManager.Debug($"[预计算] 第0帧: pos=({framePosition.X:F2},{framePosition.Y:F2}), yaw={yawRadians * 180 / Math.PI:F2}度");
|
||||
}
|
||||
|
||||
// 虚拟碰撞检测
|
||||
|
||||
// 计算车辆包围盒相对于framePosition的偏移
|
||||
@ -1116,9 +1128,11 @@ namespace NavisworksTransport.Core.Animation
|
||||
{
|
||||
var firstFrame = _animationFrames[0];
|
||||
|
||||
// 立即设置到第一帧的位置和朝向(由于MoveVehicleToPathStart已经设置过了,这里主要是确保状态同步)
|
||||
UpdateObjectPosition(firstFrame.Position, firstFrame.YawRadians);
|
||||
LogManager.Debug($"[动画开始] 确认初始位置和朝向: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2}), yaw={firstFrame.YawRadians:F3}rad");
|
||||
LogManager.Debug($"[动画开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
|
||||
// 物体已经在 MoveVehicleToPathStart 中被正确旋转到起点(包含角度修正)
|
||||
// 不需要再次旋转,否则会破坏角度修正
|
||||
LogManager.Debug($"[动画开始] 跳过初始位置设置,物体已在起点: pos=({firstFrame.Position.X:F2},{firstFrame.Position.Y:F2}), yaw={firstFrame.YawRadians:F3}rad");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1796,6 +1810,7 @@ namespace NavisworksTransport.Core.Animation
|
||||
// 我们需要手动计算旋转导致的位置偏移,并补偿
|
||||
|
||||
double deltaYaw = newYaw - _currentYaw;
|
||||
LogManager.Debug($"[UpdateObjectPosition] 当前yaw={_currentYaw * 180 / Math.PI:F2}度, 目标yaw={newYaw * 180 / Math.PI:F2}度, 旋转增量deltaYaw={deltaYaw * 180 / Math.PI:F2}度");
|
||||
|
||||
// 计算绕当前位置旋转的等效变换:
|
||||
// 1. 如果绕原点旋转deltaYaw,当前位置_currentPosition会移动到哪里?
|
||||
@ -1823,17 +1838,17 @@ namespace NavisworksTransport.Core.Animation
|
||||
_currentYaw = newYaw;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 纯平移
|
||||
incrementalTransform = Transform3D.CreateTranslation(deltaPos);
|
||||
}
|
||||
|
||||
// 应用增量变换(false = 增量模式)
|
||||
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);
|
||||
|
||||
// 更新当前位置
|
||||
_currentPosition = newPosition;
|
||||
}
|
||||
{
|
||||
// 纯平移
|
||||
incrementalTransform = Transform3D.CreateTranslation(deltaPos);
|
||||
LogManager.Debug($"[UpdateObjectPosition] 纯平移: ({deltaPos.X:F2},{deltaPos.Y:F2},{deltaPos.Z:F2})");
|
||||
}
|
||||
|
||||
// 应用增量变换(false = 增量模式)
|
||||
doc.Models.OverridePermanentTransform(modelItems, incrementalTransform, false);
|
||||
|
||||
// 更新当前位置
|
||||
_currentPosition = newPosition; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"更新部件位置失败: {ex.Message}");
|
||||
@ -2477,9 +2492,53 @@ namespace NavisworksTransport.Core.Animation
|
||||
_virtualVehicleLength = virtualVehicleLength;
|
||||
_virtualVehicleWidth = virtualVehicleWidth;
|
||||
_virtualVehicleHeight = virtualVehicleHeight;
|
||||
_pathPoints = pathPoints;
|
||||
_animatedObject = animatedObject;
|
||||
|
||||
SetupAnimation(animatedObject, durationSeconds, _route);
|
||||
// 初始化物体位置和朝向
|
||||
if (animatedObject != null)
|
||||
{
|
||||
_originalTransform = animatedObject.Transform;
|
||||
_originalCenter = animatedObject.BoundingBox().Center;
|
||||
_currentPosition = new Point3D(_originalCenter.X, _originalCenter.Y, animatedObject.BoundingBox().Min.Z);
|
||||
|
||||
// 保持当前的 _currentYaw(因为物体可能已经被 MoveVehicleToPathStart 旋转)
|
||||
// 不要从 Transform 中提取,因为 Transform 返回的是原始值,不是当前值
|
||||
LogManager.Debug($"[CreateAnimation] 保持_currentYaw={_currentYaw * 180 / Math.PI:F2}度不变, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
}
|
||||
|
||||
// 设置动画参数并预计算动画帧
|
||||
// 注意:物体应该在调用CreateAnimation之前已经通过MoveVehicleToPathStart旋转到起点
|
||||
LogManager.Debug($"[CreateAnimation开始] _currentYaw之前={_currentYaw * 180 / Math.PI:F2}度, _isVirtualVehicle={_isVirtualVehicle}");
|
||||
SetupAnimation(animatedObject, durationSeconds, _route);
|
||||
LogManager.Debug($"[CreateAnimation结束] _currentYaw之后={_currentYaw * 180 / Math.PI:F2}度");
|
||||
// 设置动画状态为Ready(动画已生成,可以播放)
|
||||
SetState(AnimationState.Ready);
|
||||
LogManager.Info($"[CreateAnimation] 动画已创建,状态设置为Ready");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置物体角度修正值(度,顺时针)
|
||||
/// </summary>
|
||||
/// <param name="rotationCorrection">角度修正值(度)</param>
|
||||
public void SetObjectRotationCorrection(double rotationCorrection)
|
||||
{
|
||||
_objectRotationCorrection = rotationCorrection;
|
||||
|
||||
// 如果动画已创建,更新物体到起点的朝向
|
||||
if (_animatedObject != null && _pathPoints != null && _pathPoints.Count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 重新计算并应用朝向
|
||||
MoveVehicleToPathStart();
|
||||
LogManager.Info($"[角度修正] 物体角度已更新: {_objectRotationCorrection:F1}°");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"[角度修正] 更新物体角度失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region 动画实现方法
|
||||
@ -2616,7 +2675,16 @@ namespace NavisworksTransport.Core.Animation
|
||||
if (_currentFrameIndex < _animationFrames.Count)
|
||||
{
|
||||
var frameData = _animationFrames[_currentFrameIndex];
|
||||
UpdateObjectPosition(frameData.Position, frameData.YawRadians);
|
||||
|
||||
// 计算实际朝向 = 路径方向 + 角度修正
|
||||
double actualYaw = frameData.YawRadians;
|
||||
if (_objectRotationCorrection != 0.0)
|
||||
{
|
||||
double correctionRad = _objectRotationCorrection * Math.PI / 180.0;
|
||||
actualYaw += correctionRad;
|
||||
}
|
||||
|
||||
UpdateObjectPosition(frameData.Position, actualYaw);
|
||||
|
||||
// 更新碰撞高亮(基于预计算结果)
|
||||
UpdateCollisionHighlightFromFrame();
|
||||
|
||||
@ -233,6 +233,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private double _virtualVehicleHeight; // 虚拟车辆高度(米)
|
||||
private double _safetyMargin; // 检测间隙(米),从路径编辑同步
|
||||
|
||||
// 角度修正相关字段
|
||||
private double _objectRotationCorrection = 0.0; // 物体角度修正值(度,顺时针)
|
||||
|
||||
// 移动物体原始尺寸(米,在选择物体时保存)
|
||||
private double _objectOriginalLength = 0.0; // 物体原始长度(X方向)
|
||||
private double _objectOriginalWidth = 0.0; // 物体原始宽度(Y方向)
|
||||
private double _objectOriginalHeight = 0.0; // 物体原始高度(Z方向)
|
||||
|
||||
// 手工碰撞对象相关字段
|
||||
private bool _isManualCollisionTargetEnabled = false;
|
||||
private ObservableCollection<ManualCollisionTargetViewModel> _manualCollisionTargets;
|
||||
@ -548,8 +556,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
_pathAnimationManager?.MoveVehicleToPathStart(vModel, points);
|
||||
}
|
||||
|
||||
// 重置角度修正值(虚拟车辆重新选择时重置)
|
||||
ObjectRotationCorrection = 0.0;
|
||||
LogManager.Debug($"[切换虚拟车辆] 已重置角度修正值为0度");
|
||||
|
||||
// 当切换到虚拟车辆模式时,根据路径类型打开通行空间可视化
|
||||
UpdatePassageSpaceVisualization();
|
||||
|
||||
// 设置已选择物体状态(虚拟车辆也算已选择)
|
||||
HasSelectedAnimatedObject = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -612,6 +627,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private set => SetProperty(ref _safetyMargin, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 物体角度修正值(度,顺时针)
|
||||
/// </summary>
|
||||
public double ObjectRotationCorrection
|
||||
{
|
||||
get => _objectRotationCorrection;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _objectRotationCorrection, value))
|
||||
{
|
||||
// 角度修正值改变时,更新物体朝向和通行空间
|
||||
UpdateObjectRotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置虚拟车辆参数(由主ViewModel调用)
|
||||
/// </summary>
|
||||
@ -769,6 +800,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
public ICommand ViewCollisionReportCommand { get; private set; }
|
||||
public ICommand SelectAnimatedObjectCommand { get; private set; }
|
||||
public ICommand ClearAnimatedObjectCommand { get; private set; }
|
||||
public ICommand EditObjectRotationCommand { get; private set; }
|
||||
public ICommand GenerateAnimationCommand { get; private set; }
|
||||
public ICommand ApplyManualTargetsFromSelectionCommand { get; private set; }
|
||||
public ICommand ClearManualTargetsCommand { get; private set; }
|
||||
@ -910,8 +942,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
PauseAnimationCommand = new RelayCommand(async () => await ExecutePauseAnimationAsync(), () => CanPauseAnimation);
|
||||
StopAnimationCommand = new RelayCommand(async () => await ExecuteStopAnimationAsync(), () => CanStopAnimation);
|
||||
ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReport(), () => HasClashDetectiveResults);
|
||||
SelectAnimatedObjectCommand = new RelayCommand(ExecuteSelectAnimatedObject);
|
||||
SelectAnimatedObjectCommand = new RelayCommand(() =>
|
||||
{
|
||||
// 重置角度修正值(每个物体的旋转独立)
|
||||
ObjectRotationCorrection = 0.0;
|
||||
LogManager.Debug($"[选择物体] 已重置角度修正值为0度");
|
||||
ExecuteSelectAnimatedObject();
|
||||
});
|
||||
ClearAnimatedObjectCommand = new RelayCommand(ExecuteClearAnimatedObject, () => HasSelectedAnimatedObject);
|
||||
EditObjectRotationCommand = new RelayCommand(ExecuteEditObjectRotation, () => HasSelectedAnimatedObject);
|
||||
GenerateAnimationCommand = new RelayCommand(ExecuteGenerateAnimation, () => CanGenerateAnimation);
|
||||
ApplyManualTargetsFromSelectionCommand = new RelayCommand(ExecuteApplyManualTargetsFromSelection);
|
||||
ClearManualTargetsCommand = new RelayCommand(ExecuteClearManualTargets, () => HasManualCollisionTargets);
|
||||
@ -1285,17 +1324,32 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
var newObject = doc.CurrentSelection.SelectedItems.First;
|
||||
if (newObject == null) return;
|
||||
|
||||
// 1. 如果有旧物体,先归位并清理旧动画
|
||||
if (_selectedAnimatedObject != null && !ReferenceEquals(_selectedAnimatedObject, newObject))
|
||||
// 1. 保存旧物体引用,在设置新物体之前
|
||||
var oldObject = _selectedAnimatedObject;
|
||||
|
||||
// 2. 如果有旧物体且与新物体不同,先归位
|
||||
if (oldObject != null && !ReferenceEquals(oldObject, newObject))
|
||||
{
|
||||
_pathAnimationManager?.RestoreObjectToCADPosition();
|
||||
LogManager.Info($"[选择物体] 已归位旧物体: {oldObject.DisplayName}");
|
||||
}
|
||||
_pathAnimationManager?.ClearAnimationResults();
|
||||
|
||||
// 2. 设置新物体
|
||||
// 2. 先保存物体原始尺寸(在设置SelectedAnimatedObject之前)
|
||||
var bbox = newObject.BoundingBox();
|
||||
double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor();
|
||||
_objectOriginalLength = (bbox.Max.X - bbox.Min.X) / metersToModelUnits;
|
||||
_objectOriginalWidth = (bbox.Max.Y - bbox.Min.Y) / metersToModelUnits;
|
||||
_objectOriginalHeight = (bbox.Max.Z - bbox.Min.Z) / metersToModelUnits;
|
||||
LogManager.Debug($"[选择物体] 保存原始尺寸: 长度={_objectOriginalLength:F2}m, 宽度={_objectOriginalWidth:F2}m, 高度={_objectOriginalHeight:F2}m");
|
||||
|
||||
// 3. 设置新物体(会触发UpdatePassageSpaceVisualization)
|
||||
SelectedAnimatedObject = newObject;
|
||||
LogManager.Info($"已选择移动物体: {SelectedAnimatedObject.DisplayName}");
|
||||
|
||||
// 重置PathAnimationManager的角度修正值(每个物体的旋转独立)
|
||||
_pathAnimationManager?.SetObjectRotationCorrection(0.0);
|
||||
|
||||
// 3. 立即移动到起点(如果路径存在)
|
||||
if (CurrentPathRoute != null && CurrentPathRoute.Points != null && _pathAnimationManager != null)
|
||||
{
|
||||
@ -1653,6 +1707,54 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行编辑物体角度修正
|
||||
/// </summary>
|
||||
private void ExecuteEditObjectRotation()
|
||||
{
|
||||
try
|
||||
{
|
||||
var dialog = new Views.EditRotationWindow(_objectRotationCorrection);
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
ObjectRotationCorrection = dialog.RotationAngle;
|
||||
LogManager.Info($"物体角度修正已更新: {_objectRotationCorrection:F1}°");
|
||||
UpdateMainStatus($"物体角度修正: {_objectRotationCorrection:F1}°");
|
||||
|
||||
// 应用角度修正到物体
|
||||
UpdateObjectRotation();
|
||||
|
||||
// 更新通行空间可视化(考虑旋转后的尺寸)
|
||||
UpdatePassageSpaceVisualization();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"编辑物体角度失败: {ex.Message}");
|
||||
UpdateMainStatus($"编辑物体角度失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新物体旋转(应用角度修正)
|
||||
/// </summary>
|
||||
private void UpdateObjectRotation()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_pathAnimationManager != null && HasSelectedAnimatedObject)
|
||||
{
|
||||
// 将角度修正传递给动画管理器
|
||||
_pathAnimationManager.SetObjectRotationCorrection(_objectRotationCorrection);
|
||||
LogManager.Debug($"[角度修正] 已更新物体旋转: {_objectRotationCorrection:F1}°");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"更新物体旋转失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#region 手工碰撞对象命令
|
||||
|
||||
private void ExecuteApplyManualTargetsFromSelection()
|
||||
@ -2408,6 +2510,51 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算旋转后的有效宽度和长度
|
||||
/// </summary>
|
||||
/// <returns>(有效宽度, 有效长度)</returns>
|
||||
private (double effectiveWidth, double effectiveLength) CalculateRotatedDimensions()
|
||||
{
|
||||
double baseLength, baseWidth;
|
||||
|
||||
if (UseVirtualVehicle)
|
||||
{
|
||||
baseLength = VirtualVehicleLength;
|
||||
baseWidth = VirtualVehicleWidth;
|
||||
}
|
||||
else if (SelectedAnimatedObject != null)
|
||||
{
|
||||
// 使用保存的原始尺寸,避免物体旋转后包围盒尺寸变化
|
||||
baseLength = _objectOriginalLength;
|
||||
baseWidth = _objectOriginalWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0, 0);
|
||||
}
|
||||
|
||||
// 如果没有角度修正,直接返回原始尺寸
|
||||
if (_objectRotationCorrection == 0.0)
|
||||
{
|
||||
return (baseWidth, baseLength);
|
||||
}
|
||||
|
||||
// 计算旋转后的有效尺寸(投影)
|
||||
double rotationRad = _objectRotationCorrection * Math.PI / 180.0;
|
||||
double cos = Math.Abs(Math.Cos(rotationRad));
|
||||
double sin = Math.Abs(Math.Sin(rotationRad));
|
||||
|
||||
// 旋转后的宽度 = |宽度*cos| + |长度*sin|
|
||||
double effectiveWidth = baseWidth * cos + baseLength * sin;
|
||||
// 旋转后的长度 = |长度*cos| + |宽度*sin|
|
||||
double effectiveLength = baseLength * cos + baseWidth * sin;
|
||||
|
||||
LogManager.Debug($"[角度修正] 旋转后尺寸: 原始({baseLength:F2}×{baseWidth:F2}) -> 有效({effectiveLength:F2}×{effectiveWidth:F2}), 角度={_objectRotationCorrection:F1}°");
|
||||
|
||||
return (effectiveWidth, effectiveLength);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据路径类型更新通行空间可视化
|
||||
/// 空轨和吊装路径默认打开通行空间(车辆通行空间模式),地面路径不打开
|
||||
@ -2423,6 +2570,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算旋转后的有效尺寸(考虑角度修正)
|
||||
(double effectiveWidth, double effectiveLength) = CalculateRotatedDimensions();
|
||||
|
||||
var renderPlugin = PathPointRenderPlugin.Instance;
|
||||
if (renderPlugin == null)
|
||||
{
|
||||
@ -2441,28 +2591,28 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
if (CurrentPathRoute.PathType == NavisworksTransport.PathType.Hoisting)
|
||||
{
|
||||
// 吊装路径:通行空间四面都加检测间隙
|
||||
passageAcrossPath = VirtualVehicleLength + 2 * safetyMargin; // X方向(长度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VirtualVehicleWidth + 2 * safetyMargin; // Y方向(宽度)+ 2*间隙(法线方向)
|
||||
passageAcrossPath = effectiveLength + 2 * safetyMargin; // 旋转后长度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(法线方向)
|
||||
passageAlongPath = VirtualVehicleHeight + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 吊装路径使用虚拟车辆尺寸: X方向(长度)={VirtualVehicleLength:F2}m, Y方向(宽度)={VirtualVehicleWidth:F2}m, Z方向(高度)={VirtualVehicleHeight:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
LogManager.Info($"[通行空间可视化] 吊装路径使用虚拟车辆尺寸: 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 高度={VirtualVehicleHeight:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
else if (CurrentPathRoute.PathType == NavisworksTransport.PathType.Ground)
|
||||
{
|
||||
// 地面路径:物体的长度方向(X轴,前进方向)朝向路径方向
|
||||
// 通行空间沿路径方向 = X方向尺寸(长度),垂直于路径方向 = Y方向尺寸(宽度),高度上方加间隙(下方不需要,因为有地面)
|
||||
passageAcrossPath = VirtualVehicleWidth + 2 * safetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VirtualVehicleHeight + safetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方)
|
||||
passageAlongPath = VirtualVehicleLength; // X方向(长度,沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 地面路径使用虚拟车辆尺寸: X方向(长度)={VirtualVehicleLength:F2}m, Y方向(宽度)={VirtualVehicleWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 地面路径使用虚拟车辆尺寸: 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
else // Rail
|
||||
{
|
||||
// 空轨路径:物体的长度方向(X轴,前进方向)朝向路径方向
|
||||
// 通行空间沿路径方向 = X方向尺寸(长度),垂直于路径方向 = Y方向尺寸(宽度),高度上下都加间隙(在空中)
|
||||
passageAcrossPath = VirtualVehicleWidth + 2 * safetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = VirtualVehicleHeight + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向,上下都加)
|
||||
passageAlongPath = VirtualVehicleLength; // X方向(长度,沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 空轨路径使用虚拟车辆尺寸: X方向(长度)={VirtualVehicleLength:F2}m, Y方向(宽度)={VirtualVehicleWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 空轨路径使用虚拟车辆尺寸: 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
}
|
||||
else if (SelectedAnimatedObject != null)
|
||||
@ -2481,30 +2631,30 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
// 吊装路径(严格垂直路径):
|
||||
// 通行空间四面都加检测间隙
|
||||
passageAcrossPath = sizeX + 2 * safetyMargin; // X方向(长度)+ 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = sizeY + 2 * safetyMargin; // Y方向(宽度)+ 2*间隙(法线方向)
|
||||
passageAcrossPath = effectiveLength + 2 * safetyMargin; // 旋转后长度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(法线方向)
|
||||
passageAlongPath = sizeZ + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 吊装路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): X方向(长度)={sizeX:F2}m, Y方向(宽度)={sizeY:F2}m, Z方向(高度)={sizeZ:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
LogManager.Info($"[通行空间可视化] 吊装路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 高度={sizeZ:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
else if (CurrentPathRoute.PathType == NavisworksTransport.PathType.Ground)
|
||||
{
|
||||
// 地面路径(可能有坡度):
|
||||
// 物体的长度方向(X轴,前进方向)朝向路径方向
|
||||
// 通行空间沿路径方向 = X方向尺寸(长度),垂直于路径方向 = Y方向尺寸(宽度),高度上方加间隙(下方不需要,因为有地面)
|
||||
passageAcrossPath = sizeY + 2 * safetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = sizeZ + safetyMargin; // Z方向(高度)+ 间隙(法线方向,只有上方)
|
||||
passageAlongPath = sizeX; // X方向(长度,沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 地面路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): X方向(长度)={sizeX:F2}m, Y方向(宽度)={sizeY:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 地面路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
else // Rail
|
||||
{
|
||||
// 空轨路径(可能有坡度):
|
||||
// 物体的长度方向(X轴,前进方向)朝向路径方向
|
||||
// 通行空间沿路径方向 = X方向尺寸(长度),垂直于路径方向 = Y方向尺寸(宽度),高度上下都加间隙(在空中)
|
||||
passageAcrossPath = sizeY + 2 * safetyMargin; // Y方向(宽度)+ 2*间隙(垂直于路径方向)
|
||||
passageAcrossPath = effectiveWidth + 2 * safetyMargin; // 旋转后宽度 + 2*间隙(垂直于路径方向)
|
||||
passageNormalToPath = sizeZ + 2 * safetyMargin; // Z方向(高度)+ 2*间隙(法线方向,上下都加)
|
||||
passageAlongPath = sizeX; // X方向(长度,沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 空轨路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): X方向(长度)={sizeX:F2}m, Y方向(宽度)={sizeY:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
passageAlongPath = effectiveLength; // 旋转后长度(沿路径方向)
|
||||
LogManager.Info($"[通行空间可视化] 空轨路径使用物体尺寸 ({SelectedAnimatedObject.DisplayName}): 有效长度={effectiveLength:F2}m, 有效宽度={effectiveWidth:F2}m, 通行空间沿路径={passageAlongPath:F2}m, 垂直路径={passageAcrossPath:F2}m, 法线={passageNormalToPath:F2}m");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -258,6 +258,10 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
<Button Content="选择物体"
|
||||
Command="{Binding SelectAnimatedObjectCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"/>
|
||||
<Button Content="调整角度"
|
||||
Command="{Binding EditObjectRotationCommand}"
|
||||
IsEnabled="{Binding HasSelectedAnimatedObject}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"/>
|
||||
<Button Content="清除"
|
||||
Command="{Binding ClearAnimatedObjectCommand}"
|
||||
IsEnabled="{Binding HasSelectedAnimatedObject}"
|
||||
@ -273,6 +277,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Label Grid.Column="0" Content="虚拟车辆:" Style="{StaticResource ParameterLabelStyle}"/>
|
||||
@ -289,6 +294,11 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
|
||||
<Run Text="{Binding VirtualVehicleHeight, StringFormat=F1, Mode=OneWay}"/>
|
||||
<Run Text="m"/>
|
||||
</TextBlock>
|
||||
<Button Grid.Column="2"
|
||||
Content="调整角度"
|
||||
Command="{Binding EditObjectRotationCommand}"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Margin="10,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 虚拟车辆提示 -->
|
||||
|
||||
112
src/UI/WPF/Views/EditRotationWindow.xaml
Normal file
112
src/UI/WPF/Views/EditRotationWindow.xaml
Normal file
@ -0,0 +1,112 @@
|
||||
<Window x:Class="NavisworksTransport.UI.WPF.Views.EditRotationWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="调整物体角度" Height="320" Width="400"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ResizeMode="NoResize"
|
||||
ShowInTaskbar="False"
|
||||
Topmost="True"
|
||||
Background="White">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/NavisworksTransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 标题栏 -->
|
||||
<Border Grid.Row="0" Background="#FFF8FBFF" BorderBrush="#FFD4E7FF" BorderThickness="0,0,0,1" Padding="20,15">
|
||||
<StackPanel>
|
||||
<TextBlock Text="调整物体角度" FontWeight="SemiBold" FontSize="14" Foreground="#FF2B579A"/>
|
||||
<TextBlock Text="调整物体在路径起点时的水平旋转角度(顺时针)" FontSize="10" Foreground="#FF666666" Margin="0,3,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 输入区域 -->
|
||||
<Border Grid.Row="1" Padding="20,15">
|
||||
<StackPanel>
|
||||
<!-- 角度输入 -->
|
||||
<Grid Margin="0,0,0,12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="80"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Text="旋转角度:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/>
|
||||
<TextBox Grid.Column="1"
|
||||
Text="{Binding RotationAngle, StringFormat=0.0, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="28"
|
||||
VerticalContentAlignment="Center"
|
||||
Padding="8,0"
|
||||
FontSize="11"
|
||||
BorderBrush="#FFCCCCCC"
|
||||
BorderThickness="1"/>
|
||||
<TextBlock Grid.Column="2" Text="°" VerticalAlignment="Center" FontSize="11" Foreground="#FF666666" Margin="8,0,0,0"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 快捷按钮 -->
|
||||
<TextBlock Text="快捷角度:" FontSize="10" Foreground="#FF666666" Margin="0,0,0,8"/>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="0°"
|
||||
Click="OnQuickAngleClick"
|
||||
Tag="0"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="70"
|
||||
Height="28"
|
||||
Margin="0,0,8,0"/>
|
||||
<Button Content="90°"
|
||||
Click="OnQuickAngleClick"
|
||||
Tag="90"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="70"
|
||||
Height="28"
|
||||
Margin="0,0,8,0"/>
|
||||
<Button Content="180°"
|
||||
Click="OnQuickAngleClick"
|
||||
Tag="180"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="70"
|
||||
Height="28"
|
||||
Margin="0,0,8,0"/>
|
||||
<Button Content="270°"
|
||||
Click="OnQuickAngleClick"
|
||||
Tag="270"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="70"
|
||||
Height="28"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- 按钮栏 -->
|
||||
<Border Grid.Row="2" Background="#FFF8FBFF" BorderBrush="#FFD4E7FF" BorderThickness="0,1,0,0" Padding="20,12">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="恢复初始值"
|
||||
Click="OnResetClick"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="90"
|
||||
Height="32"
|
||||
Margin="0,0,10,0"/>
|
||||
<Button Content="确认"
|
||||
Click="OnConfirmClick"
|
||||
Style="{StaticResource ActionButtonStyle}"
|
||||
Width="90"
|
||||
Height="32"
|
||||
Margin="0,0,10,0"/>
|
||||
<Button Content="取消"
|
||||
Click="OnCancelClick"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Width="90"
|
||||
Height="32"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
92
src/UI/WPF/Views/EditRotationWindow.xaml.cs
Normal file
92
src/UI/WPF/Views/EditRotationWindow.xaml.cs
Normal file
@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using NavisworksTransport.Utils;
|
||||
|
||||
namespace NavisworksTransport.UI.WPF.Views
|
||||
{
|
||||
public partial class EditRotationWindow : Window, INotifyPropertyChanged
|
||||
{
|
||||
private double _rotationAngle;
|
||||
|
||||
public double RotationAngle
|
||||
{
|
||||
get => _rotationAngle;
|
||||
set
|
||||
{
|
||||
if (_rotationAngle != value)
|
||||
{
|
||||
_rotationAngle = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EditRotationWindow(double currentAngle)
|
||||
{
|
||||
try
|
||||
{
|
||||
InitializeComponent();
|
||||
RotationAngle = currentAngle;
|
||||
DataContext = this;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"角度修正对话框初始化失败: {ex.Message}", ex);
|
||||
MessageBox.Show($"角度修正对话框初始化失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnQuickAngleClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is System.Windows.Controls.Button button)
|
||||
{
|
||||
LogManager.Debug($"[快捷角度] 点击按钮: {button.Content}, Tag类型: {button.Tag?.GetType()}, Tag值: {button.Tag}");
|
||||
|
||||
if (button.Tag != null)
|
||||
{
|
||||
if (button.Tag is int intTag)
|
||||
{
|
||||
RotationAngle = intTag;
|
||||
LogManager.Debug($"[快捷角度] 设置角度为: {intTag}°");
|
||||
}
|
||||
else if (button.Tag is string stringTag && double.TryParse(stringTag, out double angle))
|
||||
{
|
||||
RotationAngle = angle;
|
||||
LogManager.Debug($"[快捷角度] 设置角度为: {angle}°");
|
||||
}
|
||||
else if (button.Tag is double doubleTag)
|
||||
{
|
||||
RotationAngle = doubleTag;
|
||||
LogManager.Debug($"[快捷角度] 设置角度为: {doubleTag}°");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnResetClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RotationAngle = 0.0;
|
||||
}
|
||||
|
||||
private void OnConfirmClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnCancelClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user