#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 quene; List lstQueneId; quene.EnQuene(id); while(quene.DeQuene(id)) { TDbWall* pWall=NULL; acdbOpenObject(pWall,id,AcDb::kForRead); if(pWall!=NULL) { if(AppendWall(id)) { DList lstStyleStart,lstStyleEnd; pWall->GetIdStyles(0,lstStyleStart); pWall->GetIdStyles(1,lstStyleEnd); pWall->close(); for(long i=0;iid; if(!m_allEdge.BFindDataTo(TWallEdge(id1,NULL,NULL,0))) quene.EnQuene(id1); } for(i=0;iid; 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 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;im_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 &quene) { XPoint ptNewBase=*this; for(long k=0;kIs(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)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 lstNewNode; lstNewNode< lstMidNode; List 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)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)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<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&lstNode,Table &lstEdge1,Table &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<