1342 lines
48 KiB
C++
1342 lines
48 KiB
C++
|
#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.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.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.children.insert(it.children.end(), it1.children.begin(), it1.children.end());
|
|||
|
//it作为it2子节点的父节点
|
|||
|
for (auto& c : it2.children) {
|
|||
|
c.parent = ⁢
|
|||
|
}
|
|||
|
it.children.insert(it.children.end(), it2.children.begin(), it2.children.end());
|
|||
|
}
|
|||
|
else if (it1.orientation == -1 && it2.orientation == -1) {// 内 内
|
|||
|
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 = ⁢
|
|||
|
//将it1的子节点作为it的子节点
|
|||
|
it.children.insert(it.children.end(), it1.children.begin(), it1.children.end());
|
|||
|
it1.children.clear(); //清空it1的子节点集
|
|||
|
//it2.parent = ⁢
|
|||
|
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
|
|||
|
|
|||
|
|