445 lines
11 KiB
C++
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;
|
|
}
|
|
}
|
|
}
|
|
}
|