|
|
|
|
|
#include "StdAfx.h"
|
|
|
|
|
|
#include "KEDAlgorithm.h"
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef M_PI
|
|
|
|
|
|
#define M_PI 3.14159265358979323846
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
|
void qDeleteAll(std::vector<T*>& vec)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (auto* p : vec) {
|
|
|
|
|
|
delete p;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vec.clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><> std::string תΪ std::wstring
|
|
|
|
|
|
static std::wstring utf8_to_wstring(const std::string& s) {
|
|
|
|
|
|
if (s.empty()) return {};
|
|
|
|
|
|
int needed = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), NULL, 0);
|
|
|
|
|
|
std::wstring out(needed, 0);
|
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), &out[0], needed);
|
|
|
|
|
|
return out;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ض<EFBFBD><D8B6>ֽڱ<D6BD><DAB1><EFBFBD> (GBK/ANSI) ת<><D7AA> Unicode
|
|
|
|
|
|
static std::wstring ansi_to_wstring(const std::string& s) {
|
|
|
|
|
|
if (s.empty()) return {};
|
|
|
|
|
|
int needed = MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), NULL, 0);
|
|
|
|
|
|
std::wstring out(needed, 0);
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, s.c_str(), (int)s.size(), &out[0], needed);
|
|
|
|
|
|
return out;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> facies_boundaries.exe
|
|
|
|
|
|
bool RunFaciesBoundaries(
|
|
|
|
|
|
const std::string& exePath,
|
|
|
|
|
|
const std::string& grdPath,
|
|
|
|
|
|
const std::string& dfdPath,
|
|
|
|
|
|
std::string& outStdout,
|
|
|
|
|
|
DWORD& outExitCode,
|
|
|
|
|
|
DWORD timeoutMs,
|
|
|
|
|
|
std::atomic<bool>* cancelFlag = nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
outStdout.clear();
|
|
|
|
|
|
outExitCode = (DWORD)-1;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD><D0A3><EFBFBD><EFBFBD>䣩
|
|
|
|
|
|
std::wstringstream cmd;
|
|
|
|
|
|
cmd << L"\"" << ansi_to_wstring(exePath) << L"\" ";
|
|
|
|
|
|
cmd << L"\"" << ansi_to_wstring(grdPath) << L"\" ";
|
|
|
|
|
|
cmd << L"\"" << ansi_to_wstring(dfdPath) << L"\"";
|
|
|
|
|
|
|
|
|
|
|
|
SECURITY_ATTRIBUTES sa{ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
|
|
|
|
|
|
HANDLE hRead = NULL, hWrite = NULL;
|
|
|
|
|
|
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) return false;
|
|
|
|
|
|
SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
|
|
|
|
|
|
|
|
|
|
|
|
STARTUPINFOW si = { 0 };
|
|
|
|
|
|
PROCESS_INFORMATION pi = { 0 };
|
|
|
|
|
|
si.cb = sizeof(si);
|
|
|
|
|
|
si.hStdOutput = hWrite;
|
|
|
|
|
|
si.hStdError = hWrite;
|
|
|
|
|
|
si.dwFlags |= STARTF_USESTDHANDLES;
|
|
|
|
|
|
|
|
|
|
|
|
std::wstring cmdStr = cmd.str();
|
|
|
|
|
|
LPWSTR cmdLine = &cmdStr[0];
|
|
|
|
|
|
|
|
|
|
|
|
BOOL ok = CreateProcessW(
|
|
|
|
|
|
NULL, cmdLine, NULL, NULL, TRUE,
|
|
|
|
|
|
CREATE_NO_WINDOW, NULL, NULL, &si, &pi
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
CloseHandle(hWrite); // <20><><EFBFBD><EFBFBD><EFBFBD>̲<EFBFBD><CCB2><EFBFBD>д
|
|
|
|
|
|
|
|
|
|
|
|
if (!ok) {
|
|
|
|
|
|
CloseHandle(hRead);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//<2F>ؼ<EFBFBD><D8BC><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD><EFBFBD>ڼ<EFBFBD><DABC><EFBFBD><EFBFBD><EFBFBD> cancelFlag
|
|
|
|
|
|
const DWORD pollInterval = 100; // ÿ 100ms <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB>
|
|
|
|
|
|
DWORD totalWait = 0;
|
|
|
|
|
|
bool wasCancelled = false;
|
|
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>
|
|
|
|
|
|
if (cancelFlag && cancelFlag->load()) {
|
|
|
|
|
|
TerminateProcess(pi.hProcess, 1);
|
|
|
|
|
|
wasCancelled = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>ʱ
|
|
|
|
|
|
if (timeoutMs != INFINITE && totalWait >= timeoutMs) {
|
|
|
|
|
|
TerminateProcess(pi.hProcess, 1);
|
|
|
|
|
|
wasCancelled = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD>˳<EFBFBD>
|
|
|
|
|
|
DWORD exitCode;
|
|
|
|
|
|
if (GetExitCodeProcess(pi.hProcess, &exitCode) && exitCode != STILL_ACTIVE) {
|
|
|
|
|
|
outExitCode = exitCode;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ȴ<EFBFBD>һС<D2BB><D0A1>ʱ<EFBFBD><CAB1>
|
|
|
|
|
|
Sleep(pollInterval);
|
|
|
|
|
|
totalWait += pollInterval;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ҳ<EFBFBD><D2B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>껺<EFBFBD><EABBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
const DWORD bufSize = 4096;
|
|
|
|
|
|
char buffer[bufSize];
|
|
|
|
|
|
DWORD bytesRead = 0;
|
|
|
|
|
|
std::string output;
|
|
|
|
|
|
while (ReadFile(hRead, buffer, bufSize, &bytesRead, NULL) && bytesRead > 0) {
|
|
|
|
|
|
output.append(buffer, bytesRead);
|
|
|
|
|
|
}
|
|
|
|
|
|
outStdout = output;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>DZ<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD> false
|
|
|
|
|
|
bool success = !wasCancelled && (outExitCode == 0);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
|
|
CloseHandle(hRead);
|
|
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ΰ<EFBFBD>Χ<EFBFBD><CEA7>
|
|
|
|
|
|
static inline void ComputePolygonBBox(const CCurveEx* poly, double& xmin, double& xmax, double& ymin, double& ymax)
|
|
|
|
|
|
{
|
|
|
|
|
|
xmin = 1e20; xmax = -1e20;
|
|
|
|
|
|
ymin = 1e20; ymax = -1e20;
|
|
|
|
|
|
for (int i = 0; i < poly->num; ++i) {
|
|
|
|
|
|
xmin = std::min(xmin, (double)poly->x[i]);
|
|
|
|
|
|
xmax = std::max(xmax, (double)poly->x[i]);
|
|
|
|
|
|
ymin = std::min(ymin, (double)poly->y[i]);
|
|
|
|
|
|
ymax = std::max(ymax, (double)poly->y[i]);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KEDAlgorithm::KEDAlgorithm()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_DepositionalMap.clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KEDAlgorithm::~KEDAlgorithm()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::ProcessExistingGrd(
|
|
|
|
|
|
const CString& grdFile, // <20>Ѵ<EFBFBD><D1B4>ڵ<EFBFBD> GRD <20>ļ<EFBFBD>
|
|
|
|
|
|
const CString& kevFile, // <20><><EFBFBD><EFBFBD> KEV <20>ļ<EFBFBD>
|
|
|
|
|
|
CColorBase base,
|
|
|
|
|
|
bool isFaciesBorder,
|
|
|
|
|
|
std::function<void(int completed, int total)> progressCallback)
|
|
|
|
|
|
{
|
|
|
|
|
|
const int TOTAL_STEPS = 4;
|
|
|
|
|
|
auto reportProgress = [&](int step, bool failed = false) {
|
|
|
|
|
|
if (progressCallback) progressCallback(failed ? -1 : step, TOTAL_STEPS);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
m_cancelRequested.store(false);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> GRD <20>ļ<EFBFBD>
|
|
|
|
|
|
std::ifstream fchk(grdFile);
|
|
|
|
|
|
if (!fchk.is_open()) {
|
|
|
|
|
|
reportProgress(0, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
fchk.close();
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(1);
|
|
|
|
|
|
|
|
|
|
|
|
std::shared_ptr<CXy> pXy = nullptr;
|
|
|
|
|
|
std::vector<CCurve*> pCurves;
|
|
|
|
|
|
|
|
|
|
|
|
if (isFaciesBorder)
|
|
|
|
|
|
{
|
|
|
|
|
|
// --- <><D7BC>·<EFBFBD><C2B7> ---
|
|
|
|
|
|
CSplitPath sp;
|
|
|
|
|
|
sp.SetModuleFileName();
|
|
|
|
|
|
CString xmlPath;
|
|
|
|
|
|
xmlPath.Format("%s%s", sp.GetPath(), "facies");
|
|
|
|
|
|
sp.MakeDirectory(xmlPath);
|
|
|
|
|
|
|
|
|
|
|
|
CString outdfdPath;
|
|
|
|
|
|
outdfdPath.Format("%s%s", xmlPath, "\\facies.dfd");
|
|
|
|
|
|
|
|
|
|
|
|
CString exePath;
|
|
|
|
|
|
exePath.Format("%s%s", sp.GetPath(), "facies_boundaries.exe");
|
|
|
|
|
|
|
|
|
|
|
|
// --- <20><><EFBFBD><EFBFBD> EXE ---
|
|
|
|
|
|
std::string grdPath = grdFile;
|
|
|
|
|
|
std::string dfdPath = std::string(outdfdPath);
|
|
|
|
|
|
std::string procOut;
|
|
|
|
|
|
DWORD exitCode = 0;
|
|
|
|
|
|
|
|
|
|
|
|
bool ran = RunFaciesBoundaries(std::string(exePath), grdPath, dfdPath,
|
|
|
|
|
|
procOut, exitCode, 120000, &m_cancelRequested);
|
|
|
|
|
|
|
|
|
|
|
|
if (!ran || exitCode != 0) {
|
|
|
|
|
|
std::cerr << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> facies_boundaries.exe\n";
|
|
|
|
|
|
reportProgress(2, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
reportProgress(2);
|
|
|
|
|
|
|
|
|
|
|
|
CFile fw;
|
|
|
|
|
|
if (!fw.Open(outdfdPath, CFile::modeRead)) {
|
|
|
|
|
|
reportProgress(2, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>ʼ<EFBFBD><CABC><EFBFBD>ⲿ<EFBFBD><E2B2BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD> pXy
|
|
|
|
|
|
pXy = std::make_shared<CXy>();
|
|
|
|
|
|
pXy->DFD_Read2(fw);
|
|
|
|
|
|
fw.Close();
|
|
|
|
|
|
|
|
|
|
|
|
CPositionList list;
|
|
|
|
|
|
if (pXy->GetElement("Layer:\\Facies", list) > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (POSITION pos = list.GetHeadPosition(); pos != NULL; list.GetNext(pos)) {
|
|
|
|
|
|
COne* pOne = (COne*)(pXy->GetValueList()->GetAt(list.GetAt(pos)));
|
|
|
|
|
|
CCurve* curve = (CCurve*)pOne->GetValue();
|
|
|
|
|
|
pCurves.push_back(curve);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(3);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>߽磬ֱ<E7A3AC><D6B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м䲽<D0BC>裬<EFBFBD><E8A3AC><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
reportProgress(2);
|
|
|
|
|
|
reportProgress(3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. д<><D0B4> KEV <20>ļ<EFBFBD>
|
|
|
|
|
|
if (!GrdToKEVFile(grdFile, kevFile, pCurves, base)) {
|
|
|
|
|
|
reportProgress(3, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
reportProgress(4);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<FaciesConfig> KEDAlgorithm::LoadFaciesSettings(const CString& settingsFile,
|
|
|
|
|
|
std::map<std::string, int>& labelMap)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<FaciesConfig> samples;
|
|
|
|
|
|
|
|
|
|
|
|
std::ifstream file((LPCTSTR)settingsFile);
|
|
|
|
|
|
if(!file.is_open()) throw std::runtime_error("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>: " + settingsFile);
|
|
|
|
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
|
|
std::getline(file, line); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ
|
|
|
|
|
|
|
|
|
|
|
|
while (std::getline(file, line)) {
|
|
|
|
|
|
if (line.empty()) continue;
|
|
|
|
|
|
std::stringstream ss(line);
|
|
|
|
|
|
std::string name, sCode, sFillCol, sBorderCol, sValue, sX, sY;
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ϸ<EFBFBD>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>ͷ˳<CDB7><CBB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD>ɫ, <20>߽<EFBFBD>ɫ, <20><>ֵ, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
if (!std::getline(ss, name, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sCode, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sFillCol, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sBorderCol, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sValue, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sX, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sY, ',')) continue;
|
|
|
|
|
|
|
|
|
|
|
|
FaciesConfig config;
|
|
|
|
|
|
config.name = name;
|
|
|
|
|
|
config.code = sCode;
|
|
|
|
|
|
config.fillColor = (COLORREF)std::stoll(sFillCol); // <20><>ȡ int <20><>ɫ
|
|
|
|
|
|
config.borderColor = (COLORREF)std::stoll(sBorderCol); // <20><>ȡ int <20><>ɫ
|
|
|
|
|
|
config.value = std::stod(sValue);
|
|
|
|
|
|
config.x = std::stod(sX); // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
config.y = std::stod(sY); // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
samples.push_back(config);
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ͼ<EFBFBD><CDBC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ Z ֵ<><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>ʾ<EFBFBD>ı<EFBFBD>
|
|
|
|
|
|
std::string faciesName;
|
|
|
|
|
|
faciesName = name + "-" + sCode;
|
|
|
|
|
|
m_DepositionalMap.insert({ faciesName, config.value });
|
|
|
|
|
|
|
|
|
|
|
|
m_ColorList.insert({ config.value , config.fillColor });
|
|
|
|
|
|
}
|
|
|
|
|
|
return samples;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<Sample> KEDAlgorithm::ReadSamplesCSV(const CString& csvFile,
|
|
|
|
|
|
std::map<std::string, int>& labelMap)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<Sample> samples;
|
|
|
|
|
|
std::ifstream file(csvFile);
|
|
|
|
|
|
if (!file.is_open()) throw std::runtime_error("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>: " + csvFile);
|
|
|
|
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
|
|
std::getline(file, line); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ
|
|
|
|
|
|
while (std::getline(file, line)) {
|
|
|
|
|
|
std::stringstream ss(line);
|
|
|
|
|
|
std::string sx, sy, sz;
|
|
|
|
|
|
if (!std::getline(ss, sx, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sy, ',')) continue;
|
|
|
|
|
|
if (!std::getline(ss, sz, ',')) continue;
|
|
|
|
|
|
if (sx.empty() || sy.empty()) continue;
|
|
|
|
|
|
|
|
|
|
|
|
double x = std::stod(sx);
|
|
|
|
|
|
double y = std::stod(sy);
|
|
|
|
|
|
|
|
|
|
|
|
if (labelMap.find(sz) == labelMap.end()) {
|
|
|
|
|
|
int newId = static_cast<int>(labelMap.size());
|
|
|
|
|
|
labelMap[sz] = newId;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_DepositionalMap.insert({ sz, labelMap[sz] });
|
|
|
|
|
|
samples.push_back({ x, y, labelMap[sz] });
|
|
|
|
|
|
}
|
|
|
|
|
|
return samples;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double KEDAlgorithm::KdeLogDensityBrute(const std::vector<FaciesConfig>& samples,
|
|
|
|
|
|
int label, double qx, double qy,
|
|
|
|
|
|
double bandwidth) const
|
|
|
|
|
|
{
|
|
|
|
|
|
if (samples.empty()) return -std::numeric_limits<double>::infinity();
|
|
|
|
|
|
|
|
|
|
|
|
double log_coeff = -std::log(2.0 * M_PI) - 2.0 * std::log(bandwidth);
|
|
|
|
|
|
double sum_exp = 0.0;
|
|
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& s : samples) {
|
|
|
|
|
|
if (s.value != label) continue;
|
|
|
|
|
|
double dx = qx - s.x;
|
|
|
|
|
|
double dy = qy - s.y;
|
|
|
|
|
|
double dist2 = dx * dx + dy * dy;
|
|
|
|
|
|
double log_p = log_coeff - 0.5 * dist2 / (bandwidth * bandwidth);
|
|
|
|
|
|
sum_exp += std::exp(log_p);
|
|
|
|
|
|
++n;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (n == 0) return -std::numeric_limits<double>::infinity();
|
|
|
|
|
|
return std::log(sum_exp / n);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::WriteDSAAFromGrid(const std::string& output_grd,
|
|
|
|
|
|
const std::vector<float>& grid_data,
|
|
|
|
|
|
int nx, int ny,
|
|
|
|
|
|
double minx, double maxx,
|
|
|
|
|
|
double miny, double maxy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (static_cast<size_t>(nx * ny) != grid_data.size() || grid_data.empty())
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
float zmin = *std::min_element(grid_data.begin(), grid_data.end());
|
|
|
|
|
|
float zmax = *std::max_element(grid_data.begin(), grid_data.end());
|
|
|
|
|
|
|
|
|
|
|
|
std::ofstream out(output_grd);
|
|
|
|
|
|
if (!out.is_open()) return false;
|
|
|
|
|
|
|
|
|
|
|
|
out << "DSAA\n";
|
|
|
|
|
|
out << nx << " " << ny << "\n";
|
|
|
|
|
|
out << minx << " " << maxx << "\n";
|
|
|
|
|
|
out << miny << " " << maxy << "\n";
|
|
|
|
|
|
out << zmin << " " << zmax << "\n";
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < ny; ++j) {
|
|
|
|
|
|
int src_row = ny - 1 - j;
|
|
|
|
|
|
for (int i = 0; i < nx; ++i) {
|
|
|
|
|
|
size_t index = static_cast<size_t>(src_row) * nx + i;
|
|
|
|
|
|
out << grid_data[index] << " ";
|
|
|
|
|
|
if ((i + 1) % 10 == 0) out << "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
out << "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::GrdToKEVFile(const CString &gridFile, const CString &outputFile,
|
|
|
|
|
|
std::vector<CCurve*> pCurves, CColorBase &base)
|
|
|
|
|
|
{
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
if (!CreateFaciesLines(pXy, pCurves))
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɫ
|
|
|
|
|
|
CArray<CColorItem, CColorItem> ColorList;
|
|
|
|
|
|
base.GetColor(ColorList);
|
|
|
|
|
|
if (ColorList.GetSize() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
POSITION pt = pXy->FindFirstElement(DOUBLEFOX_MESH);
|
|
|
|
|
|
if (pt == nullptr)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
COne* pOne1 = pXy->GetAt(pt);
|
|
|
|
|
|
CMesh* pMesh = (CMesh*)pOne1->GetValue();
|
|
|
|
|
|
|
|
|
|
|
|
pMesh->color.SetColor(ColorList);
|
|
|
|
|
|
pMesh->UpdateColorRuler();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pXy->SaveAsWithExtension(outputFile);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::CreateFaciesLines(std::shared_ptr<CXy> pXy, std::vector<CCurve*> pCurves)
|
|
|
|
|
|
{
|
|
|
|
|
|
CString strLayerMark = _T("Layer:\\<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\\<EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
|
|
|
|
|
CLayer* pLayer = pXy->FindAddLayer(strLayerMark);
|
|
|
|
|
|
|
|
|
|
|
|
AddFaciesCurves(pXy, pCurves, strLayerMark);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KEDAlgorithm::AddFaciesCurves(std::shared_ptr<CXy> pXy, std::vector<CCurve*> curves, CString layerName)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (size_t i = 0; i < curves.size(); i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
CCurve* pCurve = curves.at(i);
|
|
|
|
|
|
if (pCurve == NULL) continue;
|
|
|
|
|
|
|
|
|
|
|
|
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, layerName);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::KEDMeshAlgorithm(const CString& csvFile, const CString& kevFile,
|
|
|
|
|
|
double grid_interval, double bandwidth, double beta, int anchor_radius,
|
|
|
|
|
|
std::function<void(int completed, int total)> progressCallback)
|
|
|
|
|
|
{
|
|
|
|
|
|
const int TOTAL_STEPS = 6;
|
|
|
|
|
|
auto reportProgress = [&](int step, bool failed = false) {
|
|
|
|
|
|
if (progressCallback) {
|
|
|
|
|
|
progressCallback(failed ? -1 : step, TOTAL_STEPS);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
m_cancelRequested.store(false);
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
std::map<std::string, int> labelMap;
|
|
|
|
|
|
auto samples = LoadFaciesSettings(csvFile, labelMap);
|
|
|
|
|
|
if (samples.empty()) {
|
|
|
|
|
|
reportProgress(0, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
reportProgress(1);
|
|
|
|
|
|
int num_classes = static_cast<int>(labelMap.size());
|
|
|
|
|
|
if (num_classes == 0) {
|
|
|
|
|
|
reportProgress(1, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>Χ
|
|
|
|
|
|
double minx = 1e20, maxx = -1e20, miny = 1e20, maxy = -1e20;
|
|
|
|
|
|
for (const auto& s : samples)
|
|
|
|
|
|
{
|
|
|
|
|
|
minx = std::min(minx, s.x);
|
|
|
|
|
|
maxx = std::max(maxx, s.x);
|
|
|
|
|
|
miny = std::min(miny, s.y);
|
|
|
|
|
|
maxy = std::max(maxy, s.y);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int nx = static_cast<int>((maxx - minx) / grid_interval) + 1;
|
|
|
|
|
|
int ny = static_cast<int>((maxy - miny) / grid_interval) + 1;
|
|
|
|
|
|
std::cout << "Grid nx=" << nx << " ny=" << ny << std::endl;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ͼ
|
|
|
|
|
|
std::vector<cv::Mat> probMaps;
|
|
|
|
|
|
probMaps.reserve(num_classes);
|
|
|
|
|
|
for (int c = 0; c < num_classes; ++c)
|
|
|
|
|
|
probMaps.emplace_back(cv::Mat::zeros(ny, nx, CV_32F));
|
|
|
|
|
|
|
|
|
|
|
|
// KDE + <20><><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD>
|
|
|
|
|
|
#pragma omp parallel
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<double> log_densities(num_classes);
|
|
|
|
|
|
#pragma omp for collapse(2) schedule(dynamic)
|
|
|
|
|
|
for (int iy = 0; iy < ny; ++iy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_cancelRequested.load()) continue;
|
|
|
|
|
|
for (int ix = 0; ix < nx; ++ix)
|
|
|
|
|
|
{
|
|
|
|
|
|
double gx = minx + ix * grid_interval;
|
|
|
|
|
|
double gy = maxy - iy * grid_interval;
|
|
|
|
|
|
|
|
|
|
|
|
for (int c = 0; c < num_classes; ++c)
|
|
|
|
|
|
log_densities[c] = KdeLogDensityBrute(samples, c, gx, gy, bandwidth);
|
|
|
|
|
|
|
|
|
|
|
|
double max_log = *std::max_element(log_densities.begin(), log_densities.end());
|
|
|
|
|
|
if (max_log <= -1e20)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int c = 0; c < num_classes; ++c)
|
|
|
|
|
|
probMaps[c].at<float>(iy, ix) = 1.0f / num_classes;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
double sum_exp = 0.0;
|
|
|
|
|
|
for (int c = 0; c < num_classes; ++c)
|
|
|
|
|
|
if (log_densities[c] > -1e20)
|
|
|
|
|
|
sum_exp += std::exp(log_densities[c] - max_log);
|
|
|
|
|
|
for (int c = 0; c < num_classes; ++c)
|
|
|
|
|
|
{
|
|
|
|
|
|
double p = 0.0;
|
|
|
|
|
|
if (log_densities[c] > -1e20)
|
|
|
|
|
|
p = std::exp(log_densities[c] - max_log) / sum_exp;
|
|
|
|
|
|
p = (1.0 - beta) * p + beta * (1.0 / num_classes);
|
|
|
|
|
|
probMaps[c].at<float>(iy, ix) = static_cast<float>(p);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(2);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>
|
|
|
|
|
|
cv::Mat initialGrid(ny, nx, CV_8UC1, cv::Scalar(0));
|
|
|
|
|
|
for (int iy = 0; iy < ny; ++iy)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int ix = 0; ix < nx; ++ix)
|
|
|
|
|
|
{
|
|
|
|
|
|
int best_label = 0;
|
|
|
|
|
|
float best_prob = probMaps[0].at<float>(iy, ix);
|
|
|
|
|
|
for (int c = 1; c < num_classes; ++c)
|
|
|
|
|
|
{
|
|
|
|
|
|
float p = probMaps[c].at<float>(iy, ix);
|
|
|
|
|
|
if (p > best_prob) { best_prob = p; best_label = c; }
|
|
|
|
|
|
}
|
|
|
|
|
|
initialGrid.at<uchar>(iy, ix) = static_cast<uchar>(best_label);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(3);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>̬ѧ<CCAC><D1A7><EFBFBD><EFBFBD>
|
|
|
|
|
|
cv::Mat tempGrid = initialGrid.clone();
|
|
|
|
|
|
cv::morphologyEx(tempGrid, tempGrid, cv::MORPH_OPEN,
|
|
|
|
|
|
cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
|
|
|
|
|
|
cv::morphologyEx(tempGrid, tempGrid, cv::MORPH_CLOSE,
|
|
|
|
|
|
cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(9, 9)));
|
|
|
|
|
|
|
|
|
|
|
|
cv::Mat finalGrid = tempGrid.clone();
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(4);
|
|
|
|
|
|
// ê<><C3AA><EFBFBD>ӹ<EFBFBD>
|
|
|
|
|
|
for (const auto& s : samples)
|
|
|
|
|
|
{
|
|
|
|
|
|
int col = static_cast<int>(std::round((s.x - minx) / grid_interval));
|
|
|
|
|
|
int row = static_cast<int>(std::round((maxy - s.y) / grid_interval));
|
|
|
|
|
|
if (col >= 0 && col < finalGrid.cols &&
|
|
|
|
|
|
row >= 0 && row < finalGrid.rows)
|
|
|
|
|
|
{
|
|
|
|
|
|
cv::circle(finalGrid, cv::Point(col, row), anchor_radius,
|
|
|
|
|
|
cv::Scalar(s.value), -1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CSplitPath sp;
|
|
|
|
|
|
sp.SetModuleFileName();
|
|
|
|
|
|
CString xmlPath = "";
|
|
|
|
|
|
xmlPath.Format("%s%s", sp.GetPath(), "facies");
|
|
|
|
|
|
sp.MakeDirectory(xmlPath);
|
|
|
|
|
|
|
|
|
|
|
|
CString gridFile = "";
|
|
|
|
|
|
gridFile.Format("%s%s", xmlPath, "\\facies.grd");
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> GRD
|
|
|
|
|
|
std::vector<float> grid_data;
|
|
|
|
|
|
grid_data.reserve(finalGrid.total());
|
|
|
|
|
|
for (int i = 0; i < finalGrid.rows; ++i)
|
|
|
|
|
|
for (int j = 0; j < finalGrid.cols; ++j)
|
|
|
|
|
|
grid_data.push_back(static_cast<float>(finalGrid.at<uchar>(i, j)));
|
|
|
|
|
|
|
|
|
|
|
|
if (!WriteDSAAFromGrid(std::string(gridFile), grid_data,
|
|
|
|
|
|
finalGrid.cols, finalGrid.rows,
|
|
|
|
|
|
minx, maxx, miny, maxy))
|
|
|
|
|
|
{
|
|
|
|
|
|
reportProgress(5, true);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(5);
|
|
|
|
|
|
|
|
|
|
|
|
CArray<CColorItem, CColorItem> ColorList;
|
|
|
|
|
|
CColorBase base;
|
|
|
|
|
|
base.Clear();
|
|
|
|
|
|
for (const auto& pair : m_ColorList)
|
|
|
|
|
|
{
|
|
|
|
|
|
CColorItem colorMesh;
|
|
|
|
|
|
colorMesh.SetColor(pair.second);
|
|
|
|
|
|
colorMesh.z = pair.first;
|
|
|
|
|
|
colorMesh.m_bContinue = true;
|
|
|
|
|
|
ColorList.Add(colorMesh);
|
|
|
|
|
|
}
|
|
|
|
|
|
base.SetColor(ColorList);
|
|
|
|
|
|
|
|
|
|
|
|
ProcessExistingGrd(gridFile, kevFile, base, true, progressCallback);
|
|
|
|
|
|
reportProgress(6);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::IDWMeshAlgorithm(const CString& csvFile,
|
|
|
|
|
|
const CString& kevFile,
|
|
|
|
|
|
const CString& boundaryFile,
|
|
|
|
|
|
double grid_interval,
|
|
|
|
|
|
int subblock_count,
|
|
|
|
|
|
int idw_neighbors,
|
|
|
|
|
|
double idw_power,
|
|
|
|
|
|
bool use_shepard,
|
|
|
|
|
|
bool smooth_boundary,
|
|
|
|
|
|
bool isFaciesBorder,
|
|
|
|
|
|
std::function<void(int completed, int total)> progressCallback)
|
|
|
|
|
|
{
|
|
|
|
|
|
const int TOTAL_STEPS = 6;
|
|
|
|
|
|
auto reportProgress = [&](int step, bool failed = false) {
|
|
|
|
|
|
if (progressCallback) progressCallback(failed ? -1 : step, TOTAL_STEPS);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
m_cancelRequested.store(false);
|
|
|
|
|
|
|
|
|
|
|
|
//<2F><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
std::map<std::string, int> labelMap;
|
|
|
|
|
|
auto samples = LoadFaciesSettings(csvFile, labelMap);
|
|
|
|
|
|
if (samples.empty()) { reportProgress(0, true); return false; }
|
|
|
|
|
|
int num_classes = static_cast<int>(labelMap.size());
|
|
|
|
|
|
reportProgress(1);
|
|
|
|
|
|
|
|
|
|
|
|
//<2F><><EFBFBD>㷶Χ<E3B7B6><CEA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
double minx = 1e20, maxx = -1e20, miny = 1e20, maxy = -1e20;
|
|
|
|
|
|
float sample_zmin = std::numeric_limits<float>::max();
|
|
|
|
|
|
float sample_zmax = std::numeric_limits<float>::lowest();
|
|
|
|
|
|
for (const auto& s : samples)
|
|
|
|
|
|
{
|
|
|
|
|
|
minx = std::min(minx, s.x);
|
|
|
|
|
|
maxx = std::max(maxx, s.x);
|
|
|
|
|
|
miny = std::min(miny, s.y);
|
|
|
|
|
|
maxy = std::max(maxy, s.y);
|
|
|
|
|
|
sample_zmin = std::min(sample_zmin, static_cast<float>(s.value));
|
|
|
|
|
|
sample_zmax = std::max(sample_zmax, static_cast<float>(s.value));
|
|
|
|
|
|
}
|
|
|
|
|
|
reportProgress(2);
|
|
|
|
|
|
|
|
|
|
|
|
//<2F><>ȡ<EFBFBD>߽<EFBFBD><DFBD>ļ<EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD><DAB9><EFBFBD>)
|
|
|
|
|
|
std::vector<CCurveEx*> vBorder;
|
|
|
|
|
|
if (!boundaryFile.IsEmpty())
|
|
|
|
|
|
{
|
|
|
|
|
|
vBorder = GetDFDBorder(boundaryFile);
|
|
|
|
|
|
}
|
|
|
|
|
|
bool use_custom_border = !vBorder.empty();
|
|
|
|
|
|
|
|
|
|
|
|
//<2F><>չ<EFBFBD><D5B9>Χ
|
|
|
|
|
|
minx -= grid_interval;
|
|
|
|
|
|
miny -= grid_interval;
|
|
|
|
|
|
maxx += grid_interval;
|
|
|
|
|
|
maxy += grid_interval;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> + KDTree
|
|
|
|
|
|
int nx = static_cast<int>((maxx - minx) / grid_interval) + 1;
|
|
|
|
|
|
int ny = static_cast<int>((maxy - miny) / grid_interval) + 1;
|
|
|
|
|
|
const float NO_DATA_VALUE = 1e301;
|
|
|
|
|
|
std::vector<float> grid_data(nx * ny, NO_DATA_VALUE);
|
|
|
|
|
|
|
|
|
|
|
|
PointCloud cloud; cloud.pts = samples;
|
|
|
|
|
|
typedef KDTreeSingleIndexAdaptor<
|
|
|
|
|
|
L2_Simple_Adaptor<double, PointCloud>,
|
|
|
|
|
|
PointCloud, 2> my_kd_tree_t;
|
|
|
|
|
|
my_kd_tree_t index(2, cloud, KDTreeSingleIndexAdaptorParams(10));
|
|
|
|
|
|
index.buildIndex();
|
|
|
|
|
|
reportProgress(3);
|
|
|
|
|
|
|
|
|
|
|
|
// ================= <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӳ<EFBFBD><D3B3> =================
|
|
|
|
|
|
std::vector<int> uniqueValues;
|
|
|
|
|
|
std::map<int, int> valueToIndex;
|
|
|
|
|
|
int vIdx = 0;
|
|
|
|
|
|
for (const auto& pair : m_ColorList) {
|
|
|
|
|
|
uniqueValues.push_back(pair.first); // <20>洢<EFBFBD><E6B4A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
valueToIndex[pair.first] = vIdx++; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ -> <20><><EFBFBD><EFBFBD><EFBFBD>±<EFBFBD> (0, 1, 2...)
|
|
|
|
|
|
}
|
|
|
|
|
|
// ȷ<><C8B7> num_classes <20><>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ɫ<EFBFBD><C9AB><EFBFBD><EFBFBD>Сһ<D0A1><D2BB>
|
|
|
|
|
|
num_classes = static_cast<int>(uniqueValues.size());
|
|
|
|
|
|
// ==================================================================
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ֿ鲢<D6BF><E9B2A2> IDW <20><>ֵ
|
|
|
|
|
|
int block_h = ny / subblock_count;
|
|
|
|
|
|
std::atomic<int> completed_rows{ 0 };
|
|
|
|
|
|
int total_rows = ny;
|
|
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for schedule(dynamic)
|
|
|
|
|
|
for (int by = 0; by < subblock_count; ++by)
|
|
|
|
|
|
{
|
|
|
|
|
|
int startY = by * block_h;
|
|
|
|
|
|
int endY = (by == subblock_count - 1) ? ny : (by + 1) * block_h;
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<size_t> ret_indexes(idw_neighbors);
|
|
|
|
|
|
std::vector<double> out_dists_sqr(idw_neighbors);
|
|
|
|
|
|
std::vector<double> class_weights_local(num_classes);
|
|
|
|
|
|
|
|
|
|
|
|
for (int iy = startY; iy < endY; ++iy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (m_cancelRequested.load()) break;
|
|
|
|
|
|
|
|
|
|
|
|
for (int ix = 0; ix < nx; ++ix)
|
|
|
|
|
|
{
|
|
|
|
|
|
double qx = minx + ix * grid_interval;
|
|
|
|
|
|
double qy = maxy - iy * grid_interval;
|
|
|
|
|
|
|
|
|
|
|
|
// <20>߽<EFBFBD><DFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
if (use_custom_border && !IsPointInPolygon(qx, qy, vBorder))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
double query_pt[2] = { qx, qy };
|
|
|
|
|
|
nanoflann::KNNResultSet<double> resultSet(idw_neighbors);
|
|
|
|
|
|
resultSet.init(&ret_indexes[0], &out_dists_sqr[0]);
|
|
|
|
|
|
index.findNeighbors(resultSet, &query_pt[0]);
|
|
|
|
|
|
|
|
|
|
|
|
std::fill(class_weights_local.begin(), class_weights_local.end(), 0.0);
|
|
|
|
|
|
double R = sqrt(out_dists_sqr.back()) + 1e-9;
|
|
|
|
|
|
|
|
|
|
|
|
for (int k = 0; k < idw_neighbors; ++k)
|
|
|
|
|
|
{
|
|
|
|
|
|
double d = sqrt(out_dists_sqr[k]) + 1e-9;
|
|
|
|
|
|
double w = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
if (use_shepard)
|
|
|
|
|
|
{
|
|
|
|
|
|
w = pow((R - d) / (R * d + 1e-9), 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (idw_power == 2.0)
|
|
|
|
|
|
{
|
|
|
|
|
|
w = 1.0 / (d * d);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
w = 1.0 / pow(d, idw_power);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int phys_value = cloud.pts[ret_indexes[k]].value;
|
|
|
|
|
|
int safe_index = valueToIndex[phys_value];
|
|
|
|
|
|
class_weights_local[safe_index] += w;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int best_idx = 0;
|
|
|
|
|
|
double best_w = -1.0;
|
|
|
|
|
|
for (int lbl = 0; lbl < num_classes; ++lbl)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (class_weights_local[lbl] > best_w)
|
|
|
|
|
|
{
|
|
|
|
|
|
best_idx = lbl;
|
|
|
|
|
|
best_w = class_weights_local[lbl];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
grid_data[iy * nx + ix] = static_cast<float>(uniqueValues[best_idx]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//<2F><>̬<EFBFBD>н<EFBFBD><D0BD>Ȼش<C8BB>
|
|
|
|
|
|
int done = ++completed_rows;
|
|
|
|
|
|
if (progressCallback && (done % (ny / 100) == 0))
|
|
|
|
|
|
{
|
|
|
|
|
|
// ÿԼ1%<25><><EFBFBD><EFBFBD>
|
|
|
|
|
|
int percent = static_cast<int>((done * 100.0) / total_rows);
|
|
|
|
|
|
progressCallback(percent, 100); // ʵʱ<CAB5>ٷֱ<D9B7>ģʽ
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(4);
|
|
|
|
|
|
|
|
|
|
|
|
qDeleteAll(vBorder);
|
|
|
|
|
|
|
|
|
|
|
|
// д<><D0B4> GRD (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Чֵ<D0A7><D6B5><EFBFBD><EFBFBD>z<EFBFBD><7A>Χ)
|
|
|
|
|
|
CSplitPath sp;
|
|
|
|
|
|
sp.SetModuleFileName();
|
|
|
|
|
|
CString xmlPath;
|
|
|
|
|
|
xmlPath.Format("%s%s", sp.GetPath(), "facies");
|
|
|
|
|
|
sp.MakeDirectory(xmlPath);
|
|
|
|
|
|
|
|
|
|
|
|
CString gridFile;
|
|
|
|
|
|
gridFile.Format("%s%s", xmlPath, "\\facies_idw.grd");
|
|
|
|
|
|
|
|
|
|
|
|
WriteDSAAFromGridKeepZRange(
|
|
|
|
|
|
std::string(CT2A(gridFile)),
|
|
|
|
|
|
grid_data, nx, ny,
|
|
|
|
|
|
minx, maxx, miny, maxy,
|
|
|
|
|
|
sample_zmin, sample_zmax);
|
|
|
|
|
|
|
|
|
|
|
|
reportProgress(5);
|
|
|
|
|
|
|
|
|
|
|
|
CArray<CColorItem, CColorItem> ColorList;
|
|
|
|
|
|
CColorBase base;
|
|
|
|
|
|
base.Clear();
|
|
|
|
|
|
for (const auto& pair : m_ColorList)
|
|
|
|
|
|
{
|
|
|
|
|
|
CColorItem colorMesh;
|
|
|
|
|
|
colorMesh.SetColor(pair.second);
|
|
|
|
|
|
colorMesh.z = pair.first;
|
|
|
|
|
|
colorMesh.m_bContinue = true;
|
|
|
|
|
|
ColorList.Add(colorMesh);
|
|
|
|
|
|
}
|
|
|
|
|
|
base.SetColor(ColorList);
|
|
|
|
|
|
|
|
|
|
|
|
//<2F><><EFBFBD><EFBFBD> KEV
|
|
|
|
|
|
ProcessExistingGrd(gridFile, kevFile, base, isFaciesBorder, progressCallback);
|
|
|
|
|
|
reportProgress(6);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KEDAlgorithm::StopTask()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_cancelRequested.store(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD> + <20><><EFBFBD><EFBFBD> + ȥë<C8A5>̣<EFBFBD>
|
|
|
|
|
|
void KEDAlgorithm::PostProcessFaciesBoundaries(
|
|
|
|
|
|
std::vector<CCurve*>& pCurves,
|
|
|
|
|
|
double sigma_smooth,
|
|
|
|
|
|
int min_seg_cells,
|
|
|
|
|
|
double drop_closed_thresh,
|
|
|
|
|
|
double dx, double dy)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<CCurve*> filtered;
|
|
|
|
|
|
filtered.reserve(pCurves.size());
|
|
|
|
|
|
|
|
|
|
|
|
for (auto* curve : pCurves)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!curve || curve->num < 3) continue;
|
|
|
|
|
|
|
|
|
|
|
|
//ȥ<><C8A5>̫<EFBFBD><CCAB><EFBFBD>߶<EFBFBD>
|
|
|
|
|
|
double totalLen = 0.0;
|
|
|
|
|
|
for (int i = 1; i < curve->num; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
double dx_ = curve->x[i] - curve->x[i - 1];
|
|
|
|
|
|
double dy_ = curve->y[i] - curve->y[i - 1];
|
|
|
|
|
|
totalLen += std::sqrt(dx_ * dx_ + dy_ * dy_);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (totalLen < min_seg_cells * std::min(dx, dy))
|
|
|
|
|
|
{
|
|
|
|
|
|
delete curve;
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>˹ƽ<CBB9><C6BD><EFBFBD>ߣ<EFBFBD><DFA3><EFBFBD><EFBFBD>β<EFBFBD><CEB2>棩
|
|
|
|
|
|
if (sigma_smooth > 0.1)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<double> newX(curve->num), newY(curve->num);
|
|
|
|
|
|
int r = static_cast<int>(sigma_smooth * 2.0);
|
|
|
|
|
|
double sigma2 = sigma_smooth * sigma_smooth;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < curve->num; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
double sumW = 0.0, sumX = 0.0, sumY = 0.0;
|
|
|
|
|
|
for (int j = std::max(0, i - r); j < std::min(curve->num, i + r + 1); ++j)
|
|
|
|
|
|
{
|
|
|
|
|
|
double w = std::exp(-0.5 * (std::pow(i - j, 2) / sigma2));
|
|
|
|
|
|
sumW += w;
|
|
|
|
|
|
sumX += w * curve->x[j];
|
|
|
|
|
|
sumY += w * curve->y[j];
|
|
|
|
|
|
}
|
|
|
|
|
|
newX[i] = sumX / sumW;
|
|
|
|
|
|
newY[i] = sumY / sumW;
|
|
|
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < curve->num; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
curve->x[i] = newX[i];
|
|
|
|
|
|
curve->y[i] = newY[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
filtered.push_back(curve);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pCurves.swap(filtered);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<CCurveEx*> KEDAlgorithm::GetDFDBorder(const CString& path)
|
|
|
|
|
|
{
|
|
|
|
|
|
CString borderFile = path;
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>жϵ<EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* @param qx <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> X <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* @param qy <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Y <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD> true<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> false
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool KEDAlgorithm::IsPointInPolygon(double qx, double qy, const std::vector<CCurveEx*>& polygons)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>û<EFBFBD>б߽磬<DFBD><E7A3AC><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ڱ߽<DAB1><DFBD><EFBFBD>
|
|
|
|
|
|
if (polygons.empty()) return true;
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto* poly : polygons) {
|
|
|
|
|
|
if (!poly || poly->num < 3) continue;
|
|
|
|
|
|
|
|
|
|
|
|
int crossings = 0;
|
|
|
|
|
|
int num_vertices = poly->num;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>պ϶<D5BA><CFB6><EFBFBD><EFBFBD>Σ<EFBFBD><CEA3><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>
|
|
|
|
|
|
if (poly->x[0] == poly->x[num_vertices - 1] && poly->y[0] == poly->y[num_vertices - 1]) {
|
|
|
|
|
|
num_vertices--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0, j = num_vertices - 1; i < num_vertices; j = i++) {
|
|
|
|
|
|
double xi = poly->x[i], yi = poly->y[i];
|
|
|
|
|
|
double xj = poly->x[j], yj = poly->y[j];
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>߷<EFBFBD><DFB7><EFBFBD><EFBFBD><EFBFBD> qx <20><><EFBFBD><EFBFBD> X <20><><EFBFBD><EFBFBD><F2B7A2B3><EFBFBD><EFBFBD>ߣ<EFBFBD>ͳ<EFBFBD><CDB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>αߵĽ<DFB5><C4BD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
if (((yi > qy) != (yj > qy)) && // <20>߶ο<DFB6>Խˮƽ<CBAE><C6BD> y=qy
|
|
|
|
|
|
(qx < (xj - xi) * (qy - yi) / (yj - yi) + xi)) // <20><><EFBFBD>齻<EFBFBD><E9BDBB><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD> qx <20>Ҳ<EFBFBD>
|
|
|
|
|
|
{
|
|
|
|
|
|
crossings++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>
|
|
|
|
|
|
if (crossings % 2 == 1) return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD><EFBFBD>ζ<EFBFBD><CEB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD>
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::WriteDSAAFromGridKeepZRange(const std::string& output_grd, const std::vector<float>& grid_data,
|
|
|
|
|
|
int nx, int ny, double minx, double maxx, double miny, double maxy, float zmin, float zmax)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (static_cast<size_t>(nx * ny) != grid_data.size() || grid_data.empty())
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
std::ofstream out(output_grd);
|
|
|
|
|
|
if (!out.is_open()) return false;
|
|
|
|
|
|
|
|
|
|
|
|
out << "DSAA\n";
|
|
|
|
|
|
out << nx << " " << ny << "\n";
|
|
|
|
|
|
out << minx << " " << maxx << "\n";
|
|
|
|
|
|
out << miny << " " << maxy << "\n";
|
|
|
|
|
|
out << zmin << " " << zmax << "\n";
|
|
|
|
|
|
|
|
|
|
|
|
for (int j = 0; j < ny; ++j) {
|
|
|
|
|
|
int src_row = ny - 1 - j;
|
|
|
|
|
|
for (int i = 0; i < nx; ++i) {
|
|
|
|
|
|
size_t index = static_cast<size_t>(src_row) * nx + i;
|
|
|
|
|
|
out << grid_data[index] << " ";
|
|
|
|
|
|
if ((i + 1) % 10 == 0) out << "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
out << "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::unordered_map<std::string, int> KEDAlgorithm::GetDepositionalMap()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_DepositionalMap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KEDAlgorithm::NNMeshAlgorithm(const CString& csvFile,
|
|
|
|
|
|
const CString& kevFile,
|
|
|
|
|
|
const CString& boundaryFile,
|
|
|
|
|
|
double grid_interval,
|
|
|
|
|
|
double sigma,
|
|
|
|
|
|
int open_iter,
|
|
|
|
|
|
int close_iter,
|
|
|
|
|
|
bool isFaciesBorder,
|
|
|
|
|
|
std::function<void(int completed, int total)> progressCallback)
|
|
|
|
|
|
{
|
|
|
|
|
|
const int TOTAL_STEPS = 6;
|
|
|
|
|
|
auto reportProgress = [&](int step, bool failed = false) {
|
|
|
|
|
|
if (progressCallback) progressCallback(failed ? -1 : step, TOTAL_STEPS);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
m_cancelRequested.store(false);
|
|
|
|
|
|
std::map<std::string, int> labelMap;
|
|
|
|
|
|
auto samples = LoadFaciesSettings(csvFile, labelMap);
|
|
|
|
|
|
if (samples.empty()) { reportProgress(0, true); return false; }
|
|
|
|
|
|
int num_classes = static_cast<int>(labelMap.size());
|
|
|
|
|
|
reportProgress(1);
|
|
|
|
|
|
|
|
|
|
|
|
double minx = 1e20, maxx = -1e20, miny = 1e20, maxy = -1e20;
|
|
|
|
|
|
float sample_zmin = std::numeric_limits<float>::max();
|
|
|
|
|
|
float sample_zmax = std::numeric_limits<float>::lowest();
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& s : samples) {
|
|
|
|
|
|
minx = std::min(minx, s.x); maxx = std::max(maxx, s.x);
|
|
|
|
|
|
miny = std::min(miny, s.y); maxy = std::max(maxy, s.y);
|
|
|
|
|
|
sample_zmin = std::min(sample_zmin, (float)s.value);
|
|
|
|
|
|
sample_zmax = std::max(sample_zmax, (float)s.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Python: np.arange(start, stop + step*0.1, step)
|
|
|
|
|
|
// <20><>֤<EFBFBD><D6A4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
|
|
|
|
|
|
int nx = static_cast<int>(std::floor((maxx - minx + grid_interval * 0.01) / grid_interval)) + 1;
|
|
|
|
|
|
int ny = static_cast<int>(std::floor((maxy - miny + grid_interval * 0.01) / grid_interval)) + 1;
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<CCurveEx*> vBorder;
|
|
|
|
|
|
if (!boundaryFile.IsEmpty())
|
|
|
|
|
|
{
|
|
|
|
|
|
vBorder = GetDFDBorder(boundaryFile);
|
|
|
|
|
|
}
|
|
|
|
|
|
bool use_custom_border = !vBorder.empty();
|
|
|
|
|
|
|
|
|
|
|
|
PointCloud cloud; cloud.pts = samples;
|
|
|
|
|
|
typedef KDTreeSingleIndexAdaptor<L2_Simple_Adaptor<double, PointCloud>, PointCloud, 2> my_kd_tree_t;
|
|
|
|
|
|
my_kd_tree_t index(2, cloud, KDTreeSingleIndexAdaptorParams(10));
|
|
|
|
|
|
index.buildIndex();
|
|
|
|
|
|
|
|
|
|
|
|
reportProgress(2);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ɳ<EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD> (Label<65><6C><EFBFBD><EFBFBD>ͼ)
|
|
|
|
|
|
cv::Mat gridMat(ny, nx, CV_32SC1);
|
|
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
|
for (int iy = 0; iy < ny; ++iy) {
|
|
|
|
|
|
if (m_cancelRequested.load()) continue;
|
|
|
|
|
|
for (int ix = 0; ix < nx; ++ix) {
|
|
|
|
|
|
double qx = minx + ix * grid_interval;
|
|
|
|
|
|
double qy = maxy - iy * grid_interval; // ע<><D7A2>Y<EFBFBD>᷽<EFBFBD><E1B7BD>ͨ<EFBFBD><CDA8><EFBFBD>Ƿ<EFBFBD><C7B7>ģ<EFBFBD><C4A3><EFBFBD>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դϰ<D4B4><CFB0>
|
|
|
|
|
|
|
|
|
|
|
|
double query_pt[2] = { qx, qy };
|
|
|
|
|
|
size_t ret_index;
|
|
|
|
|
|
double out_dist_sqr;
|
|
|
|
|
|
nanoflann::KNNResultSet<double> resultSet(1);
|
|
|
|
|
|
resultSet.init(&ret_index, &out_dist_sqr);
|
|
|
|
|
|
index.findNeighbors(resultSet, &query_pt[0]);
|
|
|
|
|
|
|
|
|
|
|
|
gridMat.at<int>(iy, ix) = cloud.pts[ret_index].value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(3);
|
|
|
|
|
|
|
|
|
|
|
|
// 1. <20><>ȡ<EFBFBD><C8A1><EFBFBD>в<EFBFBD><D0B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ (std::map <20><><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
|
|
|
|
std::vector<int> uniqueValues;
|
|
|
|
|
|
for (const auto& pair : m_ColorList) {
|
|
|
|
|
|
uniqueValues.push_back(pair.first);
|
|
|
|
|
|
}
|
|
|
|
|
|
int actualNumClasses = static_cast<int>(uniqueValues.size());
|
|
|
|
|
|
|
|
|
|
|
|
// ================= <20><>˹<EFBFBD><CBB9><EFBFBD><EFBFBD>ƽ<EFBFBD><C6BD> =================
|
|
|
|
|
|
if (sigma > 0.1 && actualNumClasses > 0) {
|
|
|
|
|
|
std::vector<cv::Mat> probLayers(actualNumClasses);
|
|
|
|
|
|
for (int i = 0; i < actualNumClasses; ++i)
|
|
|
|
|
|
probLayers[i] = cv::Mat::zeros(ny, nx, CV_32F);
|
|
|
|
|
|
|
|
|
|
|
|
// One-Hot Encoding (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵӳ<D6B5>䵽ƽ<E4B5BD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
|
for (int y = 0; y < ny; ++y) {
|
|
|
|
|
|
for (int x = 0; x < nx; ++x) {
|
|
|
|
|
|
int currentVal = gridMat.at<int>(y, x);
|
|
|
|
|
|
// <20>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>Ӧ<EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
for (int i = 0; i < actualNumClasses; ++i) {
|
|
|
|
|
|
if (uniqueValues[i] == currentVal) {
|
|
|
|
|
|
probLayers[i].at<float>(y, x) = 1.0f;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20>˴<EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>
|
|
|
|
|
|
int radius = static_cast<int>(4.0 * sigma + 0.5);
|
|
|
|
|
|
int ksize = 2 * radius + 1;
|
|
|
|
|
|
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
|
for (int i = 0; i < actualNumClasses; ++i) {
|
|
|
|
|
|
cv::GaussianBlur(probLayers[i], probLayers[i],
|
|
|
|
|
|
cv::Size(ksize, ksize),
|
|
|
|
|
|
sigma, sigma,
|
|
|
|
|
|
cv::BORDER_REFLECT);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Argmax <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD><EFBFBD>߸<EFBFBD><DFB8>ʵIJ<CAB5><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭΪ<D4AD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ)
|
|
|
|
|
|
#pragma omp parallel for
|
|
|
|
|
|
for (int y = 0; y < ny; ++y) {
|
|
|
|
|
|
for (int x = 0; x < nx; ++x) {
|
|
|
|
|
|
int best_idx = 0;
|
|
|
|
|
|
float max_prob = -1.0f;
|
|
|
|
|
|
for (int i = 0; i < actualNumClasses; ++i) {
|
|
|
|
|
|
float p = probLayers[i].at<float>(y, x);
|
|
|
|
|
|
if (p > max_prob) {
|
|
|
|
|
|
max_prob = p;
|
|
|
|
|
|
best_idx = i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
gridMat.at<int>(y, x) = uniqueValues[best_idx];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_cancelRequested.load()) { reportProgress(-1, true); return false; }
|
|
|
|
|
|
reportProgress(4);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>̬ѧ<CCAC><D1A7><EFBFBD><EFBFBD>
|
|
|
|
|
|
if (open_iter > 0 || close_iter > 0) {
|
|
|
|
|
|
// ʹ<><CAB9><EFBFBD><EFBFBD>Բ<EFBFBD>ˣ<EFBFBD><CBA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ı߽<C4B1><DFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ<EFBFBD>Բ<EFBFBD><D4B2><EFBFBD><EFBFBD>
|
|
|
|
|
|
cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
|
|
|
|
|
|
cv::Mat optimizedGrid = gridMat.clone();
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0, 1, 2
|
|
|
|
|
|
for (int i = 0; i < actualNumClasses; ++i) {
|
|
|
|
|
|
int physValue = uniqueValues[i];
|
|
|
|
|
|
|
|
|
|
|
|
cv::Mat mask;
|
|
|
|
|
|
// Ѱ<><D1B0>ͼ<EFBFBD><CDBC><EFBFBD>е<EFBFBD><D0B5><EFBFBD> physValue <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
cv::inRange(gridMat, cv::Scalar(physValue), cv::Scalar(physValue), mask);
|
|
|
|
|
|
|
|
|
|
|
|
if (open_iter > 0)
|
|
|
|
|
|
cv::morphologyEx(mask, mask, cv::MORPH_OPEN, element, cv::Point(-1, -1), open_iter);
|
|
|
|
|
|
|
|
|
|
|
|
if (close_iter > 0)
|
|
|
|
|
|
cv::morphologyEx(mask, mask, cv::MORPH_CLOSE, element, cv::Point(-1, -1), close_iter);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>ƽ<EFBFBD><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɰ<EFBFBD><C9B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ȥ
|
|
|
|
|
|
optimizedGrid.setTo(cv::Scalar(physValue), mask);
|
|
|
|
|
|
}
|
|
|
|
|
|
gridMat = optimizedGrid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
reportProgress(5);
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<float> grid_data;
|
|
|
|
|
|
grid_data.reserve(nx * ny);
|
|
|
|
|
|
|
|
|
|
|
|
for (int iy = 0; iy < ny; ++iy) {
|
|
|
|
|
|
for (int ix = 0; ix < nx; ++ix) {
|
|
|
|
|
|
double rx = minx + ix * grid_interval;
|
|
|
|
|
|
double ry = maxy - iy * grid_interval;
|
|
|
|
|
|
|
|
|
|
|
|
if (use_custom_border && !IsPointInPolygon(rx, ry, vBorder)) {
|
|
|
|
|
|
grid_data.push_back(1e301);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
grid_data.push_back((float)gridMat.at<int>(iy, ix));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
qDeleteAll(vBorder);
|
|
|
|
|
|
|
|
|
|
|
|
CSplitPath sp;
|
|
|
|
|
|
sp.SetModuleFileName();
|
|
|
|
|
|
CString xmlPath;
|
|
|
|
|
|
xmlPath.Format("%s%s", sp.GetPath(), "facies");
|
|
|
|
|
|
sp.MakeDirectory(xmlPath);
|
|
|
|
|
|
|
|
|
|
|
|
CString gridPath;
|
|
|
|
|
|
gridPath.Format("%s%s", xmlPath, "\\facies_nn.grd");
|
|
|
|
|
|
|
|
|
|
|
|
WriteDSAAFromGridKeepZRange(
|
|
|
|
|
|
std::string(CT2A(gridPath)),
|
|
|
|
|
|
grid_data, nx, ny,
|
|
|
|
|
|
minx, maxx, miny, maxy,
|
|
|
|
|
|
sample_zmin, sample_zmax);
|
|
|
|
|
|
|
|
|
|
|
|
CArray<CColorItem, CColorItem> ColorList;
|
|
|
|
|
|
CColorBase base;
|
|
|
|
|
|
base.Clear();
|
|
|
|
|
|
for (const auto& pair : m_ColorList)
|
|
|
|
|
|
{
|
|
|
|
|
|
CColorItem colorMesh;
|
|
|
|
|
|
colorMesh.SetColor(pair.second);
|
|
|
|
|
|
colorMesh.z = pair.first;
|
|
|
|
|
|
colorMesh.m_bContinue = true;
|
|
|
|
|
|
ColorList.Add(colorMesh);
|
|
|
|
|
|
}
|
|
|
|
|
|
base.SetColor(ColorList);
|
|
|
|
|
|
|
|
|
|
|
|
ProcessExistingGrd(gridPath, kevFile, base, isFaciesBorder, progressCallback);
|
|
|
|
|
|
|
|
|
|
|
|
reportProgress(6);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|