//-----------------------------------------------------------------------------+ // Copyright (C), 1998-2007, Beijing Tangent Software Co. Ltd. // = FileName : TSearchRegionFromCurve 类 // = Version : ver2.0 // = Author : wlw // = CreateDate : 2002-09-09 // = Description: TSearchRegionFromCurve 定义 // = Maintainers: // //-----------------------------------------------------------------------------+ #include "StdAfx.h" #include "TSearchRegionFromCurve.h" #include "TGGeRegionIndex.h" #include "TGGeCurveInline.h" extern int operator & (const TADSGePoint3d &pt0, TGGePoly2D &poly); TDPtrList TSearchRegionFromCurve::g_lstAllSortSides; TCHAR TSearchRegionFromCurve::s_chConstructed = 0; TSearchRegionFromCurve::TSearchRegionFromCurve() { _XSearchRegionFromCurve(); } void TSearchRegionFromCurve::_XSearchRegionFromCurve() { ASSERT(!s_chConstructed); s_chConstructed = 1; TGGeRegionSide::g_pAllWalls = &m_sides; TGGeRegion::g_pAllSpaces = &m_regions; TGGeRegion::g_nGlobalIndex = 0; g_lstAllSortSides.Reset(); } // 有曲线集构造排序曲线表 void TSearchRegionFromCurve::InitStart(const TDPtrList &lstSegs) { // 构造排序墙 long nLen = lstSegs.Length(); int nStep = nLen/100; if (nStep < 1) { nStep = 1; } BOOL bEcho = (g_bEchoSearch && nStep >= 2); if (bEcho) { acedSetStatusBarProgressMeter(_T("曲线排序"), 0, nLen); } for (long i = 0; i < nLen; i++) { const TGGeCurveSegment &seg = lstSegs[i]; if (seg.Is(CURVE_CIRCLE)) { continue; } if (bEcho) { if (!(i%nStep)) { acedSetStatusBarProgressMeterPos(i); } } TGGeRegionSide *pSide = new TGGeRegionSide(seg); if (!*pSide) { delete pSide; continue; } else { NewAppend(pSide); } } if (bEcho) { acedRestoreStatusBar(); } } // 释放全局变量 TSearchRegionFromCurve::~TSearchRegionFromCurve() { TGGeRegionSide::g_pAllWalls = NULL; TGGeRegion::g_pAllSpaces = NULL; TGGeRegion::g_nGlobalIndex = 0; g_lstAllSortSides.Reset(); s_chConstructed = 0; m_sides.Reset(); m_regions.Reset(); } TGGeRegionSide *TSearchRegionFromCurve::HitTest(TADSGePoint3d ptMid) { int num = m_sides.Length(); for (int i = 0; i < num; i++) { TGGeRegionSide *pSide = m_sides[i]; TGGeCurveSegment &seg = *pSide; int nPrFlag = (ptMid & seg); if (nPrFlag == PR_INSIDE) { return pSide; } } return NULL; } //求最外区域, 返回数目 // 算法: // 1. 取面积最大的区域,一定是外边界 // 2. 搜索出外边界所包含的各个区域 // 3. 从总区域中扣除外边界和它内部的区域 // 4. 如果总区域数不为0,则返回1. int TSearchRegionFromCurve::GetOutsideRegions1(TDPtrList &lstOutIndex) const { TDPtrList lstRegs; int nRegionNum = m_regions.Length(); if (!nRegionNum) { return FALSE; } for (int i = 0; i < nRegionNum; i++) { const TGGeRegion ® = m_regions[i]; double dPathArea = reg.PathArea(); TGGePoly2D polyTemp; reg.CenterPoly2D(polyTemp); TADSGePoint3d ptMid = polyTemp.GetInsidePoint(); TGGeRegionIndex *pReg = new TGGeRegionIndex(i, dPathArea, ptMid); lstRegs.Append(pReg); } lstRegs.QuickSort(TGGeRegionIndex::CompareRegion); int nTotalRegNum = nRegionNum; while(nRegionNum > 0) { TGGeRegionIndex *pIdx = lstRegs.Tail(); lstOutIndex.Append(new int(pIdx->m_nIndex)); TGGePoly2D poly2d; m_regions[pIdx->m_nIndex].CenterPoly2D(poly2d); lstRegs.Remove(nRegionNum-1); nRegionNum--; int nStep = nRegionNum / 100; if (nStep < 1) { nStep = 1; } if (g_bEchoSearch && nStep > 1) { acedSetStatusBarProgressMeter(_T("求外边界"), 0, nRegionNum); } for (int n = 0; n < nRegionNum; n++) { if (g_bEchoSearch && nStep > 1 && !(n % nStep)) { acedSetStatusBarProgressMeterPos((nTotalRegNum-nRegionNum)); } TGGeRegionIndex *pReg = lstRegs[n]; if ((pReg->m_ptInside&poly2d) == PR_INSIDE) { lstRegs.Remove(); n--; nRegionNum--; } } if (g_bEchoSearch && nStep > 1) { acedRestoreStatusBar(); } } return lstOutIndex.Length(); } // 在全局边表中添加一项并根据需要构造排序边表 // Status: 考虑了墙体的底标高 void TSearchRegionFromCurve::NewAppend(TGGeRegionSide *pSide) { m_sides.Append(pSide); for (int n = 0; n < 2; n++) { //建立排序表提高速度,R14下速度提高不明显 TADSGePoint3d &ptVertex = n ? pSide->EndPoint() : pSide->StartPoint(); int nVerNum = g_lstAllSortSides.Length(); for (int i = 0; i < nVerNum; i++) { TSortSideOnVertex *pVertex = g_lstAllSortSides[i]; int nRes = ComparePointBySortXY(&ptVertex, &pVertex->m_ptLoc); if (nRes == 0) { ptVertex = pVertex->m_ptLoc; //精确相等 pVertex->Insert(pSide); break; } else if (nRes < 0) { //在i之前插入 TSortSideOnVertex *pSortSide1 = new TSortSideOnVertex(ptVertex); pSortSide1->Insert(pSide); g_lstAllSortSides.Insert(pSortSide1); break; } } if (i == nVerNum) { TSortSideOnVertex *pSortSide1 = new TSortSideOnVertex(ptVertex); pSortSide1->Insert(pSide); g_lstAllSortSides.Append(pSortSide1); } } } // 功能: 找所有的空间 // 并设置外墙标志 // 返回室外空间 TGGeRegion * TSearchRegionFromCurve::SearchRegions() { // 找每边两侧的区域 int nLen = m_sides.Length(); int nStep = nLen / 100; if (nStep < 1) { nStep = 1; } if (g_bEchoSearch) { TCString sMsg(256); sMsg << _T("对") << nLen << _T("条边搜索区域"); acedSetStatusBarProgressMeter(sMsg, 0, nLen); } for (int i = 0; i < nLen; i++) { TGGeRegionSide &aSide = *m_sides[(int)i]; TSortSideOnVertex *pSortWalls = aSide.GetStartNode(); if (!pSortWalls) //当前墙孤立 { continue; } if (g_bEchoSearch && !(i % nStep)) { acedSetStatusBarProgressMeterPos(i); } aSide.g_pCurRegion = NULL; if (!aSide.GetLeftRegion()) { aSide.g_pCurRegion = new TGGeRegion; aSide.g_pCurRegion->Push(&aSide); if (aSide.Trival(aSide.GetStartNode(), 0) == RTNORM) { m_regions.Append(aSide.g_pCurRegion); int nSideNum = TGGeRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { TGGeRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } } else { delete TGGeRegionSide::g_pCurRegion; TGGeRegionSide::g_pCurRegion = NULL; } } if (!aSide.GetRighttRegion()) { aSide.g_pCurRegion = new TGGeRegion; aSide.g_pCurRegion->Push(&aSide); if (aSide.Trival(aSide.GetStartNode(), 1) == RTNORM) { m_regions.Append(aSide.g_pCurRegion); int nSideNum = TGGeRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { TGGeRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } } else { delete TGGeRegionSide::g_pCurRegion; TGGeRegionSide::g_pCurRegion = NULL; } } } if (g_bEchoSearch) { acedRestoreStatusBar(); } // 查找外边的墙 TGGeRegion *extCell = NULL; int nRegionNum = m_regions.Length(); if (nRegionNum == 2) // 室内外空间边界重合 { TGGeRegion &sp = *m_regions[0]; if (sp.PathArea() < 0) // 逆时针 { if (sp[0]->GetRighttRegion() == &sp) { extCell = &sp; } else { extCell = m_regions[1]; } } else { if (sp[0]->GetLeftRegion() == &sp) { extCell = &sp; } else { extCell = m_regions[1]; } } } else //常规情况, 取面积最大的为 { ads_real dAreaMax = 0.0; for (int k = 0; k < nRegionNum; k++) { TGGeRegion *pRegion = m_regions[k]; ads_real dCurArea = pRegion->PathArea(); if (fabs(dCurArea) > dAreaMax) { extCell = pRegion; dAreaMax = fabs(dCurArea); } } } return extCell; } // 搜索一墙的左右房间 // 参数: // aWall(IN)--给定的墙 // lSpace(OUT)--左边的空间 // rSpace(OUT)--右边的空间 // 返回: RTNORM/RTERROR int TSearchRegionFromCurve::SerachTwoRegion(TGGeRegionSide &aSide, TGGeRegion &lRegion, TGGeRegion &rRegion) { if (!aSide) { return RTERROR; } aSide.g_pCurRegion = &lRegion; aSide.SetLeftRegion(&lRegion); lRegion.Push(&aSide); if (aSide.Trival(aSide.GetStartNode(), 0) != RTNORM) { return RTERROR; } int nSideNum = TGGeRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { TGGeRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } aSide.g_pCurRegion = &rRegion; aSide.SetRightRegion(&rRegion); rRegion.Push(&aSide); if (aSide.Trival(aSide.GetStartNode(), 1) != RTNORM) { return RTERROR; } nSideNum = TGGeRegionSide::g_pCurRegion->Length(); for (n = 0; n < nSideNum; n++) { TGGeRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } return RTNORM; } //移除重合的区域,返回移除的数目 int TSearchRegionFromCurve::RemoveDupRegions() { int nRemoveNum = 0; TDPtrList ®ions = m_regions; int nRegionNum = regions.Length(); for (int i = 0; i < nRegionNum; i++) { TGGeRegion ®Src = *regions[i]; BOOL bFindRev = FALSE; for (int j = i+1; j < nRegionNum; j++) { TGGeRegion ®Dest = *regions[j]; if (regDest.IsEqualTo(regSrc)) { regions.Remove(); nRemoveNum++; bFindRev = TRUE; break; } } if (bFindRev) { nRegionNum--; } } return nRemoveNum; } // 从初始组中移邻接的区域到当前组, 返回移动的数目 int TSearchRegionFromCurve::AddAdjacentRegion(TDPtrList &curGroup, TDPtrList &initGroup) const { int nInitNum = initGroup.Length(); if (!nInitNum) { return FALSE; } curGroup.Reset(); curGroup.Append(new int(*initGroup[0])); initGroup.Remove(); //移除当前 nInitNum--; BOOL bRepeat = FALSE; //发生组移动时,设置标记 do { bRepeat = FALSE; for (int n = 0; n < nInitNum; n++) { int &idxRegion = *initGroup[n]; const TGGeRegion ®ion = m_regions[idxRegion]; BOOL bFind = FALSE; for (int i = 0; i < curGroup.Length(); i++) { int &idxRegion1 = *curGroup[i]; ASSERT(idxRegion != idxRegion1); if (region.IsAdjacentTo(m_regions[idxRegion1])) { bFind = TRUE; curGroup.Append(new int(idxRegion)); break; } } if (bFind) { nInitNum--; n--; initGroup.Remove(); bRepeat = TRUE; } } } while(bRepeat); return curGroup.Length(); } //求最外区域, 返回数目 int TSearchRegionFromCurve::GetOutsideRegions(TDPtrList &lstOutIndex) const { TDPtrList initGroup; int nRegionNum = m_regions.Length(); for (int i = 0; i < nRegionNum; i++) { initGroup.Append(new int(i)); } if (!nRegionNum) { return FALSE; } TDPtrList newGroup; if (g_bEchoSearch) { acedSetStatusBarProgressMeter(_T("判断区域边界"), 0, nRegionNum); } int nPos = 0; do { if (!!newGroup)//完成一组的划分 { int idx = *newGroup[0]; double dArea = fabs(m_regions[idx].PathArea()); for (int n = 1; n < newGroup.Length(); n++) { int idx1 = *newGroup[n]; double dArea1 = fabs(m_regions[idx1].PathArea()); if (dArea1 > dArea) { dArea = dArea1; idx = idx1; } } lstOutIndex.Append(new int(idx)); if (g_bEchoSearch) { nPos += newGroup.Length(); acedSetStatusBarProgressMeterPos(nPos); } } } while(AddAdjacentRegion(newGroup, initGroup)); if (g_bEchoSearch) { acedRestoreStatusBar(); } return lstOutIndex.Length(); } int TSearchRegionFromCurve::ComparePointBySortXY(const TADSGePoint3d *p1, const TADSGePoint3d *p2) { double xDist = (p1->x - p2->x); if (xDist < -_DIST_SNAP) { return -1; } else if (xDist > _DIST_SNAP) { return 1; } double yDist = (p1->y - p2->y); if (yDist < -_DIST_SNAP) { return -1; } else if (yDist > _DIST_SNAP) { return 1; } return 0; }