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 _autoAdjustmentProvider; private readonly Func _alignToGroundProvider; private readonly bool _isGroundLiftEnabled; private double _vehicleHeightInMeters = 0.15; private bool _requireWidthLarger = false; private bool _isAlignToGroundResult; private bool _alignToGroundRequested = false; /// /// 门型偏好:true=宽>高,false=高>宽(默认) /// 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 autoAdjustmentProvider = null, Func 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; } } }