#pragma once #include #include "DrawOperator/Mesh.h" #include "DrawModel/Dimension2D.h" #include "DrawOperator/unordered_dense.h" #include "Util.h" #include "clipper2/clipper.h" /** * 游离区计算类 */ class UndecidedZone { public: UndecidedZone(CMesh* pMesh) : m_pMesh(pMesh) { m_pMesh->GetNumber(m_numx, m_numy); m_pMesh->GetDelt(m_dx, m_dy); m_pDfg = m_pMesh->GetDfg(); } /** * 计算在这个范围内的连通区域 * * \param zMin z 值最小值 * \param zMax z 值最大值 * \return */ std::vector> ComputeRegions(double zMin, double zMax) const { std::vector> result; Regions regions = FindAllRegions(zMin, zMax); for (const Region& region : regions) { auto regionResult = ComputeRegion(region); result.insert(result.end(), std::make_move_iterator(regionResult.begin()), std::make_move_iterator(regionResult.end())); } return result; } /** * 获取指定范围的网格下标,连通的会放在一起 * * \param zMin * \param zMax * \return */ std::vector>> FindAllRegions(double zMin, double zMax) const { if (zMin > zMax) { return {}; } if (IsZOutofMesh(zMin, zMax)) { return {}; } auto pred = [this, zMin, zMax](int x, int y) { double z = m_pDfg->Value(x, y); return InRange(z, zMin, zMax); }; return FindAllRegions(pred); } private: using Point = std::pair; using Region = std::vector; using Regions = std::vector; using Pred = std::function; /** * 根据连通的节点计算包围的区域 * * \param region * \return */ std::vector> ComputeRegion(const Region& region) const { struct PointHash { size_t operator()(const std::pair& p) const { return std::hash()(p.first) ^ (std::hash()(p.second) << 1); } }; struct Edge { Point p1, p2; void normalize() { if (p1 > p2) std::swap(p1, p2); } bool operator==(const Edge& other) const { return p1 == other.p1 && p2 == other.p2; } }; struct EdgeHash { size_t operator()(const Edge& e) const { return std::hash()(e.p1.first) ^ (std::hash()(e.p1.second) << 1) ^ (std::hash()(e.p2.first) << 2) ^ (std::hash()(e.p2.second) << 3); } }; std::unordered_map edgeCount; // 1. 统计所有边出现次数(四条边构成每个格子) for (const Point& pt : region) { int x = pt.first; int y = pt.second; std::array edges = { Edge{{x, y}, {x + 1, y}}, // bottom Edge{{x + 1, y}, {x + 1, y + 1}}, // right Edge{{x + 1, y + 1}, {x, y + 1}}, // top Edge{{x, y + 1}, {x, y}} // left }; for (auto& edge : edges) { edge.normalize(); edgeCount[edge]++; } } // 2. 只保留出现一次的边(即外边) std::unordered_map, PointHash> pointToEdges; std::unordered_set boundaryEdges; for (const auto& [edge, count] : edgeCount) { if (count == 1) { pointToEdges[edge.p1].push_back(edge); pointToEdges[edge.p2].push_back(edge); boundaryEdges.insert(edge); } } // 3. 从边界边追踪构造轮廓(可能多个多边形) std::vector> result; std::unordered_set visited; while (!boundaryEdges.empty()) { // 任选一条未使用边开始追踪 Edge startEdge = *boundaryEdges.begin(); Point current = startEdge.p1; std::vector contour; contour.push_back(current); visited.insert(startEdge); boundaryEdges.erase(startEdge); Point next = startEdge.p2; contour.push_back(next); while (next != current) { const auto& edges = pointToEdges[next]; bool found = false; for (const Edge& e : edges) { if (visited.count(e) == 0) { Point other = (e.p1 == next) ? e.p2 : e.p1; contour.push_back(other); visited.insert(e); boundaryEdges.erase(e); next = other; found = true; break; } } if (!found) break; // 不闭合就退出 } // 4. 转换 contour 到实际坐标系并生成 CCurveEx if (contour.size() >= 3) { auto curve = std::make_unique(); curve->Create(static_cast(contour.size())); for (size_t i = 0; i < contour.size(); ++i) { curve->x[i] = m_pMesh->left + contour[i].first * m_dx; curve->y[i] = m_pMesh->bottom + contour[i].second * m_dy; } result.push_back(std::move(curve)); } } return result; } Clipper2Lib::PathD CreatePathD(const Point& point) const { double left = m_pMesh->left + point.first * m_dx; double bottom = m_pMesh->bottom + point.second * m_dy; double right = left + m_dx; double top = bottom + m_dy; return Clipper2Lib::PathD{ {left, top}, { right, top}, {right, bottom}, {left, bottom} }; } std::unique_ptr CreateCurveEx(const Clipper2Lib::PathD& path) const { assert(!path.empty()); auto pCurve = std::make_unique(); pCurve->Create(static_cast(path.size()) + 1); size_t i = 0; for (; i < path.size(); i++) { pCurve->x[i] = path[i].x; pCurve->y[i] = path[i].y; } pCurve->x[i] = path[0].x; pCurve->y[i] = path[0].y; return pCurve; } Regions FindAllRegions(Pred pred) const { Regions regions; std::vector> visited(m_numx, std::vector(m_numy, false)); for (int i = 0; i < m_numx; i++) { for (int j = 0; j < m_numy; j++) { if (!visited[i][j] && pred(i, j)) { regions.push_back(Bfs(i, j, visited, pred)); } } } return regions; } std::vector Bfs(int x, int y, std::vector>& visited, Pred pred) const { std::queue q; std::vector region; // 上下左右 std::vector dx = { -1, 1, 0, 0 }; std::vector dy = { 0, 0, -1, 1 }; q.push({ x, y }); visited[x][y] = true; while (!q.empty()) { Point p = q.front(); q.pop(); region.push_back(p); for (int d = 0; d < 4; d++) { int ni = p.first + dx[d]; int nj = p.second + dy[d]; if ((ni >= 0 && ni < m_numx) && (nj >= 0 && nj < m_numy)) { if (pred(ni, nj) && !visited[ni][nj]) { visited[ni][nj] = true; q.push({ ni, nj }); } } } } return region; } bool IsZOutofMesh(double zMin, double zMax) const { double mZmin = 0.0; double mZmax = 0.0; m_pMesh->GetM(mZmin, mZmax); return (zMin >= mZmax || zMax <= mZmin); } CMesh* m_pMesh = nullptr; CDimension2D* m_pDfg = nullptr; double m_dx = 0.0; double m_dy = 0.0; long m_numx = 0; long m_numy = 0; };