Merge pull request 'fix: HLR 结果中删除 AecDbEwFitting 产生的退化圆弧' (#11) from home-lenovo-legion-r9000/fix/aecdbcamera-fitting-degenerate-arc into main

Reviewed-on: https://git.ethereal-realm.top/gjm/envi-code/pulls/11
This commit was merged in pull request #11.
This commit is contained in:
gjm committed 2026-10-16 21:34:50 +08:00
commit 775b3c181c
1 file changed
+78 -40
+78 -40
View File
@@ -6,6 +6,7 @@
#include "CoreTools.h"
#include "HlrCutOption.h"
#include "aecdbewpipebase.h"
#include "AecDbEwFitting.h"
#include "compare_double.h"
#include "simpleproperty.h"
#include "hlrcommands.h"
@@ -534,24 +535,88 @@ namespace
//#endif
}
// 弧长/半径 的比值小于此值即视为"退化圆弧"(圆心角极小)。
const double kMinArcLengthRadiusRatio = 1e-6;
// 判断指定 id 的实体是否为 AecDbEwFitting。
bool isFittingId(const AcDbObjectId &id)
{
if (id == AcDbObjectId::kNull)
return false;
// 判断 HLR 结果实体是否为"退化圆弧":实体是 AcDbArc,且 弧长/半径 的比值极小。
// 这类圆弧的圆心角极小,HLR 计算时圆心角会溢出,使结果由"很小一段"变成
// "反向的大圆弧",需要从结果中删除。
bool isDegenerateArc(AcDbEntity *pEnt)
AcDbEntityPointer ent(id, AcDb::kForRead);
if (ent.openStatus() != Acad::eOk)
return false;
AcDbEntity *pEnt = ent;
return AecDbEwFitting::cast(pEnt) != NULL;
}
// result2 的键是"产生该批结果的实体指针",这类实体没有 id(是补充实体)。
// 补充实体由某个数据库实体产生,mpAdditional 记录了"数据库实体id -> 其产生的补充实体",
// 因此需反查该指针归属的数据库实体 id,再用该 id 判断类型。
// 找不到归属(例如构筑物融合后不在数据库中的实体)时返回 kNull。
AcDbObjectId fittingIdOfResultKey(AcDbEntity *pSrc, const IDMapEntities &mpAdditional)
{
if (pSrc == NULL)
return AcDbObjectId::kNull;
IDMapEntities::const_iterator it(mpAdditional.begin());
for (; it != mpAdditional.end(); ++it)
{
if (it->second.find(pSrc) != -1) // pSrc 是该 id 产生的补充实体
return it->first;
}
return AcDbObjectId::kNull;
}
// 判断 HLR 结果实体是否为需要删除的"退化圆弧":
// 实体是 AcDbArc,且圆心角为 PI(HLR 计算圆心角溢出后的特征)。
bool isDegenerateArcEntity(AcDbEntity *pEnt)
{
AcDbArc *pArc(AcDbArc::cast(pEnt));
if (pArc == NULL)
return false;
double dRadius(pArc->radius());
if (COMPARE_DOUBLE::equal_zero(dRadius, 1e-9))
return true; // 半径≈0,本身即退化
return COMPARE_DOUBLE::equal(pArc->totalAngle(), PI, 1e-9);
}
double dRatio(pArc->length() / dRadius);
return dRatio < kMinArcLengthRadiusRatio;
// 删除 result1 / result2 中由 AecDbEwFitting 经 HLR 计算产生的、圆心角为 PI 的圆弧。
// result1 的键是数据库实体 id,直接判断该 id 是否为 AecDbEwFitting;
// result2 的键是无 id 的补充实体指针,需经 mpAdditional 反查归属的数据库实体 id 再判断。
void removeFittingDegenerateArcs(IDMapEntities &result1
, EntMapEntities &result2
, const IDMapEntities &mpAdditional)
{
IDMapEntities::iterator it(result1.begin());
for (; it != result1.end(); ++it)
{
if (!isFittingId(it->first))
continue;
for (int i(it->second.length() - 1); i >= 0; --i)
{
if (isDegenerateArcEntity(it->second[i]))
{
delete it->second[i];
it->second.removeAt(i);
}
}
}
EntMapEntities::iterator it2(result2.begin());
for (; it2 != result2.end(); ++it2)
{
if (!isFittingId(fittingIdOfResultKey(it2->first, mpAdditional)))
continue;
for (int i(it2->second.length() - 1); i >= 0; --i)
{
if (isDegenerateArcEntity(it2->second[i]))
{
delete it2->second[i];
it2->second.removeAt(i);
}
}
}
}
bool zeroLength(AcDbCurve *pCrv, const double &tol)
@@ -1986,35 +2051,8 @@ void AecDbXCamera::hlrCalc(AcDbObjectIdArray &arIds
HlrCalc(arIds, arAdditional_all, pVp.get(), control, result1, result2);
// 删除 HLR 计算中"退化"的圆弧(弧长/半径 比值极小)。
// 这类圆弧圆心角极小,计算时会溢出,由"很小一段"变成"反向的大圆弧"。
{
IDMapEntities::iterator it(result1.begin());
for (; it != result1.end(); ++it)
{
for (int i(it->second.length() - 1); i >= 0; --i)
{
if (isDegenerateArc(it->second[i]))
{
delete it->second[i];
it->second.removeAt(i);
}
}
}
EntMapEntities::iterator it2(result2.begin());
for (; it2 != result2.end(); ++it2)
{
for (int i(it2->second.length() - 1); i >= 0; --i)
{
if (isDegenerateArc(it2->second[i]))
{
delete it2->second[i];
it2->second.removeAt(i);
}
}
}
}
// 删除由 AecDbEwFitting 经 HLR 计算产生的"退化"圆弧(圆心角溢出为 PI)。
removeFittingDegenerateArcs(result1, result2, mpAdditional);
if (result1.empty() && result2.empty())
{