BambuSrc/libslic3r/Fill/Bridge.cpp

1335 lines
47 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 <windows.h>
#include <sstream>
#include <string>
#include <filesystem>
#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<Point_t> 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<Point_t> 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<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);
}
}*/
// 为 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);
// }
//};
//判断两个点是否相等
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<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(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<Polygon_t> 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<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) {
if (std::abs(bg::area(poly.outer())) > area_threshold) {
offsetRing.emplace_back(poly.outer());
}
}
return offsetRing;
}
// 合并多个环
std::vector<Ring> Bridge::merge(std::vector<RingNode> rns, const RingNode rn) {
// 将环转换为多边形
std::vector<Polygon_t> input;
for (RingNode _rn : rns) {
Polygon_t poly;
std::vector<Point_t> outerBoundary(_rn.ring.begin(), _rn.ring.end());
bg::assign_points(poly.outer(), outerBoundary);
input.push_back(poly);
}
Polygon_t poly2;
std::vector<Point_t> 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<Ring> allRings;
for (const auto& poly : result) {
allRings.emplace_back(poly.outer());
}
//// 过滤掉被其他环完全包含的环
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 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<RingNode> nodes; //互交后产生的节点
bool isFind = false;
do {
isFind = false;
nodes.clear();
// 按 orientation 从大到小排序
std::sort(nodeHandles.begin(), nodeHandles.end(), compareByOrientationDesc);
int r = nodeHandles.size();
std::vector<std::vector<int>> matrix(r, std::vector<int>(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<int> dIndex;
for (size_t j = r - 1; j > 0; --j) {
std::vector<RingNode> 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<int>& row = matrix[i];
for (int& element : row) {
element = 0;
}
}
}
if (rVector.size() > 0) {
std::vector<Ring> rings = merge(rVector, nodeHandles[j]);
std::vector<IdIndex> 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<RingNode> offsetNodes;
//偏移
for (auto node : nodeHandles) {
std::vector<Ring> ring0 = offsetRing(node.ring, static_cast<double>(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<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));
}
}
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<IdIndex> 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<RingNode>& 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;
}
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<IdIndex>& 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<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 {
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<int>(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<std::pair<size_t, size_t>> visited;
std::vector<IdIndex> visited;
dfs(findNode({ 1,1 }), visited);
}
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
) {
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())),
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<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), bm.from_ii, 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;
//}
// 将 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<float>(pt.x()),
// static_cast<float>(pt.y())),
// color
// ));
// }
// return vertices;
//}
//所有环转换成顶点数组集
//std::vector<sf::VertexArray> Bridge::convert2vertex()
//{
// std::vector<sf::VertexArray> 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<sf::VertexArray> Bridge::convertBridge()
//{
// std::vector<sf::VertexArray> verteies;
// for (const auto& map : bridges) {
// sf::VertexArray arr(sf::LineStrip);
// arr.append(sf::Vertex(
// sf::Vector2f(static_cast<float>(map.from.x()),
// static_cast<float>(map.from.y())),
// sf::Color::White
// ));
// arr.append(sf::Vertex(
// sf::Vector2f(static_cast<float>(map.to.x()),
// static_cast<float>(map.to.y())),
// sf::Color::White
// ));
// sf::VertexArray arr1(sf::LineStrip);
// arr1.append(sf::Vertex(
// sf::Vector2f(static_cast<float>(map.from2.x()),
// static_cast<float>(map.from2.y())),
// sf::Color::White
// ));
// arr1.append(sf::Vertex(
// sf::Vector2f(static_cast<float>(map.to2.x()),
// static_cast<float>(map.to2.y())),
// sf::Color::White
// ));
// verteies.push_back(arr);
// verteies.push_back(arr1);
// }
// return verteies;
//}
} // namespace Slic3r