BambuStudio/libslic3r/Fill/Bridge.cpp

1342 lines
48 KiB
C++
Raw Normal View History

#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