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.
nmWTAI-Platform/Src/nmNum/nmCalculation/nmCalculationUtils.cpp

352 lines
10 KiB
C++

#include "nmCalculationUtils.h"
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QCoreApplication>
#include <fstream>
#include <float.h>
#include "pch.h"
namespace
{
QString krigingText(const char* sourceText)
{
return QCoreApplication::translate("nmCalculationUtils", sourceText);
}
bool isFiniteValue(double value)
{
#ifdef _MSC_VER
return _finite(value) != 0;
#else
return std::isfinite(value);
#endif
}
void setKrigingError(QString* errorMessage, const QString& message)
{
if(errorMessage != NULL) {
*errorMessage = message;
}
}
}
nmCalculationUtils::nmCalculationUtils() {
}
bool nmCalculationUtils::copyFileToDir(QString filePath, QString destDir) {
// 如果文件不存在,则退出
if(!QFile::exists(filePath)) {
return false;
}
// 如果目标目录不存在,则创建
if(!QDir(destDir).exists()) {
if(!QDir().mkdir(destDir)) {
qWarning() << "cannot mkdir:" << destDir;
return false;
}
}
// 获取源文件的文件名
QString fileName = QFileInfo(filePath).fileName();
// 构造目标文件的完整路径
QString destinationFilePath = QDir(destDir).filePath(fileName);
// 如果目标文件已存在,则删除
if(QFile::exists(destinationFilePath)) {
QFile destinationFile(destinationFilePath);
if(!destinationFile.remove()) {
qWarning() << "cannot delete file:" << destinationFilePath;
return false;
}
}
// 拷贝文件
if(QFile::copy(filePath, destinationFilePath)) {
qDebug() << "file copy success:" << destinationFilePath;
return true;
} else {
qWarning() << "file copy failed:" << destinationFilePath;
return false;
}
return true;
}
bool nmCalculationUtils::createDirectoryIfNotExists(QString directoryPath) {
QDir dir(directoryPath);
// 检查目录是否存在
if(dir.exists()) {
// 目录已存在
return true;
}
// 尝试创建目录
if(dir.mkpath(directoryPath)) {
// 创建成功
return true;
}
// 创建失败
qDebug() << "创建目录失败,错误代码。";
return false;
}
bool nmCalculationUtils::copyFile(const std::string& sourcePath, const std::string& destinationPath) {
std::ifstream src(sourcePath, std::ios::binary); // 以二进制模式打开源文件
std::ofstream dst(destinationPath, std::ios::binary); // 以二进制模式打开目标文件
if(!src || !dst) {
std::cerr << "文件打开失败" << std::endl;
return false;
}
dst << src.rdbuf(); // 拷贝文件内容
return true;
}
bool nmCalculationUtils::removeDirectory(const QString &dirPath) {
QDir dir(dirPath);
if(!dir.exists()) {
qDebug() << "Directory does not exist.";
return true;
}
// 获取目录中的所有文件和目录
QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);
foreach(QFileInfo fileInfo, fileList) {
if(fileInfo.isDir()) {
// 递归删除子目录
if(!removeDirectory(fileInfo.absoluteFilePath())) {
return false;
}
} else {
// 删除文件
if(!QFile::remove(fileInfo.absoluteFilePath())) {
qDebug() << "Failed to remove file:" << fileInfo.absoluteFilePath();
return false;
}
}
}
// 删除目录自身
if(!dir.rmdir(dirPath)) {
qDebug() << "Failed to remove directory:" << dirPath;
return false;
}
return true;
}
bool nmCalculationUtils::writeFile(const QStringList& content, const QString &filePath) {
QFile file(filePath);
//检查
if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning("Cannot open file for writing: %s", qPrintable(file.errorString()));
return false;
}
QTextStream out(&file);
out << content.join("\n");
file.close();
return true;
}
QStringList nmCalculationUtils::readFile(const QString &filePath) {
QStringList content;
// 打开文件
QFile file(filePath);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Failed to open file:" << filePath;
return content;
}
// 使用QTextStream读取文件
QTextStream in(&file);
while(!in.atEnd()) {
// 读取一行
QString line = in.readLine();
// 将行内容放入QStringList
content.append(line);
}
// 关闭文件
file.close();
return content;
}
bool nmCalculationUtils::calculateKriging(
const QVector<QPointF>& targetPoints,
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
double nugget,
double sill,
double range,
int model,
const QString& licensePath,
QVector<double>& outputValues,
QString* errorMessage)
{
outputValues.clear();
setKrigingError(errorMessage, QString());
if(targetPoints.isEmpty()) {
setKrigingError(errorMessage, krigingText("No interpolation points are available."));
return false;
}
if(measurementPoints.size() < 2) {
setKrigingError(errorMessage,
krigingText("At least two measurement points are required."));
return false;
}
if(measurementPoints.size() != measurementValues.size()) {
setKrigingError(errorMessage,
krigingText("Measurement point coordinates and values do not match."));
return false;
}
if(!isFiniteValue(nugget) || !isFiniteValue(sill) ||
!isFiniteValue(range) || nugget < 0.0 || sill <= 0.0 || range <= 0.0) {
setKrigingError(errorMessage, krigingText("Kriging parameters are invalid."));
return false;
}
if(model < 0 || model > 2) {
setKrigingError(errorMessage, krigingText("The Kriging model is invalid."));
return false;
}
for(int i = 0; i < targetPoints.size(); ++i) {
if(!isFiniteValue(targetPoints[i].x()) || !isFiniteValue(targetPoints[i].y())) {
setKrigingError(errorMessage,
krigingText("An interpolation point contains an invalid coordinate."));
return false;
}
}
for(int i = 0; i < measurementPoints.size(); ++i) {
if(!isFiniteValue(measurementPoints[i].x()) ||
!isFiniteValue(measurementPoints[i].y()) ||
!isFiniteValue(measurementValues[i])) {
setKrigingError(errorMessage,
krigingText("A measurement point contains invalid data."));
return false;
}
for(int j = 0; j < i; ++j) {
if(measurementPoints[i] == measurementPoints[j]) {
setKrigingError(errorMessage,
krigingText("Measurement point coordinates cannot be duplicated."));
return false;
}
}
}
if(licensePath.isEmpty() || !QFileInfo(licensePath).exists()) {
setKrigingError(errorMessage, krigingText("The solver license file was not found."));
return false;
}
HMODULE dll = LoadLibrary(L"HX_NWTM.dll");
if(dll == NULL) {
setKrigingError(errorMessage, krigingText("Failed to load HX_NWTM.dll."));
return false;
}
typedef void (*HX_NWTM_KRINGING_Func)(HX_KRING_OUTPUT&,
const HX_KRING_INPUT,
std::string);
HX_NWTM_KRINGING_Func krigingFunction =
(HX_NWTM_KRINGING_Func)GetProcAddress(dll, "HX_NWTM_KRINGING");
if(krigingFunction == NULL) {
FreeLibrary(dll);
setKrigingError(errorMessage,
krigingText("The Kriging interface was not found in HX_NWTM.dll."));
return false;
}
// 求解器p参数每行保存{x, y}并保持targetPoints的原始顺序.
dVec2 targetData;
targetData.reserve(targetPoints.size());
for(int i = 0; i < targetPoints.size(); ++i) {
dVec1 point(2, 0.0);
point[0] = targetPoints[i].x();
point[1] = targetPoints[i].y();
targetData.push_back(point);
}
// 求解器v参数每行保存{x, y, value},坐标和值按相同下标配对.
dVec2 measurementData;
measurementData.reserve(measurementPoints.size());
for(int i = 0; i < measurementPoints.size(); ++i) {
dVec1 point(3, 0.0);
point[0] = measurementPoints[i].x();
point[1] = measurementPoints[i].y();
point[2] = measurementValues[i];
measurementData.push_back(point);
}
bool calculationSucceeded = true;
QString calculationError;
// 局部作用域保证求解器输入、输出对象在FreeLibrary前析构.
{
HX_KRING_INPUT input(nugget, sill, range, model,
targetData, measurementData);
HX_KRING_OUTPUT output;
try {
krigingFunction(output, input, licensePath.toStdString());
} catch(const std::exception& exception) {
calculationSucceeded = false;
calculationError = krigingText("Kriging calculation failed: %1")
.arg(QString::fromLocal8Bit(exception.what()));
} catch(...) {
calculationSucceeded = false;
calculationError = krigingText("Kriging calculation failed.");
}
if(calculationSucceeded &&
output.v.size() != static_cast<size_t>(targetPoints.size())) {
calculationSucceeded = false;
calculationError = krigingText(
"The Kriging result count does not match the interpolation points.");
}
if(calculationSucceeded) {
outputValues.reserve(targetPoints.size());
for(size_t i = 0; i < output.v.size(); ++i) {
if(!isFiniteValue(output.v[i])) {
calculationSucceeded = false;
calculationError = krigingText(
"The Kriging result contains an invalid value.");
break;
}
outputValues.append(output.v[i]);
}
}
}
FreeLibrary(dll);
if(!calculationSucceeded) {
outputValues.clear();
setKrigingError(errorMessage, calculationError);
}
return calculationSucceeded;
}