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/TrendGenerateMesh.h

208 lines
7.7 KiB
C

1 month ago
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <Eigen/Dense>
#include <omp.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace NItem
{
// --- <20><><EFBFBD><EFBFBD><EFBFBD>ṹ ---
struct TrendParam {
double angle; double ratio;
double cx, cy; double weight;
};
struct GridResult {
int nx, ny;
double xMin, xMax, yMin, yMax, step;
std::vector<double> gx, gy, zi;
};
class GeoEngine
{
public:
void initGridStrict(const std::vector<double>& sx, const std::vector<double>& sy, double step, GridResult& grid) {
auto x_mm = std::minmax_element(sx.begin(), sx.end());
auto y_mm = std::minmax_element(sy.begin(), sy.end());
double dx = *x_mm.second - *x_mm.first;
double dy = *y_mm.second - *y_mm.first;
// 10% <20>߽<EFBFBD><DFBD><EFBFBD>չ
grid.xMin = *x_mm.first - dx * 0.1;
grid.yMin = *y_mm.first - dy * 0.1;
double targetMaxX = *x_mm.second + dx * 0.1;
double targetMaxY = *y_mm.second + dy * 0.1;
grid.step = step;
grid.nx = 0;
for (double x = grid.xMin; x < targetMaxX + step - 1e-8; x += step) grid.nx++;
grid.ny = 0;
for (double y = grid.yMin; y < targetMaxY + step - 1e-8; y += step) grid.ny++;
// <20><><EFBFBD><EFBFBD>ʵ<EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>߽<EFBFBD>
grid.xMax = grid.xMin + (grid.nx - 1) * step;
grid.yMax = grid.yMin + (grid.ny - 1) * step;
size_t total = (size_t)grid.nx * grid.ny;
grid.gx.assign(total, 0.0);
grid.gy.assign(total, 0.0);
grid.zi.assign(total, 0.0);
// <20><><EFBFBD>ɱ<EFBFBD>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y Ϊ<><CEAA> (<28><>С<EFBFBD><D0A1><EFBFBD><EFBFBD>)<29><>X Ϊ<><CEAA> (<28><>С<EFBFBD><D0A1><EFBFBD><EFBFBD>)
for (int r = 0; r < grid.ny; ++r) {
double cur_y = grid.yMin + r * step;
for (int c = 0; c < grid.nx; ++c) {
size_t idx = (size_t)r * grid.nx + c;
grid.gx[idx] = grid.xMin + c * step;
grid.gy[idx] = cur_y;
}
}
}
/**
* 2. <EFBFBD><EFBFBD>С<EFBFBD><EFBFBD><EFBFBD>ʲ<EFBFBD>ֵ (TPS) + <EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
*/
void calculateSpline(const std::vector<double>& sx, const std::vector<double>& sy, const std::vector<double>& sz,
const std::vector<TrendParam>& trends, int fusionMode, GridResult& grid) {
int n = sx.size();
if (n == 0 || trends.empty()) return;
std::vector<std::vector<double>> trendResults(trends.size());
for (size_t t_idx = 0; t_idx < trends.size(); ++t_idx) {
const auto& t = trends[t_idx];
double rad = (90.0 - t.angle) * M_PI / 180.0;
double cosA = std::cos(rad), sinA = std::sin(rad);
std::vector<double> tx(n), ty(n);
for (int i = 0; i < n; ++i) {
double dx = sx[i] - t.cx;
double dy = sy[i] - t.cy;
tx[i] = (dx * cosA + dy * sinA) / t.ratio;
ty[i] = -dx * sinA + dy * cosA;
}
Eigen::MatrixXd A(n, n);
Eigen::VectorXd b(n);
for (int i = 0; i < n; ++i) {
b(i) = sz[i];
for (int j = 0; j < n; ++j) {
double r = std::sqrt(std::pow(tx[i] - tx[j], 2) + std::pow(ty[i] - ty[j], 2));
A(i, j) = (r < 1e-12) ? 0 : r * r * std::log(r);
}
}
A.diagonal().array() += 1e-12; // <20>ȶ<EFBFBD><C8B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
Eigen::VectorXd weights = A.fullPivLu().solve(b);
std::vector<double> cur_zi(grid.gx.size());
#pragma omp parallel for schedule(dynamic)
for (long long i = 0; i < (long long)grid.gx.size(); ++i) {
double dx = grid.gx[i] - t.cx;
double dy = grid.gy[i] - t.cy;
double rx = (dx * cosA + dy * sinA) / t.ratio;
double ry = -dx * sinA + dy * cosA;
double val = 0;
for (int j = 0; j < n; ++j) {
double r = std::sqrt(std::pow(rx - tx[j], 2) + std::pow(ry - ty[j], 2));
val += weights(j) * ((r < 1e-12) ? 0 : r * r * std::log(r));
}
cur_zi[i] = val;
}
trendResults[t_idx] = cur_zi;
}
grid.zi.assign(grid.gx.size(), 0.0);
#pragma omp parallel for schedule(static)
for (long long i = 0; i < (long long)grid.gx.size(); ++i) {
if (fusionMode == 1) {
double maxVal = -1e18;
for (const auto& res : trendResults) if (res[i] > maxVal) maxVal = res[i];
grid.zi[i] = maxVal;
}
else {
double sumV = 0, sumW = 0;
for (size_t t = 0; t < trends.size(); ++t) {
sumV += trendResults[t][i] * trends[t].weight;
sumW += trends[t].weight;
}
grid.zi[i] = (sumW > 1e-12) ? sumV / sumW : 0;
}
}
}
/**
* 3. <EFBFBD><EFBFBD><EFBFBD><EFBFBD> GRD (<EFBFBD><EFBFBD>׼ DSAA)
* <EFBFBD>޸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> yMin yMax<EFBFBD><EFBFBD>ȷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>ֵ (+20)
*/
void exportToGRD(const std::string& filename, const GridResult& grid) {
std::ofstream f(filename);
if (!f.is_open()) return;
auto mm = std::minmax_element(grid.zi.begin(), grid.zi.end());
f << "DSAA\n";
f << grid.nx << " " << grid.ny << "\n";
f << std::fixed << std::setprecision(6) << grid.xMin << " " << grid.xMax << "\n";
f << grid.yMin << " " << grid.yMax << "\n"; // <20>޸<EFBFBD>Ϊ yMin yMax
f << std::scientific << std::setprecision(6) << *mm.first << " " << *mm.second << "\n";
// <20><> Surfer 10<31><30><EFBFBD><EFBFBD>ֵһ<D6B5>еı<D0B5>׼д<D7BC><D0B4>
for (size_t i = 0; i < grid.zi.size(); ++i) {
f << grid.zi[i];
if ((i + 1) % 10 == 0 || (i + 1) == grid.zi.size()) f << "\n";
else f << " ";
}
}
};
bool loadSandstoneCSV(const std::string& fname, std::vector<double>& x, std::vector<double>& y, std::vector<double>& z) {
std::ifstream f(fname);
if (!f.is_open()) return false;
std::string line; std::getline(f, line);
while (std::getline(f, line)) {
if (line.empty()) continue;
std::stringstream ss(line);
std::string item; std::vector<std::string> row;
while (std::getline(ss, item, ',')) row.push_back(item);
if (row.size() >= 4) {
try {
x.push_back(std::stod(row[1])); y.push_back(std::stod(row[2])); z.push_back(std::stod(row[3]));
}
catch (...) { continue; }
}
}
return !x.empty();
}
}
//
//int main() {
// GeoEngine engine;
// GridResult grid;
// std::vector<double> sx, sy, sz;
//
// // 1. <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
// if (!loadSandstoneCSV("G:/Desktop/333.csv", sx, sy, sz)) return -1;
//
// // 2. <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> 20)
// engine.initGridStrict(sx, sy, 20.0, grid);
//
// // 3. ȷ<><C8B7><EFBFBD><EFBFBD>ת<EFBFBD><D7AA><EFBFBD><EFBFBD> (<28><> Python fixed <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
// auto x_mm = std::minmax_element(sx.begin(), sx.end());
// auto y_mm = std::minmax_element(sy.begin(), sy.end());
// double midX = (*x_mm.first + *x_mm.second) / 2.0;
// double midY = (*y_mm.first + *y_mm.second) / 2.0;
//
// // 4. <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EBB5BC>
// TrendParam p1 = { 0.0, 0.0, midX, midY, 1.0 };
// engine.calculateSpline(sx, sy, sz, { p1 }, 0, grid);
// engine.exportToGRD("G:/Desktop/result_cpp_fixed.grd", grid);
//}