NavisworksTransport/src/UI/WPF/Views/EditRotationWindow.xaml.cs

431 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using NavisworksTransport.UI.WPF.Converters;
using NavisworksTransport.Utils;
using NavisworksTransport.Utils.CoordinateSystem;
using System.Numerics;
namespace NavisworksTransport.UI.WPF.Views
{
public partial class EditRotationWindow : Window, INotifyPropertyChanged
{
private enum RotationAxisTarget
{
X,
Y,
Z
}
private double _rotationXDegrees;
private double _rotationYDegrees;
private double _rotationZDegrees;
private double _groundPathLiftHeightInMeters;
private RotationAxisTarget _activeAxisTarget = RotationAxisTarget.Z;
private ObjectStartPlacementRequest _adjustmentRequest;
private readonly ObjectPassageProjectionOptimizationRequest _autoAdjustmentRequest;
private readonly Func<ObjectPassageProjectionOptimizationResult> _autoAdjustmentProvider;
private readonly Func<Vector3, ObjectPassageProjectionOptimizationResult> _alignToGroundProvider;
private readonly bool _isGroundLiftEnabled;
private double _vehicleHeightInMeters = 0.15;
private bool _requireWidthLarger = false;
private bool _isAlignToGroundResult;
private bool _alignToGroundRequested = false;
/// <summary>
/// 门型偏好true=宽>高false=高>宽(默认)
/// </summary>
public bool RequireWidthLarger
{
get => _requireWidthLarger;
set => _requireWidthLarger = value;
}
public (double sx, double sy, double sz)? AutoAdjustAabbSizes { get; set; }
public bool AlignToGroundRequested => _alignToGroundRequested;
public bool IsAlignToGroundResult { get => _isAlignToGroundResult; set => _isAlignToGroundResult = value; }
public double VehicleHeightInMeters
{
get => _vehicleHeightInMeters;
set => _vehicleHeightInMeters = value;
}
public double RotationXDegrees
{
get => _rotationXDegrees;
set
{
if (_rotationXDegrees != value)
{
_rotationXDegrees = value;
OnPropertyChanged();
OnPropertyChanged(nameof(RotationCorrection));
}
}
}
public double RotationYDegrees
{
get => _rotationYDegrees;
set
{
if (_rotationYDegrees != value)
{
_rotationYDegrees = value;
OnPropertyChanged();
OnPropertyChanged(nameof(RotationCorrection));
}
}
}
public double RotationZDegrees
{
get => _rotationZDegrees;
set
{
if (_rotationZDegrees != value)
{
_rotationZDegrees = value;
OnPropertyChanged();
OnPropertyChanged(nameof(RotationCorrection));
}
}
}
public LocalEulerRotationCorrection RotationCorrection =>
new LocalEulerRotationCorrection(RotationXDegrees, RotationYDegrees, RotationZDegrees);
public double GroundPathLiftHeightInMeters
{
get => _groundPathLiftHeightInMeters;
set
{
if (Math.Abs(_groundPathLiftHeightInMeters - value) > 1e-9)
{
_groundPathLiftHeightInMeters = value;
OnPropertyChanged();
}
}
}
public bool IsGroundLiftEnabled => _isGroundLiftEnabled;
public string GroundLiftHint => _isGroundLiftEnabled
? "仅地面路径生效,正值向上偏移,负值向下偏移。"
: "上下偏移当前仅对地面路径生效。";
public ObjectStartPlacementRequest AdjustmentRequest => _adjustmentRequest;
public EditRotationWindow(
LocalEulerRotationCorrection currentRotation,
double currentGroundLiftHeightInMeters,
bool isGroundLiftEnabled,
ObjectPassageProjectionOptimizationRequest autoAdjustmentRequest = null,
Func<ObjectPassageProjectionOptimizationResult> autoAdjustmentProvider = null,
Func<Vector3, ObjectPassageProjectionOptimizationResult> alignToGroundProvider = null)
{
try
{
InitializeComponent();
RotationXDegrees = currentRotation.XDegrees;
RotationYDegrees = currentRotation.YDegrees;
RotationZDegrees = currentRotation.ZDegrees;
_isGroundLiftEnabled = isGroundLiftEnabled;
_autoAdjustmentRequest = autoAdjustmentRequest;
_autoAdjustmentProvider = autoAdjustmentProvider;
_alignToGroundProvider = alignToGroundProvider;
// 默认上下偏移 = 物流车高度(若未设置过)
GroundPathLiftHeightInMeters = Math.Abs(currentGroundLiftHeightInMeters) < 1e-9
? VehicleHeightInMeters
: currentGroundLiftHeightInMeters;
_adjustmentRequest = ObjectStartPlacementRequest.CreateRotationCorrection(currentRotation, currentGroundLiftHeightInMeters);
DataContext = this;
Loaded += (sender, args) => ZAxisTextBox.Focus();
}
catch (Exception ex)
{
LogManager.Error($"角度修正对话框初始化失败: {ex.Message}", ex);
MessageBox.Show($"角度修正对话框初始化失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void OnYAxisRotateClick(object sender, RoutedEventArgs e)
{
double newValue = RotationYDegrees + 90.0;
RotationYDegrees = NormalizeDisplayDegrees(newValue);
YAxisTextBox.Focus();
YAxisTextBox.SelectAll();
LogManager.Debug($"[Y轴旋转] 增加 90°: {newValue:F3} → {RotationYDegrees:F3}");
}
private void OnAutoAdjustClick(object sender, RoutedEventArgs e)
{
if (_autoAdjustmentProvider == null && _autoAdjustmentRequest == null)
{
MessageBox.Show("当前路径或物体尺寸不足,无法自动调整。", "自动调整", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
// 同步门型偏好和车辆高度到请求
if (_autoAdjustmentRequest != null)
{
_autoAdjustmentRequest.RequireWidthLarger = _requireWidthLarger;
_autoAdjustmentRequest.VehicleHeightModelUnits =
UnitsConverter.ConvertFromMeters(_vehicleHeightInMeters);
}
var oldCursor = System.Windows.Input.Mouse.OverrideCursor;
try
{
System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
ObjectPassageProjectionOptimizationResult result = _autoAdjustmentProvider != null
? _autoAdjustmentProvider()
: ObjectPassageProjectionOptimizer.Optimize(_autoAdjustmentRequest);
if (!result.Success)
{
MessageBox.Show(result.ErrorMessage ?? "自动调整失败。", "自动调整", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
RotationXDegrees = NormalizeDisplayDegrees(result.Correction.XDegrees);
RotationYDegrees = NormalizeDisplayDegrees(result.Correction.YDegrees);
RotationZDegrees = NormalizeDisplayDegrees(result.Correction.ZDegrees);
if (result.ComputedLiftOffsetModelUnits.HasValue)
{
GroundPathLiftHeightInMeters = Math.Round(UnitsConverter.ConvertToMeters(result.ComputedLiftOffsetModelUnits.Value), 3);
}
if (result.AabbSx.HasValue)
AutoAdjustAabbSizes = (result.AabbSx.Value, result.AabbSy.Value, result.AabbSz.Value);
LogManager.Debug(
$"[自动调整] 已写入角度: {RotationCorrection}, " +
$"截面宽度={result.Score.WidthAcrossPath:F3}, 高度={result.Score.HeightAlongHostUp:F3}, 面积={result.Score.Area:F3}");
}
finally
{
System.Windows.Input.Mouse.OverrideCursor = oldCursor;
}
}
private void OnAlignToGroundClick(object sender, RoutedEventArgs e)
{
LogManager.Info($"[贴合地面] 按钮被点击, provider={_alignToGroundProvider != null}");
if (_alignToGroundProvider == null)
{
MessageBox.Show("当前无法使用贴合地面功能。", "贴合地面", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
_alignToGroundRequested = true;
TryCommitInputValues();
_adjustmentRequest = ObjectStartPlacementRequest.CreateTranslationOnly(GroundPathLiftHeightInMeters);
DialogResult = false;
Close();
}
private void OnQuickAngleClick(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
LogManager.Debug($"[快捷角度] 点击按钮: {button.Content}, Tag类型: {button.Tag?.GetType()}, Tag值: {button.Tag}");
if (button.Tag != null)
{
double? parsedAngle = null;
if (button.Tag is int intTag)
{
parsedAngle = intTag;
}
else if (button.Tag is string stringTag && double.TryParse(stringTag, out double angle))
{
parsedAngle = angle;
}
else if (button.Tag is double doubleTag)
{
parsedAngle = doubleTag;
}
if (parsedAngle.HasValue)
{
ApplyQuickAngle(parsedAngle.Value);
LogManager.Debug($"[快捷角度] 设置 {_activeAxisTarget} 轴角度为: {parsedAngle.Value}°");
}
}
}
}
private void OnAxisTextBoxGotFocus(object sender, RoutedEventArgs e)
{
if (ReferenceEquals(sender, XAxisTextBox))
{
_activeAxisTarget = RotationAxisTarget.X;
return;
}
if (ReferenceEquals(sender, YAxisTextBox))
{
_activeAxisTarget = RotationAxisTarget.Y;
return;
}
_activeAxisTarget = RotationAxisTarget.Z;
}
private void OnResetClick(object sender, RoutedEventArgs e)
{
RotationXDegrees = 0.0;
RotationYDegrees = 0.0;
RotationZDegrees = 0.0;
}
private void OnConfirmClick(object sender, RoutedEventArgs e)
{
if (!TryCommitInputValues())
{
return;
}
_adjustmentRequest = ObjectStartPlacementRequest.CreateRotationCorrection(RotationCorrection, GroundPathLiftHeightInMeters);
DialogResult = true;
Close();
}
private void OnTranslateClick(object sender, RoutedEventArgs e)
{
if (!TryCommitInputValues())
{
return;
}
_adjustmentRequest = ObjectStartPlacementRequest.CreateTranslationOnly(GroundPathLiftHeightInMeters);
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));
}
private void ApplyQuickAngle(double angle)
{
switch (_activeAxisTarget)
{
case RotationAxisTarget.X:
RotationXDegrees = angle;
break;
case RotationAxisTarget.Y:
RotationYDegrees = angle;
break;
case RotationAxisTarget.Z:
default:
RotationZDegrees = angle;
break;
}
}
private bool TryCommitInputValues()
{
if (!TryUpdateNumberTextBox(XAxisTextBox, "请输入有效的 X 轴角度。"))
{
return false;
}
if (!TryUpdateNumberTextBox(YAxisTextBox, "请输入有效的 Y 轴角度。"))
{
return false;
}
if (!TryUpdateNumberTextBox(ZAxisTextBox, "请输入有效的 Z 轴角度。"))
{
return false;
}
if (!TryUpdateNumberTextBox(GroundLiftTextBox, "请输入有效的上下偏移值。"))
{
return false;
}
if (!TryUpdateNumberTextBox(VehicleHeightTextBox, "请输入有效的物流车高度。"))
{
return false;
}
if (VehicleHeightInMeters < 0.0)
{
ShowInputError("物流车高度必须大于或等于 0。", VehicleHeightTextBox);
return false;
}
return true;
}
private static bool TryUpdateNumberTextBox(TextBox textBox, string message)
{
BindingExpression binding = textBox.GetBindingExpression(TextBox.TextProperty);
if (EditableNumberConverter.IsIntermediateText(textBox.Text))
{
ShowInputError(message, textBox);
return false;
}
if (!EditableNumberConverter.TryParseNumber(textBox.Text.Trim(), System.Globalization.CultureInfo.CurrentCulture, typeof(double), out _))
{
ShowInputError(message, textBox);
return false;
}
try
{
binding?.UpdateSource();
}
catch (Exception)
{
ShowInputError(message, textBox);
return false;
}
if (Validation.GetHasError(textBox))
{
ShowInputError(message, textBox);
return false;
}
return true;
}
private static void ShowInputError(string message, TextBox textBox)
{
MessageBox.Show(message, "输入错误", MessageBoxButton.OK, MessageBoxImage.Warning);
textBox.Focus();
textBox.SelectAll();
}
private static double NormalizeDisplayDegrees(double degrees)
{
double normalized = degrees % 360.0;
if (normalized < 0.0)
{
normalized += 360.0;
}
return Math.Abs(normalized) < 1e-9 ? 0.0 : normalized;
}
}
}