//-----------------------------------------------------------------------------+ // Copyright (C), 1998-2007, SH Software Co. Ltd. // = FileName : XSearchRegionFromCurve 类 // = Version : ver2.0 // = Author : zjq // = CreateDate : 2002-09-09 // = Description: XSearchRegionFromCurve 定义 // = Maintainers: // //-----------------------------------------------------------------------------+ #include "StdAfx.h" #include "XSearchRegionFromCurve.h" #include "XRegionIndex.h" #include "XCurveInline.h" extern int operator & (const XPoint &pt0, XPoly2D &poly); DList XSearchRegionFromCurve::g_lstAllSortSides; TCHAR XSearchRegionFromCurve::s_chConstructed = 0; XSearchRegionFromCurve::XSearchRegionFromCurve() { _XSearchRegionFromCurve(); } void XSearchRegionFromCurve::_XSearchRegionFromCurve() { ASSERT(!s_chConstructed); s_chConstructed = 1; XRegionSide::g_pAllWalls = &m_sides; XRegion::g_pAllSpaces = &m_regions; XRegion::g_nGlobalIndex = 0; g_lstAllSortSides.Reset(); } // 有曲线集构造排序曲线表 void XSearchRegionFromCurve::InitStart(const DList &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 XCurveSegment &seg = lstSegs[i]; if (seg.Is(CURVE_CIRCLE)) { continue; } if (bEcho) { if (!(i%nStep)) { acedSetStatusBarProgressMeterPos(i); } } XRegionSide *pSide = new XRegionSide(seg); if (!*pSide) { delete pSide; continue; } else { NewAppend(pSide); } } if (bEcho) { acedRestoreStatusBar(); } } // 释放全局变量 XSearchRegionFromCurve::~XSearchRegionFromCurve() { XRegionSide::g_pAllWalls = NULL; XRegion::g_pAllSpaces = NULL; XRegion::g_nGlobalIndex = 0; g_lstAllSortSides.Reset(); s_chConstructed = 0; m_sides.Reset(); m_regions.Reset(); } XRegionSide *XSearchRegionFromCurve::HitTest(XPoint ptMid) { int num = m_sides.Length(); for (int i = 0; i < num; i++) { XRegionSide *pSide = m_sides[i]; XCurveSegment &seg = *pSide; int nPrFlag = (ptMid & seg); if (nPrFlag == PR_INSIDE) { return pSide; } } return NULL; } //求最外区域, 返回数目 // 算法: // 1. 取面积最大的区域,一定是外边界 // 2. 搜索出外边界所包含的各个区域 // 3. 从总区域中扣除外边界和它内部的区域 // 4. 如果总区域数不为0,则返回1. int XSearchRegionFromCurve::GetOutsideRegions1(DList &lstOutIndex) const { DList lstRegs; int nRegionNum = m_regions.Length(); if (!nRegionNum) { return FALSE; } for (int i = 0; i < nRegionNum; i++) { const XRegion ® = m_regions[i]; double dPathArea = reg.PathArea(); XPoly2D polyTemp; reg.CenterPoly2D(polyTemp); XPoint ptMid = polyTemp.GetInsidePoint(); XRegionIndex *pReg = new XRegionIndex(i, dPathArea, ptMid); lstRegs.Append(pReg); } lstRegs.QuickSort(XRegionIndex::CompareRegion); int nTotalRegNum = nRegionNum; while(nRegionNum > 0) { XRegionIndex *pIdx = lstRegs.Tail(); lstOutIndex.Append(new int(pIdx->m_nIndex)); XPoly2D 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)); } XRegionIndex *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 XSearchRegionFromCurve::NewAppend(XRegionSide *pSide) { m_sides.Append(pSide); for (int n = 0; n < 2; n++) { //建立排序表提高速度,R14下速度提高不明显 XPoint &ptVertex = n ? pSide->EndPoint() : pSide->StartPoint(); int nVerNum = g_lstAllSortSides.Length(); int i(0); for (i = 0; i < nVerNum; i++) { XSortSideOnVertex *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之前插入 XSortSideOnVertex *pSortSide1 = new XSortSideOnVertex(ptVertex); pSortSide1->Insert(pSide); g_lstAllSortSides.Insert(pSortSide1); break; } } if (i == nVerNum) { XSortSideOnVertex *pSortSide1 = new XSortSideOnVertex(ptVertex); pSortSide1->Insert(pSide); g_lstAllSortSides.Append(pSortSide1); } } } // 功能: 找所有的空间 // 并设置外墙标志 // 返回室外空间 XRegion * XSearchRegionFromCurve::SearchRegions() { // 找每边两侧的区域 int nLen = m_sides.Length(); int nStep = nLen / 100; if (nStep < 1) { nStep = 1; } if (g_bEchoSearch) { XString sMsg(256); sMsg << _T("对") << nLen << _T("条边搜索区域"); acedSetStatusBarProgressMeter(sMsg, 0, nLen); } for (int i = 0; i < nLen; i++) { XRegionSide &aSide = *m_sides[(int)i]; XSortSideOnVertex *pSortWalls = aSide.GetStartNode(); if (!pSortWalls) //当前墙孤立 { continue; } if (g_bEchoSearch && !(i % nStep)) { acedSetStatusBarProgressMeterPos(i); } aSide.g_pCurRegion = NULL; if (!aSide.GetLeftRegion()) { aSide.g_pCurRegion = new XRegion; aSide.g_pCurRegion->Push(&aSide); if (aSide.Trival(aSide.GetStartNode(), 0) == RTNORM) { m_regions.Append(aSide.g_pCurRegion); int nSideNum = XRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { XRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } } else { delete XRegionSide::g_pCurRegion; XRegionSide::g_pCurRegion = NULL; } } if (!aSide.GetRighttRegion()) { aSide.g_pCurRegion = new XRegion; aSide.g_pCurRegion->Push(&aSide); if (aSide.Trival(aSide.GetStartNode(), 1) == RTNORM) { m_regions.Append(aSide.g_pCurRegion); int nSideNum = XRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { XRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } } else { delete XRegionSide::g_pCurRegion; XRegionSide::g_pCurRegion = NULL; } } } if (g_bEchoSearch) { acedRestoreStatusBar(); } // 查找外边的墙 XRegion *extCell = NULL; int nRegionNum = m_regions.Length(); if (nRegionNum == 2) // 室内外空间边界重合 { XRegion &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++) { XRegion *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 XSearchRegionFromCurve::SerachTwoRegion(XRegionSide &aSide, XRegion &lRegion, XRegion &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 = XRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { XRegionSide &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 = XRegionSide::g_pCurRegion->Length(); for (int n = 0; n < nSideNum; n++) { XRegionSide &wl = *(*aSide.g_pCurRegion)[n]; if (wl.GetCurSide()) { wl.SetRightRegion(aSide.g_pCurRegion); } else { wl.SetLeftRegion(aSide.g_pCurRegion); } } return RTNORM; } //移除重合的区域,返回移除的数目 int XSearchRegionFromCurve::RemoveDupRegions() { int nRemoveNum = 0; DList ®ions = m_regions; int nRegionNum = regions.Length(); for (int i = 0; i < nRegionNum; i++) { XRegion ®Src = *regions[i]; BOOL bFindRev = FALSE; for (int j = i+1; j < nRegionNum; j++) { XRegion ®Dest = *regions[j]; if (regDest.IsEqualTo(regSrc)) { regions.Remove(); nRemoveNum++; bFindRev = TRUE; break; } } if (bFindRev) { nRegionNum--; } } return nRemoveNum; } // 从初始组中移邻接的区域到当前组, 返回移动的数目 int XSearchRegionFromCurve::AddAdjacentRegion(DList &curGroup, DList &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 XRegion ®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 XSearchRegionFromCurve::GetOutsideRegions(DList &lstOutIndex) const { DList initGroup; int nRegionNum = m_regions.Length(); for (int i = 0; i < nRegionNum; i++) { initGroup.Append(new int(i)); } if (!nRegionNum) { return FALSE; } DList 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 XSearchRegionFromCurve::ComparePointBySortXY(const XPoint *p1, const XPoint *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; }