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.
kev/Drawer/Module/GeoSigmaDraw/MeshGenerationBorder.h

260 lines
6.7 KiB
C

1 month ago
#pragma once
#include "StdAfx.h"
#include <vector>
#include <cmath>
#include <algorithm>
#include <list>
// <20>򵥵ĵ<F2B5A5B5><C4B5>
struct Pnt {
double x, y;
};
namespace NoGeosUtils
{
double Dist(const Pnt& a, const Pnt& b) {
return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2));
}
double PerpendicularDistance(const Pnt& pt, const Pnt& lineStart, const Pnt& lineEnd) {
double dx = lineEnd.x - lineStart.x;
double dy = lineEnd.y - lineStart.y;
double mag = std::sqrt(dx * dx + dy * dy);
if (mag < 1e-10) return Dist(pt, lineStart);
double u = ((pt.x - lineStart.x) * dx + (pt.y - lineStart.y) * dy) / (mag * mag);
Pnt intersection;
if (u < 0.0f) intersection = lineStart;
else if (u > 1.0f) intersection = lineEnd;
else {
intersection.x = lineStart.x + u * dx;
intersection.y = lineStart.y + u * dy;
}
return Dist(pt, intersection);
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˹-<2D>տ<EFBFBD> (Douglas-Peucker) <20><>ϡ<EFBFBD>
void DouglasPeucker(const std::vector<Pnt>& pointList, double epsilon, std::vector<Pnt>& out) {
if (pointList.size() < 2) return;
double dmax = 0.0;
size_t index = 0;
size_t end = pointList.size() - 1;
for (size_t i = 1; i < end; i++) {
double d = PerpendicularDistance(pointList[i], pointList[0], pointList[end]);
if (d > dmax) {
index = i;
dmax = d;
}
}
if (dmax > epsilon) {
std::vector<Pnt> recResults1;
std::vector<Pnt> recResults2;
std::vector<Pnt> firstLine(pointList.begin(), pointList.begin() + index + 1);
std::vector<Pnt> lastLine(pointList.begin() + index, pointList.end());
DouglasPeucker(firstLine, epsilon, recResults1);
DouglasPeucker(lastLine, epsilon, recResults2);
out.assign(recResults1.begin(), recResults1.end() - 1);
out.insert(out.end(), recResults2.begin(), recResults2.end());
}
else {
out.clear();
out.push_back(pointList[0]);
out.push_back(pointList[end]);
}
}
// Chaikin ƽ<><C6BD><EFBFBD>㷨 (<28><><EFBFBD><EFBFBD>ֱ<EFBFBD><D6B1>)
// <20><><EFBFBD><EFBFBD>һ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD><D0B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 90 <20><><EFBFBD><EFBFBD><EFBFBD>ҵĽ<D2B5>
std::vector<Pnt> ChaikinSmooth(const std::vector<Pnt>& points, int iterations) {
if (points.size() < 3) return points;
std::vector<Pnt> current = points;
const double RIGHT_ANGLE_TOLERANCE = 0.15;
for (int iter = 0; iter < iterations; iter++) {
size_t n = current.size();
if (n < 3) break;
std::vector<Pnt> next;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Щ<EFBFBD><D0A9><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD> (<28><>ֱ<EFBFBD><D6B1>)
std::vector<bool> keepCorner(n, false);
for (size_t i = 0; i < n - 1; i++) {
// <20><>ȡǰ<C8A1><C7B0><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD>պϻ<D5BA>·)
Pnt prev = (i == 0) ? current[n - 2] : current[i - 1];
Pnt curr = current[i];
Pnt succ = current[i + 1];
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
double x1 = prev.x - curr.x;
double y1 = prev.y - curr.y;
double x2 = succ.x - curr.x;
double y2 = succ.y - curr.y;
double len1 = std::sqrt(x1 * x1 + y1 * y1);
double len2 = std::sqrt(x2 * x2 + y2 * y2);
if (len1 > 1e-9 && len2 > 1e-9) {
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ: (v1 . v2) / |v1||v2|
double dot = x1 * x2 + y1 * y2;
double cosTheta = dot / (len1 * len2);
// <20>ж<EFBFBD><D0B6>Ƿ<EFBFBD><C7B7>ӽ<EFBFBD> 90 <20><> (<28><><EFBFBD><EFBFBD><EFBFBD>ӽ<EFBFBD> 0)
if (std::abs(cosTheta) < RIGHT_ANGLE_TOLERANCE) {
keepCorner[i] = true;
}
}
}
// <20><><EFBFBD>ڱպ϶<D5BA><CFB6><EFBFBD><EFBFBD>Σ<EFBFBD><CEA3><EFBFBD>β<EFBFBD><CEB2>ͬһ<CDAC><D2BB><EFBFBD>㣬״̬<D7B4><CCAC><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC>
if (n > 0) keepCorner[n - 1] = keepCorner[0];
// <20><><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>
for (size_t i = 0; i < n - 1; i++)
{
Pnt p0 = current[i];
Pnt p1 = current[i + 1];
Pnt q, r;
// --- ȷ<><C8B7> Q <20><> (<28><><EFBFBD><EFBFBD> p0) ---
if (keepCorner[i])
{
q = p0; // <20><><EFBFBD><EFBFBD> p0 <20><>ֱ<EFBFBD>ǣ<EFBFBD>Q <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> p0 <20><><EFBFBD><EFBFBD> (<28><><EFBFBD>и<EFBFBD>)
}
else
{
q.x = 0.75 * p0.x + 0.25 * p1.x;
q.y = 0.75 * p0.y + 0.25 * p1.y;
}
// --- ȷ<><C8B7> R <20><> (<28><><EFBFBD><EFBFBD> p1) ---
// ע<>⣺p1 <20>ı<EFBFBD><C4B1><EFBFBD>״̬<D7B4><CCAC> keepCorner[i+1] <20><><EFBFBD><EFBFBD>
if (keepCorner[i + 1])
{
r = p1; // <20><><EFBFBD><EFBFBD> p1 <20><>ֱ<EFBFBD>ǣ<EFBFBD>R <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> p1 <20><><EFBFBD><EFBFBD>
}
else
{
r.x = 0.25 * p0.x + 0.75 * p1.x;
r.y = 0.25 * p0.y + 0.75 * p1.y;
}
// <20><><EFBFBD><EFBFBD> Q (<28><><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD>)
if (next.empty() || std::abs(next.back().x - q.x) > 1e-9 || std::abs(next.back().y - q.y) > 1e-9) {
next.push_back(q);
}
// <20><><EFBFBD><EFBFBD> R (<28><><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD>)
if (std::abs(next.back().x - r.x) > 1e-9 || std::abs(next.back().y - r.y) > 1e-9) {
next.push_back(r);
}
}
// ȷ<><C8B7><EFBFBD>պ<EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɽ<EFBFBD><C9BD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2><EFBFBD>ӣ<EFBFBD>ǿ<EFBFBD>Ʊպ<C6B1>)
if (!next.empty()) {
Pnt first = next.front();
Pnt last = next.back();
if (std::abs(first.x - last.x) > 1e-9 || std::abs(first.y - last.y) > 1e-9) {
next.push_back(first);
}
}
current = next;
}
return current;
}
// <20>򵥵<EFBFBD> Moore-Neighbor <20>߽<EFBFBD>׷<EFBFBD><D7B7> (<28><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>߽<EFBFBD>)
// gridFunc: <20><><EFBFBD><EFBFBD> true <20><>ʾ<EFBFBD><CABE>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD>
std::vector<Pnt> TraceBoundary(int nx, int ny, double xmin, double ymin, double dx, double dy,
std::function<bool(int, int)> gridFunc)
{
std::vector<Pnt> boundary;
// --- Ѱ<><D1B0><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC> ---
int sx = -1, sy = -1;
for (int j = 0; j < ny; ++j)
{
for (int i = 0; i < nx; ++i)
{
if (gridFunc(i, j))
{
sx = i; sy = j;
goto FoundStart; // <20>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>½ǵ<C2BD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
}
}
}
return boundary; // <20><>
FoundStart:
int cx = sx; // <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int cy = sy;
int dir = 0; // 0:<3A><>, 1:<3A><>, 2:<3A><>, 3:<3A><> (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><D8B5>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD>)
struct Edge
{
double x1, y1, x2, y2;
bool operator==(const Edge& other) const
{
// <20><><EFBFBD><EFBFBD><EFBFBD>߱Ƚ<DFB1>
return (std::abs(x1 - other.x1) < 1e-9 && std::abs(y1 - other.y1) < 1e-9 && std::abs(x2 - other.x2) < 1e-9 && std::abs(y2 - other.y2) < 1e-9) ||
(std::abs(x1 - other.x2) < 1e-9 && std::abs(y1 - other.y2) < 1e-9 && std::abs(x2 - other.x1) < 1e-9 && std::abs(y2 - other.y1) < 1e-9);
}
};
std::vector<Pnt> rawPoints;
int vx = sx, vy = sy;
int facing = 1; // 0:<3A><>(y+), 1:<3A><>(x+), 2:<3A><>(y-), 3:<3A><>(x-)
// <20><>ʼ״̬<D7B4><CCAC>¼
int start_vx = vx, start_vy = vy, start_facing = facing;
bool first_step = true;
auto is_valid = [&](int c, int r) {
if (c < 0 || c >= nx || r < 0 || r >= ny) return false;
return gridFunc(c, r);
};
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߼<EFBFBD><DFBC><EFBFBD>׷<EFBFBD>ٸ<EFBFBD><D9B8>ӵ<EFBFBD>**<2A><>϶**
// <20><><EFBFBD>ֶ<EFBFBD><D6B6><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD>ձ<EFBFBD><D5B1><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int loop_safety = 0;
int max_loop = nx * ny * 4;
do {
// <20><>¼<EFBFBD><C2BC>ǰ<EFBFBD><C7B0>
Pnt p;
p.x = xmin + vx * dx - dx * 0.5; // ע<>⣺GridGenerationBoundary<72><79>xmin<69><6E><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB>DZ<EFBFBD>Ե<EFBFBD><D4B5>
p.y = ymin + vy * dy - dy * 0.5; // <20><><EFBFBD><EFBFBD>Python<6F><6E><EFBFBD><EFBFBD> cx = xmin + c * dx<64><78>ͨ<EFBFBD><CDA8>xmin<69>ǵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
boundary.push_back(p);
int left_x = vx, left_y = vy; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> facing <20><><EFBFBD><EFBFBD>
int right_x = vx, right_y = vy;
// <20><>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD>ߵĸ<DFB5><C4B8><EFBFBD>
int c1_x, c1_y; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (facing == 0) { c1_x = vx - 1; c1_y = vy; }
else if (facing == 1) { c1_x = vx; c1_y = vy; }
else if (facing == 2) { c1_x = vx; c1_y = vy - 1; }
else { c1_x = vx - 1; c1_y = vy - 1; }
bool q1 = is_valid(vx, vy);
bool q2 = is_valid(vx - 1, vy);
bool q3 = is_valid(vx - 1, vy - 1);
bool q4 = is_valid(vx, vy - 1);
int state = (q2 ? 8 : 0) | (q1 ? 4 : 0) | (q4 ? 2 : 0) | (q3 ? 1 : 0);
break;
} while (vx != start_vx || vy != start_vy || first_step);
return boundary;
}
};