#include "../ClipperUtils.hpp" #include "../ExPolygon.hpp" #include "../Surface.hpp" #include "../ShortestPath.hpp" #include #include #include #include #include "Bridge.hpp" namespace Slic3r { /* Polylines Bridge::fill_surface(const Surface* surface, const FillParams& params) { auto thread_id = std::this_thread::get_id(); std::stringstream ss; std::string base_path = "D:/logs/"; ss << base_path << "thread-" << thread_id; std::string file_name = ss.str(); short index = 1; while (std::filesystem::exists(file_name)) { file_name = ss.str() + "-" + std::to_string(index); } std::ofstream outfile(file_name + ".txt"); Polylines polylines_out; { Points points = surface->expolygon.contour.points; Point first = points[0]; points.push_back(first); outfile << "OutPoint\n"; for (Point one : points) { double x = one.x(); double y = one.y(); outfile << "Point(" << x << "," << y << "),\n"; Point_t temp = { x ,y }; } } { Polygons inPolygons = surface->expolygon.holes; for (Polygon one : inPolygons) { Points points = one.points; Point first = points[0]; points.push_back(first); outfile << "InPoint\n"; for (Point two : points) { double x = two.x(); double y = two.y(); outfile << "Point(" << x << "," << y << "),\n"; } } } outfile.close(); return polylines_out; }*/ /*Polylines Bridge::fill_surface(const Surface* surface, const FillParams& params) { Polylines polylines_out; Polygon_t polygon; auto thread_id = std::this_thread::get_id(); std::stringstream ss; std::string base_path = "D:/logs/"; ss << base_path << "thread-" << thread_id; std::string file_name = ss.str(); std::ofstream outfile(file_name + ".txt", std::ios_base::app); { double area = surface->expolygon.contour.area(); //>e+08 if (area < 9000000000) { return polylines_out; } Points points = surface->expolygon.contour.points; Point first = points[0]; points.push_back(first); std::vector outerBoundary; outerBoundary.reserve(points.size()); //outfile << "//**********Out**********\n"; for (Point one : points) { double x = one.x(); double y = one.y(); //outfile << "Point(" << x << "," << y << "),\n"; Point_t temp = { x ,y }; outerBoundary.push_back(temp); } bg::append(polygon.outer(), outerBoundary); } { Polygons inPolygons = surface->expolygon.holes; for (Polygon one : inPolygons) { Ring innerRing; innerRing.reserve(one.points.size() + 1); Points points = one.points; Point first = points[0]; points.push_back(first); //outfile << "//**********In**********\n"; for (Point two : points) { double x = two.x(); double y = two.y(); //outfile << "Point(" << x << "," << y << "),\n"; Point_t temp = { x,y }; innerRing.push_back(temp); } polygon.inners().push_back(innerRing); } } this->polygon = polygon; this->offset = 30000; printTree(); int b_size = bridges.size(); BridgeMap bm = bridges[0]; IdIndex parent(1, 1); traverseRing(findNode(bm.from_ii), parent, bm.from, bm.from2, true); Point_t last = { bm.from.x(),bm.from.y() }; path.emplace_back(last); outfile << "//**********Line**********\n"; for (Point_t one : path) { double x = one.x(); double y = one.y(); outfile << "Point(" << x << "," << y << "),\n"; } for (size_t i = 0; i + 1 < path.size(); ++i) { //outfile << "//**********Line**********\n"; Point p1 = { path[i].x(),path[i].y() }; Point p2 = { path[i + 1].x() ,path[i + 1].y() }; //outfile << "Point(" << p1 << "," << p2 << "),\n"; Polyline line = { p1, p2 }; polylines_out.push_back(line); } outfile.close(); return polylines_out; }*/ Polylines Bridge::fill_surface(const Surface* surface, const FillParams& params) { Polylines polylines_out; Polygon_t polygon; polylines_out.clear(); { double area = surface->expolygon.contour.area(); //>e+08 if (area < 900000000) { return polylines_out; } Points points = surface->expolygon.contour.points; Point first = points[0]; points.push_back(first); std::vector outerBoundary; outerBoundary.reserve(points.size()); for (Point one : points) { double x = one.x(); double y = one.y(); Point_t temp = { x ,y }; outerBoundary.push_back(temp); } bg::append(polygon.outer(), outerBoundary); } { Polygons inPolygons = surface->expolygon.holes; for (Polygon one : inPolygons) { Ring innerRing; innerRing.reserve(one.points.size() + 1); Points points = one.points; Point first = points[0]; points.push_back(first); for (Point two : points) { double x = two.x(); double y = two.y(); Point_t temp = { x,y }; innerRing.push_back(temp); } polygon.inners().push_back(innerRing); } } this->polygon = polygon; //auto abc = float(scale_(this->overlap - 0.5 * this->spacing)); //if (abc < 0) { // abc = -abc; //} //this->offset = abc; this->offset = 40000; printTree(); int b_size = bridges.size(); BridgeMap bm = bridges[0]; IdIndex parent(1, 1); traverseRing(findNode(bm.from_ii), parent, bm.from, bm.from2, true); Point_t last = { bm.from.x(),bm.from.y() }; path.emplace_back(last); for (size_t i = 0; i + 1 < path.size(); ++i) { Point p1 = { path[i].x(),path[i].y() }; Point p2 = { path[i + 1].x() ,path[i + 1].y() }; Polyline line = { p1, p2 }; polylines_out.push_back(line); } return polylines_out; } //void Bridge::_fill_surface_single(const FillParams& params, unsigned int thickness_layers, const std::pair& direction, ExPolygon expolygon, Polylines& polylines_out) //{ // expolygon.rotate(-direction.first); // // this->_min_spacing = scale_(this->spacing); // assert(params.density > 0.0001f && params.density <= 1.f); // this->_line_spacing = coord_t(coordf_t(this->_min_spacing) / params.density); // this->_diagonal_distance = this->_line_spacing * 2; // this->_line_oscillation = this->_line_spacing - this->_min_spacing; // only for Line infill // BoundingBox bounding_box = expolygon.contour.bounding_box(); // // // define flow spacing according to requested density // if (params.density > 0.9999f && !params.dont_adjust) { // this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing); // this->spacing = unscale(this->_line_spacing); // } // else { // // extend bounding box so that our pattern will be aligned with other layers // // Transform the reference point to the rotated coordinate system. // bounding_box.merge(align_to_grid( // bounding_box.min, // Point(this->_line_spacing, this->_line_spacing), // direction.second.rotated(-direction.first))); // } // Polygon outPolygon = bounding_box.polygon(); // Polygon_t polygon; // std::vector outerBoundary; // outerBoundary.reserve(outPolygon.points.size()); // for (Point one : outPolygon.points) { // double x = one.x(); // double y = one.y(); // Point_t temp = { x,y }; // outerBoundary.push_back(temp); // } // bg::append(polygon.outer(), outerBoundary); // // //std::vector innerBoundary; // // Polygons inPolygons = expolygon.holes; // for (Polygon one :inPolygons) { // Ring innerRing; // for (Point two: one.points) { // double x = two.x(); // double y = two.y(); // Point_t temp = { x,y }; // innerRing.push_back(temp); // } // polygon.inners().push_back(innerRing); // } // this->polygon = polygon; // this->offset = float(scale_(this->overlap - 0.5 * this->spacing)); // printTree(); // for (size_t i = 0; i + 1 < path.size(); ++i) { // // Point p1 = { path[i].x(),path[i].y()}; // Point p2 = { path[i + 1].x(),path[i + 1].y()}; // Polyline line = { p1, p2 }; // polylines_out.push_back(line); // } //} /*void Bridge::_fill_surface_single(const FillParams& params, unsigned int thickness_layers, const std::pair& direction, ExPolygon expolygon, Polylines& polylines_out) { //this->_min_spacing = scale_(this->spacing); //assert(params.density > 0.0001f && params.density <= 1.f); //this->_line_spacing = coord_t(coordf_t(this->_min_spacing) / params.density); //this->_diagonal_distance = this->_line_spacing * 2; //this->_line_oscillation = this->_line_spacing - this->_min_spacing; // only for Line infill //BoundingBox bounding_box = expolygon.contour.bounding_box(); //// define flow spacing according to requested density ////根据要求的密度定义流间距 //if (params.density > 0.9999f && !params.dont_adjust) { // this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing); // this->spacing = unscale(this->_line_spacing); //} //else { // // extend bounding box so that our pattern will be aligned with other layers // // Transform the reference point to the rotated coordinate system. // //扩展边界框,使我们的图案与其他层对齐 // //将参考点变换到旋转坐标系。 // bounding_box.merge(align_to_grid( // bounding_box.min, // Point(this->_line_spacing, this->_line_spacing), // direction.second.rotated(-direction.first))); //} BoundingBox bounding_box = expolygon.contour.bounding_box(); Polygon outPolygon = bounding_box.polygon(); Polygon_t polygon; std::vector outerBoundary; outerBoundary.reserve(outPolygon.points.size()); for (Point one : outPolygon.points) { double x = one.x(); double y = one.y(); Point_t temp = { x,y }; outerBoundary.push_back(temp); } bg::append(polygon.outer(), outerBoundary); //std::vector innerBoundary; Polygons inPolygons = expolygon.holes; for (Polygon one : inPolygons) { Ring innerRing; innerRing.reserve(one.points.size()); for (Point two : one.points) { double x = two.x(); double y = two.y(); Point_t temp = { x,y }; innerRing.push_back(temp); } polygon.inners().push_back(innerRing); } int inSize = polygon.inners().size(); // Bridge bridge(polygon, float(scale_(this->overlap - 0.5 * this->spacing))); this->polygon = polygon; this->offset = float(scale_(this->overlap - 0.5 * this->spacing)); printTree(); //outputPaths(); for (size_t i = 0; i + 1 < path.size(); ++i) { Point p1 = { path[i].x(),path[i].y()}; Point p2 = { path[i + 1].x(),path[i + 1].y()}; Polyline line = { p1, p2 }; polylines_out.push_back(line); } }*/ // 为 std::pair 定义哈希函数 //template<> //struct std::hash> { // std::size_t operator()(const std::pair& p) const noexcept { // return std::hash()(p.first) ^ (std::hash()(p.second) << 1); // } //}; //判断两个点是否相等 bool equal(Point_t p1, Point_t p2) { return p1.x() == p2.x() && p1.y() == p2.y(); } // 计算点到原点的距离平方 double distance_to_origin_sq(const Point_t& p) { return bg::get<0>(p) * bg::get<0>(p) + bg::get<1>(p) * bg::get<1>(p); } //将节点加入处理节点集合中 RingNode Bridge::formatNode(const size_t id, const size_t index, const Ring& ring, const int orientation) { Ring ringNode; ringNode.assign(ring.begin(), ring.end()); RingNode node({ id, index }, ringNode, orientation); return node; } void Bridge::addNode(RingNode& node) { // 检查键是否存在 const auto it = ringNodes.find(node.id.id); if (it != ringNodes.end()) { // 键已存在,将新节点添加到对应向量的末尾 it->second.emplace_back(node); } else { // 键不存在,创建一个新的向量并插入到 map 中 ringNodes[node.id.id] = { node }; } } void Bridge::removeNode(IdIndex id) { auto it = ringNodes.find(id.id); if (it != ringNodes.end()) { std::vector& nodes = it->second; nodes.erase(std::remove_if(nodes.begin(), nodes.end(), [id](RingNode x) { return x.id.id == id.id && x.id.index == id.index; }), nodes.end()); } } //查找节点 RingNode& Bridge::findNode(const IdIndex ii) { const auto it = ringNodes.find(ii.id); std::vector& nodes = it->second; const auto it1 = std::find_if(nodes.begin(), nodes.end(), [ii](const RingNode& node) { return node.id.index == ii.index; }); return *it1; } //计算多边形的外边界和内边界 void Bridge::computePolygonBoundaries(Polygon_t& polygon) { // 提取外边界 boundaries.outerBoundary = bg::exterior_ring(polygon); // 获取内边界 const auto& interiors = bg::interior_rings(polygon); for (const auto& inner : interiors) { boundaries.innerBoundaries.push_back(inner); } } // 判断多边形A是否包含多边形B bool isPolygonContained(const Polygon_t& polyA, const Polygon_t& polyB) { // 检查B的所有点是否都在A内部 for (const auto& point : bg::exterior_ring(polyB)) { if (!bg::within(point, polyA)) { return false; } } // 检查A和B的环是否有交叉 std::vector intersection; bg::intersection(polyA, polyB, intersection); // 如果交集的总面积等于B的面积,则A包含B double totalArea = 0.0; for (const auto& poly : intersection) { totalArea += bg::area(poly); } return std::abs(totalArea - bg::area(polyB)) < 1e-9; } // 判断两个环是否相交(不包括包含关系) bool Bridge::ringsIntersect(const RingNode rn1, const RingNode rn2) { // 将环转换为多边形 Polygon_t poly1, poly2; bg::append(poly1.outer(), rn1.ring); bg::append(poly2.outer(), rn2.ring); // 首先检查是否相交(包括边界相交) if (!bg::intersects(poly1, poly2)) { return false; } if (bg::area(poly1) == bg::area(poly2)) { return false; } // 如果存在包含关系,则不算作相交 if (isPolygonContained(poly1, poly2) || isPolygonContained(poly2, poly1)) { return false; } return true; } //获取环偏移后的环(可能为空) std::vector Bridge::offsetRing(const Ring& ring, const double distance) { // 将环包装成多边形 Polygon_t inputPolygon; inputPolygon.outer() = ring; // 修复几何数据 bg::correct(inputPolygon); // 使用 multi_polygon 作为 buffer 的输出类型 bg::model::multi_polygon result; // 使用对称距离策略 bg::buffer(inputPolygon, result, bg::strategy::buffer::distance_symmetric(distance), bg::strategy::buffer::side_straight(), bg::strategy::buffer::join_round(), bg::strategy::buffer::end_round(), bg::strategy::buffer::point_circle()); // 提取偏移后的环 std::vector offsetRing; for (const auto& poly : result) { if (std::abs(bg::area(poly.outer())) > area_threshold) { offsetRing.emplace_back(poly.outer()); } } return offsetRing; } // 合并多个环 std::vector Bridge::merge(std::vector rns, const RingNode rn) { // 将环转换为多边形 std::vector input; for (RingNode _rn : rns) { Polygon_t poly; std::vector outerBoundary(_rn.ring.begin(), _rn.ring.end()); bg::assign_points(poly.outer(), outerBoundary); input.push_back(poly); } Polygon_t poly2; std::vector outerBoundary2(rn.ring.begin(), rn.ring.end()); bg::append(poly2.outer(), outerBoundary2); // 合并所有结果多边形 MultiPolygon result; if (input.size() > 1) { // 初始化当前多边形为外多边形 bg::convert(poly2, result); // 依次从当前多边形中减去每个内多边形 for (const auto& inner : input) { MultiPolygon temp; bg::difference(result, inner, temp); result = temp; } } else { if (rns[0].orientation == -1 && rn.orientation == 1) { bg::difference(input[0], poly2, result); } else if (rns[0].orientation == 1 && rn.orientation == -1) { bg::difference(poly2, input[0], result); } else if (rns[0].orientation == 1 && rn.orientation == 1) { bg::union_(input[0], poly2, result); } } std::vector allRings; for (const auto& poly : result) { allRings.emplace_back(poly.outer()); } //// 过滤掉被其他环完全包含的环 std::vector disjointRings; for (size_t i = 0; i < allRings.size(); ++i) { bool isContained = false; for (size_t j = 0; j < allRings.size(); ++j) { if (i != j && bg::within(allRings[i], allRings[j])) { isContained = true; break; } } if (!isContained) { disjointRings.push_back(allRings[i]); } } return disjointRings; } // 比较函数:按 orientation 从大到小排序 bool compareByOrientationDesc(const RingNode& a, const RingNode& b) { return a.orientation > b.orientation; } //生成环集 void Bridge::generateRings() { //获取多边形的外边界和内边界 computePolygonBoundaries(polygon); Ring ring = boundaries.outerBoundary; bg::correct(ring); RingNode node = formatNode(maxRid++, 1, ring, -1); nodeHandles.emplace_back(node); addNode(node); for (auto& inner : boundaries.innerBoundaries) { bg::correct(inner); RingNode node = formatNode(maxRid++, 1, inner, 1); nodeHandles.emplace_back(node); addNode(node); } int m = 0; double t = 0.5; //遍历当前用于判断互交的节点集 while (!nodeHandles.empty()) { std::vector nodes; //互交后产生的节点 bool isFind = false; do { isFind = false; nodes.clear(); // 按 orientation 从大到小排序 std::sort(nodeHandles.begin(), nodeHandles.end(), compareByOrientationDesc); int r = nodeHandles.size(); std::vector> matrix(r, std::vector(r, 0)); // 初始化为0 for (size_t i = 0; i < nodeHandles.size(); ++i) { for (size_t j = i + 1; j < nodeHandles.size(); ++j) { if (ringsIntersect(nodeHandles[i], nodeHandles[j])) { matrix[i][j] = 1; isFind = true; } } } std::set dIndex; for (size_t j = r - 1; j > 0; --j) { std::vector rVector; for (size_t i = 0; i < j; ++i) { if (matrix[i][j] == 1) { rVector.push_back(nodeHandles[i]); dIndex.insert(i); dIndex.insert(j); //将i行全部置为0 std::vector& row = matrix[i]; for (int& element : row) { element = 0; } } } if (rVector.size() > 0) { std::vector rings = merge(rVector, nodeHandles[j]); std::vector id_indices; for (auto& ring2 : rings) { int orientation = (rVector[0].orientation + nodeHandles[j].orientation) <= 0 ? -1 : 1; // 外与内 外与外 -> 向内; 内与内 -> 向外 if (rVector.size() > 1) { orientation = -1; } RingNode node1 = formatNode(++maxRid, 1, ring2, orientation); if (bg::area(node1.ring) > area_threshold) { nodes.emplace_back(node1); addNode(node1); IdIndex _ii(maxRid, 1); id_indices.emplace_back(_ii); } } if (id_indices.size() > 0) { for (RingNode rn : rVector) { MergeMap mm(rn.id, nodeHandles[j].id, id_indices); mergeMap.emplace_back(mm); } } } } // 逆向遍历删除,避免影响前面元素的索引 for (auto it = dIndex.rbegin(); it != dIndex.rend(); ++it) { int index = *it; if (index >= 0 && index < nodeHandles.size()) { nodeHandles.erase(nodeHandles.begin() + index); } } //是否存在互交 if (!nodes.empty()) { for (auto& n : nodes) { nodeHandles.emplace_back(n); } } } while (isFind); std::vector offsetNodes; //偏移 for (auto node : nodeHandles) { std::vector ring0 = offsetRing(node.ring, static_cast(node.orientation) * offset * t); if (ring0.size() == 1) { RingNode node0 = formatNode(node.id.id, ++node.id.index, ring0[0], node.orientation); if (bg::area(node0.ring) > area_threshold) { addNode(node0); offsetNodes.emplace_back(node0); } } else if (ring0.size() > 1) { std::vector id_indices; for (auto r : ring0) { RingNode node0 = formatNode(++maxRid, 1, r, node.orientation); if (bg::area(node0.ring) > area_threshold) { addNode(node0); offsetNodes.emplace_back(node0); IdIndex ii(maxRid, 1); id_indices.emplace_back(ii); } } //分裂映射 offsetMap.insert(std::pair>({ node.id.id,node.id.index }, id_indices)); } } t = 1; //清空 nodeHandles.clear(); if (!offsetNodes.empty()) { if (offsetNodes.size() == 2) { Polygon_t poly1, poly2; bg::append(poly1.outer(), offsetNodes[0].ring); bg::append(poly2.outer(), offsetNodes[1].ring); std::vector id_indices; if (offsetNodes[0].orientation == 1 && isPolygonContained(poly1, poly2)) { MergeMap mm(offsetNodes[0].id, offsetNodes[1].id, id_indices); containMap.emplace_back(mm); break; } if (offsetNodes[1].orientation == 1 && isPolygonContained(poly2, poly1)) { MergeMap mm(offsetNodes[1].id, offsetNodes[0].id, id_indices); containMap.emplace_back(mm); break; } } //重填 nodeHandles.insert(nodeHandles.end(), offsetNodes.begin(), offsetNodes.end()); } } } //形成树 void Bridge::formatTree() { //遍历不同环类型的节点集合 for (auto& ringNode : ringNodes) { // 使用反向迭代器进行反序遍历 std::vector& vec = ringNode.second; const auto it0 = ringNode.second.begin(); if (it0->orientation == 1) { // 向外 倒序 for (size_t i = ringNode.second.size() - 1; i > 0; i--) { ringNode.second[i].children.emplace_back(ringNode.second[i - 1]); ringNode.second[i - 1].parent = &ringNode.second[i]; } } else { //向内 正序 for (int i = 0; i < vec.size() - 1; i++) { ringNode.second[i].children.emplace_back(ringNode.second[i + 1]); ringNode.second[i + 1].parent = &ringNode.second[i]; } } } //遍历分裂/合并映射 for (auto& map : offsetMap) { //偏移产生的分裂 RingNode& it1 = findNode(map.first); for (const auto& ii : map.second) { RingNode& it2 = findNode(ii); it1.children.emplace_back(it2); } } for (auto& map : containMap) { RingNode& it1 = findNode(map.ii1); //内 RingNode& it2 = findNode(map.ii2); //外 it2.children.insert(it2.children.end(), it1.children.begin(), it1.children.end()); it1.isHide = true; } for (auto& map : mergeMap) { //合并 RingNode& it1 = findNode(map.ii1); RingNode& it2 = findNode(map.ii2); for (const auto& ii : map.nodes) { RingNode& it = findNode(ii); std::cout << it1.id.id << "," << it1.id.index << ":" << it2.id.id << "," << it2.id.index << "->" << it.id.id << "," << it.id.index << std::endl; if (it1.orientation == -1 && it2.orientation == 1) { it1.parent->children.emplace_back(it); it.parent = it1.parent; IdIndex _ii = it1.id; //将it1从父节点的子节点集中移除 it1.parent->children.erase(std::remove_if(it1.parent->children.begin(), it1.parent->children.end(), [_ii](RingNode x) { return x.id.id == _ii.id && x.id.index == _ii.index; }), it1.parent->children.end()); //it作为it2子节点的父节点 for (auto& c : it2.children) { c.parent = ⁢ } it.children.insert(it.children.end(), it2.children.begin(), it2.children.end()); } else if (it1.orientation == 1 && it2.orientation == -1) //外 内 { it2.parent->children.emplace_back(it); it2.isHide = true; it1.isHide = true; IdIndex _ii = it2.id; //将it2从父节点的子节点集中移除 it2.parent->children.erase(std::remove_if(it2.parent->children.begin(), it2.parent->children.end(), [_ii](RingNode x) { return x.id.id == _ii.id && x.id.index == _ii.index; }), it2.parent->children.end()); it.children.insert(it.children.end(), it1.children.begin(), it1.children.end()); } else if (it1.orientation == 1 && it2.orientation == 1) { //外 外 //it作为it1子节点的父节点 it.children.insert(it.children.end(), it1.children.begin(), it1.children.end()); it.children.insert(it.children.end(), it2.children.begin(), it2.children.end()); } else if (it1.orientation == -1 && it2.orientation == -1) {// 内 内 it1.parent->children.emplace_back(it); IdIndex _ii = it1.id; //将it1从父节点的子节点集中移除 it1.parent->children.erase(std::remove_if(it1.parent->children.begin(), it1.parent->children.end(), [_ii](RingNode x) { return x.id.id == _ii.id && x.id.index == _ii.index; }), it1.parent->children.end()); it2.parent->children.emplace_back(it); IdIndex _ii2 = it2.id; //将it2从父节点的子节点集中移除 it2.parent->children.erase(std::remove_if(it2.parent->children.begin(), it2.parent->children.end(), [_ii2](RingNode x) { return x.id.id == _ii2.id && x.id.index == _ii2.index; }), it2.parent->children.end()); } } } } //树遍历 void Bridge::dfs(RingNode& node, std::vector& visited) { bool flag = false; for (auto& one : visited) { if (one == node.id) { flag = true; break; } } if (flag) { return; } visited.emplace_back(node.id); // 处理当前节点 std::cout << "rId: " << node.id.id << ", rIndex: " << node.id.index << ", orientation: " << node.orientation << ", isHide: " << (node.isHide ? "true" : "false") << std::endl; Polygon_t poly; bg::assign(poly, node.ring); //verteies.push_back(convertToSFML(poly, sf::Color::Red)); // 递归遍历子节点 for (auto& child : node.children) { handleBridge(node.id, child.id); dfs(findNode(child.id), visited); } } //找到多边形环第 N 条边的中心点 Point_t Bridge::findCenterPointOnEdge(Ring& ring, size_t N, double d0, size_t& e_index) { // 获取第 N 条边的两个端点 const Point_t start = ring[N]; const Point_t end = ring[N + 1]; // 计算中点 const double mid_x = (start.x() + end.x()) / 2; const double mid_y = (start.y() + end.y()) / 2; Point_t p(mid_x, mid_y); if (d0 > 0) { std::size_t n = ring.size() - 1; // 环的边数 double remainingDist = d0; // 计算 p0 到边终点(顺时针方向下一点)的距离 double distToEnd = bg::distance(p, ring[N + 1]); // 如果 d0 小于等于到边终点的距离,直接在当前边上计算 if (remainingDist <= distToEnd) { // 计算从 p0 到边终点的方向向量 double dx = bg::get<0>(ring[N + 1]) - bg::get<0>(p); double dy = bg::get<1>(ring[N + 1]) - bg::get<1>(p); double length = std::sqrt(dx * dx + dy * dy); if (length < 1e-9) { // 特殊情况:p0 几乎是边的终点 return ring[N + 1]; } // 归一化方向向量 double unitDx = dx / length; double unitDy = dy / length; // 计算新点坐标 double newX = bg::get<0>(p) + unitDx * remainingDist; double newY = bg::get<1>(p) + unitDy * remainingDist; Point_t p0(newX, newY); e_index = N; return p0; } // 剩余距离超过当前边,需要继续到下一条边 remainingDist -= distToEnd; // 沿顺时针方向继续搜索后续边 for (std::size_t i = 2; i < n; ++i) { std::size_t currentIndex = (N + i) % n; Segment edge(ring[currentIndex], ring[currentIndex + 1]); double edgeLength = bg::distance(edge.first, edge.second); // 如果剩余距离小于等于当前边长度,在当前边上计算 if (remainingDist <= edgeLength) { // 计算边的方向向量 double dx = bg::get<0>(edge.second) - bg::get<0>(edge.first); double dy = bg::get<1>(edge.second) - bg::get<1>(edge.first); double length = std::sqrt(dx * dx + dy * dy); if (length < 1e-9) { e_index = currentIndex; return edge.first; } // 归一化方向向量 double unitDx = dx / length; double unitDy = dy / length; // 计算新点坐标 double newX = bg::get<0>(edge.first) + unitDx * remainingDist; double newY = bg::get<1>(edge.first) + unitDy * remainingDist; Point_t p0(newX, newY); e_index = currentIndex; return p0; } // 否则继续到下一条边 remainingDist -= edgeLength; } } else { e_index = N; } return p; } // 计算点到线段的最近点 Point_t closest_point_on_segment(const Point_t p, const Point_t& seg_start, const Point_t& seg_end) { const double x = bg::get<0>(p); const double y = bg::get<1>(p); const double x1 = bg::get<0>(seg_start); const double y1 = bg::get<1>(seg_start); const double x2 = bg::get<0>(seg_end); const double y2 = bg::get<1>(seg_end); // 线段向量 const double dx = x2 - x1; const double dy = y2 - y1; // 如果线段长度为零,返回起点 if (dx == 0 && dy == 0) { return seg_start; } // 计算投影参数t double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); // 限制 t 在 [0,1] 范围内,确保投影点在线段上 t = std::max(0.0, std::min(1.0, t)); // 计算投影点坐标 return Point_t(bg::get<0>(seg_start) + t * dx, bg::get<1>(seg_start) + t * dy); } // 在环的边上查找离给定点最近的点 Point_t find_closest_point_on_ring_edges(Ring& ring, const Point_t& p0, size_t& e_index1) { Point_t closest = ring[0]; // 初始化为Ring的第一个点 double minDist = bg::distance(p0, closest); // 遍历Ring的每条边 for (size_t i = 0; i < ring.size(); ++i) { // 获取当前边的两个端点 Point_t a = ring[i]; Point_t b = ring[(i + 1) % ring.size()]; // 处理闭合边 // 计算点到边的最近点 Point_t projection = closest_point_on_segment(p0, a, b); // 计算距离 double dist = bg::distance(p0, projection); // 更新最近点 if (dist < minDist) { minDist = dist; closest = projection; e_index1 = i; } } return closest; } Point_t Bridge::find_point_at_distance_clockwise(Ring& ring, const Point_t& start_point, size_t _index, double d, size_t& e_index) { // 确保环是闭合的(首尾点相同) Ring normalized_r1 = ring; if (!normalized_r1.empty() && !bg::equals(normalized_r1.front(), normalized_r1.back())) { normalized_r1.push_back(normalized_r1.front()); } double remaining_distance = d; size_t current_edge = _index; Point_t current_point = start_point; while (remaining_distance > 0) { // 获取当前边的终点 Point_t next_point = normalized_r1[(current_edge + 1) % normalized_r1.size()]; // 计算当前边剩余长度 double edge_length = bg::distance(current_point, next_point); if (edge_length >= remaining_distance) { // 目标点在当前边上 double ratio = remaining_distance / edge_length; double x = current_point.x() + ratio * (next_point.x() - current_point.x()); double y = current_point.y() + ratio * (next_point.y() - current_point.y()); e_index = current_edge; return Point_t(x, y); } else { // 目标点在下一条边上,更新剩余距离 remaining_distance -= edge_length; current_point = next_point; current_edge = (current_edge + 1) % normalized_r1.size(); } } e_index = _index; return start_point; } //在环上寻找长度最大的边索引 size_t Bridge::findLongestEdgeIndex(const Ring& ring) { std::vector max_indices; double max_length = 0.0; const size_t n = ring.size(); // 遍历所有边,收集最大长度边的索引 for (size_t i = 0; i < n - 1; ++i) { const auto& p1 = ring[i]; const auto& p2 = ring[i + 1]; const double current_length = bg::distance(p1, p2); if (current_length > max_length) { max_length = current_length; max_indices.clear(); max_indices.push_back(i); } else if (current_length == max_length) { max_indices.push_back(i); } } isFront = !isFront; if (max_indices.size() > 1) { sel_edge_index = isFront ? max_indices[0] : max_indices[max_indices.size() - 1]; } else { sel_edge_index = isFront ? (max_indices[0] + 1) % (n - 1) : (max_indices[0] - 1 + n) % (n - 1); } return sel_edge_index; } //点在环上的位置索引 int findPointIndex(const Ring& ring, const Point_t& p0) { for (size_t i = 0; i < ring.size(); ++i) { if (equal(ring[i], p0)) { return static_cast(i); } } return -1; // 未找到 } void insert_point_on_ring(Ring& ring, Point_t& point, size_t index, RingNode& rn) { size_t s0 = rn.ring.size(); size_t s = ring.size(); const auto insertPos = ring.begin() + index + 1; ring.insert(insertPos, point); bg::correct(ring); //调整方向为顺时针 size_t s1 = ring.size(); size_t s01 = rn.ring.size(); } //在第N条边上进行内外环桥接,并插入桥接点 void Bridge::handleBridge(IdIndex o_ii, IdIndex i_ii) { //判断环上是否存在桥接 for (auto& b : bridges) { if (b.to_ii == i_ii) { return; } } RingNode& inner = findNode(i_ii); RingNode& outer = findNode(o_ii); size_t edge_index_inner = findLongestEdgeIndex(inner.ring); size_t edge_index_outer = findLongestEdgeIndex(outer.ring); double _offset = 0; Point_t p0, p1, p2, p3; size_t p0_index = 0, p0_index_1 = 0, p1_index = 0, p2_index = 0, p2_index_1 = 0, p3_index = 0; bool _f = false; int _loop = 0; do { //从内到外 p0 = findCenterPointOnEdge(inner.ring, edge_index_inner, _offset, p0_index); Point_t p0_o = find_closest_point_on_ring_edges(outer.ring, p0, p0_index_1); //从外到内 p2 = findCenterPointOnEdge(outer.ring, edge_index_outer, _offset, p2_index); Point_t p2_i = find_closest_point_on_ring_edges(inner.ring, p2, p2_index_1); double _d0 = bg::distance(p0, p0_o); double _d1 = bg::distance(p2, p2_i); if (_d0 > (2 * offset) && _d1 > (2 * offset)) { _offset += offset; _f = true; continue; } if (_d0 < _d1) { //从内到外 p2 = p0_o; p2_index = p0_index_1; } else { p0 = p2_i; p0_index = p2_index_1; } p1 = find_point_at_distance_clockwise(inner.ring, p0, p0_index, offset, p1_index); p3 = find_point_at_distance_clockwise(outer.ring, p2, p2_index, offset, p3_index); if (!bridges.empty()) { BridgeMap bm = bridges.back(); double d0 = bg::distance(bm.to, p2); double d1 = bg::distance(bm.to2, p2); double d2 = bg::distance(bm.to, p3); double d3 = bg::distance(bm.to2, p3); if (d0 < offset || d1 < offset || d2 < offset || d3 < offset) { _offset += offset; _f = true; } else { _f = false; } } } while (_f); Segment seg1(p2, p1); Segment seg2(p3, p0); insert_point_on_ring(inner.ring, p1, p1_index, inner); insert_point_on_ring(inner.ring, p0, p0_index, inner); insert_point_on_ring(outer.ring, p3, p3_index, outer); insert_point_on_ring(outer.ring, p2, p2_index, outer); if (bg::intersects(seg1, seg2)) { BridgeMap edge(p2, p1, p3, p0, o_ii, i_ii, edge_index_outer); bridges.push_back(edge); } else { BridgeMap edge(p2, p0, p3, p1, o_ii, i_ii, edge_index_outer); bridges.push_back(edge); } } //输出树结构 void Bridge::printTree() { generateRings(); formatTree(); // 用于记录已访问的节点 //std::unordered_set> visited; std::vector visited; dfs(findNode({ 1,1 }), visited); } int findIndex(std::vector points, const Point_t& p0) { for (int i = 0; i < points.size(); ++i) { if (equal(points[i], p0)) { return static_cast(i); } } return -1; // 未找到 } //递归遍历环 void Bridge::traverseRing( RingNode& node, IdIndex parent, Point_t& start, Point_t& end, bool isOutermostLayer ) { int size = node.ring.size(); int s_index = findPointIndex(node.ring, start); int e_index = findPointIndex(node.ring, end); std::vector c_points; std::vector cc_points; std::vector points; for (int i = s_index; !equal(node.ring[i], end); i = (i + 1) % size) { c_points.emplace_back(node.ring[i]); } c_points.emplace_back(end); for (int i = s_index; !equal(node.ring[i], end); i = (i - 1 + size) % size) { cc_points.emplace_back(node.ring[i]); } cc_points.emplace_back(end); if (cc_points.size() > c_points.size()) { points.assign(cc_points.begin(), cc_points.end()); } else { points.assign(c_points.begin(), c_points.end()); } int index = 0; do { //转换成SFML 顶点 /* path.emplace_back(sf::Vertex( sf::Vector2f(static_cast(points[index].x()), static_cast(points[index].y())), node.id.id == 1 ? sf::Color::Red : sf::Color::White ));*/ path.emplace_back(points[index]); BridgeMap* bridge = nullptr; //判断该点是否为桥接点 for (auto& bm : bridges) { if (equal(bm.from, points[index]) || equal(bm.from2, points[index])) { bridge = &bm; break; } } if (bridge != nullptr) { RingNode& rn = findNode(bridge->to_ii); //to 环 if (equal(bridge->from, points[index])) { traverseRing(rn, node.id, bridge->to, bridge->to2, false); index = findIndex(points, bridge->from2); } else if (equal(bridge->from2, points[index])) { traverseRing(rn, node.id, bridge->to2, bridge->to, false); index = findIndex(points, bridge->from); /*if (index == -1) index = findIndex(points, bridge->from2);*/ } if (index == -1) { std::cout << bridge->from.x() << "," << bridge->from.y() << std::endl; break; } /* path.emplace_back(sf::Vertex( sf::Vector2f(static_cast(points[index].x()), static_cast(points[index].y())), sf::Color::Red ));*/ path.emplace_back(points[index]); } index += isOutermostLayer ? -1 : 1; } while (index > 0 && index < points.size()); } //画路径 SFML顶点数组集 //std::vector Bridge::outputPaths() //{ // printTree(); // //第一个桥接边 // BridgeMap bm = bridges[0]; // IdIndex parent(1, 1); // //遍历 // traverseRing(findNode(bm.from_ii), bm.from_ii, bm.from, bm.from2, true); // //形成闭环 // path.emplace_back(sf::Vertex( // sf::Vector2f(static_cast(bm.from.x()), // static_cast(bm.from.y())), // sf::Color::Red // )); // return path; //} // 将 Boost 多边形转换为 SFML 顶点数组 //sf::VertexArray Bridge::convertToSFML(const Polygon_t& poly, const sf::Color& color) //{ // sf::VertexArray vertices(sf::LineStrip); // // // 外环 // for (const auto& pt : poly.outer()) { // vertices.append(sf::Vertex( // sf::Vector2f(static_cast(pt.x()), // static_cast(pt.y())), // color // )); // } // return vertices; //} //所有环转换成顶点数组集 //std::vector Bridge::convert2vertex() //{ // std::vector verteies; // for (const auto& map : ringNodes) { // for (const auto& m : map.second) { // if (m.isHide) continue; // Polygon_t poly; // bg::assign(poly, m.ring); // verteies.push_back(convertToSFML(poly, sf::Color::Red)); // } // } // return verteies; //} //std::vector Bridge::convertBridge() //{ // std::vector verteies; // for (const auto& map : bridges) { // sf::VertexArray arr(sf::LineStrip); // arr.append(sf::Vertex( // sf::Vector2f(static_cast(map.from.x()), // static_cast(map.from.y())), // sf::Color::White // )); // arr.append(sf::Vertex( // sf::Vector2f(static_cast(map.to.x()), // static_cast(map.to.y())), // sf::Color::White // )); // sf::VertexArray arr1(sf::LineStrip); // arr1.append(sf::Vertex( // sf::Vector2f(static_cast(map.from2.x()), // static_cast(map.from2.y())), // sf::Color::White // )); // arr1.append(sf::Vertex( // sf::Vector2f(static_cast(map.to2.x()), // static_cast(map.to2.y())), // sf::Color::White // )); // verteies.push_back(arr); // verteies.push_back(arr1); // } // return verteies; //} } // namespace Slic3r