包含: - furniture-3d-system:Next.js 16 全栈应用(资产中心、产品管理、3D装配动画) - autocad-plugin:AutoCAD 家具导出插件源码 - 资产中心改造:编辑弹窗化、删除功能、Toast反馈、自定义Select组件 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
303 lines
9.3 KiB
C#
303 lines
9.3 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Autodesk.AutoCAD.DatabaseServices;
|
||
using Autodesk.AutoCAD.Geometry;
|
||
using Autodesk.AutoCAD.BoundaryRepresentation;
|
||
using BrepFace = Autodesk.AutoCAD.BoundaryRepresentation.Face;
|
||
|
||
namespace FurnitureExporter;
|
||
|
||
/// <summary>
|
||
/// 倒角检测器 - 从板材实体中提取倒角/圆角信息
|
||
/// </summary>
|
||
public class ChamferDetector
|
||
{
|
||
private readonly Database _db;
|
||
private Point3d _originOffset = Point3d.Origin;
|
||
|
||
// 检测参数
|
||
private const double MIN_CHAMFER_SIZE = 0.5; // 最小倒角尺寸 0.5mm
|
||
private const double MAX_CHAMFER_SIZE = 50; // 最大倒角尺寸 50mm
|
||
private const double MIN_FILLET_RADIUS = 1; // 最小圆角半径 1mm
|
||
private const double MAX_FILLET_RADIUS = 100; // 最大圆角半径 100mm
|
||
|
||
public ChamferDetector(Database db)
|
||
{
|
||
_db = db;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从板材实体中检测倒角和圆角
|
||
/// </summary>
|
||
public List<EdgeFeatureInfo> DetectEdgeFeatures(ObjectId solidId, string panelId, Point3d? originOffset = null)
|
||
{
|
||
_originOffset = originOffset ?? Point3d.Origin;
|
||
var features = new List<EdgeFeatureInfo>();
|
||
|
||
using var tr = _db.TransactionManager.StartTransaction();
|
||
|
||
var solid = tr.GetObject(solidId, OpenMode.ForRead) as Solid3d;
|
||
if (solid == null)
|
||
{
|
||
tr.Commit();
|
||
return features;
|
||
}
|
||
|
||
try
|
||
{
|
||
using var brep = new Brep(solid);
|
||
int featureIndex = 0;
|
||
|
||
// 遍历所有面,检测圆柱面(圆角)和平面相交的特殊边
|
||
foreach (var face in brep.Faces)
|
||
{
|
||
try
|
||
{
|
||
// face.Surface 常常是修剪/偏移表面,先剥离到基础几何类型
|
||
var surface = BrepSurfaceUtils.Unwrap(face.Surface);
|
||
|
||
// 检测圆角(圆柱面)
|
||
if (surface is Cylinder cylinder)
|
||
{
|
||
var radius = cylinder.Radius;
|
||
|
||
// 过滤:圆角的半径通常较小,而孔的半径通常大于5mm
|
||
if (radius >= MIN_FILLET_RADIUS && radius <= MAX_FILLET_RADIUS)
|
||
{
|
||
// 判断是圆角还是孔
|
||
if (IsFilletFace(face, cylinder, solid))
|
||
{
|
||
var feature = ExtractFilletInfo(cylinder, face, panelId, featureIndex++);
|
||
if (feature != null)
|
||
{
|
||
features.Add(feature);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 检测倒角(倾斜平面)
|
||
else if (surface is Plane plane)
|
||
{
|
||
if (IsChamferFace(face, plane, solid))
|
||
{
|
||
var feature = ExtractChamferInfo(plane, face, panelId, featureIndex++);
|
||
if (feature != null)
|
||
{
|
||
features.Add(feature);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
catch (System.Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"[ChamferDetector] Error: {ex.Message}");
|
||
}
|
||
|
||
tr.Commit();
|
||
return features;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断圆柱面是否为圆角(而非孔的侧面)
|
||
/// </summary>
|
||
private bool IsFilletFace(BrepFace face, Cylinder cylinder, Solid3d solid)
|
||
{
|
||
try
|
||
{
|
||
// 获取圆柱半径
|
||
var radius = cylinder.Radius;
|
||
|
||
// 获取实体尺寸
|
||
var solidExt = solid.GeometricExtents;
|
||
var solidSize = solidExt.MaxPoint - solidExt.MinPoint;
|
||
var maxSolidDim = Math.Max(solidSize.X, Math.Max(solidSize.Y, solidSize.Z));
|
||
|
||
// 圆角特征:半径较小(相对于实体尺寸)
|
||
var radiusRatio = radius / maxSolidDim;
|
||
|
||
// 如果半径小于实体最大尺寸的10%,很可能是圆角
|
||
if (radiusRatio < 0.1)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断平面是否为倒角面
|
||
/// </summary>
|
||
private bool IsChamferFace(BrepFace face, Plane plane, Solid3d solid)
|
||
{
|
||
try
|
||
{
|
||
// 获取平面法向量
|
||
var normal = plane.Normal.GetNormal();
|
||
|
||
// 倒角面的法向量不会与主轴完全平行
|
||
var absNormal = new Vector3d(Math.Abs(normal.X), Math.Abs(normal.Y), Math.Abs(normal.Z));
|
||
|
||
// 如果法向量与任意主轴的夹角在25°-65°之间,可能是倒角
|
||
var maxComponent = Math.Max(absNormal.X, Math.Max(absNormal.Y, absNormal.Z));
|
||
var minComponent = Math.Min(absNormal.X, Math.Min(absNormal.Y, absNormal.Z));
|
||
|
||
// 倒角面的法向量不会太接近主轴(>0.9)也不会太远离(<0.4)
|
||
if (maxComponent > 0.4 && maxComponent < 0.9 && minComponent > 0.1)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提取圆角信息
|
||
/// </summary>
|
||
private EdgeFeatureInfo? ExtractFilletInfo(Cylinder cylinder, BrepFace face, string panelId, int index)
|
||
{
|
||
try
|
||
{
|
||
// 使用圆柱原点作为圆角位置
|
||
var origin = cylinder.Origin;
|
||
var center = new Point3d(
|
||
origin.X + _originOffset.X,
|
||
origin.Y + _originOffset.Y,
|
||
origin.Z + _originOffset.Z
|
||
);
|
||
|
||
var axis = cylinder.AxisOfSymmetry.GetNormal();
|
||
|
||
return new EdgeFeatureInfo
|
||
{
|
||
Id = $"{panelId}_fillet_{index:D3}",
|
||
Type = "fillet",
|
||
Position = new double[]
|
||
{
|
||
Math.Round(center.X, 2),
|
||
Math.Round(center.Y, 2),
|
||
Math.Round(center.Z, 2)
|
||
},
|
||
Direction = new double[]
|
||
{
|
||
Math.Round(axis.X, 4),
|
||
Math.Round(axis.Y, 4),
|
||
Math.Round(axis.Z, 4)
|
||
},
|
||
Radius = Math.Round(cylinder.Radius, 2),
|
||
Length = 0, // 长度无法准确获取
|
||
PanelId = panelId
|
||
};
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提取倒角信息
|
||
/// </summary>
|
||
private EdgeFeatureInfo? ExtractChamferInfo(Plane plane, BrepFace face, string panelId, int index)
|
||
{
|
||
try
|
||
{
|
||
// 使用平面原点作为倒角位置
|
||
var origin = plane.PointOnPlane;
|
||
var center = new Point3d(
|
||
origin.X + _originOffset.X,
|
||
origin.Y + _originOffset.Y,
|
||
origin.Z + _originOffset.Z
|
||
);
|
||
|
||
var normal = plane.Normal.GetNormal();
|
||
|
||
return new EdgeFeatureInfo
|
||
{
|
||
Id = $"{panelId}_chamfer_{index:D3}",
|
||
Type = "chamfer",
|
||
Position = new double[]
|
||
{
|
||
Math.Round(center.X, 2),
|
||
Math.Round(center.Y, 2),
|
||
Math.Round(center.Z, 2)
|
||
},
|
||
Direction = new double[]
|
||
{
|
||
Math.Round(normal.X, 4),
|
||
Math.Round(normal.Y, 4),
|
||
Math.Round(normal.Z, 4)
|
||
},
|
||
Size = 0, // 倒角尺寸(无法准确获取)
|
||
Length = 0,
|
||
PanelId = panelId
|
||
};
|
||
}
|
||
catch
|
||
{
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 边缘特征信息(倒角/圆角)
|
||
/// </summary>
|
||
public class EdgeFeatureInfo
|
||
{
|
||
/// <summary>
|
||
/// 特征 ID
|
||
/// </summary>
|
||
public string Id { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 特征类型: "fillet"(圆角)| "chamfer"(倒角)
|
||
/// </summary>
|
||
public string Type { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 特征中心位置 [X, Y, Z] (mm)
|
||
/// </summary>
|
||
public double[] Position { get; set; } = new double[3];
|
||
|
||
/// <summary>
|
||
/// 特征方向/法向量 [X, Y, Z]
|
||
/// </summary>
|
||
public double[] Direction { get; set; } = new double[3];
|
||
|
||
/// <summary>
|
||
/// 圆角半径 (mm),仅用于 fillet 类型
|
||
/// </summary>
|
||
public double? Radius { get; set; }
|
||
|
||
/// <summary>
|
||
/// 倒角尺寸 (mm),仅用于 chamfer 类型
|
||
/// </summary>
|
||
public double? Size { get; set; }
|
||
|
||
/// <summary>
|
||
/// 特征长度 (mm)
|
||
/// </summary>
|
||
public double Length { get; set; }
|
||
|
||
/// <summary>
|
||
/// 所属板材 ID
|
||
/// </summary>
|
||
public string PanelId { get; set; } = "";
|
||
}
|