Files
envi-code/SourceCode/Code2026/AecRxBase/AecDbEntityBase.cpp
T
company-desktop 7038a98441 diag: 用 PDB 解析栈帧,定位到 AecDbEwPipeBase::copyFrom 里的多余序列化
上一版只给了"模块+RVA"的栈,我据此先后推断成
AecDbCurveBase::subGetTransformedCopy 和 AecDbEntityCommon::base_DeepClone,两者都是错的
(用户在那里下断点不命中;新加的 PerfTraceMark 打点也没有触发)。本次用符号解析定死。

本次改动:
- 新增 inc/PerfTraceMark.h:inline 的"某函数被调用过"打点,Debug 且 AEC_WRITEBACK_TRACE=1
  才生效。AecRxBase.arx 不链接 CoreLibrary(静态库只被 CoreCommand 链接),拿不到 SectionPerf,
  所以做成 header-only。
- 在 5 个候选入口打点:AecDbCurveBase::subGetTransformedCopy / subDeepClone、
  AecDbEntityBase::subDeepClone、AecDbEntityCommon::base_DeepClone、CKTCadUtility::CloneObject。
  跑一次开图,5 个都没触发 —— 这些候选被排除。
- 新增 tools/resolve_rva.ps1:用 dbghelp 的 SymLoadModuleEx / SymFromAddr 配本地 PDB,
  把"模块+RVA"解析成函数名。Windows 没有自带 symbolizer,这个脚本很轻,可反复用。

解析结果(CoreCommand.arx):
  0x58f051  AecDbEwPipeBase::copyFrom+0x41
  0x7e1300  AecDbZLineStair::DrawGuarBar3d+0x2c0
  0x7e09d0  AecDbZLineStair::DrawSteep3d+0xbe0
  0x7ddcef  AecDbZLineStair::Draw3d+0x34f

真实成因:Z 型楼梯画护栏(DrawGuarBar3d)时 copyFrom 一份管道实体,
而 AecDbEwPipeBase::copyFrom 用通用的 CopyObject(inc/AecDbEntityCommon.h:331)
做"整实体 dwgOutFields/dwgInFields 往返"来拷字段,于是截面被写成临时 SAT 文件再读回来。

而且这次序列化是多余的:copyFrom 随后把所有字段又用内存级方式拷了一遍
(曲线 clone/copyFrom、截面 clone/copyFrom、XData CopyFrom、m_arUserInfs append、
标志位/图层/线型/Breaks 逐项赋值),WriteUserInterface 写的也只是 m_arUserInfs。
所以最小修改是把那句 CopyObject 去掉,并补上源为 NULL 时清空目标的分支
(目前这个"清空"是 CopyObject 顺带完成的)。

本次只做定位与记录(分析写进 pipe-section-region-performance-plan.md 并纠正了上一版的误判),
不改 copyFrom 的行为——它影响所有管系实体的复制粘贴/块内拷贝,需要单独验证。
2026-10-28 21:28:00 +08:00

391 lines
10 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.
#include "stdafx.h"
#include "AecDbEntityBase.h"
#include "PerfTraceMark.h"
#include "AcGiViewDraw.h"
#include "AcGiExplodeDraw.h"
#include "simpleproperty.h"
#include "dbobjptr.h"
#include "AecDbObjXDataMap.h"
#include "AecGripCback.h"
ACRX_NO_CONS_DEFINE_MEMBERS(AecDbEntityBase, AcDbEntity);
AecDbEntityBase::AecDbEntityBase(void): AecDbEntityCommon()
{
}
AecDbEntityBase::~AecDbEntityBase(void) { }
Adesk::UInt32 AecDbEntityBase::subViewportDrawLogicalFlags(AcGiViewportDraw * vd)
{
// 基类实现是 protected,只能在这里取;后续计算交给 Common。
return AecDbEntityCommon::base_ViewportDrawLogicalFlags(
AcDbEntity::subViewportDrawLogicalFlags(vd));
}
Adesk::UInt32 AecDbEntityBase::subSetAttributes(AcGiDrawableTraits * traits)
{
// 基类实现是 protected,只能在这里取;后续计算交给 Common。
return AecDbEntityCommon::base_SetAttributes(
AcDbEntity::subSetAttributes(traits));
}
Adesk::Boolean AecDbEntityBase::subWorldDraw(AcGiWorldDraw *pWd)
{
// 具体实现与另一条根共用 AecDbEntityCommon::base_WorldDraw,
// 这里只保留 AcGiDrawable 虚函数这一侧的入口。
return AecDbEntityCommon::base_WorldDraw(pWd);
}
void AecDbEntityBase::subViewportDraw(AcGiViewportDraw* pMode)
{
// 具体实现与另一条根共用 AecDbEntityCommon::base_ViewportDraw,
// 这里只保留 AcGiDrawable 虚函数这一侧的入口。
AecDbEntityCommon::base_ViewportDraw(pMode);
}
//保存代理实体图元
void AecDbEntityBase::saveAs(AcGiWorldDraw *pWd,AcDb::SaveType saveType)
{
// 具体实现与另一条根共用 AecDbEntityCommon::base_SaveAs,
// 这里只保留 AcGiDrawable 虚函数这一侧的入口。
AecDbEntityCommon::base_SaveAs(pWd, saveType);
}
Adesk::Boolean AecDbEntityBase::CallWorldDraw(AcGiWorldDraw *pWd)
{
// 虚拟调用,回到最派生类的 subWorldDraw
return subWorldDraw(pWd);
}
Acad::ErrorStatus AecDbEntityBase::subExplode(AcDbVoidPtrArray& entitySet) const
{
// 具体实现与另一条根共用 AecDbEntityCommon::base_Explode,
// 这里只保留虚函数这一侧的入口。
return AecDbEntityCommon::base_Explode(entitySet);
}
Acad::ErrorStatus AecDbEntityBase::subGetGeomExtents(AcDbExtents& extents) const
{
// 具体实现与另一条根共用 AecDbEntityCommon::base_GetGeomExtents,
// 这里只保留 AcDbEntity 虚函数这一侧的入口。
return AecDbEntityCommon::base_GetGeomExtents(extents);
}
void AecDbEntityBase::subList() const
{
AcDbEntity::subList();
}
Acad::ErrorStatus AecDbEntityBase::subIntersectWith(const AcDbEntity* ent,
AcDb::Intersect intType,
AcGePoint3dArray& points,
INT_PTR thisGsMarker,
INT_PTR otherGsMarker) const
{
assertReadEnabled();
int expMode = GetExplodeMode();
if (expMode == 2)
{
return Acad::eNotImplementedYet;
}
const AcDbVoidPtrArray& entSet = Get2DBuffer();
Acad::ErrorStatus es = Acad::eNotApplicable;
int len = entSet.length();
for(int i = 0; i < len; i++)
{
AcDbEntity *pEnt = (AcDbEntity *)entSet[i];
//acutPrintf(_T("\nclass = %s"),pEnt->isA()->name());
if ( pEnt != NULL && Acad::eOk == pEnt->intersectWith(ent, intType, points, 0, otherGsMarker) )
{
es = Acad::eOk;
}
}
return es;
}
Acad::ErrorStatus AecDbEntityBase::subIntersectWith(const AcDbEntity* ent,
AcDb::Intersect intType,
const AcGePlane& projPlane,
AcGePoint3dArray& points,
INT_PTR thisGsMarker,
INT_PTR otherGsMarker) const
{
assertReadEnabled();
int expMode = GetExplodeMode();
if (expMode == 2)
{
return Acad::eNotImplementedYet;
}
const AcDbVoidPtrArray& entSet = Get2DBuffer();
Acad::ErrorStatus es;
es = Acad::eNotApplicable;
int len = entSet.length();
for (int i = 0; i < len; i++)
{
AcDbEntity *pEnt = (AcDbEntity *)entSet[i];
//acutPrintf(_T("\nclass = %s"),pEnt->isA()->name());
if ( pEnt != NULL && Acad::eOk == pEnt->intersectWith(ent, intType, projPlane, points, 0, otherGsMarker) )
{
es = Acad::eOk;
}
}
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subSetPropertiesFrom( const AcDbEntity* pEntity, Adesk::Boolean doSubents /*= Adesk::kTrue*/)
{
assertWriteEnabled();
Acad::ErrorStatus es = AcDbEntity::setPropertiesFrom(pEntity, doSubents);
// 颜色
{
setColorIndex(pEntity->colorIndex());
}
//图层
if ( database() == NULL ||
database() == pEntity->database())
{
{
setLayer(pEntity->layerId());
}
// 线型
{
setLinetype(pEntity->linetypeId());
}
#if ARX > 16
// 材质
{
setMaterial(pEntity->materialId());
}
#endif
}
// 线型比例
{
setLinetypeScale(pEntity->linetypeScale());
}
// 可见性. 总是被复制
setVisibility(pEntity->visibility());
return es;
}
#if (ARX > 15)
Acad::ErrorStatus AecDbEntityBase::subGetOsnapPoints( AcDb::OsnapMode osnapMode,
INT_PTR gsSelectionMark,
const AcGePoint3d& ptPick,
const AcGePoint3d& lastPoint,
const AcGeMatrix3d& viewXform,
AcGePoint3dArray& snapPoints,
AcDbIntArray& geomIds) const
{
return AecDbEntityCommon::base_GetOsnapPoints(osnapMode, gsSelectionMark, ptPick,
lastPoint, viewXform, snapPoints, geomIds);
}
Acad::ErrorStatus AecDbEntityBase::subGetOsnapPoints( AcDb::OsnapMode osnapMode,
INT_PTR gsSelectionMark,
const AcGePoint3d& ptPick,
const AcGePoint3d& lastPoint,
const AcGeMatrix3d& viewXform,
AcGePoint3dArray& snapPoints,
AcDbIntArray& geomIds,
const AcGeMatrix3d& insersionMat) const
{
assertReadEnabled();
return getOsnapPoints(osnapMode,gsSelectionMark,ptPick,lastPoint,viewXform,snapPoints,geomIds);
}
#endif
#if ARX>15
void AecDbEntityBase::subGripStatus(const AcDb::GripStat status)
{
}
Acad::ErrorStatus AecDbEntityBase::subGetGripPoints ( AcDbGripDataPtrArray& grips,
const double curViewUnitSize,
const int gripSize,
const AcGeVector3d& curViewDir,
const int bitflags) const
{
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subMoveGripPointsAt(const AcDbVoidPtrArray& appData,const AcGeVector3d& offset,const int bitflags)
{
return Acad::eOk;
}
#endif
Acad::ErrorStatus AecDbEntityBase::subGetGripPoints (AcGePoint3dArray& gripPoints,AcDbIntArray& osnapModes,AcDbIntArray& geomIds) const
{
assertReadEnabled();
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subMoveGripPointsAt(const AcDbIntArray& indices,const AcGeVector3d& offset)
{
assertWriteEnabled();
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subGetStretchPoints(AcGePoint3dArray& stretchPoints) const
{
assertReadEnabled();
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subMoveStretchPointsAt(const AcDbIntArray& indices,const AcGeVector3d& offset)
{
assertWriteEnabled();
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subTransformBy(const AcGeMatrix3d& xform)
{
assertWriteEnabled();
return Acad::eOk;
}
Acad::ErrorStatus AecDbEntityBase::subGetTransformedCopy(const AcGeMatrix3d& xform,
AcDbEntity*& pEnt) const
{
assertReadEnabled();
AcDbEntity *pCloned = (AcDbEntity *)clone();
((AecDbEntityBase*)pCloned)->m_nDrawDimCur = m_nDrawDimCur;
Acad::ErrorStatus es = pCloned->transformBy(xform);
if(es == Acad::eOk)
pEnt = pCloned;
else
DELETE_PTR(pCloned);
return es;
}
Acad::ErrorStatus AecDbEntityBase::subDeepClone( AcDbObject* pOwner,
AcDbObject*& pClonedObject,
AcDbIdMapping& idMap,
Adesk::Boolean isPrimary) const
{
PerfTraceMark("AecDbEntityBase::subDeepClone");
return AecDbEntityCommon::base_DeepClone(pOwner, pClonedObject, idMap, isPrimary);
}
Acad::ErrorStatus AecDbEntityBase::subWblockClone(AcRxObject* pOwner,
AcDbObject*& pClonedObject,
AcDbIdMapping& idMap,
Adesk::Boolean isPrimary) const
{
return AecDbEntityCommon::base_WblockClone(pOwner, pClonedObject, idMap, isPrimary);
}
Acad::ErrorStatus AecDbEntityBase::CallAcDbWblockClone(AcRxObject* pOwner,
AcDbObject*& pClonedObject,
AcDbIdMapping& idMap,
Adesk::Boolean isPrimary) const
{
return AcDbEntity::subWblockClone(pOwner, pClonedObject, idMap, isPrimary);
}
Acad::ErrorStatus AecDbEntityBase::dwgInFields (AcDbDwgFiler* pFiler)
{
assertWriteEnabled () ;
//----- Read parent class information first.
Acad::ErrorStatus es = AcDbEntity::dwgInFields (pFiler) ;
if ( es != Acad::eOk )
return (es) ;
return (pFiler->filerStatus ()) ;
}
Acad::ErrorStatus AecDbEntityBase::dwgOutFields(AcDbDwgFiler* pFiler) const
{
assertReadEnabled () ;
//----- Save parent class information first.
Acad::ErrorStatus es = AcDbEntity::dwgOutFields (pFiler) ;
if ( es != Acad::eOk )
return (es) ;
return (pFiler->filerStatus ()) ;
}
Acad::ErrorStatus AecDbEntityBase::dxfInFields (AcDbDxfFiler* pFiler)
{
assertWriteEnabled () ;
//----- Read parent class information first.
Acad::ErrorStatus es = AcDbEntity::dxfInFields (pFiler) ;
if ( es != Acad::eOk )
return (es) ;
return (pFiler->filerStatus ()) ;
}
Acad::ErrorStatus AecDbEntityBase::dxfOutFields(AcDbDxfFiler* pFiler) const
{
assertReadEnabled () ;
//----- Save parent class information first.
Acad::ErrorStatus es = AcDbEntity::dxfOutFields (pFiler) ;
if ( es != Acad::eOk )
return (es) ;
return (pFiler->filerStatus ()) ;
}
int AecDbEntityBase::ComparedTo(AecDbEntityBase* pEntOther) const
{
return -1;
}
double AecDbEntityBase::GetArea() const
{
assertReadEnabled();
if (!Has3DBuffer())
{
AcGiViewDraw dc(NULL,NULL);
Draw3d(dc);
}
double dArea = 0.0,dAreaAll = 0.0;
AcDbVoidPtrArray arEntPtrs;
GetDraw3dables(arEntPtrs);
AcDbEntity* pEnt = NULL;
for (int i = 0;i < arEntPtrs.length();i++)
{
pEnt = (AcDbEntity*)arEntPtrs.at(i);
AcDb3dSolid* pSolid = AcDb3dSolid::cast(pEnt);
if (pSolid != NULL)
{
pSolid->getArea(dArea);
dAreaAll += fabs(dArea);
}
}
return dAreaAll;
}
Acad::ErrorStatus AecDbEntityBase::setTransparency(const AcCmTransparency &trans, Adesk::Boolean doSubents)
{
AssertWriteEnabled();
return AcDbEntity::setTransparency(trans, doSubents);
}