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/GVision/GmtSurfaceGrid/GmtSurfaceInterp.cpp

513 lines
13 KiB
C++

1 month ago
#include "GmtSurfaceInterp.h"
#include <afx.h>
#include <afxext.h>
#include <gmt/gmt.h>
#include <netcdf.h>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <fstream>
#include <algorithm>
#include <string>
#include "DrawModel\\BaseLib.h"
#include "DrawOperator\\DrawLib.h"
#include <sstream>
template <typename T>
void qDeleteAll(std::vector<T*>& vec)
{
for (auto* p : vec) {
delete p;
}
vec.clear();
}
// <20><>ȡ<EFBFBD>߽<EFBFBD><DFBD><EFBFBD>/<2F>߿<EFBFBD>
static std::vector<CCurveEx*> get_border(CString borderFile)
{
if (!CFindFileEx::IsFileExists(borderFile)) {
return {};
}
std::shared_ptr<CXy> pXy = std::make_shared<CXy>();
borderFile = borderFile.Trim();
if (borderFile.GetLength() <= 0 || borderFile == "NULL") {
return {};
}
if (!pXy->ReadWithExtension(borderFile)) {
return {};
}
std::vector<CCurveEx*> result;
CPtrList* pl = pXy->GetValueList();
for (POSITION pos = pl->GetHeadPosition(); pos != nullptr; pl->GetNext(pos)) {
COne* pOne = (COne*)pl->GetAt(pos);
if (pOne->GetType() == DOUBLEFOX_CURVE) {
CCurveEx* pCurve = (CCurveEx*)(pOne->GetValue());
CCurveEx* pCurveNew = new CCurveEx();
*pCurveNew = *pCurve;
result.push_back(pCurveNew);
}
}
return result;
}
static void CreateBorder(std::shared_ptr<CXy> pXy, std::vector<CCurveEx*>& ccurves)
{
CLayer* pLayerBorder = pXy->FindAddLayer("<EFBFBD>߽<EFBFBD>11");
for (auto* pCurve : ccurves) {
POSITION posNew = pXy->AddElement(pCurve, DOUBLEFOX_CURVE);
pXy->SetElementLayer(posNew, pLayerBorder);
}
}
static void AddContourCurve(std::shared_ptr<CXy> pXy, vector<CCurve*>* curves, vector<CString*>* layer)
{
for (size_t i = 0; i < curves->size(); i++)
{
CCurve* pCurve = curves->at(i);
if (pCurve == NULL) continue;
CString* pName = layer->at(i);
CCurveEx* ce = new CCurveEx(pCurve->num);
for (int i = 0; i < ce->num; i++)
{
ce->x[i] = pCurve->x[i];
ce->y[i] = pCurve->y[i];
ce->z[i] = pCurve->z[i];
}
ce->nPoint = pCurve->nPoint;
ce->GetLocation();
POSITION pos = NULL;
if (pCurve->name)
ce->SetName(pCurve->name);
pos = pXy->AddElement(ce, DOUBLEFOX_CURVE);
pXy->SetElementLayer(pos, *pName);
}
}
/**
* <EFBFBD><EFBFBD><EFBFBD>ɵ<EFBFBD>ֵ<EFBFBD><EFBFBD>
*
* \\param pXy
* \\param pMeshNew
* \\param pDfg
* \\param contourStep
* \\param contourMarkStep
* \\return
*/
static bool CreateContourLines(std::shared_ptr<CXy> pXy, CMesh* pMeshNew, double contourStep, int contourMarkStep)
{
// <20><><EFBFBD>ɵ<EFBFBD>ֵ<EFBFBD><D6B5>
if (abs(contourStep) < 1E-5)
{
return false;
}
CString strLayerMark = _T("Layer:\\<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>\\<EFBFBD><EFBFBD>ע");
CString strLayerOther = _T("Layer:\\<EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>\\<EFBFBD>ޱ<EFBFBD>ע");
CString curLayerName = pXy->GetCurrentLayer()->GetPathName();
CLayer* pMarkLayer = pXy->FindLayer(strLayerMark);
CLayer* pOtherLayer = pXy->FindLayer(strLayerOther);
if (pMarkLayer == nullptr)
{
pMarkLayer = pXy->FindAddLayer(strLayerMark);
pMarkLayer->HowToViewCurve = new CHowToViewCurve();
pMarkLayer->HowToViewCurve->EnableDrawSourceCurve(FALSE);
CCurveInName* pInName = new CCurveInName();
CRect8 rect = pMeshNew->GetRect();
pInName->text_h = rect.Width() / 300;
pInName->m_size.cx = pInName->text_h * 0.06;
pInName->color = RGB(0, 0, 0);
pMarkLayer->HowToViewCurve->Add(pInName);
}
if (pOtherLayer == nullptr)
{
pOtherLayer = pXy->FindAddLayer(strLayerOther);
pOtherLayer->HowToViewCurve = new CHowToViewCurve();
pOtherLayer->HowToViewCurve->EnableDrawSourceCurve(FALSE);
CCurveProperties* pview = new CCurveProperties();
pview->color = RGB(0, 0, 0);
pOtherLayer->HowToViewCurve->Add(pview);
}
std::vector<CCurve*> pCurves;
std::vector<CString*> pLayers;
pMeshNew->ContourCreate(&pCurves, &pLayers, contourStep, contourMarkStep,
strLayerMark, strLayerOther, pMeshNew->GetDfg()->range[0], pMeshNew->GetDfg()->range[1]);
AddContourCurve(pXy, &pCurves, &pLayers);
qDeleteAll(pCurves);
qDeleteAll(pLayers);
return true;
}
/**
* <EFBFBD>ж<EFBFBD> dx dY <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* \\param vec <EFBFBD><EFBFBD><EFBFBD>򼯺ϣ<EFBFBD><EFBFBD><EFBFBD>Ȼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>պϵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* \\param dX
* \\param dY
* \\return
*/
static bool any_contains(std::vector<CCurveEx*>& vec, double dX, double dY)
{
return std::any_of(vec.begin(), vec.end(), [dX, dY](CCurveEx* pBorder) {
return (pBorder->IsInside(dX, dY));
});
}
/**
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>У<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>׺<EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɶ<EFBFBD>Ӧ<EFBFBD><EFBFBD>ʽ
*
* \\param pXy
* \\param gridFile
* \\param outputFile Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
* \\return
*/
static bool SaveFile(CString gridFile, CString outputFile, double contourStep, int contourMarkStep, CString borderFile)
{
std::shared_ptr<CXy> pXy = std::make_shared<CXy>();
pXy->FromGridAuto(gridFile);
CLayer *pLayer = pXy->FindAddLayer("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
CPositionList pointList;
int index = pXy->GetElement(DOUBLEFOX_MESH, pointList);
if (pointList.GetSize() == 0)
{
return false;
}
COne* pNewOne = pXy->GetAt(pointList.GetHead());
pNewOne->SetLayer(pLayer);
CMesh* pMeshNew = (CMesh*)pNewOne->value;
CreateContourLines(pXy, pMeshNew, contourStep, contourMarkStep);
pXy->SaveAsWithExtension(outputFile);
return true;
}
bool WriteDSAA(const char* netcdf_file, const char* output_grd)
{
int ncid, varid, xvar, yvar;
if (nc_open(netcdf_file, NC_NOWRITE, &ncid) != NC_NOERR)
{
fprintf(stderr, "Failed to open NetCDF file: %s\n", netcdf_file);
return false;
}
nc_inq_varid(ncid, "z", &varid);
nc_inq_varid(ncid, "x", &xvar);
nc_inq_varid(ncid, "y", &yvar);
size_t x_len, y_len;
nc_inq_dimlen(ncid, 0, &x_len);
nc_inq_dimlen(ncid, 1, &y_len);
std::vector<float> z(x_len * y_len);
std::vector<double> xs(x_len);
std::vector<double> ys(y_len);
nc_get_var_float(ncid, varid, z.data());
nc_get_var_double(ncid, xvar, xs.data());
nc_get_var_double(ncid, yvar, ys.data());
nc_close(ncid);
float zmin = 1e30f, zmax = -1e30f;
for (float val : z)
{
if (!std::isnan(val))
{
zmin = min(zmin, val);
zmax = max(zmax, val);
}
}
std::ofstream out(output_grd);
out << "DSAA\n";
out << x_len << " " << y_len << "\n";
out << xs.front() << " " << xs.back() << "\n";
out << ys.front() << " " << ys.back() << "\n";
out << zmin << " " << zmax << "\n";
for (size_t j = 0; j < y_len; ++j)
{
for (size_t i = 0; i < x_len; ++i)
{
size_t idx = j * x_len + i;
float v = z[idx];
if (std::isnan(v)) out << "1.000000E+30 ";
else out << v << " ";
if ((i + 1) % 10 == 0) out << "\n";
}
out << "\n";
}
out.close();
return true;
}
//bool ConvertFaultFile(const char* input_file, const char* output_file)
//{
// std::ifstream infile(input_file);
// if (!infile.is_open())
// {
// fprintf(stderr, "Failed to open fault file: %s\n", input_file);
// return false;
// }
//
// std::ofstream outfile(output_file);
// if (!outfile.is_open())
// {
// fprintf(stderr, "Failed to create converted fault file: %s\n", output_file);
// return false;
// }
//
// double x, y;
// int id, last_id = -1;
// while (infile >> x >> y >> id)
// {
// if (id != last_id)
// {
// outfile << "> -Z\n";
// last_id = id;
// }
// outfile << x << " " << y << "\n";
// }
//
// infile.close();
// outfile.close();
// return true;
//}
/**
* <EFBFBD><EFBFBD>dfd<EFBFBD><EFBFBD>ʽ<EFBFBD>ļ<EFBFBD>ת<EFBFBD><EFBFBD><EFBFBD><EFBFBD>gmt<EFBFBD><EFBFBD>ʶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* \\param input_file .dfd
* \\param output_file .dat
* \\param layer_name Layer M <EFBFBD>ϲ<EFBFBD> / Layer M <EFBFBD>߽<EFBFBD>
* \\return
*/
bool ConvertDfdFile(const char* input_file, const char* output_file, const char* layer_name)
{
std::ofstream outfile(output_file);
if (!outfile.is_open()) {
fprintf(stderr, "Failed to create converted file: %s\n", output_file);
return false;
}
CString cstrBorderFile(input_file);
std::vector<CCurveEx*> borderList = get_border(cstrBorderFile);
for (const auto& curve : borderList) {
if (!curve) continue;
// ÿ<><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>дһ<D0B4><D2BB> Pline
outfile << "> -Z\n";
for (size_t i = 0; i < curve->num; ++i) {
outfile << curve->x[i] << " " << curve->y[i] << "\n";
}
}
outfile.close();
return true;
}
bool ExtractBounds(const char* xyz_input, double bounds[4])
{
char cmd[256];
snprintf(cmd, sizeof(cmd), "SplineInterpolation info %s -C", xyz_input);
FILE* pipe = _popen(cmd, "r");
if (!pipe)
{
fprintf(stderr, "Failed to run SplineInterpolation info.\n");
return false;
}
if (fscanf_s(pipe, "%lf %lf %lf %lf", &bounds[0], &bounds[1], &bounds[2], &bounds[3]) != 4)
{
fprintf(stderr, "Failed to parse SplineInterpolation info output.\n");
_pclose(pipe);
return false;
}
_pclose(pipe);
return true;
}
bool GmtSurfaceInterp(const char* xyz_input, const char* grid_output, double step, double tension,
const char* fault_file, const char* boundary_file, const char* outputfile, double contourStep, int contourMarkStep,
double XMin, double YMin, double XMax, double YMax)
{
if (step <= 0 || tension < 0)
return false;
double clip = 0.001;
void* session = GMT_Create_Session("surface_interp", GMT_SESSION_EXTERNAL, 0, NULL);
if (!session) {
fprintf(stderr, "Failed to create GMT session.\n");
return false;
}
bool hasFault = fault_file && strlen(fault_file) > 0;
bool hasBoundary = boundary_file && strlen(boundary_file) > 0;
// ת<><D7AA><EFBFBD>ϲ<EFBFBD> dfd
if (hasFault) {
if (!ConvertDfdFile(fault_file, "converted_fault.dat", "Layer M <20>ϲ<EFBFBD>")) {
fprintf(stderr, "Failed to convert fault file.\n");
GMT_Destroy_Session(session);
return false;
}
}
// ת<><D7AA><EFBFBD>߽<EFBFBD> dfd
if (hasBoundary) {
if (!ConvertDfdFile(boundary_file, "converted_boundary.dat", "Layer M <20>߽<EFBFBD>")) {
fprintf(stderr, "Failed to convert boundary file.\n");
GMT_Destroy_Session(session);
return false;
}
}
GMT_DATASET* data = (GMT_DATASET*)GMT_Read_Data(session, GMT_IS_DATASET, GMT_IS_FILE, GMT_IS_PLP,
GMT_READ_NORMAL, NULL, xyz_input, NULL);
if (!data) {
fprintf(stderr, "Failed to read input file: %s\n", xyz_input);
GMT_Destroy_Session(session);
return false;
}
char input_vf[GMT_VF_LEN] = { 0 };
if (GMT_Open_VirtualFile(session, GMT_IS_DATASET, GMT_IS_PLP, GMT_IN, data, input_vf) != GMT_NOERROR) {
fprintf(stderr, "Failed to register virtual file.\n");
GMT_Destroy_Session(session);
return false;
}
double bounds[4];
bounds[0] = XMin;
bounds[1] = XMax;
bounds[2] = YMin;
bounds[3] = YMax;
if (XMin == 0 && XMax == 0)
{
//<2F><><EFBFBD><EFBFBD>Ĭ<EFBFBD>ϱ߽<CFB1>û<EFBFBD>У<EFBFBD><D0A3><EFBFBD>ʹ<EFBFBD><CAB9>gmt<6D><74>ȡ
if (!ExtractBounds(xyz_input, bounds)) {
fprintf(stderr, "Failed to extract region from dataset.\n");
GMT_Destroy_Session(session);
return false;
}
}
int nx = static_cast<int>((bounds[1] - bounds[0]) / step + 0.5);
int ny = static_cast<int>((bounds[3] - bounds[2]) / step + 0.5);
double adj_x_max = bounds[0] + nx * step;
double adj_y_max = bounds[2] + ny * step;
char tmp_nc[] = "tmp_output.nc";
char args[512];
snprintf(args, sizeof(args),
"-R%.8f/%.8f/%.8f/%.8f -I%.8f/%.8f -T%.3f -C%.4f -G%s -Vn %s",
bounds[0], adj_x_max, bounds[2], adj_y_max,
step, step, tension, clip, tmp_nc, input_vf);
if (GMT_Call_Module(session, "surface", GMT_MODULE_CMD, args) != GMT_NOERROR) {
fprintf(stderr, "Surface interpolation failed.\n");
GMT_Destroy_Session(session);
return false;
}
if (hasFault) {
char mask_cmd[512];
snprintf(mask_cmd, sizeof(mask_cmd),
"converted_fault.dat -R%.8f/%.8f/%.8f/%.8f -I%.8f/%.8f -N1/1/NaN -Gfault_mask.nc -Vn",
bounds[0], adj_x_max, bounds[2], adj_y_max, step, step);
if (GMT_Call_Module(session, "grdmask", GMT_MODULE_CMD, mask_cmd) != GMT_NOERROR) {
fprintf(stderr, "Failed to generate mask from fault file.\n");
GMT_Destroy_Session(session);
return false;
}
}
if (hasBoundary) {
char boundary_mask_cmd[512];
snprintf(boundary_mask_cmd, sizeof(boundary_mask_cmd),
"converted_boundary.dat -R%.8f/%.8f/%.8f/%.8f -I%.8f/%.8f -NNaN/1 -Gboundary_mask.nc -Vn",
bounds[0], adj_x_max, bounds[2], adj_y_max, step, step);
if (GMT_Call_Module(session, "grdmask", GMT_MODULE_CMD, boundary_mask_cmd) != GMT_NOERROR) {
fprintf(stderr, "Failed to generate mask from boundary file.\n");
GMT_Destroy_Session(session);
return false;
}
}
if (hasFault) {
char math_cmd[256];
snprintf(math_cmd, sizeof(math_cmd), "fault_mask.nc %s MUL = temp.nc", tmp_nc);
if (GMT_Call_Module(session, "grdmath", GMT_MODULE_CMD, math_cmd) != GMT_NOERROR) {
fprintf(stderr, "Failed to apply fault mask.\n");
GMT_Destroy_Session(session);
return false;
}
strcpy_s(tmp_nc, "temp.nc");
}
if (hasBoundary) {
char math_cmd2[256];
snprintf(math_cmd2, sizeof(math_cmd2), "boundary_mask.nc %s MUL = clipped.nc", tmp_nc);
if (GMT_Call_Module(session, "grdmath", GMT_MODULE_CMD, math_cmd2) != GMT_NOERROR) {
fprintf(stderr, "Failed to apply boundary mask.\n");
GMT_Destroy_Session(session);
return false;
}
strcpy_s(tmp_nc, "clipped.nc");
}
GMT_Destroy_Session(session);
if (!WriteDSAA(tmp_nc, grid_output)) {
fprintf(stderr, "Failed to write .grd output file.\n");
return false;
}
if (hasFault) {
std::remove("converted_fault.dat");
std::remove("fault_mask.nc");
std::remove("temp.nc");
}
if (hasBoundary) {
std::remove("converted_boundary.dat");
std::remove("boundary_mask.nc");
std::remove("clipped.nc");
}
std::remove("tmp_output.nc");
SaveFile(grid_output, outputfile, contourStep, contourMarkStep, boundary_file);
std::remove(grid_output);
return true;
}