Files
envi-code/SourceCode/Code2026/tg_shs/shs_utility/wallgraph.cpp
T
2026-09-28 15:28:50 +08:00

445 lines
11 KiB
C++

#include "stdafx.h"
#include "wallgraph.h"
TWallEdge::TWallEdge(AcDbObjectId idWall,TWallNode*pNode0,TWallNode*pNode1,double ang)
:m_idWall(idWall),m_pNode0(pNode0),m_pNode1(pNode1),m_fBulge(ang)
{
if(m_pNode0!=NULL)
m_pNode0->AppendEdge(this);
if(m_pNode1!=NULL)
m_pNode1->AppendEdge(this);
}
TWallNode* TWallGraph::FindOrAddNode(XPoint pt)//ok
{
TWallNode* pWallNode=new TWallNode(pt);
if(!m_allNode.SortIn(pWallNode))
{
delete pWallNode;
return m_allNode.GetCurData();
}
else
return pWallNode;
}
bool TWallGraph::AppendWall(AcDbObjectId idWall)//ok
{
if(m_allEdge.BFindDataTo(TWallEdge(idWall,NULL,NULL,0)))
return false;
TDbWall* pWall=NULL;
acdbOpenObject(pWall,idWall,AcDb::kForRead);
if(pWall!=NULL)
{
TWallNode *pNode0=FindOrAddNode(pWall->StartPoint());
TWallNode *pNode1=FindOrAddNode(pWall->EndPoint());
pWall->close();
double bulge=pWall->GetBulge();
if(pNode0!=pNode1)
{
TWallEdge *pNewEdge=new TWallEdge(idWall,pNode0,pNode1,bulge);
m_allEdge.InsertCur(pNewEdge);
return true;
}
}
return false;
}
TWallGraph::TWallGraph(AcDbObjectId id)//ok
{
TListQuene<AcDbObjectId> quene;
List<AcDbObjectId> lstQueneId;
quene.EnQuene(id);
while(quene.DeQuene(id))
{
TDbWall* pWall=NULL;
acdbOpenObject(pWall,id,AcDb::kForRead);
if(pWall!=NULL)
{
if(AppendWall(id))
{
DList<TWallData::IdDotStyle> lstStyleStart,lstStyleEnd;
pWall->GetIdStyles(0,lstStyleStart);
pWall->GetIdStyles(1,lstStyleEnd);
pWall->close();
for(long i=0;i<lstStyleStart.Length();i++)
{
AcDbObjectId id1=lstStyleStart[i]->id;
if(!m_allEdge.BFindDataTo(TWallEdge(id1,NULL,NULL,0)))
quene.EnQuene(id1);
}
for(i=0;i<lstStyleEnd.Length();i++)
{
AcDbObjectId id1=lstStyleEnd[i]->id;
if(!m_allEdge.BFindDataTo(TWallEdge(id1,NULL,NULL,0)))
quene.EnQuene(id1);
}
}
pWall->close();
}
}
}
void TWallGraph::MoveNode(AcDbObjectId idWall,XPoint ptNewBase)
{
if(m_allNode.GetLength()<2)
return;
TWallNode *pNodeStart;
if(m_allEdge.BFindDataTo(TWallEdge(idWall,NULL,NULL,0)))
{
TWallEdge *pEdge=m_allEdge.GetCurData();
pNodeStart=pEdge->m_pNode0;
if(pEdge->m_pNode0->Distance2d(ptNewBase)>pEdge->m_pNode1->Distance2d(ptNewBase))
pNodeStart=pEdge->m_pNode1;
}
else
return;
TWallNode *pNodeDest=NULL;
if(m_allNode.BFindDataTo(TWallNode(ptNewBase)))
pNodeDest=m_allNode.GetCurData();
if(pNodeDest!=NULL)
{
if(pNodeDest==pNodeStart)
{
if(ptNewBase==XPoint(*pNodeDest))//精确相等
return;
}
else
{
ConbineNode(pNodeDest,pNodeStart);
pNodeStart=pNodeDest;
}
}
pNodeStart->SetPoint(ptNewBase);
TListQuene<TWallNode*> quene;
quene.EnQuene(pNodeStart);
pNodeStart->AddFlag(VISITED);
int count=0;
while(quene.GetHeadData(pNodeStart))
{
pNodeStart->Move(quene);
#ifndef NDEBUG
//pNodeStart->Draw(count++);
#endif
quene.DeQuene(pNodeStart);
}
for(m_allNode.MoveToFirst();!m_allNode.IsOut();m_allNode.MoveToNext())
m_allNode.GetCurData()->ClearFlag();
for(m_allEdge.MoveToFirst();!m_allEdge.IsOut();m_allEdge.MoveToNext())
m_allEdge.GetCurData()->ClearFlag();
}
void TWallGraph::ConbineNode(TWallNode* pNode0,TWallNode* pNode1)
{
for(long i=0;i<pNode1->m_allEdge.GetLength();i++)
{
TWallEdge *pEdge=pNode1->m_allEdge[i];
if(pEdge->m_pNode0==pNode0||pEdge->m_pNode1==pNode0)//连接边
{
TDbWall* pWall=NULL;
acdbOpenObject(pWall,pEdge->m_idWall,AcDb::kForWrite);
if(pWall!=NULL)
{
pWall->erase();
pWall->close();
}
pNode0->m_allEdge.FindAndDel(pEdge);
if(m_allEdge.FindTo(pEdge))
m_allEdge.DelCur();
}
else//非连接边,将连接关系过渡给pNode0
{
if(pEdge->m_pNode0==pNode1)
pEdge->m_pNode0=pNode0;
else
pEdge->m_pNode1=pNode0;
pNode0->AppendEdge(pEdge);
}
}
if(m_allNode.FindTo(pNode1))
m_allNode.DelCur();
}
//当前节点放射边的另一端被加入队列,以继续移动
void TWallNode::Move(Quene<TWallNode*> &quene)
{
XPoint ptNewBase=*this;
for(long k=0;k<m_allEdge.GetLength();k++)
{
TWallEdge *pEdge=m_allEdge[k];
if(pEdge->Is(VISITED))
continue;
pEdge->AddFlag(VISITED);
TDbWall*pWall=NULL;
acdbOpenObject(pWall,pEdge->m_idWall,AcDb::kForWrite);
if(pWall!=NULL)
{
XCurveSegment cvOld=*pWall;
double elev=pWall->GetElevation();
double nOffset=pWall->GetDist2Me(ptNewBase);
pWall->assertWriteEnabled();
if(pEdge->m_pNode0->Is(VISITED)&&pEdge->m_pNode1->Is(VISITED))//两边端点已经给定,只能调整左右宽
{
pWall->StartPoint().x=pEdge->m_pNode0->x;
pWall->StartPoint().y=pEdge->m_pNode0->y;
pWall->EndPoint().x=pEdge->m_pNode1->x;
pWall->EndPoint().y=pEdge->m_pNode1->y;
pWall->SetWidth(0, pWall->GetWidth(0)+nOffset);
pWall->SetWidth(1, pWall->GetWidth(1)-nOffset);
#ifndef NDEBUG
//pWall->setColorIndex(1);
#endif
pWall->close();
continue;
}
XCurveSegment segBase=pWall->XCurveSegment::Offset(nOffset, LS_FINITE);
*(XCurveSegment*)pWall = segBase;
pWall->SetWidth(0, pWall->GetWidth(0)+nOffset);
pWall->SetWidth(1, pWall->GetWidth(1)-nOffset);
TWallNode *pNewNode;
if(pEdge->m_pNode0==this)//边的起点在这个节点
{
pWall->StartPoint()=ptNewBase;
pNewNode=pEdge->m_pNode1;
}
else//边的终点在这个节点
{
pWall->EndPoint()=ptNewBase;
pNewNode=pEdge->m_pNode0;
}
//确定当前墙边的另一点
XCurveSegment segOther;
segBase.SetLineFlag(LS_INFINITE);
segBase.SetElevation(0);
if(pNewNode->GetSegOther(segBase,segOther))//不共线
{
XPoint pt1,pt2;
int nRet=segBase.Intersection(segOther,pt1,pt2);//一定相交
if(nRet==2)
{
if(pNewNode->Distance2d(pt2)<pNewNode->Distance2d(pt1))
pt1=pt2;
}
if(pEdge->m_pNode0==this)//边的起点在这个节点
pWall->EndPoint()=pt1;
else//边的终点在这个节点
pWall->StartPoint()=pt1;
}
if(pEdge->m_pNode0==this)//边的起点在这个节点
pNewNode->SetPoint(pWall->EndPoint());
else//边的终点在这个节点
pNewNode->SetPoint(pWall->StartPoint());
pWall->SetElevation(elev);
pWall->close();
quene.EnQuene(pNewNode);
pNewNode->AddFlag(VISITED);
List<TWallNode*> lstNewNode;
lstNewNode<<pNewNode;
for(long j=0;j<lstNewNode.GetLength();j++)
{
pNewNode=lstNewNode[j];
for(long i=0;i<quene.GetLength();i++)
{
TWallNode* pOtherNode=quene[i];
List<TWallNode*> lstMidNode;
List<TWallEdge*> lstEdge1,lstEdge2;
pNewNode->GetMidNode(pOtherNode,lstMidNode,lstEdge1,lstEdge2);
for(lstEdge1.MoveToFirst(),lstEdge2.MoveToFirst(),lstMidNode.MoveToFirst();!lstEdge1.IsOut();
lstEdge1.MoveToNext(),lstEdge2.MoveToNext(),lstMidNode.MoveToNext())
{
TWallEdge *pWallEdge1=lstEdge1.GetCurData();
TWallEdge *pWallEdge2=lstEdge2.GetCurData();
TWallNode *pNodeMid=lstMidNode.GetCurData();
if(pWallEdge1->Is(VISITED)||pWallEdge2->Is(VISITED)||pNodeMid->Is(VISITED))
continue;
pWallEdge1->AddFlag(VISITED);
pWallEdge2->AddFlag(VISITED);
TDbWall*pWall=NULL;
acdbOpenObject(pWall,pWallEdge1->m_idWall,AcDb::kForWrite);
if(pWall!=NULL)
{
TDbWall* pWall1=NULL;
acdbOpenObject(pWall1,pWallEdge2->m_idWall,AcDb::kForWrite);
if(pWall1!=NULL)
{
pWall->assertWriteEnabled();
pWall1->assertWriteEnabled();
XCurveSegment cv1=*pWall;
XCurveSegment cv2=*pWall1;
cv1.SetLineFlag(LS_INFINITE);
cv2.SetLineFlag(LS_INFINITE);
double offset1=cv1.GetDist2Me(*pNewNode),offset2=cv2.GetDist2Me(*pOtherNode);
cv1=cv1.Offset(offset1,LS_INFINITE);
cv2=cv2.Offset(offset2,LS_INFINITE);
pWall->SetWidth(0, pWall->GetWidth(0)+offset1);
pWall->SetWidth(1, pWall->GetWidth(1)-offset1);
pWall1->SetWidth(0, pWall1->GetWidth(0)+offset2);
pWall1->SetWidth(1, pWall1->GetWidth(1)-offset2);
XPoint pt1,pt2;
cv1.SetElevation(0);
cv2.SetElevation(0);
int nRet=cv1.Intersection(cv2,pt1,pt2);
if(nRet==0)//共线 
{
XCurveSegment segOther;
if(pNodeMid->GetSegOther(cv1,segOther))//试图通过另一个方向的已定点来确定pt1
{
int nRet=cv1.Intersection(segOther,pt1,pt2);//一定相交
if(nRet==2)
{
if(pNodeMid->Distance2d(pt2)<pNodeMid->Distance2d(pt1))
pt1=pt2;
}
}
else
{
if(pNodeMid==pWallEdge1->m_pNode0)
pt1=cv1.StartPoint();
else
pt1=cv1.EndPoint();
}
}
else if(nRet==2)
{
if(pNodeMid->Distance2d(pt2)<pNodeMid->Distance2d(pt1))
pt1=pt2;
}
if(pNodeMid==pWallEdge1->m_pNode0)
{
pWall->StartPoint().x=pt1.x;
pWall->StartPoint().y=pt1.y;
pWall->EndPoint().x=pNewNode->x;
pWall->EndPoint().y=pNewNode->y;
}
else
{
pWall->StartPoint().x=pNewNode->x;
pWall->StartPoint().y=pNewNode->y;
pWall->EndPoint().x=pt1.x;
pWall->EndPoint().y=pt1.y;
}
if(pNodeMid==pWallEdge2->m_pNode0)
{
pWall1->StartPoint().x=pt1.x;
pWall1->StartPoint().y=pt1.y;
pWall1->EndPoint().x=pOtherNode->x;
pWall1->EndPoint().y=pOtherNode->y;
}
else
{
pWall1->StartPoint().x=pOtherNode->x;
pWall1->StartPoint().y=pOtherNode->y;
pWall1->EndPoint().x=pt1.x;
pWall1->EndPoint().y=pt1.y;
}
pNodeMid->SetPoint(pt1);
quene.EnQuene(pNodeMid);
pNodeMid->AddFlag(VISITED);
lstNewNode<<pNodeMid;
pWall1->close();
}
pWall->close();
}
}
}
}
}
}
}
//返回多墙的共同基线(与seg1不共线)
bool TWallNode::GetSegOther(XCurveSegment seg1,XCurveSegment &seg2,bool bFirst)
{
AddFlag(LOCKED);
bool bRet=false;
for(m_allEdge.MoveToFirst();!m_allEdge.IsOut();m_allEdge.MoveToNext())
{
TWallEdge *pEdge=m_allEdge.GetCurData();
if(pEdge->Is(VISITED))
continue;
seg2=pEdge->GetCurve();
seg2.SetElevation(0);
XPoint pt;
if(bFirst)
{
if(seg1.Intersection(seg2,pt,pt)==0)//平行(由于相交一定共线)
continue;
}
else
{
if(seg1.Intersection(seg2,pt,pt)>0)//不平行
continue;
}
TWallNode *pNode;
if(pEdge->m_pNode0==this)
pNode=pEdge->m_pNode1;
else
pNode=pEdge->m_pNode0;
if(pNode->Is(LOCKED))
continue;
else if(pNode->Is(VISITED))
{
double nOffset=seg2.GetDist2Me(*pNode);
seg2=seg2.Offset(nOffset,LS_INFINITE);
bRet=true;
break;
}
else if(pNode->GetSegOther(seg2,seg2,false))
{
bRet=true;
break;
}
}
RemoveFlag(LOCKED);
return bRet;
}
void TWallNode::GetMidNode(TWallNode*pOtherNode,Table<TWallNode*>&lstNode,Table<TWallEdge*> &lstEdge1,Table<TWallEdge*> &lstEdge2)
{
if(pOtherNode==this)
return;
for(m_allEdge.MoveToFirst();!m_allEdge.IsOut();m_allEdge.MoveToNext())
{
TWallEdge *pEdge1=m_allEdge.GetCurData();
TWallNode* pNodeMid=pEdge1->m_pNode0==this?pEdge1->m_pNode1:pEdge1->m_pNode0;
for(pOtherNode->m_allEdge.MoveToFirst();!pOtherNode->m_allEdge.IsOut();pOtherNode->m_allEdge.MoveToNext())
{
TWallEdge *pEdge2=pOtherNode->m_allEdge.GetCurData();
if(pEdge2->m_pNode0==pNodeMid||pEdge2->m_pNode1==pNodeMid)
{
lstNode<<pNodeMid;
lstEdge1<<pEdge1;
lstEdge2<<pEdge2;
break;
}
}
}
}