对代码进行审查并优化

This commit is contained in:
tian 2026-02-16 11:55:45 +08:00
parent 2fb883ae18
commit 178aa995ff
33 changed files with 310 additions and 69 deletions

115
AGENTS.md
View File

@ -217,6 +217,121 @@ using NavisworksTransport.Utils;
| 常量 | PascalCase | `MaxHeightDiff` |
| 枚举 | PascalCase | `GridGenerationMode` |
### 代码开发原则
#### 1. 禁止硬编码默认值
函数的参数和初始化时不要使用硬编码的默认值,应从配置读取或使用命名常量:
```csharp
// ❌ 错误:硬编码默认值
public GridMap Generate(double cellSize = 0.5) { }
// ❌ 错误:构造函数中硬编码
public PathPlanner() {
_cellSize = 0.5;
_maxSlope = 15.0;
}
// ✅ 正确:从配置读取
public GridMap Generate(double cellSize) {
cellSize = cellSize > 0 ? cellSize : ConfigManager.Instance.Current.PathEditing.CellSizeMeters;
// ...
}
// ✅ 正确:使用命名常量
private const double DEFAULT_CELL_SIZE_METERS = 0.5;
public PathPlanner(double cellSize = DEFAULT_CELL_SIZE_METERS) { }
```
#### 2. 不向后兼容
本项目专门针对 Navisworks 2026 开发,**程序中不要写向后兼容代码**
```csharp
// ❌ 错误:向后兼容代码
#if NAVISWORKS_2025
// 2025 specific code
#elif NAVISWORKS_2026
// 2026 specific code
#endif
// ❌ 错误:运行时版本检查
if (NavisworksVersion.Major < 2026) {
// 兼容旧版本的代码
}
// ✅ 正确直接针对2026编写
var clashResult = Autodesk.Navisworks.Api.Clash.ClashResult.GetAllResults();
```
#### 3. 不随意加回退逻辑
程序中不要随意加回退逻辑,避免过度防御性编程导致隐藏问题:
```csharp
// ❌ 错误:过度回退逻辑
public double GetCellSize() {
try {
return ConfigManager.Instance.Current.PathEditing.CellSizeMeters;
}
catch {
return 0.5; // 隐藏了配置读取失败的问题!
}
}
// ❌ 错误:静默回退
double value = GetConfigValue("cellSize");
if (value <= 0) value = 0.5; // 为什么<=0配置验证应该保证这一点
// ✅ 正确:让问题暴露出来
public double GetCellSize() {
return ConfigManager.Instance.Current.PathEditing.CellSizeMeters;
// 如果配置有问题,让它抛出异常,在源头解决
}
```
#### 4. 代码复用优先
规划和编写新功能或新模块时,**尽量复用项目中的代码,尤其是工具和辅助类**
```csharp
// ❌ 错误:重复造轮子
public static double MyConvertUnits(double value) {
// 自己写一套单位转换逻辑...
}
// ✅ 正确:复用现有的 UnitsConverter
using NavisworksTransport.Utils;
double meters = UnitsConverter.ConvertToMeters(distance);
// ❌ 错误:自己实现集合通知
public class MyCollection : ObservableCollection<T> {
// 重写一大堆线程安全代码...
}
// ✅ 正确:复用 ThreadSafeObservableCollection
using NavisworksTransport.UI.WPF.Collections;
var collection = new ThreadSafeObservableCollection<Item>();
// ❌ 错误:自己写几何计算
public double Distance(Point3D a, Point3D b) {
return Math.Sqrt(Math.Pow(a.X - b.X, 2) + ...);
}
// ✅ 正确:复用 GeometryHelper
using NavisworksTransport.Utils;
double distance = GeometryHelper.Distance(pointA, pointB);
```
**复用检查清单:**
- 需要单位转换?→ 使用 `UnitsConverter`
- 需要几何计算?→ 使用 `GeometryHelper`
- 需要日志记录?→ 使用 `LogManager`
- 需要线程安全的集合?→ 使用 `ThreadSafeObservableCollection`
- 需要坐标转换?→ 使用 `CoordinateConverter`
- 需要路径相关工具?→ 使用 `PathHelper`
### 单位系统 - 极其重要
**所有网格地图和路径规划计算必须使用模型单位,严禁混用米制单位。**

View File

@ -628,7 +628,10 @@ namespace NavisworksTransport
var pathId = doc.Models.CreatePathId(precomputed.Item2);
precomputedPathIds.Add((pathId.ModelIndex, pathId.PathId));
}
catch { /* 忽略获取PathId失败的记录 */ }
catch (Exception ex)
{
LogManager.Warning($"[PathId匹配] 获取PathId失败: {ex.Message}");
}
}
}

View File

@ -898,6 +898,29 @@ namespace NavisworksTransport.Core.Config
return defaultValue;
}
/// <summary>
/// 获取 float 配置值(带默认值,不抛出异常)
/// </summary>
private float GetFloatValueWithDefault(TomlTable table, string key, float defaultValue, List<string> missingItems)
{
if (!table.ContainsKey(key))
{
missingItems.Add($"{key}");
LogManager.Debug($"配置项 '{key}' 不存在,使用默认值: {defaultValue}");
return defaultValue;
}
var value = table[key];
if (value is long longValue)
return (float)longValue;
if (value is double doubleValue)
return (float)doubleValue;
missingItems.Add($"{key} (类型错误)");
LogManager.Warning($"配置项 '{key}' 类型错误,使用默认值: {defaultValue}");
return defaultValue;
}
/// <summary>
/// 获取 int 配置值(带默认值,不抛出异常)
/// </summary>

View File

@ -200,7 +200,12 @@ namespace NavisworksTransport.Core.Database
finally
{
// 重新打开连接
try { _database.Connection.Open(); } catch { }
try { _database.Connection.Open(); }
catch (Exception ex)
{
LogManager.Error($"[数据库恢复] 重新打开连接失败: {ex.Message}");
throw;
}
}
LogManager.Info($"数据库恢复完成: {backupFilePath}");

View File

@ -237,7 +237,10 @@ namespace NavisworksTransport.Core
return true;
}
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[楼层管理器] 检查类别失败: {ex.Message}");
}
return false;
}

View File

@ -1216,7 +1216,10 @@ namespace NavisworksTransport
fileSizeInfo = $" ({sizeMB:F1}MB)";
}
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[分层管理器] 获取文件大小失败: {ex.Message}");
}
// 更新状态:导出成功
string successProgressInfo = (currentIndex > 0 && totalCount > 0) ? $" ({currentIndex}/{totalCount})" : "";

View File

@ -1015,7 +1015,10 @@ namespace NavisworksTransport
{
ExecuteNonQuery("DELETE FROM sqlite_sequence");
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[数据库] 重置自增ID失败: {ex.Message}");
}
LogManager.Info("已清空所有数据表");
}

View File

@ -1463,7 +1463,10 @@ namespace NavisworksTransport
// 这里可以添加更详细的属性读取逻辑
}
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[通道列表] 获取物流属性失败: {ex.Message}");
}
// 获取尺寸信息
double length = 0, width = 0, height = 0;
@ -1477,7 +1480,10 @@ namespace NavisworksTransport
height = Math.Abs(boundingBox.Max.Z - boundingBox.Min.Z);
}
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[通道列表] 获取包围盒失败: {ex.Message}");
}
// 添加子项
item.SubItems.Add(channelType);
@ -1601,7 +1607,10 @@ namespace NavisworksTransport
{
ModelHighlightHelper.ClearCategory(ChannelPreviewHighlightCategory);
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[通道预览] 清除高亮失败: {ex.Message}");
}
}
catch (Exception ex)
{
@ -2456,7 +2465,10 @@ namespace NavisworksTransport
if (content.StartsWith("{") && content.EndsWith("}"))
return "JSON";
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[路径格式检测] 读取文件失败: {ex.Message}");
}
return "未知";
}
}

View File

@ -72,6 +72,31 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class AutoPathFinder
{
/// <summary>
/// 缓坡速度系数 - 当坡度在 3cm 到 25cm 之间时使用
/// </summary>
private const float SLOPE_SPEED_FACTOR_GENTLE = 0.8f;
/// <summary>
/// 楼梯速度系数 - 当坡度在 25cm 到 50cm 之间时使用
/// </summary>
private const float SLOPE_SPEED_FACTOR_STAIR = 0.5f;
/// <summary>
/// 陡坡速度系数 - 当坡度超过 50cm 时使用
/// </summary>
private const float SLOPE_SPEED_FACTOR_STEEP = 0.1f;
/// <summary>
/// A*高度惩罚因子 - 用于计算距离目标高度的速度扣减
/// </summary>
private const double HEIGHT_PENALTY_FACTOR = 0.1;
/// <summary>
/// 转弯角度阈值(弧度)- 用于检测路径转弯
/// </summary>
private const double TURN_ANGLE_THRESHOLD_RADIANS = 0.1;
/// <summary>
/// 获取水平边连接允许的最大高度差(米)
/// 从配置文件读取足以支持台阶连接约0.15米和地面到楼梯底部的连接约0.3米)
@ -382,9 +407,9 @@ namespace NavisworksTransport.PathPlanning
double heightRatio = heightDiff / maxHeightDiff;
if (heightRatio < 0.06) return (float)baseSpeed; // 平地 (<3cm即<0.06*0.5m)
if (heightRatio <= 0.5) return (float)(baseSpeed * 0.8); // 缓坡 (≤0.25m)
if (heightRatio <= 1.0) return (float)(baseSpeed * 0.5); // 楼梯 (≤0.5m)
return (float)(baseSpeed * 0.1); // 过陡 (>0.5m)
if (heightRatio <= 0.5) return (float)(baseSpeed * SLOPE_SPEED_FACTOR_GENTLE); // 缓坡 (≤0.25m)
if (heightRatio <= 1.0) return (float)(baseSpeed * SLOPE_SPEED_FACTOR_STAIR); // 楼梯 (≤0.5m)
return (float)(baseSpeed * SLOPE_SPEED_FACTOR_STEEP); // 过陡 (>0.5m)
}
/// <summary>
@ -1404,8 +1429,7 @@ namespace NavisworksTransport.PathPlanning
// 距离目标高度越近速度越快A*成本越低)
// 公式:速度 = 1 / (1 + 距离 * 惩罚系数)
// 例如距离0m → 速度1.0x, 距离3m → 速度0.77x, 距离6m → 速度0.625x
const double penaltyFactor = 0.1;
return (float)(1.0 / (1.0 + distanceToTarget * penaltyFactor));
return (float)(1.0 / (1.0 + distanceToTarget * HEIGHT_PENALTY_FACTOR));
}
/// <summary>
@ -1962,7 +1986,7 @@ namespace NavisworksTransport.PathPlanning
return 0;
int turns = 0;
const double angleThreshold = 0.1; // 弧度
const double angleThreshold = TURN_ANGLE_THRESHOLD_RADIANS; // 弧度
for (int i = 1; i < path.Count - 1; i++)
{

View File

@ -14,6 +14,11 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class ChannelHeightDetector
{
/// <summary>
/// 默认射线投射容差(米)- 与配置中的安全间隙一致
/// </summary>
private const double DEFAULT_RAYCAST_TOLERANCE_METERS = 0.1;
/// <summary>
/// 当前使用的坐标系
/// </summary>
@ -25,7 +30,7 @@ namespace NavisworksTransport.PathPlanning
/// 构造函数(自动使用当前坐标系)
/// </summary>
/// <param name="raycastTolerance">射线投射容差(米)</param>
public ChannelHeightDetector(double raycastTolerance = 0.1)
public ChannelHeightDetector(double raycastTolerance = DEFAULT_RAYCAST_TOLERANCE_METERS)
: this(CoordinateSystemManager.Instance.Current, raycastTolerance)
{
}
@ -35,7 +40,7 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
/// <param name="coordinateSystem">坐标系</param>
/// <param name="raycastTolerance">射线投射容差(米)</param>
public ChannelHeightDetector(ICoordinateSystem coordinateSystem, double raycastTolerance = 0.1)
public ChannelHeightDetector(ICoordinateSystem coordinateSystem, double raycastTolerance = DEFAULT_RAYCAST_TOLERANCE_METERS)
{
_coordinateSystem = coordinateSystem ?? throw new ArgumentNullException(nameof(coordinateSystem));
_heightCache = new Dictionary<string, ChannelHeightInfo>();

View File

@ -13,6 +13,11 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class GridMap
{
/// <summary>
/// 默认高度层查找容差(米)- 与配置中的安全间隙一致
/// </summary>
private const double DEFAULT_LAYER_TOLERANCE_METERS = 0.1;
/// <summary>
/// 当前使用的坐标系
/// </summary>
@ -339,7 +344,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="z">Z坐标</param>
/// <param name="tolerance">容差默认0.1m</param>
/// <returns>符合条件的高度层如果没有则返回null</returns>
public HeightLayer? FindLayerContainingZ(GridPoint2D gridPosition, double z, double tolerance = 0.1)
public HeightLayer? FindLayerContainingZ(GridPoint2D gridPosition, double z, double tolerance = DEFAULT_LAYER_TOLERANCE_METERS)
{
if (!IsValidGridPosition(gridPosition))
return null;
@ -436,7 +441,7 @@ namespace NavisworksTransport.PathPlanning
/// <param name="zCoord">Z坐标模型单位</param>
/// <param name="tolerance">Z坐标容差模型单位默认0.1</param>
/// <returns>是否可通行</returns>
public bool IsPassableAt3DPoint(GridPoint2D gridPosition, double zCoord, double tolerance = 0.1)
public bool IsPassableAt3DPoint(GridPoint2D gridPosition, double zCoord, double tolerance = DEFAULT_LAYER_TOLERANCE_METERS)
{
if (!IsValidGridPosition(gridPosition))
return false;

View File

@ -11,6 +11,16 @@ namespace NavisworksTransport.PathPlanning
/// </summary>
public class PathOptimizer
{
/// <summary>
/// 共线检测容差(米)
/// </summary>
private const double COLLINEAR_TOLERANCE_METERS = 0.1;
/// <summary>
/// 重复点检测容差(米)- 用于检测坐标完全相同的点
/// </summary>
private const double DUPLICATE_POINT_TOLERANCE_METERS = 0.001;
/// <summary>
/// 路径优化配置参数
/// </summary>
@ -387,7 +397,7 @@ namespace NavisworksTransport.PathPlanning
/// <returns>如果三点在同一直线上且方向一致返回true</returns>
private bool IsCollinear(Point3D p1, Point3D p2, Point3D p3)
{
const double tolerance = 0.1; // 容差值,单位:模型单位
const double tolerance = COLLINEAR_TOLERANCE_METERS; // 容差值,单位:模型单位
// 🔥 修复:使用统一的高度检查函数
if (HasHeightChange(p1, p2, p3))
@ -406,7 +416,7 @@ namespace NavisworksTransport.PathPlanning
double dy23 = p3.Y - p2.Y;
// 🔥 修复:使用更严格的容差检查真正的重复点(坐标完全相同)
const double duplicatePointTolerance = 0.001; // 用很小的值检查真正的重复点
const double duplicatePointTolerance = DUPLICATE_POINT_TOLERANCE_METERS; // 用很小的值检查真正的重复点
bool isSegment1Zero = Math.Abs(dx12) < duplicatePointTolerance && Math.Abs(dy12) < duplicatePointTolerance;
bool isSegment2Zero = Math.Abs(dx23) < duplicatePointTolerance && Math.Abs(dy23) < duplicatePointTolerance;

View File

@ -50,7 +50,9 @@ namespace NavisworksTransport.PathPlanning
LogManager.Info($"[空间哈希] 开始构建空间索引:{triangles.Count} 个三角形");
_totalTriangles = triangles.Count;
_cellSize = Math.Max(gridSize * 2, 0.1); // 使用稍大的单元格减少重复
if (gridSize <= 0)
throw new ArgumentException("gridSize 必须大于0", nameof(gridSize));
_cellSize = gridSize * 2; // 使用稍大的单元格减少重复
_spatialHash.Clear();
// 计算或使用提供的边界框

View File

@ -4,6 +4,7 @@ using System.Diagnostics;
using System.Linq;
using Autodesk.Navisworks.Api;
using NavisworksTransport.Utils;
using NavisworksTransport.Core.Config;
using static NavisworksTransport.CategoryAttributeManager;
using g4;
@ -340,7 +341,7 @@ namespace NavisworksTransport.PathPlanning
new Point3D(10 * metersToModelUnits, 10 * metersToModelUnits, 3 * metersToModelUnits)
);
double voxelSize = 0.5 * metersToModelUnits; // 0.5米体素
double voxelSize = ConfigManager.Instance.Current.PathEditing.CellSizeMeters * metersToModelUnits; // 使用配置的网格大小作为体素大小
var grid = new VoxelGrid(bounds, voxelSize);

View File

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using NavisworksTransport.Core.Models;
@ -37,7 +38,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
@ -30,7 +31,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace NavisworksTransport.UI.WPF.Converters
@ -22,7 +23,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
}

View File

@ -94,7 +94,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("IsNotNullToBoolConverter不支持反向转换");
return Binding.DoNothing;
}
}
}

View File

@ -56,7 +56,7 @@ namespace NavisworksTransport.UI.WPF.Converters
/// </summary>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("CountToVisibilityConverter不支持反向转换");
return Binding.DoNothing;
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
@ -26,7 +27,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Globalization;
using System.IO;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;
@ -36,7 +37,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace NavisworksTransport.UI.WPF.Converters
@ -30,7 +31,7 @@ namespace NavisworksTransport.UI.WPF.Converters
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
}

View File

@ -2820,7 +2820,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
if (volume > 1000) // 大于1000立方米
return "大型物体 - 包围盒很大,容易与路径相交";
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[碰撞分析] 获取物体包围盒失败: {ex.Message}");
}
return "未知原因 - 建议手动检查";
}

View File

@ -87,10 +87,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private bool _showControlVisualization = true; // 默认显示控制点连线
private bool _showPathLines = true; // 默认显示路径线(地面连线)
private bool _showObjectSpace = false; // 默认不显示通行空间
// 兼容旧代码的互斥属性(已废弃,使用独立开关)
private bool _isStandardLineMode = false;
private bool _isRibbonLineMode = true;
private bool _isObjectSpaceMode = false;
// 渲染模式已改为独立开关_showControlVisualization, _showPathLines, _showObjectSpace
// 下面的互斥属性已废弃并删除
// 路径策略参数
private PathStrategyOption _selectedPathStrategy;

View File

@ -1746,7 +1746,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
}
catch { }
catch (Exception ex)
{
LogManager.Warning($"[坐标系探索] 设置视图状态失败: {ex.Message}");
}
resultDialog.ShowDialog();

View File

@ -1,3 +1,4 @@
using System;
using System.Windows;
namespace NavisworksTransport.UI.WPF.Views
@ -68,7 +69,10 @@ namespace NavisworksTransport.UI.WPF.Views
{
dialog.Owner = System.Windows.Application.Current?.MainWindow;
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[坐标系对话框] 设置Owner失败: {ex.Message}");
}
}
dialog.ShowDialog();

View File

@ -198,7 +198,10 @@ namespace NavisworksTransport.UI.WPF.Views
System.Windows.Clipboard.SetText(coordinate);
ShowButtonFeedback(CopyCenterButton);
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[坐标窗口] 复制到剪贴板失败: {ex.Message}");
}
}
/// <summary>
@ -212,7 +215,10 @@ namespace NavisworksTransport.UI.WPF.Views
System.Windows.Clipboard.SetText(coordinate);
ShowButtonFeedback(CopyTopButton);
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[坐标窗口] 复制到剪贴板失败: {ex.Message}");
}
}
/// <summary>
@ -226,7 +232,10 @@ namespace NavisworksTransport.UI.WPF.Views
System.Windows.Clipboard.SetText(coordinate);
ShowButtonFeedback(CopyBottomButton);
}
catch { }
catch (Exception ex)
{
LogManager.Debug($"[坐标窗口] 复制到剪贴板失败: {ex.Message}");
}
}
/// <summary>

View File

@ -490,7 +490,7 @@ namespace NavisworksTransport.UI.WPF.Views
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
@ -512,7 +512,7 @@ namespace NavisworksTransport.UI.WPF.Views
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
@ -542,7 +542,7 @@ namespace NavisworksTransport.UI.WPF.Views
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}
@ -562,7 +562,7 @@ namespace NavisworksTransport.UI.WPF.Views
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
return Binding.DoNothing;
}
}

View File

@ -56,11 +56,7 @@ namespace NavisworksTransport.Utils
var center1 = GetBoundingBoxCenter(box1);
var center2 = GetBoundingBoxCenter(box2);
double dx = center1.X - center2.X;
double dy = center1.Y - center2.Y;
double dz = center1.Z - center2.Z;
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
return GeometryHelper.CalculatePointDistance(center1, center2);
}
/// <summary>

View File

@ -142,10 +142,10 @@ namespace NavisworksTransport
/// </summary>
/// <typeparam name="T">返回类型</typeparam>
/// <param name="operation">要执行的操作</param>
/// <param name="defaultValue">操作失败时的默认返回值</param>
/// <param name="operationName">操作名称(用于日志)</param>
/// <returns>操作结果</returns>
protected T SafeComOperation<T>(Func<T> operation, T defaultValue = default(T), string operationName = "COM操作")
/// <exception cref="COMException">COM操作失败时抛出</exception>
protected T SafeComOperation<T>(Func<T> operation, string operationName = "COM操作")
{
try
{
@ -157,17 +157,17 @@ namespace NavisworksTransport
catch (COMException comEx)
{
LogManager.Error($"[COM操作] COM异常 - {operationName}: {comEx.Message} (HRESULT: 0x{comEx.ErrorCode:X8})");
return defaultValue;
throw;
}
catch (InvalidComObjectException)
{
LogManager.Error($"[COM操作] COM对象已无效 - {operationName}");
return defaultValue;
throw;
}
catch (Exception ex)
{
LogManager.Error($"[COM操作] 一般异常 - {operationName}: {ex.Message}");
return defaultValue;
throw;
}
}
@ -176,14 +176,14 @@ namespace NavisworksTransport
/// </summary>
/// <param name="operation">要执行的操作</param>
/// <param name="operationName">操作名称(用于日志)</param>
/// <returns>操作是否成功</returns>
protected bool SafeComOperation(Action operation, string operationName = "COM操作")
/// <exception cref="COMException">COM操作失败时抛出</exception>
protected void SafeComOperation(Action operation, string operationName = "COM操作")
{
return SafeComOperation(() =>
SafeComOperation(() =>
{
operation();
return true;
}, false, operationName);
}, operationName);
}
#endregion

View File

@ -334,10 +334,7 @@ namespace NavisworksTransport
if (point1 == null || point2 == null)
throw new ArgumentNullException("世界坐标点不能为空");
double dx = point2.X - point1.X;
double dy = point2.Y - point1.Y;
double dz = point2.Z - point1.Z;
return Math.Sqrt(dx * dx + dy * dy + dz * dz);
return GeometryHelper.CalculatePointDistance(point1, point2);
}
/// <summary>

View File

@ -14,13 +14,23 @@ namespace NavisworksTransport
/// </summary>
public class GeometryHelper
{
/// <summary>
/// 默认轮廓提取容差(米)
/// </summary>
private const double DEFAULT_OUTLINE_TOLERANCE_METERS = 0.5;
/// <summary>
/// 1厘米容差- 用于精确几何计算
/// </summary>
private const double TOLERANCE_1CM_METERS = 0.01;
/// <summary>
/// 提取模型项的顶视图轮廓
/// </summary>
/// <param name="modelItem">模型项</param>
/// <param name="tolerance">容差</param>
/// <returns>轮廓点集合</returns>
public static List<Point3D> ExtractTopViewOutline(ModelItem modelItem, double tolerance = 0.5)
public static List<Point3D> ExtractTopViewOutline(ModelItem modelItem, double tolerance = DEFAULT_OUTLINE_TOLERANCE_METERS)
{
var points = new List<Point3D>();
@ -594,7 +604,7 @@ namespace NavisworksTransport
{
iteration++;
var nextEdgeIndex = -1;
var tolerance = 0.01; // 1cm容差稍微放宽
var tolerance = TOLERANCE_1CM_METERS; // 1cm容差稍微放宽
for (int i = 0; i < remainingEdges.Count; i++)
{
@ -747,7 +757,7 @@ namespace NavisworksTransport
// 第1步移除重复点
var uniquePoints = new List<Point2D>();
const double tolerance = 0.01; // 1cm容差
const double tolerance = TOLERANCE_1CM_METERS; // 1cm容差
foreach (var point in contour)
{

View File

@ -22,9 +22,10 @@ namespace NavisworksTransport.Utils
/// </summary>
private const double VIEW_BOUNDING_BOX_EXPANSION_FACTOR = 1.2;
/// <summary> 视野扩展范围(米)
/// <summary>
/// 默认视野扩展范围(米)- 用于调整视角时确保目标完全可见
/// </summary>
const double EXPANSION_METERS = 10.0;
private const double DEFAULT_VIEW_EXPANSION_METERS = 10.0;
/// <summary>
/// 智能调整视角:调整到路径中心,确保整个路径都在视野内
@ -106,7 +107,7 @@ namespace NavisworksTransport.Utils
// 3. 计算扩展边距
double boxWidth = viewBoundingBox.Max.X - viewBoundingBox.Min.X;
double expansionFactor = VIEW_BOUNDING_BOX_EXPANSION_FACTOR + (EXPANSION_METERS / baseDimension);
double expansionFactor = VIEW_BOUNDING_BOX_EXPANSION_FACTOR + (DEFAULT_VIEW_EXPANSION_METERS / baseDimension);
double expansionMargin = boxWidth * (expansionFactor - 1) / 2;
// 4. 应用视角(使用通用方法,带 ZoomBox