WuYongJie 5821d73291 初始提交:3D家具安装展示系统
包含:
- furniture-3d-system:Next.js 16 全栈应用(资产中心、产品管理、3D装配动画)
- autocad-plugin:AutoCAD 家具导出插件源码
- 资产中心改造:编辑弹窗化、删除功能、Toast反馈、自定义Select组件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:00:19 +08:00

303 lines
9.3 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.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; } = "";
}