#include "StdAfx.h" #include "UnfoldInstallSanitarySys.h" #define WALL_MAX_THICK (DocGetCurMeterUnitDraw() ? 1 : 1000) // 墙体最大厚度 UnfoldInstallSanitarySys::UnfoldInstallSanitarySys() { m_dElev = 0.0; m_pNodeStart = NULL; m_nInstallType = 0; m_bErrorNote = false; m_bCreatPipe = true; m_bPipeDir = true; m_tolVec.setEqualVector(0.01); } void UnfoldInstallSanitarySys::IsCreatPipe(bool bCreatPipe) { m_bCreatPipe = bCreatPipe; } bool UnfoldInstallSanitarySys::GetErrorNote() { return m_bErrorNote; } void UnfoldInstallSanitarySys::SetErrorNote(bool bErrorNote) { m_bErrorNote = bErrorNote; } // 设置明装还是安装方式 void UnfoldInstallSanitarySys::SetInstallType(int nInstallType) { m_nInstallType = nInstallType; } void UnfoldInstallSanitarySys::AutoLinkSanitary( const SanitarySysData &data ) { m_dPipeDn = GetPipeDn(data.id); m_sysPipe = data.type; m_idPipe = data.id; m_ptFeed = data.pt; m_ptFeed.z = 0; InitWallEnt(); ModifyUsefulWall(); // 将洁具按距离给水点远近排序 SanitarySysData sanData = data; std::vector &vecSanNode = sanData.vecSanitaryNode; Sort(vecSanNode, sanData.pt); // 按洁具点距给水点远近连接洁具 LinkSanitary(sanData); } void UnfoldInstallSanitarySys::LinkSanitary(const SanitarySysData &data) { // 获得最远洁具给水点 洁具id std::vector vecNode = data.vecSanitaryNode; std::vector::iterator it = vecNode.begin(); AcGePoint3d ptSan = it->pt; ptSan.z = 0; AcDbObjectId idSan = it->idSanitary; AcGePoint3d ptFeed = data.pt; ptFeed.z = 0; AcGeVector3d vtPipe = AcGeVector3d::kXAxis, vtDir; AcDbLine lineStart, lineEnd; double dWallThick = 0.0; bool bIsParallel = false; bool bExtendFeedPipe = true; AcGeVector3d vtSan; bIsParallel = IsSanPtsParallel(vecNode, vtSan); m_tolVec.setEqualVector(0.01); CString sNote = _T("供水明装无法检测到可用上华墙体 "); // 设定主干方向 if (ConfirmPipeDir(vtPipe, ptSan, vtDir)) { AcGePoint3d ptFar; if (!IsVertivalPipe(m_idPipe))// 更新供水管 { AcGePoint3d ptS, ptE, ptOnLine; GetPipePoint(m_idPipe, ptS, ptE); ptS.z = 0; ptE.z = 0; ptS = Wcs2Ucs(ptS); ptE = Wcs2Ucs(ptE); AcGeVector3d vt = ptE - ptS; vt.normalize(); ptS = Ucs2Wcs(ptS); ptE = Ucs2Wcs(ptE); AcDbLine lineFeed; lineFeed.setStartPoint(ptS); lineFeed.setEndPoint(ptE); lineFeed.getClosestPointTo(ptSan, ptOnLine, Adesk::kTrue); if (fabs(ptS.distanceTo(ptE) - ptOnLine.distanceTo(ptS) - ptOnLine.distanceTo(ptE)) < 0.001)// 洁具点在管线上的投影点在管线上 { bExtendFeedPipe = false; } vtPipe.normalize(); if (vtPipe.isEqualTo(vt, m_tolVec)) { ptFar = ptS; AddPipeLine(ptS, ptE, PipeType::eMainPipe); } else { ptFar = ptE; m_bPipeDir = false; } } // 查找给水点的起始墙体 if (!GetIntersectWall(ptFar, vtDir, lineStart, vtPipe, true)) { if (bIsParallel) { LinkSanWithoutWall(vecNode, vtPipe, bExtendFeedPipe, vtSan); } else if (!m_bErrorNote) { AfxMessageBox(sNote, MB_OK); m_bErrorNote = true; } return; } } else { // 主干方向无法确定时,查找最近墙体 if (!GetWallMiddleLine(ptFeed, lineStart)) { if (bIsParallel) { LinkSanWithoutWall(vecNode, vtPipe, bExtendFeedPipe, vtSan); } else if (!m_bErrorNote) { AfxMessageBox(sNote, MB_OK); m_bErrorNote = true; } return; } } // 查找最远洁具点的终止墙体 GetSanitaryDir(vtDir, idSan); if (!GetIntersectWall(ptSan, vtDir.perpVector(), lineEnd, vtDir.negate(), false)) { if (!GetWallMiddleLine(ptSan, lineEnd)) { if (bIsParallel) { LinkSanWithoutWall(vecNode, vtPipe, bExtendFeedPipe, vtSan); } else if (!m_bErrorNote) { AfxMessageBox(sNote, MB_OK); m_bErrorNote = true; } return; } } // 搜寻最短路径 std::vector vecRoad; if (!GetWallRoad(lineStart, lineEnd, vecRoad)) { if (!m_bErrorNote) { AfxMessageBox(sNote, MB_OK); m_bErrorNote = true; } return; } // 设定主干 if (!SetMainPipe(vecRoad, vecNode)) { return; } m_vecRoad = vecRoad; // 连接洁具 LinkSanitary(vecRoad, vecNode); // 设定管线标高 SetLinkableNode(); if (!IsVertivalPipe(m_idPipe))// 更新供水管 { Entity ent; ads_name name; acdbGetAdsName(name, m_idPipe); ent = name; ent.Erase(); } } // 连接无墙洁具 void UnfoldInstallSanitarySys::LinkSanWithoutWall(std::vector &vecNode, AcGeVector3d &vtPipe, bool bExtendFeedPipe, AcGeVector3d &vtSan) { std::vector::iterator it; it = vecNode.begin(); AcGePoint3d ptSan = it->pt, ptInter, ptE; ptSan.z = 0; ptSan = Wcs2Ucs(ptSan); m_ptFeed = Wcs2Ucs(m_ptFeed); AcGePoint3d ptX, ptY; ptX.x = ptSan.x; ptX.y = m_ptFeed.y; ptX.z = 0; ptY.x = m_ptFeed.x; ptY.y = ptSan.y; ptY.z = 0; if (IsVertivalPipe(m_idPipe)) { if (vecNode.size() > 1) { vtPipe = vtSan; } else { vtPipe = ptX - m_ptFeed; } } AcDbLine lineMain; lineMain.setStartPoint(m_ptFeed); AcGeVector3d vtX, vtY; vtX = ptY - m_ptFeed; vtY = ptX - m_ptFeed; if (vtX.isParallelTo(vtPipe, m_tolVec)) { lineMain.setEndPoint(ptY); ptSan = Ucs2Wcs(ptSan); m_ptFeed = Ucs2Wcs(m_ptFeed); ptY = Ucs2Wcs(ptY); ptE = ptY; if (bExtendFeedPipe) { AddPipeLine(m_ptFeed, ptY, PipeType::eMainPipe); } } else if (vtY.isParallelTo(vtPipe, m_tolVec)) { lineMain.setEndPoint(ptX); ptSan = Ucs2Wcs(ptSan); m_ptFeed = Ucs2Wcs(m_ptFeed); ptX = Ucs2Wcs(ptX); ptE = ptX; if (bExtendFeedPipe) { AddPipeLine(m_ptFeed, ptX, PipeType::eMainPipe); } } else { return; } // 存储洁具点结构 for (it = vecNode.begin(); it != vecNode.end(); it++) { m_mapSanPt.insert(std::make_pair(it->idSanitary, it->pt)); } if (vecNode.size() > 1 && vtSan.isPerpendicularTo(vtPipe))// 供水管和洁具线垂直,管线直接穿过洁具点 { LinkSanCrossPipe(vecNode, ptE); } else// 供水管和洁具线平行,直接投影 { LinkSan2Proj(vecNode, lineMain); } if (!IsVertivalPipe(m_idPipe))// 更新供水管 { Entity ent; ads_name name; acdbGetAdsName(name, m_idPipe); ent = name; ent.Erase(); } } // 连接管线直接穿过洁具点的洁具 void UnfoldInstallSanitarySys::LinkSanCrossPipe(std::vector &vecNode, AcGePoint3d &ptCross) { if (!IsVertivalPipe(m_idPipe)) { AcGePoint3d ptStart, ptEnd; GetPipePoint(m_idPipe, ptStart, ptEnd); ptStart.z = 0; m_ptFeed = ptStart; } LinkNode *pNodeS = new LinkNode; LinkNode *pNodeFeed = new LinkNode; pNodeS->ptCur = ptCross; pNodeS->type = Point_Int; pNodeS->pPreNode = pNodeFeed; pNodeFeed->ptCur = m_ptFeed; pNodeFeed->type = Point_Feed; pNodeFeed->pPreNode = NULL; pNodeFeed->m_vecNode.push_back(pNodeS); AcGePoint3d ptSan; std::vector::reverse_iterator itRev; for (itRev = vecNode.rbegin(); itRev != vecNode.rend(); itRev++) { ptSan = (*itRev).pt; ptSan.z = 0; LinkNode *pNode = new LinkNode; LinkNode *pNodeSan = new LinkNode; pNode->ptCur = ptSan; pNode->type = Point_Int | Point_KW; pNode->m_vecNode.push_back(pNodeSan); pNodeS->m_vecNode.push_back(pNode); pNode->pPreNode = pNodeS; pNodeSan->ptCur = ptSan; pNodeSan->type = Point_Sanitary; pNodeSan->pPreNode = pNode; pNodeS = pNode; } m_pNodeStart = pNodeFeed; ModifyPipeElve();// 设定管线标高 } // 连接投影到管线的洁具点 void UnfoldInstallSanitarySys::LinkSan2Proj(std::vector &vecNode, AcDbLine &lineMain) { AcGePoint3d ptSan, ptInter; std::vector::iterator it; while (!vecNode.empty()) { it = vecNode.begin(); ptSan = (*it).pt; ptSan.z = 0; ptSan = Wcs2Ucs(ptSan); lineMain.getClosestPointTo(ptSan, ptInter, Adesk::kTrue); ptSan = Ucs2Wcs(ptSan); ptInter = Ucs2Wcs(ptInter); if (ptSan.distanceTo(ptInter) < 0.001) { ptSan.z = 100; } AddPipeLine(ptInter, ptSan, PipeType::eBranch); vecNode.erase(it); } // 设定管线标高 SetLinkableNode(); } // 判断所有洁具点是否共线 bool UnfoldInstallSanitarySys::IsSanPtsParallel(std::vector &vecNode, AcGeVector3d &vtSan) { m_tolVec.setEqualVector(0.001); if (vecNode.size() < 2) { return true; } std::vector::iterator it; it = vecNode.begin(); AcGeVector3d vtFirst, vtSecond; AcGePoint3d ptFirst, ptSecond, ptThird; ptFirst = it->pt; ptFirst.z = 0; it++; ptSecond = it->pt; ptSecond.z = 0; vtFirst = ptFirst - ptSecond; ptFirst = Wcs2Ucs(ptFirst); ptSecond = Wcs2Ucs(ptSecond); it++; vtSan = ptFirst - ptSecond; ptSecond = Ucs2Wcs(ptSecond); while (it != vecNode.end()) { ptThird = it->pt; ptThird.z = 0; vtSecond = ptSecond - ptThird; if (!vtFirst.isParallelTo(vtSecond, m_tolVec)) { return false; } ptSecond = ptThird; it++; } return true; } // 设定主干 bool UnfoldInstallSanitarySys::SetMainPipe(std::vector &vecRoad, std::vector &vecNode) { if (vecRoad.size() < 1) { return false; } std::vector::iterator itWall; AcGePoint3d ptOnLine, ptS, ptE, ptPerS, ptPerE; AcGeVector3d vt, vtPer, vtStart, vtCur; std::vector vecLine; AcDbLine line; double dWidth = 0.0, dDistPipe2Wall = 0.0, dDistOldPipe2Wall = m_dDistPipe2Wall;; AcDbLine *pLine = NULL; bool bNotTurned = false; for (itWall = vecRoad.begin(); itWall != vecRoad.end(); itWall++) { if (NULL == (*itWall)) { continue; } dWidth = (*itWall)->dWidth / 2; ptS = (*itWall)->ptS; ptE = (*itWall)->ptE; ptS.z = 0; ptE.z = 0; pLine = new AcDbLine(); line.setStartPoint(ptS); line.setEndPoint(ptE); // 起始墙体和终止墙体需要特殊设定 if (itWall == vecRoad.begin())// 起始墙体 { if (!IsVertivalPipe(m_idPipe))// 给水管为非立管时 { // 根据墙体两侧是否有洁具 确定管线与墙体的位置(即管线安置在墙体有洁具的一侧) bool bSeted = false;// 能否确定管线与墙的关系 std::vector::iterator itSan; for (itSan = vecNode.begin(); itSan != vecNode.end(); itSan++) { AcGePoint3d ptSan = (*itSan).pt; ptSan.z = 0; if (line.getClosestPointTo(ptSan, ptOnLine) == Acad::eOk && ptOnLine.distanceTo(ptSan) < m_dDistSearchWall) { AcGeVector3d vtLine = ptE - ptS; vt = ptSan - ptOnLine; vt.normalize(); if (vtLine.isPerpendicularTo(vt, m_tolVec)) { bSeted = true; break; } } } GetPipePoint(m_idPipe, ptS, ptE); ptS.z = 0; ptE.z = 0; if (line.getClosestPointTo(m_ptFeed, ptOnLine) == Acad::eOk) { if (!bSeted)// 无法确定管线沿墙方向,穿墙布线 { vt = ptOnLine - m_ptFeed; if (!IsVertivalPipe(m_idPipe)) { vt = ptE - ptS; if (!m_bPipeDir) { vt = ptS - ptE; } } vt.normalize(); } ptOnLine = ptOnLine + vt * ((*itWall)->dWidth / 2 + m_dDistPipe2Wall); } // 延长管线从给水点到关联墙体 AcDbLine lineStart; lineStart.setStartPoint(ptS); lineStart.setEndPoint(ptE); AcGePoint3d ptTmp; lineStart.getClosestPointTo(ptOnLine, ptTmp); if (ptTmp.distanceTo(ptOnLine) > 0.001 && ptOnLine.distanceTo(m_ptFeed) > 0.001) { AcDbLine *pLineNew = new AcDbLine(); pLineNew->setStartPoint(m_ptFeed); pLineNew->setEndPoint(ptOnLine); vecLine.push_back(pLineNew); } m_ptFeed = ptOnLine; } else// 给水管为立管时,偏移距离为立管距墙距离 { vtStart = ptE - ptS; bNotTurned = true; line.getClosestPointTo(m_ptFeed, ptOnLine); dDistPipe2Wall = ptOnLine.distanceTo(m_ptFeed) - (*itWall)->dWidth / 2; } ptS = line.startPoint(); ptE = line.endPoint(); SetStartPipe(pLine, m_ptFeed, line, vtPer); if ((*itWall)->id == vecRoad.back()->id)// 路径只存在一个墙体 { AcGePoint3d ptStart = pLine->startPoint(); if (bNotTurned)// 墙体和起始墙体平行 { vtCur = ptE - ptS; if (vtCur.isParallelTo(vtStart, m_tolVec)) { m_dDistPipe2Wall = dDistPipe2Wall; } } SetEndPipe(pLine, (*vecNode.begin()).pt, line, dWidth); m_dDistPipe2Wall = dDistOldPipe2Wall; pLine->setStartPoint(ptStart); AcGePoint3dArray arryPts; arryPts.setLogicalLength(0); pLine->intersectWith(&line, AcDb::kOnBothOperands, arryPts); if (arryPts.length() > 0)// 主干和墙体相交,无法连接 { AfxMessageBox(_T("无法获取最优路径 "), MB_OK); return false; } } } else if ((*itWall)->id == vecRoad.back()->id)// 终止墙体 { if (bNotTurned)// 墙体和起始墙体平行 { vtCur = ptE - ptS; if (vtCur.isParallelTo(vtStart, m_tolVec)) { m_dDistPipe2Wall = dDistPipe2Wall; } } SetEndPipe(pLine, (*vecNode.begin()).pt, line, dWidth); m_dDistPipe2Wall = dDistOldPipe2Wall; } else // 中间墙体 { if (bNotTurned)// 墙体和起始墙体平行 { vtCur = ptE - ptS; if (vtCur.isParallelTo(vtStart, m_tolVec)) { m_dDistPipe2Wall = dDistPipe2Wall; } else { m_dDistPipe2Wall = dDistOldPipe2Wall; bNotTurned = false; } } SetMiddlePipe(ptS, ptE, line, vecNode, dWidth, ptPerS, ptPerE, vtPer); pLine->setStartPoint(ptS); pLine->setEndPoint(ptE); } vecLine.push_back(pLine); ptPerS = ptS; ptPerE = ptE; } ModifyPipe(vecLine, dWidth); std::vector::iterator it; for (it = vecLine.begin(); it != vecLine.end(); it++) { if (NULL == (*it) || (*it)->startPoint().distanceTo((*it)->endPoint()) < 0.001) { continue; } AddPipeLine((*it)->startPoint(), (*it)->endPoint(), PipeType::eMainPipe); } FreeLine(vecLine); return true; } // 根据主干 设定分支管和小支管 void UnfoldInstallSanitarySys::LinkSanitary(std::vector &vecRoad, std::vector &vecNode) { std::vector::iterator it; AcGePoint3d ptSan, ptS, ptE; AcDbObjectId idSan; AcDbLine line; AcGeVector3d vt; while (!vecNode.empty()) { it = vecNode.begin(); ptSan = (*it).pt; ptSan.z = 0; idSan = (*it).idSanitary; GetSanitaryDir(vt, idSan); if (!GetIntersectWall(ptSan, vt.perpVector(), line, vt.negate(), false)) { if (!GetWallMiddleLine(ptSan, line)) { vecNode.erase(it); continue; } } ptS = line.startPoint(); ptE = line.endPoint(); ptS.z = 0; ptE.z = 0; if (LinkSanitary2MainPipe(ptSan, ptS, ptE, vecNode)) { m_mapSanPt.insert(std::make_pair(it->idSanitary, it->pt));// 存储洁具点结构 } vecNode.erase(it); } } #define MAX_DIST 100000 // 添加支管和小支管 bool UnfoldInstallSanitarySys::LinkSanitary2MainPipe(const AcGePoint3d &ptSan, const AcGePoint3d &ptS, const AcGePoint3d &ptE, const std::vector vecNode) { AcDbLine line; line.setStartPoint(ptS); line.setEndPoint(ptE); AcDbLine lineCheck; AcGePoint3d ptOnLine, ptCheck, ptOnPipe, ptStart, ptEnd; if (line.getClosestPointTo(ptSan, ptOnLine) != Acad::eOk) { return false; } AcGeVector3d vtCheck = ptSan - ptOnLine, vtPipe; vtCheck.normalize(); ptCheck = ptOnLine + vtCheck * 1000; lineCheck.setStartPoint(ptOnLine); lineCheck.setEndPoint(ptCheck); std::vector vecRoad; double dDist = 0.0, dLen = 0.0, dDist1 = 0.0, dDist2 = 0.0; std::map mapPipe; std::map::iterator itMap; if (GetExtendPipe(mapPipe, lineCheck, ptSan, false))// 获取到可直接连接的主干 { itMap = mapPipe.begin(); ptOnPipe = (*itMap).second.ptIntersect; AcDbLine *pLine = (*itMap).second.pLine; if (NULL == pLine) { return false; } ptStart = pLine->startPoint(); ptEnd = pLine->endPoint(); dLen = ptStart.distanceTo(ptEnd); dDist1 = ptStart.distanceTo(ptOnPipe); dDist2 = ptEnd.distanceTo(ptOnPipe); AcGeVector3d vt = ptSan - ptOnLine; vt.normalize(); if (CheckPipe2Wall(ptEnd, ptOnPipe, line)) { if (fabs(dLen - dDist1 - dDist2) < 0.001)// 交点在管线上 { ; } else if (fabs(dDist1 - dLen - dDist2) < 0.001)// 交点在终点的延长线上 { if (!CheckPipePos(ptEnd, ptOnPipe)) { AcGePoint3d ptPer = ptEnd; ptEnd = ptEnd + vt * m_dDistPipe2Wall; ptOnPipe = ptOnPipe + vt * m_dDistPipe2Wall; AddPipeLine(ptPer, ptEnd, PipeType::eBranch); } AddPipeLine(ptEnd, ptOnPipe, PipeType::eMainPipe); } else if (fabs(dDist2 - dLen - dDist1) < 0.001)// 交点在起点的延长线上 { if (!CheckPipePos(ptStart, ptOnPipe)) { AcGePoint3d ptPer = ptStart; ptStart = ptStart + vt * m_dDistPipe2Wall; ptOnPipe = ptOnPipe + vt * m_dDistPipe2Wall; AddPipeLine(ptPer, ptStart, PipeType::eBranch); } AddPipeLine(ptStart, ptOnPipe, PipeType::eMainPipe); } AcGePoint3d ptSanitary = ptSan; if (ptOnPipe.distanceTo(ptSanitary) < 0.001)// 洁具直接穿过主干线 { ptSanitary.z = 100; } AddPipeLine(ptOnPipe, ptSanitary, PipeType::eSmallPipe);// 小支管不用偏移 return true; } } // 得到所有与墙线相交的主干 if (GetExtendPipe(mapPipe, line, ptSan, false)) { if(ExtendPipe2San(mapPipe, ptSan, ptOnLine, line)) { return true; } } // 延长墙体 得到主干 if (GetExtendPipe(mapPipe, line, ptSan, true)) { if(ExtendPipe2San(mapPipe, ptSan, ptOnLine, line)) { return true; } } // 未找到可连接管线,继续寻找最短路径 if (!GetBranchWallRoad(line, vecRoad)) { return false; } SetNewMainPipe(ptSan, vecRoad, vecNode); return true; } // 沿墙体延长管线 连接洁具 bool UnfoldInstallSanitarySys::ExtendPipe2San(std::map &mapPipe, const AcGePoint3d &ptSan, AcGePoint3d &ptOnLine, AcDbLine &line) { AcGePoint3d ptS, ptE, ptSanitary = ptSan; double dLen = 0.0, dDist1 = 0.0, dDist2 = 0.0 , dWallThick = 0.0; AcGePoint3d ptMainEnd; AcGePoint3d ptMainStart; std::map::iterator itMap; AcDbLine line1, line2; bool bRet1 = false, bRet2 = false; m_vtSan = ptSanitary - ptOnLine; while (!mapPipe.empty()) { itMap = mapPipe.begin(); ptMainEnd = ptOnLine; ptMainStart = (*itMap).second.ptIntersect; bRet1 = GetNearestWall(ptMainEnd, ptMainEnd - ptMainStart, line1, dWallThick); ptS = (*itMap).second.pLine->startPoint(); ptE = (*itMap).second.pLine->endPoint(); bRet2 = GetNearestWall(ptS, ptE - ptS, line2, dWallThick); if (bRet2 && bRet1) { if (CheckPipe2Wall(ptMainStart, ptMainEnd, line1) && CheckPipe2Wall(ptS, ptMainStart, line2)) { break; } } else if (bRet1 && CheckPipe2Wall(ptMainStart, ptMainEnd, line1) && (*itMap).second.nId == 0)// 与供水管相交时,不用考虑供水管延长线是否穿越墙体 { break; } mapPipe.erase(itMap); } if (mapPipe.empty()) { return false; } AcDbObjectId id; WallData *pNode = NULL; GetWallId(m_vecAllWall, line, id); CheckWallInLst(m_vecAllWall, id, pNode); if (NULL == pNode) { return false; } OffSetPipe(ptMainStart, ptMainEnd, ptSan - ptMainEnd, pNode->dWidth / 2); AddPipeLine(ptMainEnd, ptSanitary, PipeType::eSmallPipe); AddPipeLine(ptMainStart, ptMainEnd, PipeType::eMainPipe); dLen = ptS.distanceTo(ptE); dDist1 = ptS.distanceTo(ptMainStart); dDist2 = ptE.distanceTo(ptMainStart); AcGeVector3d vt = ptSan - ptOnLine; vt.normalize(); if (fabs(dDist1 - dLen - dDist2) < 0.001) { AddPipeLine(ptE, ptMainStart, PipeType::eMainPipe); } else if (fabs(dDist2 - dLen - dDist1) < 0.001) { AddPipeLine(ptS, ptMainStart, PipeType::eMainPipe); } return true; } // 释放管线节点 void UnfoldInstallSanitarySys::FreeLine(std::vector &vecLine) { std::vector::iterator it; for (it = vecLine.begin(); it != vecLine.end(); it++) { if ((*it) != NULL) { delete *it; *it = NULL; } } } // 释放路径节点 void UnfoldInstallSanitarySys::FreeNode(std::vector &vecNode) { std::vector::iterator it; for (it = vecNode.begin(); it != vecNode.end(); it++) { if ((*it) != NULL) { delete *it; *it = NULL; } } } // 连接次级主干 void UnfoldInstallSanitarySys::SetNewMainPipe(const AcGePoint3d &pt, std::vector &vecRoad, const std::vector &vecNode) { WallData *pNodeS = NULL, *pNodeE = NULL; AcGePoint3d ptNodeS, ptNodeS2, ptNodeE, ptNodeE2; std::vector::reverse_iterator itCur; std::vector::iterator itNor; if (vecRoad.empty()) { return; } // 查找本路线相连的已存在的管线 itCur = vecRoad.rbegin(); // 记录修改前的墙体数据 pNodeS = *itCur; ptNodeS = pNodeS->ptS; ptNodeS2 = pNodeS->ptE; AcDbLine line; AcGePoint3d ptS = (*itCur)->ptS; AcGePoint3d ptE = (*itCur)->ptE; ptS.z = 0; ptE.z = 0; line.setStartPoint(ptS); line.setEndPoint(ptE); AcGePoint3d ptOnLine, ptPerS, ptPerE, ptStart, ptEnd; AcGeVector3d vtPer; double dLen = 0.0, dDist1 = 0.0, dDist2 = 0.0, dDist = 0.0; std::map mapLink; // 得到所有与起始墙线相交的主干 bool bExtendWall = false; if (!GetExtendPipe(mapLink, line, pt, false))// 找不到相关管线 { bExtendWall = true; GetExtendPipe(mapLink, line, pt, true);// 延长墙体 } // 设定起始墙体 if (mapLink.empty()) { return; } std::map::iterator itMap = mapLink.begin(); ptOnLine = (*itMap).second.ptIntersect; AcGePoint3d ptMainEnd = ptOnLine; AcGePoint3d ptMainStart; ptPerS = (*itMap).second.pLine->startPoint(); ptPerE = (*itMap).second.pLine->endPoint(); vtPer = ptPerE - ptPerS; vtPer = vtPer.perpVector(); (*itCur)->ptE = ptOnLine; // 设置结束管线 itNor = vecRoad.begin(); pNodeE = *itNor; ptNodeE = pNodeE->ptS; ptNodeE2 = pNodeE->ptE; ptS = vecRoad.front()->ptS; ptE = vecRoad.front()->ptE; ptS.z = 0; ptE.z = 0; line.setStartPoint(ptS); line.setEndPoint(ptE); AcGePoint3d ptOnWall; line.getClosestPointTo(pt, ptOnWall); (*itNor)->ptS = ptOnWall; ptEnd = ptOnWall; // 连接次级主干 LinkNewMainPipe(vecRoad, vecNode, mapLink, pt, ptOnLine, ptPerS, ptPerE, vtPer); // 恢复墙体数据 pNodeE->ptS = ptNodeE; pNodeE->ptE = ptNodeE2; pNodeE->ptS = ptNodeE; pNodeE->ptE = ptNodeE2; } void UnfoldInstallSanitarySys::LinkNewMainPipe(std::vector &vecRoad, const std::vector &vecNode, std::map &mapLink, const AcGePoint3d &pt, AcGePoint3d &ptOnLine, AcGePoint3d &ptPerS, AcGePoint3d ptPerE, AcGeVector3d &vtPer) { AcGePoint3d ptMainEnd = ptOnLine; AcGePoint3d ptMainStart; std::vector::reverse_iterator itCur; std::map::iterator itMap = mapLink.begin(); double dWidth = 0.0; std::vector vecLine; AcDbLine line; AcGePoint3d ptS, ptE; for (itCur = vecRoad.rbegin(); itCur != vecRoad.rend(); itCur++) { if (NULL == *itCur) { continue; } ptE = (*itCur)->ptS; ptS = (*itCur)->ptE; ptS.z = 0; ptE.z = 0; line.setStartPoint(ptS); line.setEndPoint(ptE); AcDbLine *pLine = new AcDbLine; dWidth = (*itCur)->dWidth / 2; SetMiddlePipe(ptS, ptE, line, vecNode, dWidth, ptPerS, ptPerE, vtPer); if (itCur == vecRoad.rbegin() && fabs((*itMap).first - MAX_DIST) < 0.001)// 与主干延长线相交时,延长主干 { AcDbLine *pLineExtend = new AcDbLine; ptMainStart = (*itMap).second.pLine->endPoint(); // 交点在主干反方向时 if (ptMainEnd.distanceTo((*itMap).second.pLine->endPoint()) - (*itMap).second.pLine->startPoint().distanceTo((*itMap).second.pLine->endPoint())) { ptMainStart = (*itMap).second.pLine->startPoint(); } AcGeVector3d vt = ptE - ptS; vt.normalize(); if (!CheckPipePos(ptMainStart, ptMainEnd))// 判断延长线是否与其他管线碰撞 { AcGePoint3d ptOld = ptMainStart; ptMainStart = ptMainStart + vt * m_dDistPipe2Wall; ptMainEnd = ptMainEnd + vt * m_dDistPipe2Wall; AddPipeLine(ptOld, ptMainStart, PipeType::eMainPipe); } pLineExtend->setStartPoint(ptMainStart); pLineExtend->setEndPoint(ptMainEnd); vecLine.push_back(pLineExtend); } pLine->setStartPoint(ptS); pLine->setEndPoint(ptE); vecLine.push_back(pLine); ptPerE = pLine->endPoint(); ptPerS = pLine->startPoint(); } // 设定洁具点到管线的连线 AddPipeLine(ptE, pt, PipeType::eBranch); ModifyPipe(vecLine, dWidth); std::vector::iterator it; for (it = vecLine.begin(); it != vecLine.end(); it++) { if (*it == NULL || (*it)->startPoint().distanceTo((*it)->endPoint()) < 0.001) { continue; } AddPipeLine((*it)->startPoint(), (*it)->endPoint(), PipeType::eMainPipe); } FreeLine(vecLine); } // 检查管线是否沿墙敷设 bool UnfoldInstallSanitarySys::CheckPipe2Wall(const AcGePoint3d &ptS, const AcGePoint3d &ptE, const AcDbLine &lineStartWall) { AcDbLine line; line.setStartPoint(ptS); line.setEndPoint(ptE); AcGeVector3d vtLine = ptS - ptE, vtPipe2Wall, vtWall, vt; vtLine.normalize(); AcGePoint3d ptStart, ptEnd, ptOnLine1, ptOnLine2; double dLen = 0.0, dDist2Start = 0.0, dDist2End = 0.0, dLength = 0.0, dDist2End2 = 0.0, dDist2Start2 = 0.0, dWallLen = 0.0; dLen = ptS.distanceTo(ptE); const double dDist = DocGetMeterUnitDim() ? 0.70 : 700; AcDbLine lineWall; lineWall.setStartPoint(lineStartWall.startPoint()); lineWall.setEndPoint(lineStartWall.endPoint()); lineWall.getClosestPointTo(ptS, ptOnLine1, Adesk::kTrue); if (ptS.distanceTo(ptOnLine1) > 0.001) { vtPipe2Wall = ptOnLine1 - ptS; } else { vtPipe2Wall = m_vtSan; } vtPipe2Wall.normalize(); double dDist2Wall = ptS.distanceTo(ptOnLine1); // 找到所有与管线平行墙体 std::vector::iterator it; for (it = m_vecAllWall.begin(); it != m_vecAllWall.end(); it++) { // 墙体和管线的关系 ptStart = (*it)->ptS; ptEnd = (*it)->ptE; dLength = ptStart.distanceTo(ptEnd); lineWall.setStartPoint(ptStart); lineWall.setEndPoint(ptEnd); lineWall.getClosestPointTo(ptS, ptOnLine1, Adesk::kTrue); if (ptS.distanceTo(ptOnLine1) > 0.001) { vt = ptOnLine1 - ptS; } else { vt = m_vtSan; } vt.normalize(); vtWall = ptStart - ptEnd; vtWall.normalize(); double dDistPipe2Wall = GetDistLines(&lineWall, &line); // 平行墙体 且墙体距离管线距离为 初始墙体到管线距离 且在管线同侧 if (vtWall.isParallelTo(vtLine, m_tolVec) && fabs(dDistPipe2Wall - dDist2Wall) < dDist && vt.isEqualTo(vtPipe2Wall, m_tolVec)) { // 墙体长度 lineWall.getClosestPointTo(ptS, ptOnLine1, Adesk::kTrue); dDist2Start = ptOnLine1.distanceTo(ptStart); dDist2End = ptOnLine1.distanceTo(ptEnd); lineWall.getClosestPointTo(ptE, ptOnLine2, Adesk::kTrue); dDist2Start2 = ptOnLine2.distanceTo(ptStart); dDist2End2 = ptOnLine2.distanceTo(ptEnd); double dDistWall2Pipe = 0.0, dDistWall2Pipe2 = 0.0; AcGePoint3d ptTmp; line.getClosestPointTo(ptStart, ptTmp, Adesk::kTrue); dDistWall2Pipe = ptStart.distanceTo(ptTmp); line.getClosestPointTo(ptStart, ptTmp, Adesk::kFalse); dDistWall2Pipe2 = ptStart.distanceTo(ptTmp); if (fabs(dLength - dDist2Start - dDist2End) < 0.001 && fabs(dLength - dDist2Start2 - dDist2End2) < 0.001)// 既是起始墙体 又是结束墙体 { return true; } if (fabs(dLength - dDist2Start - dDist2End) < 0.001)// 起始墙体 { if (vtLine.isEqualTo(vtWall)) { dWallLen += ptEnd.distanceTo(ptOnLine1); } else { dWallLen += ptStart.distanceTo(ptOnLine1); } } else if (fabs(dLength - dDist2Start2 - dDist2End2) < 0.001)// 结束墙体 { if (vtLine.isEqualTo(vtWall)) { dWallLen += ptStart.distanceTo(ptOnLine2); } else { dWallLen += ptEnd.distanceTo(ptOnLine2); } } else if (fabs(dDistWall2Pipe - dDistWall2Pipe2) < 0.001)// 中间墙体 { line.getClosestPointTo(ptStart, ptOnLine1); dDist2Start = ptOnLine1.distanceTo(ptS); dDist2End = ptOnLine1.distanceTo(ptE); line.getClosestPointTo(ptEnd, ptOnLine2); dDist2Start2 = ptOnLine2.distanceTo(ptS); dDist2End2 = ptOnLine2.distanceTo(ptE); if (fabs(dLen - dDist2Start - dDist2End) < 0.001 && fabs(dLen - dDist2Start2 - dDist2End2) < 0.001) { dWallLen += ptStart.distanceTo(ptEnd); } } } } if (fabs(dWallLen - dLen) < dDist) { return true; } return false; } // 分别延长管线和墙体 求交点 bool UnfoldInstallSanitarySys::GetExtendPipe(std::map &mapLink, AcDbLine &line, const AcGePoint3d &pt, bool bExtend) { mapLink.clear(); double dDist = 0.0, dLen = 0.0, dDist1 = 0.0, dDist2 = 0.0; AcGePoint3d ptOnLine, ptS, ptE, ptLineS, ptLineE; AcGePoint3dArray arryPts; std::vector::iterator itPipe; ptLineS = line.startPoint(); ptLineE = line.endPoint(); ptLineE = Wcs2Ucs(ptLineE); ptLineS = Wcs2Ucs(ptLineS); AcGeVector3d vtWall = ptLineE - ptLineS, vtPipe; vtWall.normalize(); for (itPipe = m_vecPipeData.begin(); itPipe != m_vecPipeData.end(); itPipe++) { if ((*itPipe).type != PipeType::eMainPipe || (*itPipe).pLine == NULL) { continue; } arryPts.setLogicalLength(0); Acad::ErrorStatus es1, es2; if (bExtend) { es1 = (*itPipe).pLine->intersectWith(&line, AcDb::kExtendBoth, arryPts); } else { // 只延长管线和 墙体本身 求交点 es2 = (*itPipe).pLine->intersectWith(&line, AcDb::kExtendThis, arryPts); } ptS = (*itPipe).pLine->startPoint(); ptE = (*itPipe).pLine->endPoint(); ptS = Wcs2Ucs(ptS); ptE = Wcs2Ucs(ptE); vtPipe = ptE - ptS; vtPipe.normalize(); if (arryPts.length() == 1 && vtWall.isPerpendicularTo(vtPipe, m_tolVec)) { ptOnLine = arryPts[0]; ptOnLine.z = 0; dDist = 0.0; ptS = (*itPipe).pLine->startPoint(); ptE = (*itPipe).pLine->endPoint(); dLen = ptS.distanceTo(ptE); dDist1 = ptS.distanceTo(ptOnLine); dDist2 = ptE.distanceTo(ptOnLine); if (fabs(dLen - dDist1 - dDist2) < 0.001 && ptOnLine.distanceTo(ptS) > 0.001)// 与管线本身相交 { dDist = ptOnLine.distanceTo(pt); } else// 与管线延长线相交 { dDist = MAX_DIST; } LinkedLine WallData; WallData.pLine = (*itPipe).pLine; WallData.ptIntersect = ptOnLine; WallData.nId = itPipe->nId; mapLink.insert(std::make_pair(dDist, WallData)); } } if (mapLink.empty()) { return false; } return true; } // 添加管线 void UnfoldInstallSanitarySys::AddPipeLine(const AcGePoint3d &ptS, const AcGePoint3d &ptE, PipeType type) { if (ptS.distanceTo(ptE) < 0.001) { return; } AcDbLine *pLine = new AcDbLine; pLine->setStartPoint(ptS); pLine->setEndPoint(ptE); AcGePoint3d pt1 = ptS, pt2 = ptE; AcGeVector3d vtX = AcGeVector3d::kXAxis; AcGeVector3d vtY = AcGeVector3d::kYAxis; AcGeVector3d vt = pt1 - pt2; PipeData data; if (vt.isParallelTo(vtX, m_tolVec)) { data.drection = PipeDir::eParallelX; } else if (vt.isParallelTo(vtY, m_tolVec)) { data.drection = PipeDir::eParallelY; } else { data.drection = PipeDir::eParallelX; } data.pLine = pLine; data.type = type; data.nId = m_nId++; m_vecPipeData.push_back(data); } // 在XOY平面内与vtDir平行,并且在pt点的vtPipe方向的墙体 bool UnfoldInstallSanitarySys::GetIntersectWall( const AcGePoint3d &pt, const AcGeVector3d &vtDir, AcDbLine &line, AcGeVector3d &vtPipe, bool bExtend) { vtPipe.normalize(); AcGeVector3d vt = vtDir; vt.z = 0.0; std::vector > vecWall; std::vector >::iterator it; AcGeVector3d vtWall, vtLine; AcDbLine lineWall; AcGePoint3d ptOnLine, ptEnt = pt; ptEnt.z = 0; AcGeTol tolVec; tolVec.setEqualVector(0.1); for (it = m_vecWallSide.begin(); it != m_vecWallSide.end(); it++) { if (it->first.GetCurveType() == CURVE_LINE) { lineWall.setStartPoint(it->first.StartPoint()); lineWall.setEndPoint(it->first.EndPoint()); lineWall.getClosestPointTo(ptEnt, ptOnLine); double dDist = ptEnt.distanceTo(ptOnLine); ptOnLine.z = 0; ptOnLine = Wcs2Ucs(ptOnLine); AcGePoint3d ptSan = pt; ptSan = Wcs2Ucs(ptSan); vtLine = ptOnLine - ptSan; vtLine.normalize(); vtLine.z = 0; vtWall = Wcs2Ucs(it->first.StartPoint()) - Wcs2Ucs(it->first.EndPoint()); vtWall.z = 0.0; if (vtWall.isParallelTo(vt, tolVec) && (vtLine.isEqualTo(vtPipe, tolVec))) { vecWall.push_back(*it); } } } // 找到距离pt最近的墙体 XCurveSegment segNear, segFar; if (GetWallSide(pt, vecWall, segNear, segFar)) { // 墙体厚度 AcGePoint3d ptS = segFar.StartPoint(); AcGePoint3d ptE = segFar.EndPoint(); ptS.z = 0.0; ptE.z = 0.0; AcDbLine lineTemp(ptS, ptE); AcGePoint3d pt = segNear.StartPoint(); pt.z = 0.0; AcGePoint3d ptPrj; const double dDist = DocGetMeterUnitDim() ? 1.0 : 1000; double dDistWall2San = 0.0; if (lineTemp.getClosestPointTo(pt, ptPrj, Adesk::kTrue) == Acad::eOk) { double dWallThick = pt.distanceTo(ptPrj); if (!bExtend) { // 墙体距离Pt点距离大于1000时,查找失败 lineTemp.getClosestPointTo(ptEnt, ptOnLine, Adesk::kTrue); dDistWall2San = ptEnt.distanceTo(ptOnLine); if (dDistWall2San - dWallThick / 2 > dDist + dWallThick * 0.5) { return false; } } AcGeVector3d vt = pt - ptPrj; vt.normalize(); line.setStartPoint(segFar.StartPoint() + vt * dWallThick * 0.5); line.setEndPoint(segFar.EndPoint() + vt * dWallThick * 0.5); return true; } } return false; } // 设置起始管线 void UnfoldInstallSanitarySys::SetStartPipe(AcDbLine *pLine, AcGePoint3d &ptStart, const AcDbLine &line, AcGeVector3d &vtPer) { AcGePoint3d ptTmp; if (line.getClosestPointTo(ptStart, ptTmp) != Acad::eOk) { return; } AcGeVector3d vt = ptStart - ptTmp; vt.normalize(); AcGePoint3d ptEnd; ptEnd = line.endPoint() + vt * ptStart.distanceTo(ptTmp); if (!CheckPipePos(ptStart, ptEnd)) { ptTmp = ptStart; ptStart = ptStart + vt * m_dDistPipe2Wall; ptEnd = ptEnd + vt * m_dDistPipe2Wall; AddPipeLine(ptTmp, ptStart, PipeType::eMainPipe); } vtPer = vt; pLine->setEndPoint(ptEnd); pLine->setStartPoint(ptStart); } // 设置中间管线 void UnfoldInstallSanitarySys::SetMiddlePipe(AcGePoint3d &ptStart, AcGePoint3d &ptEnd, const AcDbLine &line, const std::vector &vecNode, double dWidth, AcGePoint3d &ptPerS, AcGePoint3d &ptPerE, AcGeVector3d &vtPer) { AcGePoint3d ptS = line.startPoint(); AcGePoint3d ptE = line.endPoint(); AcGePoint3d ptOnLine; bool bSeted = false; AcGeVector3d vt; std::vector::const_iterator itSan; // 根据墙体两侧是否有洁具 确定管线与墙体的位置(即管线安置在墙体有洁具的一侧) for (itSan = vecNode.begin(); itSan != vecNode.end(); itSan++) { AcGePoint3d ptSan = (*itSan).pt; ptSan.z = 0; if (line.getClosestPointTo(ptSan, ptOnLine) == Acad::eOk && ptOnLine.distanceTo(ptSan) < m_dDistSearchWall) { AcGeVector3d vtLine = ptE - ptS; vt = ptSan - ptOnLine; vt.normalize(); if (vtLine.isPerpendicularTo(vt, m_tolVec)) { OffSetPipe(ptS, ptE, vt, dWidth); vtPer = vt; bSeted = true; break; } } } if (!bSeted)// 墙体两侧1000范围无洁具 { // 和上游墙体平行时,按照上游偏移方向 偏移. 垂直时,向上游方向偏移 AcGeVector3d vtNor = ptE - ptS; vt = ptPerE - ptPerS; if (!vt.isParallelTo(vtNor, m_tolVec)) { vtPer = -vt; } OffSetPipe(ptS, ptE, vtPer, dWidth); } ptStart = ptS; ptEnd = ptE; } // 设置终止管线 void UnfoldInstallSanitarySys::SetEndPipe(AcDbLine *pLine, AcGePoint3d &ptEnd, const AcDbLine &line, double dWidth) { AcGePoint3d ptTmp; ptEnd.z = 0; if (line.getClosestPointTo(ptEnd, ptTmp) != Acad::eOk) { return; } AcGeVector3d vt = ptEnd - ptTmp; AcGePoint3d ptStart; ptStart = line.startPoint(); OffSetPipe(ptStart, ptTmp, vt, dWidth); pLine->setEndPoint(ptTmp); pLine->setStartPoint(ptStart); } // 从链表起点生成管网 void UnfoldInstallSanitarySys::CreatePipeFromStart(LinkNode *pNode, std::vector &vecNode) { LinkNode *pNodeNext = NULL; if (NULL != pNode) { std::vector::iterator it; if (pNode->m_vecNode.empty()) { vecNode.push_back(pNode); return; } for (it = pNode->m_vecNode.begin(); it != pNode->m_vecNode.end(); it++) { pNodeNext = *it; CString sLayer = GetPipeLayer(m_sysPipe); TDbPipe *pPipe = new TDbPipe(); XLine x; x.SetStartPoint(pNode->ptCur); x.SetEndPoint(pNodeNext->ptCur); x.Make(); CreatePipeFromStart(pNodeNext, vecNode); } } } // 生成管线 void UnfoldInstallSanitarySys::CreatePipe() { std::vector::iterator it; CString sLayer = GetPipeLayer(m_sysPipe); InitPipeLayer(sLayer); AcGePoint3d ptS, ptE; for (it = m_vecPipeData.begin(); it != m_vecPipeData.end(); it++) { TDbPipe *pPipe = new TDbPipe(); ptS = it->pLine->startPoint(); ptE = it->pLine->endPoint(); ptS.z = m_dElev; ptE.z = m_dElev; pPipe->SetStartPoint(ptS); pPipe->SetEndPoint(ptE); pPipe->SetFlowDir(TPipeSys::kFromStart); pPipe->SetDnDiameter(m_dPipeDn); pPipe->setLayer(sLayer); pPipe->SetSysType(GetPipeSysByLayer(sLayer)); AddToCurrentSpace(pPipe, Adesk::kTrue); } } // 偏移管线 void UnfoldInstallSanitarySys::OffSetPipe(AcGePoint3d &ptS, AcGePoint3d &ptE, AcGeVector3d vt, double dWidth) { // 发生碰撞时,最多偏移2次 vt.normalize(); ptS = ptS + vt * (m_dDistPipe2Wall + dWidth); ptE = ptE + vt * (m_dDistPipe2Wall + dWidth); if (!CheckPipePos(ptS, ptE)) { ptS = ptS + vt * m_dDistPipe2Wall; ptE = ptE + vt * m_dDistPipe2Wall; if (!CheckPipePos(ptS, ptE)) { ptS = ptS + vt * m_dDistPipe2Wall; ptE = ptE + vt * m_dDistPipe2Wall; } } } // 校准管线 void UnfoldInstallSanitarySys::ModifyPipe(std::vector &vecLine, double dDist) { AcGePoint3dArray arryPts; AcGePoint3d ptTmp, ptS, ptE; AcGeVector3d vt; int n = vecLine.size(); std::vector vecNew; std::vector::iterator it; it = vecLine.begin(); if ((*it) == NULL) { return; } AcDbLine *pLineFirst = NULL, *pLineSecond = NULL; pLineFirst = *it; it++; while (it != vecLine.end()) { arryPts.setLogicalLength(0); if ((*it) == NULL || (*it)->startPoint().distanceTo((*it)->endPoint()) < (dDist + 200)) { it = vecLine.erase(it); continue; } pLineSecond = *it; Acad::ErrorStatus es = pLineFirst->intersectWith(pLineSecond,AcDb::kExtendBoth, arryPts); if (arryPts.length() == 1) { ptTmp = arryPts[0]; pLineFirst->setEndPoint(ptTmp); pLineSecond->setStartPoint(ptTmp); } else if (pLineFirst->endPoint().distanceTo(pLineSecond->startPoint()) > 0.001)// 前后两根管线平行 { ptS = pLineFirst->startPoint(); ptE = pLineFirst->endPoint(); ptS = Wcs2Ucs(ptS); ptE = Wcs2Ucs(ptE); double dDist2Pipe = GetDistLines(pLineFirst, pLineSecond); if (dDist2Pipe - (200 - m_dDistPipe2Wall) < 0.001)// 平行管线距离小于80时,平移第二根对齐第一根管 { ptE = Ucs2Wcs(ptE); pLineSecond->getClosestPointTo(ptE, ptTmp, Adesk::kTrue); pLineSecond->setStartPoint(ptE); ptE = Wcs2Ucs(ptE); ptTmp = Wcs2Ucs(ptTmp); vt = ptE - ptTmp; ptE = pLineSecond->endPoint(); ptE = Wcs2Ucs(ptE); ptE += vt; ptE = Ucs2Wcs(ptE); pLineSecond->setEndPoint(ptE); } else { vt = ptE - ptS; vt.normalize(); ptS = pLineSecond->startPoint(); pLineFirst->getClosestPointTo(ptS, ptE, Adesk::kTrue); OffSetPipe(ptS, ptE, vt, dDist / 2); pLineFirst->setEndPoint(ptE); pLineSecond->setStartPoint(ptS); AcDbLine *pLine = new AcDbLine; pLine->setStartPoint(ptE); pLine->setEndPoint(ptS); vecNew.push_back(pLine); } } pLineFirst = pLineSecond; it++; } for (it = vecNew.begin(); it != vecNew.end(); it++) { if ((*it) == NULL || (*it)->startPoint().distanceTo((*it)->endPoint()) < 0.001) { continue; } vecLine.push_back(*it); } for (it = vecLine.begin(); it != vecLine.end();) { if ((*it) == NULL || (*it)->startPoint().distanceTo((*it)->endPoint()) < 0.001) { it = vecLine.erase(it); } else { it++; } } } // 判定管线位置是否合适 bool UnfoldInstallSanitarySys::CheckPipePos(const AcGePoint3d &ptS, const AcGePoint3d &ptE) { AcDbLine line(ptS, ptE); if ((!PassParallelWall(ptS, ptE)) // 没有穿过平行墙体 && !IsPassOtherSanitarySysPt(ptS, ptE) // 没有穿过其他系统洁具点 && !IsCollidePipe(&line, m_dDistPipe2Pipe))// 没有与其他系统平行管线发生碰撞 { return true; } return false; } // 给水管是立管时 确定主干方向 bool UnfoldInstallSanitarySys::ConfirmPipeDir(AcGeVector3d &vtPipe, const AcGePoint3d &ptSan, AcGeVector3d &vtDir) { AcGePoint3d ptS, ptE, pt = ptSan; GetPipePoint(m_idPipe, ptS, ptE); m_dElev = ptS.z; ptE.z = 0; ptS.z = 0; ptE = Wcs2Ucs(ptE); ptS = Wcs2Ucs(ptS); pt.z = 0; pt = Wcs2Ucs(pt); AcGePoint3d ptX, ptY; ptX.x = pt.x; ptX.y = ptS.y; ptX.z = 0; ptY.x = ptS.x; ptY.y = pt.y; ptY.z = 0; if (IsVertivalPipe(m_idPipe))// 立管 { m_dElev = 0.0; int nIndX = PassVertivalPipeNumByLine(ptS, ptX); int nIndY = PassVertivalPipeNumByLine(ptS, ptY); // 都经过立管或都不经过立管时 if ((nIndX > 0 && nIndY > 0) || (nIndX == 0 && nIndY == 0)) { return false; } else if (nIndX > 0) { vtDir = ptY - ptS; } else { vtDir = ptX - ptS; } } else// 直管 { vtPipe = ptE - ptS; if (vtPipe.isParallelTo(ptY - ptS, m_tolVec)) { vtPipe = ptY - ptS; } else if (vtPipe.isParallelTo(ptX - ptS, m_tolVec)) { vtPipe = ptX - ptS; } vtPipe.normalize(); vtDir = vtPipe.perpVector(); } return true; } // 获取全部有用墙体边线,过滤掉厚度小于100的墙体 void UnfoldInstallSanitarySys::ModifyUsefulWall() { m_vecAllWallSide = m_vecWallSide; m_vecWallSide.clear(); XCurveSegment segNear, segFar; std::vector >::iterator it; double dWallThick = 0.0; const double dThick = DocGetMeterUnitDim() ? 0.07 : 70; for (it = m_vecAllWallSide.begin(); it != m_vecAllWallSide.end(); it++) { segNear = it->first; segFar = it->second; // 墙体厚度 AcGePoint3d ptS = segFar.StartPoint(); AcGePoint3d ptE = segFar.EndPoint(); ptS.z = 0.0; ptE.z = 0.0; AcDbLine lineTemp(ptS, ptE); AcGePoint3d pt = segNear.StartPoint(); pt.z = 0.0; AcGePoint3d ptPrj; if (lineTemp.getClosestPointTo(pt, ptPrj, Adesk::kTrue) == Acad::eOk) { dWallThick = pt.distanceTo(ptPrj); if (dWallThick - dThick > 0.001) { m_vecWallSide.push_back(*it); } } } Entity ent; PickSet ssWall(SS_FREE); for(long i = 0; i < m_ssDoorWall.Length(); i++) { ent = m_ssDoorWall[i]; if (ent.Is(_T("TCH_Wall"))) { OPENOBJ_BEGIN(ent, AcDb::kForRead, TDbWall, pWall); if(pWall && pWall->GetWidth(4) - 100.0 < 0.001) { ssWall += ent; } OPENOBJ_END(); } } m_ssDoorWall -= ssWall; } // 获取距离点最近的墙体的中线 bool UnfoldInstallSanitarySys::GetWallMiddleLine(const AcGePoint3d &pt, AcDbLine &line) { XCurveSegment segNear, segFar; if (!GetNearestWall(pt, m_dDistSearchWall, segNear, segFar)) { return false; } AcGePoint3d ptS = segFar.StartPoint(); AcGePoint3d ptE = segFar.EndPoint(); ptS.z = 0.0; ptE.z = 0.0; AcDbLine lineTemp(ptS, ptE); AcGePoint3d ptNear = segNear.StartPoint(); ptNear.z = 0.0; AcGePoint3d ptPrj; if (lineTemp.getClosestPointTo(ptNear, ptPrj, Adesk::kTrue) == Acad::eOk) { double dWallThick = ptNear.distanceTo(ptPrj); AcGeVector3d vt = ptNear - ptPrj; vt.normalize(); line.setStartPoint(segFar.StartPoint() + vt * dWallThick * 0.5); line.setEndPoint(segFar.EndPoint() + vt * dWallThick * 0.5); return true; } else { return false; } return false; } // 判断该ID是否存在于墙体链表中,若存在,则返回指向该节点的链表 bool UnfoldInstallSanitarySys::CheckWallInLst(const std::vector &vecNode, const AcDbObjectId &id, WallData *&pNodeFind) { pNodeFind = NULL; std::vector::const_iterator it; for (it = vecNode.begin(); it != vecNode.end(); it++) { if ((*it)->id == id) { pNodeFind = *it; return true; } } return false; } // 判断两个墙体节点之间是否有关联关系 bool UnfoldInstallSanitarySys::CheckRelation(WallData *pNode, WallData *pNodeFind) { for (int i = 0; i < pNode->lstNode.Length(); i++) { if (pNode->lstNode[i] == pNodeFind) { return true; } } return false; } // 把墙体关系转换为链表 void UnfoldInstallSanitarySys::SetWallMap(PickSet &ss, WallData *&pNode, std::vector &vecNode) { if (NULL == pNode) { return; } AcGePoint3d ptS, ptE; for (long l = 0; l < ss.Length(); l++) { Entity ent = ss[l];// 找出一个墙体 OPENOBJ_BEGIN(ent, AcDb::kForRead, TDbWall, pWall); if(NULL != pWall) { ptS = pWall->StartPoint(); ptS.z = 0.0; ptE = pWall->EndPoint(); ptE.z = 0.0; if ((ptS.distanceTo(pNode->ptS) < 0.001 || ptS.distanceTo(pNode->ptE) < 0.001 || ptE.distanceTo(pNode->ptS) < 0.001 || ptE.distanceTo(pNode->ptE) < 0.001) && (pWall->id() != pNode->id)) { // 该墙体和当前链表节点相连 WallData *pNodeFind = NULL; if (CheckWallInLst(vecNode, pWall->id(), pNodeFind))// 墙体在链表中 { if (NULL != pNodeFind && pNodeFind->id != pNode->id) { // 检查关联是否存在,不存在则创建关联 if (!CheckRelation(pNode, pNodeFind)) { pNode->lstNode.Append(pNodeFind); } if (!CheckRelation(pNodeFind, pNode)) { pNodeFind->lstNode.Append(pNode); } } continue; } // 墙体不在链表中,创建新节点 WallData *pNewNode = new WallData; pNewNode->dWidth = pWall->GetWidth(4); pNewNode->id = pWall->id(); pNewNode->ptE = ptE; pNewNode->ptS = ptS; pNewNode->nNum = pWall->GetOpeningIdList().Length(); pNode->lstNode.Append(pNewNode); pNewNode->lstNode.Append(pNode); vecNode.push_back(pNewNode); SetWallMap(ss, pNewNode, vecNode); } } OPENOBJ_END(); } } // 查找该节点到最近主干的所有路径 void UnfoldInstallSanitarySys::GetBranchRoad(WallData *pNode, std::map > &mapRoad, std::vector &vecRoad, double dLen, WallData *pNodePre = NULL) { if (NULL != pNode) { WallData *pNextNode = NULL; std::vector vecRef; // 排除掉该节点的父节点及兄弟节点 std::vector vecCheck = vecRoad; if (NULL != pNodePre) { for (int j = 0; j < pNodePre->lstNode.Length(); j++) { vecCheck.push_back(pNodePre->lstNode[j]); } } double dDist = 0.0; for (int i = 0; i < pNode->lstNode.Length(); i++) { vecRef = vecRoad; dDist = dLen; pNextNode = pNode->lstNode[i]; if (NULL == pNextNode) { continue; } WallData *pNodeFind = NULL; if (CheckWallInLst(m_vecRoad, pNextNode->id, pNodeFind))// 当前节点为主干墙体时,存储路径 { vecRoad = vecRef; dLen = dDist; mapRoad.insert(std::make_pair(dLen, vecRoad)); break; } if (CheckWallInLst(vecCheck, pNextNode->id, pNodeFind)) { continue; } dDist += pNextNode->ptS.distanceTo(pNextNode->ptE); vecRef.push_back(pNextNode); GetBranchRoad(pNextNode, mapRoad, vecRef, dDist, pNode); } } } // 获取起始墙体到终止墙体之间的所有路径 void UnfoldInstallSanitarySys::GetRoad(WallData *pNode, const AcDbObjectId &idEnd, std::map > &mapRoad, std::vector vecRoad, double dLen, WallData *pNodePre = NULL) { if (NULL != pNode) { WallData *pNextNode = NULL; std::vector vecRef; // 排除掉该节点的父节点及兄弟节点 std::vector vecCheck = vecRoad; if (NULL != pNodePre) { for (int j = 0; j < pNodePre->lstNode.Length(); j++) { vecCheck.push_back(pNodePre->lstNode[j]); } } double dDist = 0.0; for (int i = 0; i < pNode->lstNode.Length(); i++) { vecRef = vecRoad; dDist = dLen; pNextNode = pNode->lstNode[i]; if (NULL == pNextNode) { continue; } if (pNextNode->id == idEnd)// 当前节点为终止墙体时,存储路径 { vecRef.push_back(pNextNode); vecRoad = vecRef; dDist += pNextNode->ptS.distanceTo(pNextNode->ptE); dLen = dDist; mapRoad.insert(std::make_pair(dLen, vecRoad)); break; } WallData *pNodeFind = NULL; if (CheckWallInLst(vecCheck, pNextNode->id, pNodeFind)) { continue; } dDist += pNextNode->ptS.distanceTo(pNextNode->ptE); vecRef.push_back(pNextNode); GetRoad(pNextNode, idEnd, mapRoad, vecRef, dDist, pNode); } } } // 获得路径的转折点总数 int UnfoldInstallSanitarySys::GetTurnNum(const std::vector &vecPt) { if (vecPt.size() < 2) { return 0; } int nNum = 0; std::vector::const_iterator it = vecPt.begin(); AcGeVector3d vt1 = (*it)->ptS - (*it)->ptE, vt2; it++; while (it != vecPt.end()) { vt2 = (*it)->ptS - (*it)->ptE; if (!vt1.isParallelTo(vt2)) { nNum++; } vt1 = vt2; it++; } return nNum; } // 根据路径长度和转折点数量 取得最短路径 void UnfoldInstallSanitarySys::GetShortestRoad(std::map > &mapRoad, std::vector &vecRoad) { std::map >::iterator itMap = mapRoad.begin(); double dLen = (*itMap++).first; const double dDist = DocGetMeterUnitDim() ? 0.20 : 200; if (mapRoad.size() > 1) { while ((*itMap).first - dLen < dDist && itMap != mapRoad.end()) { itMap++; } } mapRoad.erase(itMap, mapRoad.end()); std::map > mapSorted; for (itMap = mapRoad.begin(); itMap != mapRoad.end(); itMap++) { double dNum = GetTurnNum((*itMap).second); mapSorted.insert(std::make_pair(dNum, (*itMap).second)); } itMap = mapSorted.begin(); vecRoad = (*itMap).second; } // 用墙体的起点和终点 获取墙体ID bool UnfoldInstallSanitarySys::GetWallId(const std::vector &vecWall, const AcDbLine &line, AcDbObjectId &id) { std::vector::const_iterator it; XPoint ptS, ptE; ptS = line.startPoint(); ptE = line.endPoint(); const double dDist = DocGetMeterUnitDim() ? 0.35 : 350; for (it = vecWall.begin(); it != vecWall.end(); it++) { if (*it == NULL) { continue; } if (((*it)->ptS.distanceTo(ptS) - dDist < 0.001 && (*it)->ptE.distanceTo(ptE) - dDist < 0.001) || ((*it)->ptS.distanceTo(ptE) - dDist < 0.001 && (*it)->ptE.distanceTo(ptS) - dDist < 0.001)) { id = (*it)->id; return true; } } return false; } // 查找距离该墙体最近的主干管 bool UnfoldInstallSanitarySys::GetBranchWallRoad(AcDbLine &line, std::vector &vecRoad) { AcDbObjectId idStart; AcGePoint3d ptS = line.startPoint(); AcGePoint3d ptE = line.endPoint(); std::vector vecAllRoad = m_vecAllWall; if (!GetWallId(vecAllRoad, line, idStart)) { return false; } WallData *pNodeS = NULL; if (CheckWallInLst(m_vecRoad, idStart, pNodeS)) { return false; } if (!CheckWallInLst(vecAllRoad, idStart, pNodeS)) { return false; } vecRoad.clear(); vecRoad.push_back(pNodeS); std::map > mapRoad; double dLen = 0.0; GetBranchRoad(pNodeS, mapRoad, vecRoad, dLen); GetShortestRoad(mapRoad, vecRoad); ModifyRoad(vecRoad); return true; } // 获取两个墙体之间的最短路径 并初始化墙体节点结构 bool UnfoldInstallSanitarySys::GetWallRoad(AcDbLine &lineStart, AcDbLine &lineEnd, std::vector &vecRoad) { Entity ent; PickSet ssWall(SS_FREE); for(long i = 0; i < m_ssDoorWall.Length(); i++)// 获取所有上华墙体 { ent = m_ssDoorWall[i]; if (ent.Is(_T("TCH_Wall"))) { ssWall += ent; } } ent = ssWall[0l]; WallData *pNode = new WallData; OPENOBJ_BEGIN(ent, AcDb::kForRead, TDbWall, pWall); if(pWall) { pNode->dWidth = pWall->GetWidth(4); pNode->id = pWall->id(); pNode->ptE = pWall->GetEndPoint(); pNode->ptE.z = 0.0; pNode->ptS = pWall->GetStartPoint(); pNode->ptS.z = 0.0; pNode->nNum = pWall->GetOpeningIdList().Length(); } OPENOBJ_END(); std::vector vecNode; vecNode.push_back(pNode); SetWallMap(ssWall, pNode, vecNode);// 初始化墙体节点结构 AcDbObjectId idStart, idEnd; if (!GetWallId(vecNode, lineEnd, idEnd) || !GetWallId(vecNode, lineStart, idStart)) { return false; } m_vecAllWall = vecNode; WallData *pNodeS = NULL; if (!CheckWallInLst(vecNode, idStart, pNodeS)) { return false; } vecRoad.clear(); vecRoad.push_back(pNodeS); if (idStart == idEnd)// 系统只有一个墙体 { return true; } std::map > mapRoad; double dLen = 0.0; GetRoad(pNodeS, idEnd, mapRoad, vecRoad, dLen); vecRoad.clear(); GetShortestRoad(mapRoad, vecRoad); // 获取不到路径 if (vecRoad.front()->id != pNodeS->id || vecRoad.back()->id != idEnd) { return false; } ModifyRoad(vecRoad); vecNode.clear(); return true; } // 校准墙体路径的起点到终点顺序 void UnfoldInstallSanitarySys::ModifyRoad(std::vector &vecRoad) { AcGePoint3d ptS, ptE, ptS2, ptE2; std::vector::iterator it = vecRoad.begin(); ptS = (*it)->ptS; ptE = (*it)->ptE; while (++it != vecRoad.end()) { ptS2 = (*it)->ptS; ptE2 = (*it)->ptE; if (ptS.distanceTo(ptS2) < 0.001) { it--; (*it)->ptS = ptE; (*it)->ptE = ptS; it++; } else if (ptS.distanceTo(ptE2) < 0.001) { it--; (*it)->ptS = ptE; (*it)->ptE = ptS; it++; (*it)->ptS = ptE2; (*it)->ptE = ptS2; } else if (ptE.distanceTo(ptE2) < 0.001) { (*it)->ptS = ptE2; (*it)->ptE = ptS2; } ptS = ptS2; ptE = ptE2; } } // 设定管线标高 void UnfoldInstallSanitarySys::ModifyPipeElve() { UnfoldInstallAdjustElevation Elev; Elev.SetLinkNode(m_pNodeStart); Elev.SetFeedElevation(1.0); Elev.SetFeedPipe(m_idPipe); Elev.SetSanitaryPt(m_mapSanPt); Elev.SetPipeSysType(m_sysPipe); Elev.AdjustElevation(); } // 从交点处打断管线,构造管网 void UnfoldInstallSanitarySys::SetLinkableNode() { std::vector::iterator it; std::vector::iterator itCheck; std::map::iterator itMap; std::vector vecLine;// 保存打断后的管线 // 打断连接有多个分支的管线 AcDbLine *pLine = NULL, *pLineCheck = NULL; AcGePoint3d ptCheck, ptOnLine; for (it = m_vecPipeData.begin(); it != m_vecPipeData.end(); it++) { std::map mapPts; pLine = it->pLine; for (itCheck = m_vecPipeData.begin(); itCheck != m_vecPipeData.end(); itCheck++) { pLineCheck = itCheck->pLine; ptCheck = pLineCheck->startPoint(); pLine->getClosestPointTo(ptCheck, ptOnLine); if (ptCheck.distanceTo(ptOnLine) < 0.01 && ptOnLine.distanceTo(pLine->startPoint()) > 0.01 && ptOnLine.distanceTo(pLine->endPoint()) > 0.01) { mapPts.insert(std::make_pair(pLine->startPoint().distanceTo(ptOnLine), ptOnLine)); } } if (mapPts.size() > 0) { itMap = mapPts.begin(); ptCheck = itMap->second; AcGePoint3d ptEnd = pLine->endPoint(); pLine->setEndPoint(ptCheck); itMap++; for (; itMap != mapPts.end(); itMap++) { AcDbLine *pLineNew = new AcDbLine; pLineNew->setStartPoint(ptCheck); pLineNew->setEndPoint(itMap->second); vecLine.push_back(pLineNew); ptCheck = itMap->second; } AcDbLine *pLineEnd = new AcDbLine; pLineEnd->setStartPoint(ptCheck); pLineEnd->setEndPoint(ptEnd); vecLine.push_back(pLineEnd); } } std::vector::iterator itLine; for (itLine = vecLine.begin(); itLine != vecLine.end(); itLine++) { if ((*itLine)->startPoint().distanceTo((*itLine)->endPoint()) < 0.001) { continue; } AddPipeLine((*itLine)->startPoint(), (*itLine)->endPoint(), PipeType::eMainPipe); } std::vector vecNode; GetNodeLst(vecNode); ModifyNode(vecNode); //CreatePipeFromStart(m_pNodeStart, vecNode); ModifyPipeElve();// 设定管线标高 } // 校准标高点 void UnfoldInstallSanitarySys::ModifyNode(std::vector &vecNode) { m_pNodeStart = vecNode.front(); while (m_pNodeStart->pPreNode != NULL) { m_pNodeStart = m_pNodeStart->pPreNode; } m_pNodeStart->type = Point_Feed; std::vector::iterator itNode; std::vector::iterator itN; std::vector vecEnd; LinkNode *pNode = NULL, *pNodePer = NULL, *pNodeNext = NULL; AcGeVector3d vtPer, vtNext; // 设定各个点的属性 for (itNode = vecNode.begin(); itNode != vecNode.end(); ) { if ((*itNode)->m_vecNode.empty()) { (*itNode)->type = Point_Sanitary; if ((*itNode)->ptCur.z > 1.0) { (*itNode)->ptCur.z = 0; } if (m_nInstallType == 1) { (*itNode)->type = (*itNode)->type | Point_KW; } else if (m_nInstallType == 0) { (*itNode)->pPreNode->type = Point_Int | Point_KW; } vecEnd.push_back(*itNode); } pNode = *itNode; pNodePer = pNode->pPreNode; if (pNodePer != NULL && pNode->m_vecNode.size() == 1) { pNodeNext = pNode->m_vecNode.front(); vtPer = pNodePer->ptCur - pNode->ptCur; vtNext = pNode->ptCur - pNodeNext->ptCur; if (vtNext.isParallelTo(vtPer, m_tolVec)) { pNodeNext->pPreNode = pNodePer; for (itN = pNodePer->m_vecNode.begin(); itN != pNodePer->m_vecNode.end(); itN++) { if ((*itN) == pNode) { break; } } pNodePer->m_vecNode.erase(itN); pNodePer->m_vecNode.push_back(pNodeNext); itNode = vecNode.erase(itNode); } else { itNode++; } } else { itNode++; } } } // 根据管线构造管网 void UnfoldInstallSanitarySys::GetNodeLst(std::vector &vecNode) { std::vector::iterator it; std::vector::iterator itCheck; AcDbLine *pLine = NULL, *pLineCheck = NULL; for (it = m_vecPipeData.begin(); it != m_vecPipeData.end(); it++) { pLine = it->pLine; LinkNode *pNodeS = NULL, *pNodeE = NULL, *pNodePer = NULL, *pNodeNext = NULL, *pNodeFind = NULL; // 获取起始节点 if (!CheckPtInLst(vecNode, pNodeS, pLine->startPoint())) { pNodeS = new LinkNode; pNodeS->ptCur = pLine->startPoint(); pNodeS->type = Point_Int; pNodeS->pPreNode = NULL; vecNode.push_back(pNodeS); } // 获取终止节点 if (!CheckPtInLst(vecNode, pNodeE, pLine->endPoint())) { pNodeE = new LinkNode; pNodeE->ptCur = pLine->endPoint(); pNodeE->type = Point_Int; vecNode.push_back(pNodeE); } pNodeE->pPreNode = pNodeS; if (!CheckPtInLst(pNodeS->m_vecNode, pNodeFind, pNodeE->ptCur)) { pNodeS->m_vecNode.push_back(pNodeE); } for (itCheck = m_vecPipeData.begin(); itCheck != m_vecPipeData.end(); itCheck++) { if (it->nId == itCheck->nId) { continue; } pLineCheck = itCheck->pLine; // 根据管线起点 设定其前节点 if (pNodeS->ptCur.distanceTo(pLineCheck->endPoint()) < 0.01) { if (!CheckPtInLst(vecNode, pNodePer, pLineCheck->startPoint())) { pNodePer = new LinkNode; pNodePer->ptCur = pLineCheck->startPoint(); pNodePer->type = Point_Int; pNodePer->pPreNode = NULL; pNodePer->m_vecNode.push_back(pNodeS); vecNode.push_back(pNodePer); } else if (!CheckPtInLst(pNodePer->m_vecNode, pNodeFind, pNodeS->ptCur)) { pNodePer->m_vecNode.push_back(pNodeS); } pNodeS->pPreNode = pNodePer; } else if (pNodeE->ptCur.distanceTo(pLineCheck->startPoint()) < 0.01)// 根据管线终点 设定其后续节点 { if (!CheckPtInLst(vecNode, pNodeNext, pLineCheck->endPoint())) { pNodeNext = new LinkNode; pNodeNext->ptCur = pLineCheck->endPoint(); pNodeNext->type = Point_Int; pNodeE->m_vecNode.push_back(pNodeNext); vecNode.push_back(pNodeNext); } else if (!CheckPtInLst(pNodeE->m_vecNode, pNodeFind, pNodeNext->ptCur)) { pNodeE->m_vecNode.push_back(pNodeNext); } pNodeNext->pPreNode = pNodeE; } } } } // 判断点是否在链表中,若在 ,返回该节点 bool UnfoldInstallSanitarySys::CheckPtInLst(std::vector &vecNode, LinkNode *&pNode, AcGePoint3d pt) { std::vector::iterator it; AcGePoint3d ptCur; for (it = vecNode.begin(); it != vecNode.end(); it++) { ptCur = (*it)->ptCur; if (ptCur.distanceTo(pt) < 0.01) { pNode = *it; return true; } } return false; }