BambuStudio/libslic3r/Fill/Bridge.cpp

1342 lines
48 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "../ClipperUtils.hpp"
#include "../ExPolygon.hpp"
#include "../Surface.hpp"
#include "../ShortestPath.hpp"
#include "Bridge.hpp"
//#include <utility>
//#include <algorithm>
//
//#include <boost/geometry/algorithms/buffer.hpp>
//#include <boost/geometry/algorithms/intersects.hpp>
//#include <boost/geometry/algorithms/correct.hpp>
//#include <boost/range/algorithm_ext/erase.hpp>
//#include <random>
//namespace mpd = boost::multiprecision::decimal;
namespace Slic3r {
// 为 std::pair<size_t, size_t> 定义哈希函数
//template<>
//struct std::hash<std::pair<size_t, size_t>> {
// std::size_t operator()(const std::pair<size_t, size_t>& p) const noexcept {
// return std::hash<size_t>()(p.first) ^ (std::hash<size_t>()(p.second) << 1);
// }
//};
Polylines Bridge::fill_surface(const Surface* surface, const FillParams& params)
{
Polylines polylines_out;
//BoundingBox bounding_box = surface->expolygon.contour.bounding_box();
Points points = surface->expolygon.contour.points;
Point first = points[0];
points.push_back(first);
//Polygon outPolygon = bounding_box.polygon();
Polygon_t polygon;
std::vector<Point_t> outerBoundary;
outerBoundary.reserve(points.size());
int precision = 1e7;
for (Point one : points) {
double x = one.x();
double y = one.y();
//double x_result = x / 1000000.0 + 200;
//double y_result = y / 1000000.0 + 200;
//double stored_x = std::round(x_result * precision) / precision;
//double stored_y = std::round(y_result * precision) / precision;
//Point_t temp = { stored_x ,stored_y };
Point_t temp = { x ,y };
outerBoundary.push_back(temp);
}
bg::append(polygon.outer(), outerBoundary);
//std::vector<Point_t> innerBoundary;
//Polygons inPolygons = surface->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;
auto abc = float(scale_(this->overlap - 0.5 * this->spacing));
if (abc < 0) {
abc = -abc;
}
//this->offset = abc/ 1000000.0;
this->offset = 4000000;
printTree();
int size = ringNodes.begin()->second.size();
//第一个桥接边
int b_size = bridges.size();
BridgeMap bm = bridges[0];
IdIndex parent(1, 1);
//遍历
traverseRing(findNode(bm.from_ii), parent, bm.from, bm.from2, true);
//outputPaths();
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()+200)* 1000000.0,(path[i].y()+200) * 1000000.0 };
//Point p2 = { (path[i + 1].x()+200) * 1000000.0,(path[i + 1].y()+200) * 1000000.0 };
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<float, Point>& 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<double>(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<Point_t> 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<Point_t> 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<float, Point>& 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<double>(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<Point_t> 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<Point_t> 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);
}
}*/
bool is_point_on_segment(const Point_t& p, const Segment& seg, double tolerance = 1e-6) {
// 计算点到线段的距离
double dist = bg::distance(p, seg);
// 检查距离是否在容差范围内
if (dist > tolerance) {
return false;
}
// 获取线段端点
const Point_t& p1 = seg.first;
const Point_t& p2 = seg.second;
// 检查点是否在线段的边界框内
double min_x = std::min(p1.x(), p2.x());
double max_x = std::max(p1.x(), p2.x());
double min_y = std::min(p1.y(), p2.y());
double max_y = std::max(p1.y(), p2.y());
// 考虑容差
return (p.x() >= min_x - tolerance) && (p.x() <= max_x + tolerance) &&
(p.y() >= min_y - tolerance) && (p.y() <= max_y + tolerance);
}
// 计算点到原点的距离平方
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);
}
// 找到环中距离原点最近的点作为起点
void reorder_ring_start_point(Ring& ring) {
// 找到距离原点最近的点
auto min_it = std::min_element(ring.begin(), ring.end(),
[](const Point_t& a, const Point_t& b) {
return distance_to_origin_sq(a) < distance_to_origin_sq(b);
});
// 旋转环使最近的点成为起点
std::rotate(ring.begin(), min_it, ring.end() - 1); // end()-1 保留闭合点
// 确保环保持闭合
if (!bg::equals(ring.front(), ring.back())) {
ring.back() = ring.front();
}
}
//将节点加入处理节点集合中
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) {
reorder_ring_start_point(node.ring);
// 检查键是否存在
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<RingNode>& 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<RingNode>& 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(const 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);
}
}
// 判断两个环是否相交(不包括包含关系)
bool Bridge::ringsIntersect(const Ring& ring1, const Ring& ring2)
{
// 首先检查是否相交(包括边界相交)
if (!bg::intersects(ring1, ring2)) {
return false;
}
// 然后排除包含关系
bool ring1_inside_ring2 = bg::within(ring1, ring2);
bool ring2_inside_ring1 = bg::within(ring2, ring1);
// 如果存在包含关系,则不算作相交
if (ring1_inside_ring2 || ring2_inside_ring1) {
return false;
}
return true;
}
//获取环偏移后的环(可能为空)
std::vector<Ring> Bridge::offsetRing(const Ring& ring, const double distance) {
// 将环包装成多边形
Polygon_t inputPolygon;
inputPolygon.outer() = ring;
// 修复几何数据
bg::correct(inputPolygon);
// 使用 multi_polygon 作为 buffer 的输出类型
bg::model::multi_polygon<Polygon_t> result;
// 使用对称距离策略
bg::buffer(inputPolygon, result,
bg::strategy::buffer::distance_symmetric<double>(distance),
bg::strategy::buffer::side_straight(),
bg::strategy::buffer::join_round(),
bg::strategy::buffer::end_round(),
bg::strategy::buffer::point_circle());
// 提取偏移后的环
std::vector<Ring> offsetRing;
for (const auto& poly : result) {
offsetRing.emplace_back(poly.outer());
}
return offsetRing;
}
// 查找环非邻边的相交点
std::vector<Point_t> Bridge::findNonAdjacentIntersections(const Ring& ring) {
Polygon_t poly;
bg::append(poly.outer(), ring);
std::vector<Point_t> intersections;
std::vector<bg::model::segment<Point_t>> segments;
const size_t num_points = bg::num_points(poly.outer());
// 构建所有边的线段
for (int i = 0; i < num_points - 1; ++i) {
segments.emplace_back(poly.outer()[i], poly.outer()[i + 1]);
}
// 遍历所有非邻边对
for (size_t i = 0; i < segments.size(); ++i) {
for (size_t j = i + 2; j < segments.size(); ++j) {
if ((i == 0 && j == segments.size() - 1)) continue; // 排除相邻边
std::vector<Point_t> intersection_points;
bg::intersection(segments[i], segments[j], intersection_points);
for (const auto& point : intersection_points) {
// 检查相交点是否为多边形的顶点
bool is_vertex = false;
for (const auto& vertex : polygon.outer()) {
if (bg::equals(point, vertex)) {
is_vertex = true;
break;
}
}
if (!is_vertex) {
intersections.push_back(point);
}
}
}
}
return intersections;
}
// 将环拆分成多个环
std::vector<Ring> Bridge::split(const Ring& ring, const std::vector<Point_t>& intersections) {
std::vector<Ring> rings;
std::vector<bool> visited(ring.size(), false);
Ring extendedRing = ring;
// 插入相交点到环中
for (const auto& intersection : intersections) {
for (size_t i = 0; i < ring.size(); ++i) {
Segment seg(ring[i], ring[(i + 1) % ring.size()]);
if (bg::within(intersection, seg)) {
extendedRing.insert(extendedRing.begin() + i + 1, intersection);
break;
}
}
}
std::vector<bool> newVisited(extendedRing.size(), false);
for (size_t i = 0; i < extendedRing.size(); ++i) {
if (newVisited[i]) continue;
Ring newRing;
size_t current = i;
do {
newRing.push_back(extendedRing[current]);
newVisited[current] = true;
current = (current + 1) % extendedRing.size();
} while (current != i);
if (newRing.size() > 2) {
rings.push_back(newRing);
}
}
return rings;
}
// 在环的指定位置插入点
void insert_point_in_ring(Ring& ring, const Point_t& point, size_t after_index) {
auto it = ring.begin();
std::advance(it, after_index + 1);
ring.insert(it, point);
}
// 找到环上应该插入交点的位置
std::vector<std::pair<size_t, Point_t>> find_insertion_points(const Ring& ring, const std::vector<Point_t>& intersections) {
std::vector<std::pair<size_t, Point_t>> insertion_points;
for (const auto& p : intersections) {
double min_dist = std::numeric_limits<double>::max();
size_t best_segment = 0;
for (size_t i = 0; i < ring.size() - 1; ++i) {
Point_t seg_start = ring[i];
Point_t seg_end = ring[i + 1];
// 计算点到线段的距离
double dist = bg::distance(p, bg::model::segment<Point_t>(seg_start, seg_end));
if (dist < min_dist) {
min_dist = dist;
best_segment = i;
}
}
if (min_dist < 1e-6) { // 使用小的容差值
insertion_points.emplace_back(best_segment, p);
}
}
// 按插入位置排序,从后往前插入
std::sort(insertion_points.begin(), insertion_points.end(),
[](const auto& a, const auto& b) { return a.first > b.first; });
return insertion_points;
}
// 合并两个环
std::vector<Ring> Bridge::merge(const RingNode& ring1, const RingNode& ring2) {
// 将环转换为多边形
Polygon_t poly1, poly2;
bg::append(poly1.outer(), ring1.ring);
bg::append(poly2.outer(), ring2.ring);
bg::correct(poly1); // 确保多边形是有效的
bg::correct(poly2); // 确保多边形是有效的
std::vector<Point_t> intersection_points;
bg::intersection(poly1, poly2, intersection_points);
// 将交点插入到两个多边形中
auto insertions1 = find_insertion_points(poly1.outer(), intersection_points);
for (const auto& ins : insertions1) {
insert_point_in_ring(poly1.outer(), ins.second, ins.first);
}
auto insertions2 = find_insertion_points(poly2.outer(), intersection_points);
for (const auto& ins : insertions2) {
insert_point_in_ring(poly2.outer(), ins.second, ins.first);
}
// 计算多边形交、差布尔运算
/* MultiPolygon mp0;
bg::intersection(poly1, poly2, mp0);*/
MultiPolygon mp1;
bg::difference(poly1, poly2, mp1);
MultiPolygon mp2;
bg::difference(poly2,poly1, mp2);
// 合并所有结果多边形
MultiPolygon result;
//result.insert(result.end(), mp0.begin(), mp0.end());
if (ring1.orientation == -1 && ring2.orientation == 1) {
result.insert(result.end(), mp1.begin(), mp1.end());
}
else if(ring1.orientation == 1 && ring2.orientation == -1){
result.insert(result.end(), mp2.begin(), mp2.end());
}
else {
result.insert(result.end(), mp1.begin(), mp1.end());
result.insert(result.end(), mp2.begin(), mp2.end());
}
std::vector<Ring> allRings;
for (const auto& poly : result) {
allRings.emplace_back(poly.outer());
}
//for (const auto& poly : result) {
// allRings.push_back(poly.outer());
// for (const auto& inner : poly.inners()) {
// allRings.push_back(inner);
// }
//}
//// 过滤掉被其他环完全包含的环
std::vector<Ring> 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 allRings;
}
//生成环集
void Bridge::generateRings() {
//获取多边形的外边界和内边界
computePolygonBoundaries(polygon);
//外边界
std::vector<Ring> rings = offsetRing(boundaries.outerBoundary, -offset / 2);
for (auto& r : rings) {
RingNode node = formatNode(maxRid++, 1, r, -1);
nodeHandles.emplace_back(node);
addNode(node);
}
//内边界 偏移
std::map<IdIndex,Ring> offRings; //存放待偏移的环
for (auto& inner : boundaries.innerBoundaries) {
offRings.insert({{maxRid++,1},inner });
}
std::vector<RingNode> tempRings;
for (auto& r : offRings) {
std::vector<Ring> _rings = offsetRing(r.second, offset / 2);
if (_rings.size() == 1) {
RingNode node1 = formatNode(r.first.id, r.first.index + 1, _rings[0], 1);
if (bg::area(node1.ring) > area_threshold) {
addNode(node1);
tempRings.emplace_back(node1);
}
}
else if (_rings.size() > 1) {
std::vector<IdIndex> id_indices;
for (auto& r1 : _rings) {
RingNode node0 = formatNode(++maxRid, 1, r1, 1);
if (bg::area(node0.ring) > area_threshold) {
addNode(node0);
tempRings.emplace_back(node0);
IdIndex ii(maxRid, 1);
id_indices.emplace_back(ii);
}
}
//分裂映射
offsetMap.insert(std::pair<IdIndex, std::vector<IdIndex>>({ r.first.id,r.first.index }, id_indices));
}
}
nodeHandles.insert(nodeHandles.end(), tempRings.begin(), tempRings.end());
//遍历当前用于判断自/互交的节点集
while (!nodeHandles.empty()) {
std::vector<RingNode> interNodes; //产生互交的节点集
std::vector<RingNode> nodes; //互交后产生的节点
for (auto it1 = nodeHandles.begin(); it1 != nodeHandles.end(); ++it1) {
//互交判断&处理
auto it2 = std::next(it1);
for (;it2 != nodeHandles.end(); ++it2) {
if (ringsIntersect(it1->ring, it2->ring)) {
//合并
std::vector<Ring> rings = merge(*it1, *it2);
std::vector<IdIndex> id_indices;
for (const auto& ring2 : rings) {
// 外与内 外与外 -> 向内; 内与内 -> 向外
const int orientation = (it1->orientation + it2->orientation) <= 0 ? -1 : 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);
}
}
MergeMap mm(it1->id, it2->id, id_indices);
mergeMap.emplace_back(mm);
interNodes.emplace_back(*it1);
interNodes.emplace_back(*it2);
it1++;
break;
}
}
}
//删除互交节点
for (auto& n : interNodes) {
nodeHandles.erase(std::remove(nodeHandles.begin(), nodeHandles.end(), n), nodeHandles.end());
}
//是否存在互交
if (!nodes.empty()) {
for (auto& n : nodes) {
nodeHandles.emplace_back(n);
}
}
std::vector<RingNode> offsetNodes;
//偏移
for (auto& node : nodeHandles) {
//if (node.orientation == 1) continue;
std::vector<Ring> ring0 = offsetRing(node.ring, static_cast<double>(node.orientation) * offset);
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<IdIndex> 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<IdIndex, std::vector<IdIndex>>({node.id.id,node.id.index }, id_indices));
}
}
//清空
nodeHandles.clear();
if (!offsetNodes.empty()) {
//重填
nodeHandles.insert(nodeHandles.end(), offsetNodes.begin(), offsetNodes.end());
}
}
}
//形成树
void Bridge::formatTree() {
//遍历不同环类型的节点集合
for (auto& ringNode : ringNodes) {
// 使用反向迭代器进行反序遍历
std::vector<RingNode>& vec = ringNode.second;
const auto it0 = ringNode.second.begin();
if (it0->orientation == 1) { // 向外 倒序
for (int 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 : mergeMap) { //合并
RingNode& it1 = findNode(map.ii1);
RingNode& it2 = findNode(map.ii2);
for (const auto& ii : map.nodes) {
RingNode& it = findNode(ii);
if (it.orientation == -1) { //向内
//内 外
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;
}
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);
it.parent = it2.parent;
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作为it1子节点的父节点
for (auto& c : it1.children) {
c.parent = &it;
}
it.children.insert(it.children.end(), it1.children.begin(), it1.children.end());
}
else if (it1.orientation == 1 && it2.orientation == 1) { //外 外
//it作为it1子节点的父节点
for (auto& c : it1.children) {
c.parent = &it;
}
it.children.insert(it.children.end(), it1.children.begin(), it1.children.end());
//it作为it2子节点的父节点
for (auto& c : it2.children) {
c.parent = &it;
}
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);
//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());
it2.parent->children.emplace_back(it);
//it.parent = it2.parent;
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());
}
}
else { //向外
//it1.parent = &it;
//将it1的子节点作为it的子节点
it.children.insert(it.children.end(), it1.children.begin(), it1.children.end());
it1.children.clear(); //清空it1的子节点集
//it2.parent = &it;
it.children.insert(it.children.end(), it2.children.begin(), it2.children.end());
it2.children.clear();
}
RingNode* it_parent = it.parent;
//判断是否互交
if (ringsIntersect(it.ring, it_parent->ring)) {
//合并
std::vector<Ring> rings = merge(it1, *it1.parent);
const int orientation = (it1.orientation + it1.parent->orientation) <= 0 ? -1 : 1;
RingNode node1 = formatNode(++maxRid, 1, rings[0], orientation);
if (bg::area(node1.ring) > area_threshold) {
addNode(node1);
findNode(node1.id).children.insert(findNode(node1.id).children.end(), it1.children.begin(), it1.children.end());
if (it_parent->parent != nullptr) {
IdIndex ii = it_parent->id;
it_parent->parent->children.erase(std::remove_if(it_parent->parent->children.begin(), it_parent->parent->children.end(),
[ii](RingNode x) { return x.id.id == ii.id && x.id.index == ii.index; }),
it_parent->parent->children.end());
it_parent->parent->children.emplace_back(node1);
}
}
}
}
}
}
//树遍历
//void Bridge::dfs(RingNode& node, std::unordered_set<std::pair<size_t, size_t>>& visited, size_t& edge) {
// if (visited.find({ node.id.id, node.id.index }) != visited.end()) {
// return;
// }
// visited.insert({ node.id.id, node.id.index });
// edge++;
// // 处理当前节点
// std::cout << "rId: " << node.id.id << ", rIndex: " << node.id.index
// << ", orientation: " << node.orientation
// << ", isHide: " << (node.isHide ? "true" : "false") << std::endl;
//
// Polygon poly;
// bg::assign(poly, node.ring);
// verteies.push_back(convertToSFML(poly, sf::Color::Red));
//
// // 递归遍历子节点
// for (auto& child : node.children) {
// handleBridge(node.id, child.id, child.ring.size(),edge);
// dfs(findNode(child.id), visited, edge);
// }
//}
void Bridge::dfs(RingNode& node, std::vector<IdIndex>& visited, size_t& edge) {
auto& it = std::find_if(visited.begin(), visited.end(), [node](const IdIndex& ii) {
return ii.id == node.id.id && ii.index == node.id.index;
});
if (it != visited.end()) {
return;
}
visited.emplace_back(node.id);
edge++;
// 处理当前节点
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, child.ring.size(), edge);
dfs(findNode(child.id), visited, edge);
}
}
//找到多边形环第 N 条边的中心点
Point_t Bridge::findCenterPointOnEdge(Ring& ring, size_t N) {
// 获取第 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);
const auto insertPos = ring.begin() + N + 1;
ring.insert(insertPos, p);
bg::correct(ring); //调整方向为顺时针
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
const double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
// 根据t值确定最近点
if (t <= 0.0) {
return seg_start;
}
else if (t >= 1.0) {
return seg_end;
}
else {
return Point_t(x1 + t * dx, y1 + t * dy);
}
}
// 在环的边上查找离给定点最近的点
Point_t find_closest_point_on_ring_edges(Ring& ring, const Point_t& p0) {
// 验证环是否闭合
if (ring.size() < 2 || !bg::equals(ring.front(), ring.back())) {
throw std::runtime_error("Ring is not closed");
}
Point_t closest_point;
double min_distance = std::numeric_limits<double>::max();
size_t e_index = 0;
// 遍历环的所有边
for (size_t i = 0; i < ring.size() - 1; ++i) {
const Point_t& p1 = ring[i];
const Point_t& p2 = ring[i + 1];
// 计算线段上的最近点
Point_t projected_point = closest_point_on_segment(p0, p1, p2);
// 计算距离
double distance = bg::distance(p0, projected_point);
// 更新最近点
if (distance < min_distance) {
min_distance = distance;
closest_point = projected_point;
e_index = i;
}
}
//插入
ring.insert(ring.begin()+e_index+1, closest_point);
bg::correct(ring); //调整方向为顺时针
return closest_point;
}
// 找到点所在的边(返回边起点索引)
std::pair<size_t, double> find_edge_containing_point(const Ring& ring, const Point_t& point) {
for (size_t i = 0; i < ring.size() - 1; ++i) {
const Point_t& p1 = ring[i];
const Point_t& p2 = ring[i + 1];
// 计算点到线段的距离
double seg_length = bg::distance(p1, p2);
if (seg_length == 0) continue; // 忽略零长度边
// 计算点在边上的投影参数t
double t = ((bg::get<0>(point) - bg::get<0>(p1)) * (bg::get<0>(p2) - bg::get<0>(p1)) +
(bg::get<1>(point) - bg::get<1>(p1)) * (bg::get<1>(p2) - bg::get<1>(p1))) /
(seg_length * seg_length);
// 如果点在当前边上
if (t >= 0.0 && t <= 1.0) {
Point_t proj(
bg::get<0>(p1) + t * (bg::get<0>(p2) - bg::get<0>(p1)),
bg::get<1>(p1) + t * (bg::get<1>(p2) - bg::get<1>(p1))
);
// 检查投影点与实际点的距离是否足够近
if (bg::distance(point, proj) < 1e-6) {
return { i, t };
}
}
}
}
Point_t Bridge::find_point_at_distance_clockwise(Ring& ring, const Point_t& start_point, double d)
{
// 1. 找到起点所在的边
std::pair<size_t, double> p = find_edge_containing_point(ring, start_point);
size_t edge_index = p.first;
double t = p.second;
// 计算从起点到当前边终点的剩余距离
const Point_t& p1 = ring[edge_index];
const Point_t& p2 = ring[(edge_index + 1) % ring.size() ];
double remaining_on_edge = (1.0 - t) * bg::distance(p1, p2);
// 3. 如果剩余距离足够
if (remaining_on_edge >= d) {
double new_t = t + d / bg::distance(p1, p2);
Point_t p(bg::get<0>(p1) + new_t * (bg::get<0>(p2) - bg::get<0>(p1)),
bg::get<1>(p1) + new_t * (bg::get<1>(p2) - bg::get<1>(p1)));
auto insertPos = ring.begin() + edge_index + 1;
ring.insert(insertPos, p);
bg::correct(ring); //调整方向为顺时针
return p;
}
// 4. 否则继续遍历后续边
double accumulated_distance = remaining_on_edge;
size_t current_index = (edge_index + 1) % (ring.size() - 1);
while (accumulated_distance < d) {
const Point_t& p1 = ring[current_index];
const Point_t& p2 = ring[(current_index + 1) % (ring.size() - 1)];
double segment_length = bg::distance(p1, p2);
if (accumulated_distance + segment_length >= d) {
double ratio = (d - accumulated_distance) / segment_length;
//在current_index 插入
Point_t p(bg::get<0>(p1) + ratio * (bg::get<0>(p2) - bg::get<0>(p1)),
bg::get<1>(p1) + ratio * (bg::get<1>(p2) - bg::get<1>(p1)));
auto insertPos = ring.begin() + current_index + 1;
ring.insert(insertPos, p);
bg::correct(ring); //调整方向为顺时针
return p;
}
accumulated_distance += segment_length;
current_index = (current_index + 1) % (ring.size() - 1);
}
return Point_t();
}
// 判断点是否在线段内部(非端点)
bool is_point_inside_segment(const Point_t& p, const Segment& seg) {
double x = bg::get<0>(p);
double y = bg::get<1>(p);
double x1 = bg::get<0>(seg.first);
double y1 = bg::get<1>(seg.first);
double x2 = bg::get<0>(seg.second);
double y2 = bg::get<1>(seg.second);
// 检查点是否在线段的包围盒内
if ((x < std::min(x1, x2) - 1e-6) || (x > std::max(x1, x2) + 1e-6) ||
(y < std::min(y1, y2) - 1e-6) || (y > std::max(y1, y2) + 1e-6)) {
return false;
}
// 向量叉积判断共线(可跳过,因为 intersects 已保证相交)
double cross = (x - x1) * (y2 - y1) - (y - y1) * (x2 - x1);
if (std::abs(cross) > 1e-6) return false;
return true;
}
// 判断两线段是否在内部相交(排除端点接触)
bool segments_cross(const Segment& seg1, const Segment& seg2) {
if (!bg::intersects(seg1, seg2)) return false;
std::vector<Point_t> points;
bg::intersection(seg1, seg2, points);
if (points.empty()) return false;
// 检查交点是否在两条线段的内部
for (const auto& p : points) {
if (is_point_inside_segment(p, seg1) && is_point_inside_segment(p, seg2)) {
return true;
}
}
return false;
}
//在环上寻找长度最大的边索引
size_t Bridge::findLongestEdgeIndex(const Ring& ring) {
if (ring.size() < 4) {
throw std::invalid_argument("Ring must have at least 4 points");
}
std::vector<size_t> 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 {
/*std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, n);*/
sel_edge_index = isFront?(max_indices[0] + 1) % (n - 1):(max_indices[0]-1+n)%(n-1);
}
return sel_edge_index;
}
//判断两个点是否相等
bool equal(Point_t p1, Point_t p2) {
return p1.x() == p2.x() && p1.y() == p2.y();
}
//在第N条边上进行内外环桥接并插入桥接点
void Bridge::handleBridge(IdIndex o_ii, IdIndex i_ii,const size_t ring_size, const size_t N)
{
//随机选择桥接的边
RingNode& inner = findNode(i_ii);
RingNode& outer = findNode(o_ii);
//从内到外
size_t edge_index = findLongestEdgeIndex(inner.ring);
Point_t p0 = findCenterPointOnEdge(inner.ring, edge_index);
Point_t p1 = find_point_at_distance_clockwise(inner.ring, p0, offset);
Point_t p2 = find_closest_point_on_ring_edges(outer.ring, p0);
Point_t p3 = find_point_at_distance_clockwise(outer.ring, p2, offset);
//从外到内
edge_index = findLongestEdgeIndex(outer.ring);
Point_t p2_1 = findCenterPointOnEdge(outer.ring, edge_index);
Point_t p3_1 = find_point_at_distance_clockwise(outer.ring, p2_1, offset);
Point_t p0_1 = find_closest_point_on_ring_edges(inner.ring, p2_1);
Point_t p1_1 = find_point_at_distance_clockwise(inner.ring, p0_1, offset);
//判断环上是否存在桥接
bool isExist = false;
for (auto& b : bridges) {
if (b.to_ii == i_ii) {
isExist = true;
break;
}
}
if (isExist) return;
if (bg::distance(p1, p2) < bg::distance(p1_1, p2_1)) {
Segment seg1(p2, p1);
Segment seg2(p3, p0);
if (bg::intersects(seg1, seg2)) {
BridgeMap edge(p2, p1, p3, p0, o_ii, i_ii);
bridges.push_back(edge);
}
else {
BridgeMap edge(p2, p0, p3, p1, o_ii, i_ii);
bridges.push_back(edge);
}
}
else {
Segment seg1(p2_1, p1_1);
Segment seg2(p3_1, p0_1);
if (bg::intersects(seg1, seg2)) {
BridgeMap edge(p2_1, p1_1, p3_1, p0_1, o_ii, i_ii);
bridges.push_back(edge);
}
else {
BridgeMap edge(p2_1, p0_1, p3_1, p1_1, o_ii, i_ii);
bridges.push_back(edge);
}
}
}
//输出所有环
void Bridge::printRings() {
generateRings();
// 输出环中的点信息
std::cout << "Points in the ring:" << std::endl;
for (const auto& map : ringNodes) {
std::cout << "(" << map.first << std::endl;
for (const auto& node : map.second) {
std::cout << "{" << node.id.id << "," << node.id.index << "," << node.orientation << std::endl;
for (const auto& point : node.ring) {
std::cout << "(" << bg::get<0>(point) << "," << bg::get<1>(point) << ")";
}
std::cout << "}" << std::endl;
}
std::cout << ")" << std::endl;
}
}
//输出树结构
void Bridge::printTree() {
generateRings();
formatTree();
// 用于记录已访问的节点
//std::unordered_set<std::pair<size_t, size_t>> visited;
std::vector<IdIndex> visited;
size_t edge = 1;
dfs(findNode({ 1,1 }), visited,edge);
}
//点在环上的位置索引
int findPointIndex(const Ring& ring, const Point_t& p0) {
for (size_t i = 0; i < ring.size(); ++i) {
if (ring[i].x() == p0.x() && ring[i].y() == p0.y()) {
return static_cast<int>(i);
}
}
return -1; // 未找到
}
int findIndex(std::vector<Point_t> points, const Point_t& p0) {
for (int i = 0; i < points.size(); ++i) {
if (equal(points[i], p0)){
return static_cast<int>(i);
}
}
return -1; // 未找到
}
//递归遍历环
void Bridge::traverseRing(
RingNode& node,
IdIndex parent,
Point_t& start,
Point_t& end,
bool isOutermostLayer
) {
//得到start点在环ring上的索引位置
int size = node.ring.size();
int s_index = findPointIndex(node.ring, start);
int e_index = findPointIndex(node.ring, end);
std::vector<Point_t> c_points;
std::vector<Point_t> cc_points;
std::vector<Point_t> 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<float>(points[index].x()),
static_cast<float>(points[index].y())),
sf::Color::Red
));*/
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)
break;
/* path.emplace_back(sf::Vertex(
sf::Vector2f(static_cast<float>(points[index].x()),
static_cast<float>(points[index].y())),
sf::Color::Red
));*/
path.emplace_back(points[index]);
}
index += isOutermostLayer ? -1 : 1;
} while (index > 0 && index < points.size());
}
//画路径 SFML顶点数组集
//std::vector<sf::Vertex> Bridge::outputPaths()
//{
// printTree();
// //第一个桥接边
// BridgeMap bm = bridges[0];
// IdIndex parent(1,1);
// //遍历
// traverseRing(findNode(bm.from_ii), parent, bm.from, bm.from2, true);
// //形成闭环
// path.emplace_back(sf::Vertex(
// sf::Vector2f(static_cast<float>(bm.from.x()),
// static_cast<float>(bm.from.y())),
// sf::Color::Red
// ));
// return path;
//
//}
} // namespace Slic3r