You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

623 lines
18 KiB
C++

1 month ago
#include "StdAfx.h"
#include <algorithm>
#include "keyholing.h"
#include "clipper2/clipper.core.h"
using namespace Clipper2Lib;
inline size_t GetLowestPtIdx(const Path64& path)
{
size_t result = 0;
Point64 resPt = path[0];
for (size_t i = 1; i < path.size(); ++i)
if (path[i].y < resPt.y) continue;
else if (path[i].y > resPt.y || path[i].x < resPt.x)
{
result = i;
resPt = path[i];
}
return result;
}
//inline size_t GetNearestPtIdx(const Path64& path, const Point64& pt)
//{
// size_t result = 0;
// double distSqr = DistanceSqr(path[0], pt);
// for (size_t i = 1; i < path.size(); ++i)
// {
// double ds = DistanceSqr(path[i], pt);
// if (ds >= distSqr) continue;
// distSqr = ds;
// result = i;
// }
// return result;
//}
static Point64 GetClosestPtOnSegment(const Point64& seg1, const Point64& seg2, const Point64& pt)
{
double dx = (seg2.x - seg1.x);
double dy = (seg2.y - seg1.y);
if (dx == 0.0 && dy == 0.0) return seg1;
double q = (dx * (pt.x - seg1.x) + dy * (pt.y - seg1.y)) / (Sqr(dx) + Sqr(dy));
// and restrict the point to the segment ...
q = std::fmax(0, std::fmin(1, q));
return Point64((1 - q) * seg1.x + q * seg2.x, (1 - q) * seg1.y + q * seg2.y);
}
// <20><>ת<EFBFBD><D7AA> (x, y) <20><>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ת<EFBFBD>Ƕ<EFBFBD> theta (ʹ<><CAB9>Ԥ<EFBFBD>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD><EFBFBD> cosTheta <20><> sinTheta)
inline Point64 rotatePoint(const Point64& p, double cosTheta, double sinTheta) {
return { p.x * cosTheta + p.y * sinTheta, -p.x * sinTheta + p.y * cosTheta };
}
//// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD><CFB5>ת<EFBFBD><D7AA>ʹ<EFBFBD>߶<EFBFBD>ˮƽ
//inline Point64 rotatePointToHorizontal(const Point64& p, const Point64& origin, double cosTheta, double sinTheta) {
// // ƽ<>Ƶ㵽ԭ<E3B5BD>㣬Ȼ<E3A3AC><C8BB>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD>ת
// double translatedX = p.x - origin.x;
// double translatedY = p.y - origin.y;
// return {
// translatedX * cosTheta + translatedY * sinTheta, // X<><EFBFBD><E1B7BD>
// -translatedX * sinTheta + translatedY * cosTheta // Y<><EFBFBD><E1B7BD>
// };
//}
//// <20><><EFBFBD><EFBFBD>X<EFBFBD><58>ƽ<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
//static Point64 GetClosestPtOnSegmentX(const Point64& seg1, const Point64& seg2, const Point64& pt)
//{
// int64_t dx = (seg2.x - seg1.x);
// int64_t dy = (seg2.y - seg1.y);
// if (dx == 0.0 && dy == 0.0) return seg1;
//
// int64_t segMinX = std::fmin(seg1.x, seg2.x);
//
// //if(pt.x<std::fmin(seg1.x, seg2.x))
// double q = (dx * (pt.x - seg1.x) + dy * (pt.y - seg1.y)) / (Sqr(dx) + Sqr(dy));
// // and restrict the point to the segment ...
// q = std::fmax(0, std::fmin(1, q));
// return Point64((1 - q) * seg1.x + q * seg2.x, (1 - q) * seg1.y + q * seg2.y);
//}
inline Point64 GetYIntersectPt(const Point64& ln1, const Point64& ln2, int64_t Y)
{
double dx = static_cast<double>(ln2.x - ln1.x);
if (dx == 0.0) return Point64(ln1.x, Y);
double dy = static_cast<double>(ln2.y - ln1.y);
// y = dy/dx * x + b
// b = y1 - dy/dx * x1;
double b = ln1.y - dy / dx * ln1.x;
// x = (Y - b) * dx/dy
return Point64(static_cast<int64_t>(round((Y - b) * dx / dy)), Y);
}
static void JoinAtClosestPtBelowHole(Path64& outer, Path64 hole)
{
// precondition: hole[0] is the hole's lowest vertex
// find the closest point on the outer path (cpOuter) to hole[0],
// while ensuring cpOuter is **below** holePt. (Joining with an
// 'outer' segment that's above holePt (ie y < holePt.y) risks the
// new join passing through a hole that hasn't yet been keyholed.)
int highI = static_cast<int>(outer.size()) - 1;
Point64 holePt = hole[0];
Point64 cpOuter;
int cpOuterIdx = -1;
double distSqrd = MAX_DBL;
for (size_t i = 0; i < highI; ++i)
{
Point64 nextPt = (i == highI) ? outer[0] : outer[i + 1];
// Since cpOuter.y must be below holePt.y ...
if (outer[i].y <= holePt.y && nextPt.y <= holePt.y) continue;
// 'outer' may have overlapping collinear segments due to previous
// hole joins. Therefore it's imperative when the closest segment
// happens to be one of these overlapping collinear segments, that
// the new join is with the correct one. For example, when a hole
// is on the left of an outer segment, that outer segment **must**
// be descending. Likewise, when a hole is on the right of an
// outer segment, then that outer segment must be descending.
if (CrossProduct(holePt, outer[i], nextPt) < 0) continue;
// Again make sure cpOuter.y is below holePt.y ...
Point64 cp;
if (outer[i].y <= holePt.y)
{
Point64 pt = GetYIntersectPt(outer[i], nextPt, holePt.y + 1);
cp = GetClosestPtOnSegment(pt, nextPt, holePt);
}
else if (nextPt.y <= holePt.y)
{
Point64 pt = GetYIntersectPt(outer[i], nextPt, holePt.y + 1);
cp = GetClosestPtOnSegment(outer[i], pt, holePt);
}
else
cp = GetClosestPtOnSegment(outer[i], nextPt, holePt);
double ds = DistanceSqr(cp, holePt);
if (cpOuterIdx >= 0 && ds >= distSqrd) continue;
cpOuter = cp;
distSqrd = ds;
cpOuterIdx = (cp == nextPt) ? i + 1 : i;
if (ds == 0) break;
}
// insert duplicate points into both outer and hole paths
if (cpOuter != outer[cpOuterIdx])
{
++cpOuterIdx;
if (cpOuterIdx > highI) cpOuterIdx = 0;
outer.insert(outer.begin() + cpOuterIdx, cpOuter);
}
outer.insert(outer.begin() + cpOuterIdx, cpOuter);
++cpOuterIdx;
if (cpOuterIdx >= outer.size()) cpOuterIdx = 0;
hole.insert(hole.begin(), holePt);
// finally join the hole with its outer path
outer.reserve(outer.size() + hole.size());
outer.insert(outer.begin() + cpOuterIdx, hole.begin(), hole.begin() + 1);
outer.insert(outer.begin() + cpOuterIdx, hole.begin() + 1, hole.end());
}
struct PolySorter {
inline bool operator()(const Path64& path1, const Path64& path2)
{
return path2[0].y < path1[0].y;
}
};
static bool KeyHoleOuter(const PolyPath64* outer, Paths64& paths)
{
if (!outer->Count())
{
paths.push_back(outer->Polygon());
return true;
}
Paths64 tmp;
tmp.reserve(outer->Count());
for (const auto& hole : *outer)
{
Path64 p = hole->Polygon();
// rearrange p so the lower vertex is first
size_t i = GetLowestPtIdx(p);
for (size_t j = 0; j < i; ++j)
{
Path64::iterator it = p.begin();
std::rotate(it, it + 1, p.end());
}
tmp.push_back(p);
}
// sort holes so the lowest ones are first
std::sort(tmp.begin(), tmp.end(), PolySorter());
Path64 merged = outer->Polygon();
// merge all holes into the outer path
for (Paths64::iterator it = tmp.begin(); it != tmp.end(); ++it)
{
JoinAtClosestPtBelowHole(merged, *it);
//std::cout << merged;
}
paths.push_back(merged);
// finally do any nested outer polygons
for (const auto& hole : *outer)
{
for (const auto& nested_outer : *hole)
{
if (!KeyHoleOuter(nested_outer.get(), paths))
{
return false;
}
}
}
return true;
}
bool KeyHole(const PolyTree64& polytree, Paths64& solution)
{
for (const auto& outer : polytree)
if (!KeyHoleOuter(outer.get(), solution)) return false;
return true;
}
//////////////////////////////////////////////////////////////////////////////////////
struct BoundingBox64 {
int64_t minX, minY, maxX, maxY;
BoundingBox64() {}
BoundingBox64(int64_t minX, int64_t minY, int64_t maxX, int64_t maxY)
: minX(minX), minY(minY), maxX(maxX), maxY(maxY) {}
// <20>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7><EFBFBD>Ƿ<EFBFBD><C7B7>н<EFBFBD><D0BD><EFBFBD>
bool Intersects(const BoundingBox64& other) const {
return !(other.maxX < this->minX || other.minX > this->maxX ||
other.maxY < this->minY || other.minY > this->maxY);
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ<EFBFBD><CEA7>֮<EFBFBD><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EBA3A8><EFBFBD>Թ<EFBFBD><D4B9>
double DistanceTo(const BoundingBox64& other) const {
// if (Intersects(other)) return 0;
int64_t dx = max(int64_t(0), max(minX - other.maxX, other.minX - maxX));
int64_t dy = max(int64_t(0), max(minY - other.maxY, other.minY - maxY));
return sqrt(dx * dx + dy * dy);
// return min(dx, dy, )
}
void CreateBoundary(const Path64 path) {
minX = INT64_MAX;
maxX = INT64_MIN;
minY = INT64_MAX;
maxY = INT64_MIN;
for (const auto& p : path) {
minX = min(minX, p.x);
minY = min(minY, p.y);
maxX = max(maxX, p.x);
maxY = max(maxY, p.y);
}
}
};
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD>ľ<EFBFBD><C4BE><EFBFBD>
inline double distance(const Point64& p1, const Point64& p2) {
return sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}
double Clipper64Factor = 10000;
Point64 toPoint64(double x, double y) {
int64_t nX = static_cast<int64_t>(x * Clipper64Factor);
int64_t nY = static_cast<int64_t>(y* Clipper64Factor);
return Point64(nX, nY);
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>Ϊ Clipper ʹ<>õ<EFBFBD> IntPoint <20><>ʽ
Path64 toPolygon64(const PathD& poly) {
Path64 clipperPoly;
for (const PointD& p : poly) {
clipperPoly.push_back(Point64(static_cast<int64_t>(p.x * Clipper64Factor), static_cast<int64_t>(p.y * Clipper64Factor)));
}
return clipperPoly;
}
// <20><> Clipper <20><> IntPoint <20><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD>ԭʼ Polygon <20><>ʽ
PathD fromPolygon64(const Path64& clipperPoly) {
vector<PointD> vertices;
for (const Point64& ip : clipperPoly) {
vertices.emplace_back(ip.x / Clipper64Factor, ip.y/ Clipper64Factor);
}
return PathD(vertices);
}
// <20>ҳ<EFBFBD><D2B3><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD><DFB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>
tuple<Point64, Point64, int, int, double> findClosestPointWithRotation(const Path64& poly1, const Path64& poly2, double& minDist) {
Point64 closest1, closest2;
//double minDist = distInit;
int index1 = -1, index2 = -1;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿһ<C3BF><D2BB><EFBFBD><EFBFBD>
for (int i = 0; i < poly1.size(); i++)
{
Point64 p1 = poly1[i];
Point64 p2 = poly1[(i + 1) % poly1.size()];
// <20><><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD> a-b <20><> X <20><><EFBFBD>ļн<C4BC>
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
double theta = atan2(dy, dx); // <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD> dx == 0<><30>atan2 <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
// Ԥ<>ȼ<EFBFBD><C8BC><EFBFBD> cos <20><> sin<69><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תʱ<D7AA><CAB1><EFBFBD>μ<EFBFBD><CEBC><EFBFBD>
double cosTheta = cos(theta);
double sinTheta = sin(theta);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Point64 rotatedA = rotatePoint(p1, cosTheta, sinTheta);
Point64 rotatedB = rotatePoint(p2, cosTheta, sinTheta);
// <20><><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A3AC><EFBFBD>㵽ÿ<E3B5BD><C3BF><EFBFBD>ߵľ<DFB5><C4BE><EFBFBD>
for (int j = 0; j < poly2.size(); j++)
{
Point64 point = poly2[j];
Point64 rotatedP = rotatePoint(point, cosTheta, sinTheta);
double distY = fabs(rotatedP.y - rotatedA.y);
if (distY > minDist)
{
continue;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD> x <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶εķ<CEB5>Χ<EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㴹ֱ<E3B4B9><D6B1><EFBFBD><EFBFBD>
if (rotatedP.x >= rotatedA.x && rotatedP.x <= rotatedB.x) {
//double dist = fabs(rotatedP.y - rotatedA.y); // <20><>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD>Ϊ y <20><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE>
minDist = distY;
//closestPoint = point; // <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>ϵ<EFBFBD>еĵ<D0B5>
index1 = i;
index2 = j;
closest1 = Point64{ rotatedP.x , rotatedA.y };
closest1 = rotatePoint(closest1, cosTheta, -sinTheta); // <20><>ת<EFBFBD><D7AA>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>ϵ
closest2 = point;
}
else {
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڷ<EFBFBD>Χ<EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶ζ˵<CEB6><CBB5>ľ<EFBFBD><C4BE><EFBFBD>
size_t dSpaceXA = abs(rotatedP.x - rotatedA.x);
size_t dSpaceXB = abs(rotatedP.x - rotatedB.x);
size_t dSpaceXMin = min(dSpaceXA, dSpaceXB);
if (dSpaceXA > minDist && dSpaceXB > minDist)
{
continue;
}
if (dSpaceXA < dSpaceXB) {
double dDist = distance(rotatedA, rotatedP);
if (dDist < minDist)
{
minDist = dDist;
index1 = i;
index2 = j;
//closest1 = Point64{ rotatedA.x , rotatedA.y };
//closest1 = rotatePoint(closest1, cosTheta, -sinTheta); // <20><>ת<EFBFBD><D7AA>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>
closest1 = p1;
closest2 = point;
}
}
else {
double dDist = distance(rotatedB, rotatedP);
if (dDist < minDist)
{
minDist = dDist;
index1 = i;
index2 = j;
//closest1 = Point64{ rotatedB.x , rotatedB.y };
//closest1 = rotatePoint(closest1, cosTheta, -sinTheta); // <20><>ת<EFBFBD><D7AA>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>
closest1 = p2;
closest2 = point;
}
}
}
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿһ<C3BF><D2BB><EFBFBD><EFBFBD>
for (int i = 0; i < poly2.size(); i++)
{
Point64 p1 = poly2[i];
Point64 p2 = poly2[(i + 1) % poly2.size()];
// <20><><EFBFBD><EFBFBD><EFBFBD>߶<EFBFBD> a-b <20><> X <20><><EFBFBD>ļн<C4BC>
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
double theta = atan2(dy, dx); // <20><><EFBFBD><EFBFBD>Ҫ<EFBFBD>ر<EFBFBD><D8B1><EFBFBD><EFBFBD><EFBFBD> dx == 0<><30>atan2 <20>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>
// Ԥ<>ȼ<EFBFBD><C8BC><EFBFBD> cos <20><> sin<69><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>תʱ<D7AA><CAB1><EFBFBD>μ<EFBFBD><CEBC><EFBFBD>
double cosTheta = cos(theta);
double sinTheta = sin(theta);
// <20><><EFBFBD>߶ζ˵<CEB6><CBB5><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD> X <20><>ƽ<EFBFBD>е<EFBFBD><D0B5><EFBFBD><EFBFBD><EFBFBD>ϵ
Point64 rotatedA = rotatePoint(p1, cosTheta, sinTheta);
Point64 rotatedB = rotatePoint(p2, cosTheta, sinTheta);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A3AC><EFBFBD>㵽ÿ<E3B5BD><C3BF><EFBFBD>ߵľ<DFB5><C4BE><EFBFBD>
for (int j = 0; j < poly1.size(); j++)
{
Point64 point = poly1[j];
Point64 rotatedP = rotatePoint(point, cosTheta, sinTheta);
double distY = fabs(rotatedP.y - rotatedA.y);
if (distY > minDist)
{
continue;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD>ĵ<EFBFBD><C4B5><EFBFBD> x <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶εķ<CEB5>Χ<EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㴹ֱ<E3B4B9><D6B1><EFBFBD><EFBFBD>
if (rotatedP.x >= rotatedA.x && rotatedP.x <= rotatedB.x) {
//double dist = fabs(rotatedP.y - rotatedA.y); // <20><>ֱ<EFBFBD><D6B1><EFBFBD><EFBFBD>Ϊ y <20><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE>
minDist = distY;
//closestPoint = point; // <20><><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>ϵ<EFBFBD>еĵ<D0B5>
index2 = i;
index1 = j;
closest2 = Point64{ rotatedP.x , rotatedA.y };
closest2 = rotatePoint(closest2, cosTheta, -sinTheta); // <20><>ת<EFBFBD><D7AA>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>
closest1 = point;
}
else
{
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڷ<EFBFBD>Χ<EFBFBD>ڣ<EFBFBD><DAA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߶ζ˵<CEB6><CBB5>ľ<EFBFBD><C4BE><EFBFBD>
size_t dSpaceXA = abs(rotatedP.x - rotatedA.x);
size_t dSpaceXB = abs(rotatedP.x - rotatedB.x);
size_t dSpaceXMin = min(dSpaceXA, dSpaceXB);
if (dSpaceXA > minDist && dSpaceXB > minDist)
{
continue;
}
if (dSpaceXA < dSpaceXB) {
double dDist = distance(rotatedA, rotatedP);
if (dDist < minDist)
{
minDist = dDist;
index2 = i;
index1 = j;
closest2 = p1;
closest1 = point;
}
}
else {
double dDist = distance(rotatedB, rotatedP);
if (dDist < minDist)
{
minDist = dDist;
index2 = i;
index1 = j;
closest2 = p2;
closest1 = point;
}
}
}
}
}
return { closest1, closest2, index1, index2, minDist };
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD><CEB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
tuple<Point64, Point64, int, int, double> findClosestPoints(const Path64& poly1, const Path64& poly2) {
Point64 closest1, closest2;
double minDist = 1e30;
int index1 = -1, index2 = -1;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿһ<C3BF><D2BB><EFBFBD><EFBFBD>
for (int i = 0; i < poly1.size(); i++)
{
Point64 p1 = poly1[i];
Point64 p2 = poly1[(i + 1) % poly1.size()];
// <20><><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A3AC><EFBFBD>㵽ÿ<E3B5BD><C3BF><EFBFBD>ߵľ<DFB5><C4BE><EFBFBD>
for (int j = 0; j < poly2.size(); j++)
{
Point64 point = poly2[j];
Point64 ptConn = GetClosestPtOnSegment(p1, p2, point);
double dDisConn = distance(ptConn, point);
if (dDisConn < minDist) {
minDist = dDisConn;
index1 = i;
index2 = j;
closest1 = ptConn;
closest2 = point;
}
}
}
// <20><><EFBFBD><EFBFBD><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿһ<C3BF><D2BB><EFBFBD><EFBFBD>
for (int i = 0; i < poly2.size(); i++)
{
Point64 p1 = poly2[i];
Point64 p2 = poly2[(i + 1) % poly2.size()];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ε<EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E3A3AC><EFBFBD>㵽ÿ<E3B5BD><C3BF><EFBFBD>ߵľ<DFB5><C4BE><EFBFBD>
for(int j=0;j<poly1.size();j++)
{
Point64 point = poly1[j];
Point64 ptConn = GetClosestPtOnSegment(p1, p2, point);
double dDisConn = distance(ptConn, point);
if (dDisConn < minDist)
{
minDist = dDisConn;
index2 = i;
index1 = j;
closest2 = ptConn;
closest1 = point;
}
}
}
//for (int i = 0; i < poly1.size();i++) {
// Point64 p1 = poly1[i];
// for (int j = 0; j < poly2.size();j++) {
// Point64 p2 = poly2[j];
// double dist = distance(p1, p2);
// if (dist < minDist) {
// minDist = dist;
// closest1 = p1;
// closest2 = p2;
// index1 = i;
// index2 = j;
// }
// }
//}
return { closest1, closest2, index1, index2, minDist };
}
tuple<int, Point64, Point64, int, int, double> findClosestPath(const Path64& path, const Paths64& source, const std::vector< BoundingBox64> boundings)
{
vector<int> vecSearchIndexs;
BoundingBox64 bounding;
bounding.CreateBoundary(path);
double dDistMin = INT64_MAX;
int nSearchNeareast = -1;
for (int i = 0; i < boundings.size(); i++) {
BoundingBox64* pBdCur = (BoundingBox64*)(&boundings[i]);
if (pBdCur->Intersects(bounding)) {
vecSearchIndexs.emplace_back(i);
continue;
}
double dDist = bounding.DistanceTo(*pBdCur);
if (dDist < dDistMin) {
nSearchNeareast = i;
dDistMin = dDist;
}
}
if (nSearchNeareast > -1) {
vecSearchIndexs.emplace_back(nSearchNeareast);
}
Point64 closest1, closest2;
int idxFind = -1;
int idxEdge1 = -1, idxEdge2 = -1;
dDistMin = INT64_MAX;
for (const auto& index : vecSearchIndexs)
{
Path64 item = source[index];
//auto[p1, p2, index1, index2, distance] = findClosestPoints(path, item);
double dDistOld = dDistMin;
auto[p1, p2, index1, index2, distance] = findClosestPointWithRotation(path, item, dDistMin);
if (dDistMin <= 1E-6) {
idxFind = index;
dDistMin = distance;
closest1 = p1;
closest2 = p2;
idxEdge1 = index1;
idxEdge2 = index2;
break;
}
else if (distance < dDistOld) {
idxFind = index;
dDistMin = distance;
closest1 = p1;
closest2 = p2;
idxEdge1 = index1;
idxEdge2 = index2;
}
}
//for (int i = 0; i < source.size();i++) {
// Path64 item = source[i];
// auto[p1, p2, index1, index2, distance] = findClosestPoints(path, item);
// if (distance < minDist) {
// idxFind = i;
// minDist = distance;
// closest1 = p1;
// closest2 = p2;
// idxEdge1 = index1;
// idxEdge2 = index2;
// }
//}
return { idxFind, closest1, closest2, idxEdge1, idxEdge2, dDistMin };
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ
Path64 ConnectPolygons(const Paths64& polygons) {
if (polygons.size() == 0) {
return Path64();
}
Paths64 lstSource;
std::vector< BoundingBox64> boundings;
for (const auto& polygon : polygons) {
lstSource.emplace_back(polygon);
BoundingBox64 bounding;
bounding.CreateBoundary(polygon);
boundings.emplace_back(bounding);
}
Path64 pathResult = lstSource[0];
lstSource.erase(lstSource.begin());
boundings.erase(boundings.begin());
while (lstSource.size() > 0) {
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD>
auto[findIndex, p1, p2, index1, index2, findDist] = findClosestPath(pathResult, lstSource, boundings);
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>
pathResult.insert(pathResult.begin() + index1+1, p1);
pathResult.insert(pathResult.begin() + index1+2, p2);
// <20>ϲ<EFBFBD><CFB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6><EFBFBD><EFBFBD><EFBFBD>
Path64 pathFind = lstSource[findIndex];
std::rotate(pathFind.begin(), pathFind.begin() + index2+1, pathFind.end());
pathResult.insert(pathResult.begin() + index1+3, pathFind.begin(), pathFind.end());
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8>
pathResult.insert(pathResult.begin() + index1 + 3 + pathFind.size(), p2);
pathResult.insert(pathResult.begin() + index1+3 + pathFind.size()+1, p1);
lstSource.erase(lstSource.begin() + findIndex);
boundings.erase(boundings.begin() + findIndex);
}
return pathResult;
}