#include "stdafx.h"
#include "ImageOperatorBase.h"
#include "BaseTool.h"
#include "GeoOperator.h"
#include <Eigen/Core>
#include <Eigen/Dense>
#include <omp.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <gdal.h>
#include <gdal_utils.h>
#include <gdal_priv.h>
#include <gdalwarper.h>
#include <proj.h>
#include <string.h>
#include <memory>
#include <iostream>
#include "FileOperator.h"
#include <opencv2/opencv.hpp>
#include <QMessageBox>
#include <QDir>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <QProgressDialog>
#include <gdal_priv.h>
#include <ogr_spatialref.h>  // OGRSpatialReference 用于空间参考转换
#include <gdal_alg.h>        // 用于 GDALWarp 操作



/**
 *  输入数据是ENVI格式数据
 */

std::shared_ptr<GDALDataset> OpenDataset(const QString& in_path, GDALAccess rwmode)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* dataset_ptr = (GDALDataset*)(GDALOpen(in_path.toUtf8().constData(), rwmode));
	std::shared_ptr<GDALDataset> rasterDataset(dataset_ptr, CloseDataset);
	return rasterDataset;
}

void CloseDataset(GDALDataset* ptr)
{
	GDALClose(ptr);
	ptr = NULL;
}

int TIFF2ENVI(QString in_tiff_path, QString out_envi_path)
{
	std::shared_ptr<GDALDataset> ds		   = OpenDataset(in_tiff_path);
	const char*					 args[]	   = { "-of", "ENVI", NULL };
	GDALTranslateOptions*		 psOptions = GDALTranslateOptionsNew((char**)args, NULL);
	GDALClose(GDALTranslate(out_envi_path.toUtf8().constData(), ds.get(), psOptions, NULL));
	GDALTranslateOptionsFree(psOptions);
	return 0;
}

int ENVI2TIFF(QString in_envi_path, QString out_tiff_path)
{
	std::shared_ptr<GDALDataset> ds		   = OpenDataset(in_envi_path);
	const char*					 args[]	   = { "-of", "Gtiff", NULL };
	GDALTranslateOptions*		 psOptions = GDALTranslateOptionsNew((char**)args, NULL);
	GDALClose(GDALTranslate(out_tiff_path.toUtf8().constData(), ds.get(), psOptions, NULL));
	GDALTranslateOptionsFree(psOptions);
	return 0;
}

int CreateDataset(QString new_file_path, int height, int width, int band_num, double* gt,
				  QString projection, GDALDataType gdal_dtype, bool need_gt)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDriver*					 poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	std::shared_ptr<GDALDataset> poDstDS(poDriver->Create(new_file_path.toUtf8().constData(), width,
														  height, band_num, gdal_dtype, NULL));
	if(need_gt) {
		poDstDS->SetProjection(projection.toUtf8().constData());
		poDstDS->SetGeoTransform(gt);
	} else {
	}
	GDALFlushCache((GDALDatasetH)poDstDS.get());
	return 0;
}

int saveDataset(QString new_file_path, int start_line, int start_cols, int band_ids, int datacols,
				int datarows, void* databuffer)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	std::shared_ptr<GDALDataset> poDstDS	   = OpenDataset(new_file_path, GA_Update);
	GDALDataType				 gdal_datatype = poDstDS->GetRasterBand(1)->GetRasterDataType();
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_cols, start_line, datacols, datarows,
											   databuffer, datacols, datarows, gdal_datatype, 0, 0);
	GDALFlushCache(poDstDS.get());
	return 0;
}

int block_num_pre_memory(int block_width, int height, GDALDataType gdal_datatype, double memey_size)
{
	// 计算大小
	int size_meta = 0;

	if(gdal_datatype == GDT_Byte) {
		size_meta = 1;
	} else if(gdal_datatype == GDT_UInt16) {
		size_meta = 2; // 只有双通道才能构建 复数矩阵
	} else if(gdal_datatype == GDT_UInt16) {
		size_meta = 2;
	} else if(gdal_datatype == GDT_Int16) {
		size_meta = 2;
	} else if(gdal_datatype == GDT_UInt32) {
		size_meta = 4;
	} else if(gdal_datatype == GDT_Int32) {
		size_meta = 4;
	}
	// else if (gdal_datatype == GDT_UInt64) {
	//	size_meta = 8;
	// }
	// else if (gdal_datatype == GDT_Int64) {
	//	size_meta = 8;
	// }
	else if(gdal_datatype == GDT_Float32) {
		size_meta = 4;
	} else if(gdal_datatype == GDT_Float64) {
		size_meta = 4;
	} else if(gdal_datatype == GDT_CInt16) {
		size_meta = 2;
	} else if(gdal_datatype == GDT_CInt32) {
		size_meta = 2;
	} else if(gdal_datatype == GDT_CFloat32) {
		size_meta = 4;
	} else if(gdal_datatype == GDT_CFloat64) {
		size_meta = 8;
	} else {
	}
	int block_num = int(memey_size / (size_meta * block_width));
	block_num	  = block_num > height ? height : block_num; // 行数
	block_num	  = block_num < 1 ? 1 : block_num;
	return block_num;
}

Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
ReadComplexMatrixData(int start_line, int width, int line_num,
					  std::shared_ptr<GDALDataset> rasterDataset, GDALDataType gdal_datatype)
{
	int band_num = rasterDataset->GetRasterCount();
	if(gdal_datatype == 0) {
		return Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>(0, 0);
	} else if(gdal_datatype < 8) {
		if(band_num != 2) {
			return Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>(0, 0);
		}
	} else if(gdal_datatype < 12) {
		if(band_num != 1) {
			return Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>(0, 0);
		}

	} else {
	}
	bool																   _flag = false;
	Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> data_mat(
		line_num * width, 2); // 必须强制行优先
	if(gdal_datatype == GDT_Byte) {
		Eigen::MatrixX<char> real_mat(line_num * width, 1);
		Eigen::MatrixX<char> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_UInt16) {
		Eigen::MatrixX<unsigned short> real_mat(line_num * width, 1);
		Eigen::MatrixX<unsigned short> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_Int16) {
		Eigen::MatrixX<short> real_mat(line_num * width, 1);
		Eigen::MatrixX<short> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_UInt32) {
		Eigen::MatrixX<unsigned int> real_mat(line_num * width, 1);
		Eigen::MatrixX<unsigned int> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_Int32) {
		Eigen::MatrixX<int> real_mat(line_num * width, 1);
		Eigen::MatrixX<int> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	}
	// else if (gdal_datatype == GDT_UInt64) {
	//	Eigen::MatrixX<unsigned long> real_mat(line_num * width, 1);
	//	Eigen::MatrixX<unsigned long> imag_mat(line_num * width, 1);
	//	rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
	//real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real
	//	rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
	//imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag 	data_mat.col(0) =
	//(real_mat.array().cast<double>()).array(); 	data_mat.col(1) =
	//(imag_mat.array().cast<double>()).array(); 	_flag = true;
	// }
	// else if (gdal_datatype == GDT_Int64) {
	//	Eigen::MatrixX<long> real_mat(line_num * width, 1);
	//	Eigen::MatrixX<long> imag_mat(line_num * width, 1);
	//	rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
	//real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real
	//	rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
	//imag_mat.data(), width, line_num, gdal_datatype, 0, 0); // imag 	data_mat.col(0) =
	//(real_mat.array().cast<double>()).array(); 	data_mat.col(1) =
	//(imag_mat.array().cast<double>()).array(); 	_flag = true;
	// }
	else if(gdal_datatype == GDT_Float32) {
		Eigen::MatrixX<float> real_mat(line_num * width, 1);
		Eigen::MatrixX<float> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_Float64) {
		Eigen::MatrixX<double> real_mat(line_num * width, 1);
		Eigen::MatrixX<double> imag_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  real_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // real
		rasterDataset->GetRasterBand(2)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  imag_mat.data(), width, line_num, gdal_datatype,
												  0, 0); // imag
		data_mat.col(0) = (real_mat.array().cast<double>()).array();
		data_mat.col(1) = (imag_mat.array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_CInt16) {
		Eigen::MatrixX<std::complex<short>> complex_short_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  complex_short_mat.data(), width, line_num,
												  gdal_datatype, 0, 0); // real
		data_mat.col(0) = (complex_short_mat.real().array().cast<double>()).array();
		data_mat.col(1) = (complex_short_mat.imag().array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_CInt32) {
		Eigen::MatrixX<std::complex<int>> complex_short_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  complex_short_mat.data(), width, line_num,
												  gdal_datatype, 0, 0); // real
		data_mat.col(0) = (complex_short_mat.real().array().cast<double>()).array();
		data_mat.col(1) = (complex_short_mat.imag().array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_CFloat32) {
		Eigen::MatrixX<std::complex<double>> complex_short_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  complex_short_mat.data(), width, line_num,
												  gdal_datatype, 0, 0); // real
		data_mat.col(0) = (complex_short_mat.real().array().cast<double>()).array();
		data_mat.col(1) = (complex_short_mat.imag().array().cast<double>()).array();
		_flag			= true;
	} else if(gdal_datatype == GDT_CFloat64) {
		Eigen::MatrixX<std::complex<double>> complex_short_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(1)->RasterIO(GF_Read, 0, start_line, width, line_num,
												  complex_short_mat.data(), width, line_num,
												  gdal_datatype, 0, 0); // real
		data_mat.col(0) = (complex_short_mat.real().array().cast<double>()).array();
		data_mat.col(1) = (complex_short_mat.imag().array().cast<double>()).array();
		_flag			= true;
	} else {
	}
	// 保存数据

	if(_flag) {
		return data_mat;
	} else {
		return Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>(
			0, 0); // 必须强制行优先;
	}
}

Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
ReadMatrixDoubleData(int start_line, int width, int line_num,
					 std::shared_ptr<GDALDataset> rasterDataset, GDALDataType gdal_datatype,
					 int band_idx)
{
	// 构建矩阵块，使用eigen 进行矩阵计算，加速计算
	bool																   _flag = false;
	Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> data_mat(
		line_num * width, 1); // 必须强制行优先
	if(gdal_datatype == GDT_Byte) {
		Eigen::MatrixX<char> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	} else if(gdal_datatype == GDT_UInt16) {
		Eigen::MatrixX<unsigned short> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	} else if(gdal_datatype == GDT_Int16) {
		Eigen::MatrixX<short> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	} else if(gdal_datatype == GDT_UInt32) {
		Eigen::MatrixX<unsigned int> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	} else if(gdal_datatype == GDT_Int32) {
		Eigen::MatrixX<int> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	}
	// else if (gdal_datatype == GDT_UInt64) {
	//	Eigen::MatrixX<unsigned long> real_mat(line_num * width, 1);
	//	rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
	//real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real 	data_mat.col(0) =
	//((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0; 	_flag = true;
	// }
	// else if (gdal_datatype == GDT_Int64) {
	//	Eigen::MatrixX<long> real_mat(line_num * width, 1);
	//	rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
	//real_mat.data(), width, line_num, gdal_datatype, 0, 0); // real 	data_mat.col(0) =
	//((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0; 	_flag = true;
	// }
	else if(gdal_datatype == GDT_Float32) {
		Eigen::MatrixX<float> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	} else if(gdal_datatype == GDT_Float64) {
		Eigen::MatrixX<double> real_mat(line_num * width, 1);
		rasterDataset->GetRasterBand(band_idx)->RasterIO(GF_Read, 0, start_line, width, line_num,
														 real_mat.data(), width, line_num,
														 gdal_datatype, 0, 0); // real
		data_mat.col(0) = ((real_mat.array().cast<double>()).array().pow(2)).log10() * 10.0;
		_flag			= true;
	} else {
	}

	return data_mat;
}

Eigen::MatrixXd getGeoTranslationArray(QString in_path)
{
	return Eigen::MatrixXd();
}

ImageGEOINFO getImageINFO(QString in_path)
{
	std::shared_ptr<GDALDataset> df		  = OpenDataset(in_path);
	int							 width	  = df->GetRasterXSize();
	int							 heigh	  = df->GetRasterYSize();
	int							 band_num = df->GetRasterCount();
	ImageGEOINFO				 result;
	result.width   = width;
	result.height  = heigh;
	result.bandnum = band_num;

	return result;
}

GDALDataType getGDALDataType(QString fileptah)
{
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(
		fileptah.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();

	GDALClose((GDALDatasetH)rasterDataset);
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷

	return gdal_datatype;
}

gdalImage::gdalImage()
{
	this->height		= 0;
	this->width			= 0;
	this->data_band_ids = 1;
	this->start_row		= 0;
	this->start_col		= 0;
}

/// <summary>
/// 斤拷图饺∮帮拷锟?1锟?7
/// </summary>
/// <param name="dem_path"></param>
gdalImage::gdalImage(const QString& raster_path)
{
	omp_lock_t lock;
	omp_init_lock(&lock); // 锟斤拷始斤拷斤拷
	omp_set_lock(&lock);  // 锟斤拷没斤拷锟?1锟?7
	this->img_path = raster_path;

	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注绞斤拷斤拷锟?1锟?7
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	// 锟斤拷DEM影锟斤拷
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(
		raster_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷
	this->width				   = rasterDataset->GetRasterXSize();
	this->height			   = rasterDataset->GetRasterYSize();
	this->band_num			   = rasterDataset->GetRasterCount();

	double* gt				   = new double[6];
	// 锟斤拷梅斤拷锟斤拷
	rasterDataset->GetGeoTransform(gt);
	this->gt = Eigen::MatrixXd(2, 3);
	this->gt << gt[0], gt[1], gt[2], gt[3], gt[4], gt[5];

	this->projection = rasterDataset->GetProjectionRef();
	// 斤拷斤拷
	// double* inv_gt = new double[6];;
	// GDALInvGeoTransform(gt, inv_gt); // 斤拷斤拷
	// 斤拷投影
	GDALFlushCache((GDALDatasetH)rasterDataset);
	GDALClose((GDALDatasetH)rasterDataset);
	rasterDataset = NULL; // 指矫匡拷
	this->InitInv_gt();
	delete[] gt;
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}

gdalImage::~gdalImage() {}

void gdalImage::setHeight(int height)
{
	this->height = height;
}

void gdalImage::setWidth(int width)
{
	this->width = width;
}

void gdalImage::setTranslationMatrix(Eigen::MatrixXd gt)
{
	this->gt = gt;
}

void gdalImage::setData(Eigen::MatrixXd, int data_band_ids)
{
	this->data			= data;
	this->data_band_ids = data_band_ids;
}

Eigen::MatrixXd gdalImage::getData(int start_row, int start_col, int rows_count, int cols_count,
								   int band_ids = 1)
{
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset*	rasterDataset = (GDALDataset*)(GDALOpen(
		   this->img_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType	gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	GDALRasterBand* demBand		  = rasterDataset->GetRasterBand(band_ids);

	rows_count = start_row + rows_count <= this->height ? rows_count : this->height - start_row;
	cols_count = start_col + cols_count <= this->width ? cols_count : this->width - start_col;

	Eigen::MatrixXd datamatrix(rows_count, cols_count);

	if(gdal_datatype == GDT_Byte) {
		char* temp = new char[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);
		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	} else if(gdal_datatype == GDT_UInt16) {
		unsigned short* temp = new unsigned short[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);
		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	} else if(gdal_datatype == GDT_Int16) {
		short* temp = new short[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);
		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	} else if(gdal_datatype == GDT_UInt32) {
		unsigned int* temp = new unsigned int[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);
		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	} else if(gdal_datatype == GDT_Int32) {
		int* temp = new int[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);
		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	//else if (gdal_datatype == GDT_UInt64) {
	//	unsigned long* temp = new unsigned long[rows_count * cols_count];
	//	demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
	//		rows_count, gdal_datatype, 0, 0); 	for (int i = 0; i < rows_count; i++) {
	//		for (int j = 0; j <
	//			cols_count; j++) {
	//			datamatrix(i, j) = temp[i * cols_count + j];
	//		}
	//	}
	//	delete[] temp;
	//}
	//else if (gdal_datatype == GDT_Int64) {
	//	long* temp = new long[rows_count * cols_count];
	//	demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
	//		rows_count, gdal_datatype, 0, 0); 	for (int i = 0; i < rows_count; i++) {
	//		for (int j = 0; j <
	//			cols_count; j++) {
	//			datamatrix(i, j) = temp[i * cols_count + j];
	//		}
	//	}
	//	delete[] temp;
	//}
	else if(gdal_datatype == GDT_Float32) {
		float* temp = new float[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);

		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	} else if(gdal_datatype == GDT_Float64) {
		double* temp = new double[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
						  rows_count, gdal_datatype, 0, 0);

		for(int i = 0; i < rows_count; i++) {
			for(int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	} else {
	}
	GDALClose((GDALDatasetH)rasterDataset);
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	return datamatrix;
}

Eigen::MatrixXf gdalImage::getDataf(int start_row, int start_col, int rows_count, int cols_count,
	int band_ids = 1)
{
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(
		this->img_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType	gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	GDALRasterBand* demBand = rasterDataset->GetRasterBand(band_ids);

	rows_count = start_row + rows_count <= this->height ? rows_count : this->height - start_row;
	cols_count = start_col + cols_count <= this->width ? cols_count : this->width - start_col;

	Eigen::MatrixXf datamatrix(rows_count, cols_count);

	if (gdal_datatype == GDT_Byte) {
		char* temp = new char[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_UInt16) {
		unsigned short* temp = new unsigned short[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_Int16) {
		short* temp = new short[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_UInt32) {
		unsigned int* temp = new unsigned int[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_Int32) {
		int* temp = new int[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	//else if (gdal_datatype == GDT_UInt64) {
	//	unsigned long* temp = new unsigned long[rows_count * cols_count];
	//	demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
	//		rows_count, gdal_datatype, 0, 0); 	for (int i = 0; i < rows_count; i++) {
	//		for (int j = 0; j <
	//			cols_count; j++) {
	//			datamatrix(i, j) = temp[i * cols_count + j];
	//		}
	//	}
	//	delete[] temp;
	//}
	//else if (gdal_datatype == GDT_Int64) {
	//	long* temp = new long[rows_count * cols_count];
	//	demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
	//		rows_count, gdal_datatype, 0, 0); 	for (int i = 0; i < rows_count; i++) {
	//		for (int j = 0; j <
	//			cols_count; j++) {
	//			datamatrix(i, j) = temp[i * cols_count + j];
	//		}
	//	}
	//	delete[] temp;
	//}
	else if (gdal_datatype == GDT_Float32) {
		float* temp = new float[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);

		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_Float64) {
		double* temp = new double[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);

		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else {
	}
	GDALClose((GDALDatasetH)rasterDataset);
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	return datamatrix;
}



Eigen::MatrixXi gdalImage::getDatai(int start_row, int start_col, int rows_count, int cols_count, int band_ids)
{
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(
		this->img_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType	gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	GDALRasterBand* demBand = rasterDataset->GetRasterBand(band_ids);

	rows_count = start_row + rows_count <= this->height ? rows_count : this->height - start_row;
	cols_count = start_col + cols_count <= this->width ? cols_count : this->width - start_col;

	Eigen::MatrixXi datamatrix(rows_count, cols_count);

	if (gdal_datatype == GDT_Byte) {
		char* temp = new char[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_UInt16) {
		unsigned short* temp = new unsigned short[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_Int16) {
		short* temp = new short[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_UInt32) {
		unsigned int* temp = new unsigned int[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_Int32) {
		int* temp = new int[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);
		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	//else if (gdal_datatype == GDT_UInt64) {
	//	unsigned long* temp = new unsigned long[rows_count * cols_count];
	//	demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
	//		rows_count, gdal_datatype, 0, 0); 	for (int i = 0; i < rows_count; i++) {
	//		for (int j = 0; j <
	//			cols_count; j++) {
	//			datamatrix(i, j) = temp[i * cols_count + j];
	//		}
	//	}
	//	delete[] temp;
	//}
	//else if (gdal_datatype == GDT_Int64) {
	//	long* temp = new long[rows_count * cols_count];
	//	demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,	rows_count, gdal_datatype, 0, 0); 
	//	for (int i = 0; i < rows_count; i++) {
	//		for (int j = 0; j <	cols_count; j++) {
	//			datamatrix(i, j) = temp[i * cols_count + j];
	//		}
	//	}
	//	delete[] temp;
	//}
	else if (gdal_datatype == GDT_Float32) {
		float* temp = new float[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);

		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else if (gdal_datatype == GDT_Float64) {
		double* temp = new double[rows_count * cols_count];
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp, cols_count,
			rows_count, gdal_datatype, 0, 0);

		for (int i = 0; i < rows_count; i++) {
			for (int j = 0; j < cols_count; j++) {
				datamatrix(i, j) = temp[i * cols_count + j];
			}
		}
		delete[] temp;
	}
	else {
	}
	GDALClose((GDALDatasetH)rasterDataset);
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	return datamatrix;
}

ErrorCode gdalImage::getData(double* data, int start_row, int start_col, int rows_count, int cols_count, int band_ids)
{
	ErrorCode state  =ErrorCode::SUCCESS;
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType	gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	GDALRasterBand* demBand = rasterDataset->GetRasterBand(band_ids);

	rows_count = start_row + rows_count <= this->height ? rows_count : this->height - start_row;
	cols_count = start_col + cols_count <= this->width ? cols_count : this->width - start_col;



	if (gdal_datatype == GDT_Float64) {
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, data, cols_count,rows_count, gdal_datatype, 0, 0);
	}
	else {
		state = ErrorCode::FAIL;
	}
	GDALClose((GDALDatasetH)rasterDataset);
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
	return state;
}

ErrorCode gdalImage::getData(long* data, int start_row, int start_col, int rows_count, int cols_count, int band_ids)
{
	ErrorCode state = ErrorCode::SUCCESS;
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType	gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	GDALRasterBand* demBand = rasterDataset->GetRasterBand(band_ids);

	rows_count = start_row + rows_count <= this->height ? rows_count : this->height - start_row;
	cols_count = start_col + cols_count <= this->width ? cols_count : this->width - start_col;

	if (gdal_datatype == GDT_Int32) {
		demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, data, cols_count,rows_count, gdal_datatype, 0, 0);
	}
	else {
		state = ErrorCode::FAIL;
	}
	GDALClose((GDALDatasetH)rasterDataset);
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
	return state;
}

Eigen::MatrixXd gdalImage::getGeoTranslation()
{
	return this->gt;
}

GDALDataType gdalImage::getDataType()
{
	GDALDataset* rasterDataset =
		(GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly));
	GDALDataType gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	return gdal_datatype;
}

/// <summary>
/// 
/// </summary>
/// <param name="data"></param>
/// <param name="start_row"></param>
/// <param name="start_col"></param>
/// <param name="band_ids"></param>
void gdalImage::saveImage(Eigen::MatrixXd data, int start_row = 0, int start_col = 0,
						  int band_ids = 1)
{
	GDALDataType datetype = this->getDataType();
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if(start_row + data.rows() > this->height || start_col + data.cols() > this->width) {
		QString tip = u8"file path: " + this->img_path+" image size :(  "+QString::number(this->height)+" , "+ QString::number(this->width)+" ) "+" input size ("+ QString::number(start_row + data.rows())+", "+ QString::number(start_col + data.cols())+") ";
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");

	QString filesuffer = getFileExtension(this->img_path).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver*	 poDriver = isTiff? GetGDALDriverManager()->GetDriverByName("GTiff"): GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS  = nullptr;
	if(exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	} else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
								   this->band_num, datetype, NULL); // 斤拷锟斤拷

		if (nullptr == poDstDS) {
			QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + data.rows()) + ", " + QString::number(start_col + data.cols()) + ") ";
			qDebug() << tip;
			throw std::exception(tip.toUtf8().constData());
			return;
		}

		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for(int i = 0; i < this->gt.rows(); i++) {
			for(int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
		//delete gt_ptr;
	}


	int	   datarows = data.rows();
	int	   datacols = data.cols();
	void* databuffer = nullptr;
	if (datetype == GDT_Float32) {
		 databuffer = new float[datarows * datacols];
		for (int i = 0; i < datarows; i++) {
			for (int j = 0; j < datacols; j++) {
				((float*)databuffer)[i * datacols + j] = float(data(i, j));
			}
		}

		poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
			databuffer, datacols, datarows, datetype, 0, 0);
	}
	else if (datetype == GDT_Float64) {
		 databuffer = new double[datarows * datacols];
		for (int i = 0; i < datarows; i++) {
			for (int j = 0; j < datacols; j++) {
				((double*)databuffer)[i * datacols + j] = double(data(i, j));
			}
		}

		poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
			databuffer, datacols, datarows, datetype, 0, 0);
	}
	else {

	}
	GDALFlushCache(poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	delete[] databuffer;
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}

void gdalImage::saveImage(Eigen::MatrixXf data, int start_row = 0, int start_col = 0,
	int band_ids = 1)
{
	GDALDataType datetype = this->getDataType();
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if (start_row + data.rows() > this->height || start_col + data.cols() > this->width) {
		QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + data.rows()) + ", " + QString::number(start_col + data.cols()) + ") ";
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	QString filesuffer = getFileExtension(this->img_path).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* poDriver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = nullptr;
	if (exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	}
	else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
			this->band_num, datetype, NULL); // 斤拷锟斤拷

		if (nullptr == poDstDS) {
			QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + data.rows()) + ", " + QString::number(start_col + data.cols()) + ") ";
			qDebug() << tip;
			throw std::exception(tip.toUtf8().constData());
			return;
		}

		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for (int i = 0; i < this->gt.rows(); i++) {
			for (int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
		//delete gt_ptr;
	}


	int	   datarows = data.rows();
	int	   datacols = data.cols();
	void* databuffer = nullptr;
	if (datetype == GDT_Float32) {
		databuffer = new float[datarows * datacols];
		for (int i = 0; i < datarows; i++) {
			for (int j = 0; j < datacols; j++) {
				((float*)databuffer)[i * datacols + j] = float(data(i, j));
			}
		}

		poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
			databuffer, datacols, datarows, datetype, 0, 0);
	}
	else if (datetype == GDT_Float64) {
		databuffer = new double[datarows * datacols];
		for (int i = 0; i < datarows; i++) {
			for (int j = 0; j < datacols; j++) {
				((double*)databuffer)[i * datacols + j] = double(data(i, j));
			}
		}

		poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
			databuffer, datacols, datarows, datetype, 0, 0);
	}
	else {

	}
	GDALFlushCache(poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	delete[] databuffer;
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}


void gdalImage::saveImage(Eigen::MatrixXi data, int start_row, int start_col, int band_ids)
{
	GDALDataType datetype=this->getDataType();
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if (start_row + data.rows() > this->height || start_col + data.cols() > this->width) {
		QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + data.rows()) + ", " + QString::number(start_col + data.cols()) + ") ";
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	QString filesuffer = getFileExtension(this->img_path).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* poDriver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = nullptr;
	if (exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	}
	else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
			this->band_num, GDT_Float32, NULL); // 斤拷锟斤拷
		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for (int i = 0; i < this->gt.rows(); i++) {
			for (int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
		//delete gt_ptr;
	}

	long	   datarows = data.rows();
	long	   datacols = data.cols();

	long* databuffer =	new long[datarows * datacols]; // (float*)malloc(datarows * datacols * sizeof(float));

	for (long i = 0; i < datarows; i++) {
		for (long j = 0; j < datacols; j++) {
			databuffer[i * datacols + j] = data(i, j);
		}
	}
	// poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols,
	// datarows, GDT_Float32,band_ids, num,0,0,0);
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
		databuffer, datacols, datarows, datetype, 0, 0);

	GDALFlushCache(poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	delete[] databuffer;
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}

void gdalImage::saveImage(std::shared_ptr<double> data, int start_row, int start_col, int rowcount, int colcount, int band_ids)
{
	GDALDataType datetype = this->getDataType();
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if (start_row + rowcount > this->height || start_col + colcount > this->width) {
		QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + rowcount) + ", " + QString::number(start_col + colcount) + ") ";
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	QString filesuffer = getFileExtension(this->img_path).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* poDriver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = nullptr;
	if (exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	}
	else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
			this->band_num, GDT_Float32, NULL); // 斤拷锟斤拷
		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for (int i = 0; i < this->gt.rows(); i++) {
			for (int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}

	long datarows = rowcount;
	long datacols = colcount;
	double* databuffer = new double[datarows * datacols];
	if (datetype == GDT_Float64) {
		memcpy(databuffer, data.get(), sizeof(double) * datarows * datacols);
	}
	else {
		for (long i = 0; i < datarows; i++) {
			for (long j = 0; j < datacols; j++) {
				databuffer[i * datacols + j] = data.get()[i * datacols + j];
			}
		}
	}

	// poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols,
	// datarows, GDT_Float32,band_ids, num,0,0,0);
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
		databuffer, datacols, datarows, datetype, 0, 0);

	GDALFlushCache(poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	delete[] databuffer;
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}

void gdalImage::saveImage(std::shared_ptr<float> data, int start_row, int start_col, int rowcount, int colcount, int band_ids)
{
	GDALDataType datetype = this->getDataType();
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if (start_row + rowcount > this->height || start_col + colcount > this->width) {
		QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + rowcount) + ", " + QString::number(start_col + colcount) + ") ";
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	QString filesuffer = getFileExtension(this->img_path).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* poDriver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = nullptr;
	if (exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	}
	else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
			this->band_num, GDT_Float32, NULL); // 斤拷锟斤拷
		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for (int i = 0; i < this->gt.rows(); i++) {
			for (int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}

	long datarows = rowcount;
	long datacols = colcount;
	float* databuffer = new float[datarows * datacols];
	if (datetype == GDT_Float32) {
		memcpy(databuffer, data.get(), sizeof(float) * datarows * datacols);
	}
	else {
		for (long i = 0; i < datarows; i++) {
			for (long j = 0; j < datacols; j++) {
				databuffer[i * datacols + j] = data.get()[i * datacols + j];
			}
		}
	}

	// poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols,
	// datarows, GDT_Float32,band_ids, num,0,0,0);
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
		databuffer, datacols, datarows, datetype, 0, 0);

	GDALFlushCache(poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	//delete poDstDS;
	//poDstDS = nullptr;
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	delete[] databuffer;
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}


void gdalImage::saveImage(std::shared_ptr<int> data, int start_row, int start_col, int rowcount, int colcount, int band_ids)
{
	GDALDataType datetype = this->getDataType();
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if (start_row + rowcount > this->height || start_col + colcount > this->width) {
		QString tip = u8"file path: " + this->img_path + " image size :(  " + QString::number(this->height) + " , " + QString::number(this->width) + " ) " + " input size (" + QString::number(start_row + rowcount) + ", " + QString::number(start_col + colcount) + ") ";
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	QString filesuffer = getFileExtension(this->img_path).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* poDriver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = nullptr;
	if (exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	}
	else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
			this->band_num, GDT_Float32, NULL); // 斤拷锟斤拷
		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for (int i = 0; i < this->gt.rows(); i++) {
			for (int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}

	long datarows = rowcount;
	long datacols = colcount;
	int* databuffer = new int[datarows * datacols];
	if (datetype == GDT_Int32) {
		memcpy(databuffer, data.get(), sizeof(int) * datarows * datacols);
	}
	else {
		for (long i = 0; i < datarows; i++) {
			for (long j = 0; j < datacols; j++) {
				databuffer[i * datacols + j] = data.get()[i * datacols + j];
			}
		}
	}

	// poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols,
	// datarows, GDT_Float32,band_ids, num,0,0,0);
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
		databuffer, datacols, datarows, datetype, 0, 0);

	GDALFlushCache(poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	delete[] databuffer;
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}


void gdalImage::saveImage()
{
	this->saveImage(this->data, this->start_row, this->start_col, this->data_band_ids);
}

void gdalImage::setNoDataValue(double nodatavalue = -9999, int band_ids = 1)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注绞斤拷斤拷锟?1锟?7
	// GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	GDALDataset* poDstDS = (GDALDataset*)(GDALOpen(img_path.toUtf8().constData(), GA_Update));
	poDstDS->GetRasterBand(band_ids)->SetNoDataValue(nodatavalue);
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
}

void gdalImage::setNoDataValuei(int nodatavalue, int band_ids)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注绞斤拷斤拷锟?1锟?7
	// GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	GDALDataset* poDstDS = (GDALDataset*)(GDALOpen(img_path.toUtf8().constData(), GA_Update));
	poDstDS->GetRasterBand(band_ids)->SetNoDataValue(nodatavalue);
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
}

double gdalImage::getNoDataValue(int band_ids)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注绞斤拷斤拷锟?1锟?7
	// GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	GDALDataset* poDstDS = (GDALDataset*)(GDALOpen(img_path.toUtf8().constData(), GA_Update));
	double v= poDstDS->GetRasterBand(band_ids)->GetNoDataValue( );
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	return v;
}

int gdalImage::getNoDataValuei(int band_ids)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注绞斤拷斤拷锟?1锟?7
	// GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	GDALDataset* poDstDS = (GDALDataset*)(GDALOpen(img_path.toUtf8().constData(), GA_Update));
	int v= poDstDS->GetRasterBand(band_ids)->GetNoDataValue( );
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	return v;
}
 

int gdalImage::InitInv_gt()
{
	// 1 lon lat = x
	// 1 lon lat = y
	Eigen::MatrixXd temp = Eigen::MatrixXd::Zero(2, 3);
	this->inv_gt		 = temp;
	double a			 = this->gt(0, 0);
	double b			 = this->gt(0, 1);
	double c			 = this->gt(0, 2);
	double d			 = this->gt(1, 0);
	double e			 = this->gt(1, 1);
	double f			 = this->gt(1, 2);
	double g			 = 1;
	double det_gt		 = b * f - c * e;
	if(det_gt == 0) {
		return 0;
	}
	this->inv_gt(0, 0) = (c * d - a * f) / det_gt; // 2
	this->inv_gt(0, 1) = f / det_gt;			   // lon
	this->inv_gt(0, 2) = -c / det_gt;			   // lat
	this->inv_gt(1, 0) = (a * e - b * d) / det_gt; // 1
	this->inv_gt(1, 1) = -e / det_gt;			   // lon
	this->inv_gt(1, 2) = b / det_gt;			   // lat
	return 1;
}

Landpoint gdalImage::getRow_Col(double lon, double lat)
{
	Landpoint p{ 0, 0, 0 };
	p.lon = this->inv_gt(0, 0) + lon * this->inv_gt(0, 1) + lat * this->inv_gt(0, 2); // x
	p.lat = this->inv_gt(1, 0) + lon * this->inv_gt(1, 1) + lat * this->inv_gt(1, 2); // y
	return p;
}

Landpoint gdalImage::getLandPoint(double row, double col, double ati = 0)
{
	Landpoint p{ 0, 0, 0 };
	p.lon = this->gt(0, 0) + col * this->gt(0, 1) + row * this->gt(0, 2); // x
	p.lat = this->gt(1, 0) + col * this->gt(1, 1) + row * this->gt(1, 2); // y
	p.ati = ati;
	return p;
}

void gdalImage::getLandPoint(double  row, double  col, double  ati, Landpoint& Lp)
{
	Lp.lon = this->gt(0, 0) + col * this->gt(0, 1) + row * this->gt(0, 2); // x
	Lp.lat = this->gt(1, 0) + col * this->gt(1, 1) + row * this->gt(1, 2); // y
	Lp.ati = ati;

}






double gdalImage::mean(int bandids)
{
	double mean_value  = 0;
	double count	   = this->height * this->width;
	int	   line_invert = 100;
	int	   start_ids   = 0;
	do {
		Eigen::MatrixXd sar_a = this->getData(start_ids, 0, line_invert, this->width, bandids);
		mean_value			  = mean_value + sar_a.sum() / count;
		start_ids			  = start_ids + line_invert;
	} while(start_ids < this->height);
	return mean_value;
}

double gdalImage::BandmaxValue(int bandids)
{
	double max_value   = 0;
	bool   state_max   = true;
	int	   line_invert = 100;
	int	   start_ids   = 0;
	double temp_max	   = 0;
	do {
		Eigen::MatrixXd sar_a = this->getData(start_ids, 0, line_invert, this->width, bandids);
		if(state_max) {
			state_max = false;
			max_value = sar_a.maxCoeff();
		} else {
			temp_max = sar_a.maxCoeff();
			if(max_value < temp_max) {
				max_value = temp_max;
			}
		}
		start_ids = start_ids + line_invert;
	} while(start_ids < this->height);
	return max_value;
}

double gdalImage::BandminValue(int bandids)
{
	double min_value   = 0;
	bool   state_min   = true;
	int	   line_invert = 100;
	int	   start_ids   = 0;
	double temp_min	   = 0;
	do {
		Eigen::MatrixXd sar_a = this->getData(start_ids, 0, line_invert, this->width, bandids);
		if(state_min) {
			state_min = false;
			min_value = sar_a.minCoeff();
		} else {
			temp_min = sar_a.minCoeff();
			if(min_value < temp_min) {
				min_value = temp_min;
			}
		}
		start_ids = start_ids + line_invert;
	} while(start_ids < this->height);
	return min_value;
}

GDALRPCInfo gdalImage::getRPC()
{
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	CPLSetConfigOption("GDAL_DATA", "./data");
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注斤拷锟斤拷
	// 斤拷锟斤拷
	GDALDataset* pDS = (GDALDataset*)GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly);
	// 锟斤拷元斤拷锟叫伙拷取RPC锟斤拷息
	char**		 papszRPC = pDS->GetMetadata("RPC");

	// 斤拷取锟斤拷RPC锟斤拷息斤拷山峁癸拷锟?1锟?7
	GDALRPCInfo	 oInfo;
	GDALExtractRPCInfo(papszRPC, &oInfo);

	GDALClose((GDALDatasetH)pDS);

	return oInfo;
}

Eigen::MatrixXd gdalImage::getLandPoint(Eigen::MatrixXd points)
{
	if(points.cols() != 3) {
		throw new std::exception("the size of points is equit 3!!!");
	}

	Eigen::MatrixXd result(points.rows(), 3);
	result.col(2) = points.col(2); // 锟竭筹拷
	points.col(2) = points.col(2).array() * 0 + 1;
	points.col(0).swap(points.col(2)); // 斤拷
	Eigen::MatrixXd gts(3, 2);
	gts.col(0)							 = this->gt.row(0);
	gts.col(1)							 = this->gt.row(1);

	result.block(0, 0, points.rows(), 2) = points * gts;
	return result;
}

Eigen::MatrixXd gdalImage::getHist(int bandids)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注绞斤拷斤拷锟?1锟?7
	// 锟斤拷DEM影锟斤拷
	GDALDataset*	rasterDataset = (GDALDataset*)(GDALOpen(
		   this->img_path.toUtf8().constData(), GA_ReadOnly)); // 锟斤拷只斤拷式锟斤拷取斤拷影锟斤拷

	GDALDataType	gdal_datatype = rasterDataset->GetRasterBand(1)->GetRasterDataType();
	GDALRasterBand* xBand		  = rasterDataset->GetRasterBand(bandids);

	double			dfMin		  = this->BandminValue(bandids);
	double			dfMax		  = this->BandmaxValue(bandids);
	int				count		  = int((dfMax - dfMin) / 0.01);
	count						  = count > 255 ? count : 255;
	GUIntBig* panHistogram		  = new GUIntBig[count];
	xBand->GetHistogram(dfMin, dfMax, count, panHistogram, TRUE, FALSE, NULL, NULL);
	Eigen::MatrixXd result(count, 2);
	double			delta = (dfMax - dfMin) / count;
	for(int i = 0; i < count; i++) {
		result(i, 0) = dfMin + i * delta;
		result(i, 1) = double(panHistogram[i]);
	}
	delete[] panHistogram;
	GDALClose((GDALDatasetH)rasterDataset);
	return result;
}

RasterExtend gdalImage::getExtend()
{
	RasterExtend extend{ 0,0,0,0 };
	double x1 = this->gt(0, 0);
	double y1 = this->gt(1, 0);

	double x2 = this->gt(0, 0) + (this->width - 1) * gt(0, 1) + (0) * gt(0, 2);
	double y2 = this->gt(1, 0) + (this->width - 1) * gt(1, 1) + (0) * gt(1, 2);

	double x3 = this->gt(0, 0) + (0) * gt(0, 1) + (this->height - 1) * gt(0, 2);
	double y3 = this->gt(1, 0) + (0) * gt(1, 1) + (this->height - 1) * gt(1, 2);

	double x4 = this->gt(0, 0) + (this->width - 1) * gt(0, 1) + (this->height - 1) * gt(0, 2);
	double y4 = this->gt(1, 0) + (this->width - 1) * gt(1, 1) + (this->height - 1) * gt(1, 2);


	extend.min_x = x1 < x2 ? x1 : x2;
	extend.max_x = x1 < x2 ? x2 : x1;
	extend.min_y = y1 < y2 ? y1 : y2;
	extend.max_y = y1 < y2 ? y2 : y1;


	extend.min_x = extend.min_x < x3 ? extend.min_x : x3;
	extend.max_x = extend.max_x > x3 ? extend.max_x : x3;
	extend.min_y = extend.min_y < y3 ? extend.min_y : y3;
	extend.max_y = extend.max_y > y3 ? extend.max_y : y3;


	extend.min_x = extend.min_x < x4 ? extend.min_x : x4;
	extend.max_x = extend.max_x > x4 ? extend.max_x : x4;
	extend.min_y = extend.min_y < y4 ? extend.min_y : y4;
	extend.max_y = extend.max_y > y4 ? extend.max_y : y4;
 
	return extend;
}

gdalImage CreategdalImageDouble(const QString& img_path, int height, int width, int band_num, Eigen::MatrixXd gt, QString projection, bool need_gt, bool overwrite, bool isEnvi)
{
	if (exists_test(img_path.toUtf8().constData())) {
		if (overwrite) {
			gdalImage result_img(img_path);
			return result_img;
		}
		else {
			throw "file has exist!!!";
			exit(1);
		}
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注锟斤拷锟绞斤拷锟斤拷锟斤拷锟?1锟?7
	GDALDriver* poDriver = nullptr;
	if (isEnvi) {
		poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	}
	else {
		poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	}


	GDALDataset* poDstDS = poDriver->Create(img_path.toUtf8().constData(), width, height, band_num,
		GDT_Float64, NULL); // 锟斤拷锟斤拷锟斤拷
	if (need_gt) {
		if (!projection.isEmpty()) {
			poDstDS->SetProjection(projection.toUtf8().constData());
		}
		double gt_ptr[6] = { 0 };
		for (int i = 0; i < gt.rows(); i++) {
			for (int j = 0; j < gt.cols(); j++) {
				gt_ptr[i * 3 + j] = gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}
	for (int i = 1; i <= band_num; i++) {
		poDstDS->GetRasterBand(i)->SetNoDataValue(-9999);
	}
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	gdalImage result_img(img_path);
	return result_img;
}

gdalImage CreategdalImage(const QString& img_path, int height, int width, int band_num,
						  Eigen::MatrixXd gt, QString projection, bool need_gt, bool overwrite, bool isEnvi)
{
	if(exists_test(img_path.toUtf8().constData())) {
		if(overwrite) {
			gdalImage result_img(img_path);
			return result_img;
		} else {
			throw "file has exist!!!";
			exit(1);
		}
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注锟斤拷锟绞斤拷锟斤拷锟斤拷锟?1锟?7
	GDALDriver* poDriver = nullptr;
	if (isEnvi) {
		poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	}
	else {
		poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	}
	

	GDALDataset* poDstDS  = poDriver->Create(img_path.toUtf8().constData(), width, height, band_num,
											 GDT_Float32, NULL); // 锟斤拷锟斤拷锟斤拷
	if(need_gt) {
		if (!projection.isEmpty()) {
			poDstDS->SetProjection(projection.toUtf8().constData());
		}
		double gt_ptr[6] = { 0 };
		for(int i = 0; i < gt.rows(); i++) {
			for(int j = 0; j < gt.cols(); j++) {
				gt_ptr[i * 3 + j] = gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}
	for(int i = 1; i <= band_num; i++) {
		poDstDS->GetRasterBand(i)->SetNoDataValue(-9999);
	}
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	gdalImage result_img(img_path);
	return result_img;
}

gdalImage CreategdalImage(const QString& img_path, int height, int width, int band_num, Eigen::MatrixXd gt, long epsgCode, GDALDataType eType, bool need_gt, bool overwrite, bool isENVI)
{
	if (exists_test(img_path.toUtf8().constData())) {
		if (overwrite) {
			gdalImage result_img(img_path);
			return result_img;
		}
		else {
			throw "file has exist!!!";
			exit(1);
		}
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注锟斤拷锟绞斤拷锟斤拷锟斤拷锟?1锟?7
	GDALDriver* poDriver = isENVI? GetGDALDriverManager()->GetDriverByName("ENVI"): GetGDALDriverManager()->GetDriverByName("GTiff");
	GDALDataset* poDstDS = poDriver->Create(img_path.toUtf8().constData(), width, height, band_num, eType, NULL); // 锟斤拷锟斤拷锟斤拷
	if (need_gt) {
		OGRSpatialReference oSRS;
 
		if (oSRS.importFromEPSG(epsgCode) != OGRERR_NONE) {
			qDebug() << "Failed to import EPSG code " << epsgCode  ;
			throw "Failed to import EPSG code ";
			exit(1);
		}
		char* pszWKT = NULL;
		oSRS.exportToWkt(&pszWKT);
		qDebug() << "WKT of EPSG:"<< epsgCode <<" :\n" << pszWKT ;
		poDstDS->SetProjection(pszWKT);
		double gt_ptr[6] = { 0 };
		for (int i = 0; i < gt.rows(); i++) {
			for (int j = 0; j < gt.cols(); j++) {
				gt_ptr[i * 3 + j] = gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}
	for (int i = 1; i <= band_num; i++) {
		poDstDS->GetRasterBand(i)->SetNoDataValue(-9999);
	}
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	gdalImage result_img(img_path);
	return result_img;
}

gdalImageComplex CreategdalImageComplex(const QString& img_path, int height, int width,
										int band_num, Eigen::MatrixXd gt, QString projection,
										bool need_gt, bool overwrite)
{
	if(exists_test(img_path.toUtf8().constData())) {
		if(overwrite) {
			gdalImageComplex result_img(img_path);
			return result_img;
		} else {
			throw "file has exist!!!";
			exit(1);
		}
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDriver*	 poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS  = poDriver->Create(img_path.toUtf8().constData(), width, height, band_num,
											 GDT_CFloat64, NULL);
	if(need_gt) {
		poDstDS->SetProjection(projection.toUtf8().constData());

		// 锟斤拷锟斤拷转锟斤拷锟斤拷锟斤拷
		double gt_ptr[6] = { 0 };
		for(int i = 0; i < gt.rows(); i++) {
			for(int j = 0; j < gt.cols(); j++) {
				gt_ptr[i * 3 + j] = gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
	}
	//for(int i = 1; i <= band_num; i++) {
	//	poDstDS->GetRasterBand(i)->SetNoDataValue(0); // 回波部分
	//}
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	gdalImageComplex result_img(img_path);
	return result_img;
}

gdalImageComplex BASECONSTVARIABLEAPI CreategdalImageComplexNoProj(const QString& img_path, int height, int width, int band_num, bool overwrite)
{

	// 创建新文件
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");

	GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = (poDriver->Create(img_path.toUtf8().constData(), width, height, band_num, GDT_CFloat64, NULL));
	GDALFlushCache((GDALDatasetH)poDstDS);
	GDALClose((GDALDatasetH)poDstDS);
	//poDstDS.reset();
	omp_unset_lock(&lock);	 //  
	omp_destroy_lock(&lock); //  

	gdalImageComplex result_img(img_path);
	return result_img;
}

gdalImageComplex CreateEchoComplex(const QString& img_path, int height, int width, int band_num)
{
	// 创建图像
	Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2, 3);
	//Xgeo = GeoTransform[0] + Xpixel * GeoTransform[1] + Ypixel * GeoTransform[2]
	//Ygeo = GeoTransform[3] + Xpixel * GeoTransform[4] + Ypixel * GeoTransform[5]
	// X
	gt(0, 0) = 0; gt(0, 2) = 1; gt(0, 2) = 0;
	gt(1, 0) = 0; gt(1, 1) = 0; gt(1, 2) = 1;
	// Y
	QString projection = "";
	gdalImageComplex echodata = CreategdalImageComplex(img_path, height, width, 1, gt, projection, false, true);
	return echodata;

}

int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, double* gt, int new_width,
				 int new_height, GDALResampleAlg eResample)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	GDALDataset* pDSrc = (GDALDataset*)GDALOpen(pszSrcFile, GA_ReadOnly);
	if(pDSrc == NULL) {
		return -1;
	}

	GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	if(pDriver == NULL) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -2;
	}
	int			 width		= pDSrc->GetRasterXSize();
	int			 height		= pDSrc->GetRasterYSize();
	int			 nBandCount = pDSrc->GetRasterCount();
	GDALDataType dataType	= pDSrc->GetRasterBand(1)->GetRasterDataType();

	char*		 pszSrcWKT	= NULL;
	pszSrcWKT				= const_cast<char*>(pDSrc->GetProjectionRef());

	// 锟斤拷锟矫伙拷锟酵队帮拷锟斤拷锟轿?拷锟斤拷锟揭伙拷锟?1锟?7
	if(strlen(pszSrcWKT) <= 0) {
		OGRSpatialReference oSRS;
		oSRS.importFromEPSG(4326);
		// oSRS.SetUTM(50, true);   //锟斤拷锟斤拷锟斤拷  锟斤拷锟斤拷120锟斤拷
		// oSRS.SetWellKnownGeogCS("WGS84");
		oSRS.exportToWkt(&pszSrcWKT);
	}
	qDebug() << "GDALCreateGenImgProjTransformer " << Qt::endl;
	void* hTransformArg;
	hTransformArg = GDALCreateGenImgProjTransformer((GDALDatasetH)pDSrc, pszSrcWKT, NULL, pszSrcWKT,
													FALSE, 0.0, 1);
	qDebug() << "no proj " << Qt::endl;
	//(没锟斤拷投影锟斤拷影锟斤拷锟斤拷锟斤拷锟斤拷卟锟酵?拷锟?1锟?7)
	if(hTransformArg == NULL) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -3;
	}
	qDebug() << "has proj " << Qt::endl;
	double dGeoTrans[6] = { 0 };
	int	   nNewWidth = 0, nNewHeight = 0;
	if(GDALSuggestedWarpOutput((GDALDatasetH)pDSrc, GDALGenImgProjTransform, hTransformArg,
							   dGeoTrans, &nNewWidth, &nNewHeight)
	   != CE_None) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -3;
	}

	// GDALDestroyGenImgProjTransformer(hTransformArg);
	qDebug() << "create init GDALDataset " ;
	GDALDataset* pDDst =
		pDriver->Create(pszOutFile, new_width, new_height, nBandCount, dataType, NULL);
	if(pDDst == NULL) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -2;
	}

	pDDst->SetProjection(pszSrcWKT);
	pDDst->SetGeoTransform(gt);

	GDALWarpOptions* psWo  = GDALCreateWarpOptions();
	CPLSetConfigOption("GDAL_NUM_THREADS", "ALL_CPUS"); // 使用所有可用的CPU核心
	CPLSetConfigOption("GDAL_CACHEMAX", "16000");         // 设置缓存大小为500MB
	// psWo->papszWarpOptions = CSLDuplicate(NULL);
	psWo->eWorkingDataType = dataType;
	psWo->eResampleAlg	   = eResample;

	psWo->hSrcDS		   = (GDALDatasetH)pDSrc;
	psWo->hDstDS		   = (GDALDatasetH)pDDst;
	qDebug() << "GDALCreateGenImgProjTransformer" << Qt::endl;
	psWo->pfnTransformer  = GDALGenImgProjTransform;
	psWo->pTransformerArg = GDALCreateGenImgProjTransformer(
		(GDALDatasetH)pDSrc, pszSrcWKT, (GDALDatasetH)pDDst, pszSrcWKT, FALSE, 0.0, 1);
	;

	qDebug() << "GDALCreateGenImgProjTransformer has created" << Qt::endl;
	psWo->nBandCount  = nBandCount;
	psWo->panSrcBands = (int*)CPLMalloc(nBandCount * sizeof(int));
	psWo->panDstBands = (int*)CPLMalloc(nBandCount * sizeof(int));
	for(int i = 0; i < nBandCount; i++) {
		psWo->panSrcBands[i] = i + 1;
		psWo->panDstBands[i] = i + 1;
	}

	GDALWarpOperation oWo;
	if(oWo.Initialize(psWo) != CE_None) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
		return -3;
	}
	qDebug() << "ChunkAndWarpImage:" << new_width << "," << new_height << Qt::endl;
	oWo.ChunkAndWarpMulti(0, 0, new_width, new_height);
	GDALFlushCache(pDDst);
	qDebug() << "ChunkAndWarpImage over" << Qt::endl;
	// GDALDestroyGenImgProjTransformer(psWo->pTransformerArg);
	// GDALDestroyWarpOptions(psWo);
	GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
	GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	return 0;
}

int ResampleGDALs(const char* pszSrcFile, int band_ids, GDALRIOResampleAlg eResample)
{
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	GDALDataset* pDSrc = (GDALDataset*)GDALOpen(pszSrcFile, GA_Update);
	if(pDSrc == NULL) {
		return -1;
	}

	GDALDataType		 gdal_datatype = pDSrc->GetRasterBand(1)->GetRasterDataType();

	GDALRasterBand*		 demBand	   = pDSrc->GetRasterBand(band_ids);

	int					 width		   = pDSrc->GetRasterXSize();
	int					 height		   = pDSrc->GetRasterYSize();
	int					 start_col = 0, start_row = 0, rows_count = 0, cols_count;

	int					 row_delta = int(120000000 / width);

	GDALRasterIOExtraArg psExtraArg;
	INIT_RASTERIO_EXTRA_ARG(psExtraArg);
	psExtraArg.eResampleAlg = eResample;

	do {
		rows_count = start_row + row_delta < height ? row_delta : height - start_row;
		cols_count = width;

		if(gdal_datatype == GDALDataType::GDT_UInt16) {
			unsigned short* temp = new unsigned short[rows_count * cols_count];
			demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp,
							  cols_count, rows_count, gdal_datatype, 0, 0);
			demBand->RasterIO(GF_Write, start_col, start_row, cols_count, rows_count, temp,
							  cols_count, rows_count, gdal_datatype, 0, 0, &psExtraArg);
			delete[] temp;

		} else if(gdal_datatype == GDALDataType::GDT_Int16) {
			short* temp = new short[rows_count * cols_count];
			demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp,
							  cols_count, rows_count, gdal_datatype, 0, 0);
			demBand->RasterIO(GF_Write, start_col, start_row, cols_count, rows_count, temp,
							  cols_count, rows_count, gdal_datatype, 0, 0, &psExtraArg);
			delete[] temp;
		} else if(gdal_datatype == GDALDataType::GDT_Float32) {
			float* temp = new float[rows_count * cols_count];
			demBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, temp,
							  cols_count, rows_count, gdal_datatype, 0, 0);
			demBand->RasterIO(GF_Write, start_col, start_row, cols_count, rows_count, temp,
							  cols_count, rows_count, gdal_datatype, 0, 0, &psExtraArg);
			delete[] temp;
		}
		start_row = start_row + rows_count;
	} while(start_row < height);
	GDALClose((GDALDatasetH)pDSrc);

	return 0;
}

int alignRaster(QString inputPath, QString referencePath, QString outputPath, GDALResampleAlg eResample)
{

	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
 
	GDALDataset* pDSrc = (GDALDataset*)GDALOpen(inputPath.toUtf8().constData(), GA_ReadOnly);
	if (pDSrc == NULL) {
		return -1;
	}

	GDALDataset* tDSrc = (GDALDataset*)GDALOpen(referencePath.toUtf8().constData(), GA_ReadOnly);
	if (tDSrc == NULL) {
		return -1;
	}

	long new_width = tDSrc->GetRasterXSize();
	long new_height = tDSrc->GetRasterYSize();

	GDALDriver* pDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	if (pDriver == NULL) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -2;
	}
	int			 width = pDSrc->GetRasterXSize();
	int			 height = pDSrc->GetRasterYSize();
	int			 nBandCount = pDSrc->GetRasterCount();
	GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType(); 

	char* pszSrcWKT = NULL;
	pszSrcWKT = const_cast<char*>(pDSrc->GetProjectionRef());

	if (strlen(pszSrcWKT) <= 0) {
		OGRSpatialReference oSRS;
		oSRS.importFromEPSG(4326);
		oSRS.exportToWkt(&pszSrcWKT);
	}
	qDebug() << "GDALCreateGenImgProjTransformer " << Qt::endl;
	void* hTransformArg;
	hTransformArg = GDALCreateGenImgProjTransformer((GDALDatasetH)pDSrc, pszSrcWKT, NULL, pszSrcWKT,FALSE, 0.0, 1);
	qDebug() << "no proj " << Qt::endl;
	if (hTransformArg == NULL) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -3;
	}
	qDebug() << "has proj " << Qt::endl;
	std::shared_ptr<double> dGeoTrans(new double[6], delArrPtr);
	int	   nNewWidth = 0,
		   nNewHeight = 0;

	if (GDALSuggestedWarpOutput((GDALDatasetH)pDSrc, GDALGenImgProjTransform, hTransformArg,dGeoTrans.get(), &nNewWidth, &nNewHeight) != CE_None) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -3;
	}

	GDALDataset* pDDst =	pDriver->Create(outputPath.toUtf8().constData(), new_width, new_height, pDSrc->GetRasterCount(), dataType, NULL);
	if (pDDst == NULL) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return -2;
	}

	std::shared_ptr<double> gt(new double[6], delArrPtr);
	tDSrc->GetGeoTransform(gt.get());
	pDDst->SetProjection(pszSrcWKT);
	pDDst->SetGeoTransform(gt.get());

	GDALWarpOptions* psWo = GDALCreateWarpOptions();

	psWo->eWorkingDataType = dataType;
	psWo->eResampleAlg = eResample;

	psWo->hSrcDS = (GDALDatasetH)pDSrc;
	psWo->hDstDS = (GDALDatasetH)pDDst;

 	psWo->pfnTransformer = GDALGenImgProjTransform;
	psWo->pTransformerArg = GDALCreateGenImgProjTransformer((GDALDatasetH)pDSrc, pszSrcWKT, (GDALDatasetH)pDDst, pszSrcWKT, FALSE, 0.0, 1);
	

	qDebug() << "GDALCreateGenImgProjTransformer has created" << Qt::endl;
	psWo->nBandCount = nBandCount;
	psWo->panSrcBands = (int*)CPLMalloc(nBandCount * sizeof(int));
	psWo->panDstBands = (int*)CPLMalloc(nBandCount * sizeof(int));
	for (int i = 0; i < nBandCount; i++) {
		psWo->panSrcBands[i] = i + 1;
		psWo->panDstBands[i] = i + 1;
	}

	GDALWarpOperation oWo;
	if (oWo.Initialize(psWo) != CE_None) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
		GDALClose((GDALDatasetH)(GDALDatasetH)tDSrc);
		return -3;
	}
	qDebug() << "ChunkAndWarpImage:" << new_width << "," << new_height << Qt::endl;
	oWo.ChunkAndWarpMulti(0, 0, new_width, new_height);
	GDALFlushCache(pDDst);
	qDebug() << "ChunkAndWarpImage over" << Qt::endl;
	GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
	GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
	GDALClose((GDALDatasetH)(GDALDatasetH)tDSrc);
	return 0;


}

 


int saveMatrixXcd2TiFF(Eigen::MatrixXcd data, QString out_tiff_path)
{
	int				rows = data.rows();
	int				cols = data.cols();

	Eigen::MatrixXd gt	 = Eigen::MatrixXd::Zero(2, 3);

	gdalImage		image_tiff =
		CreategdalImage(out_tiff_path, rows, cols, 2, gt, "", false, true); // 注意这里保留仿真结果
	// 保存二进制文件
	Eigen::MatrixXd real_img = data.array().real();
	Eigen::MatrixXd imag_img = data.array().imag();
	image_tiff.saveImage(real_img, 0, 0, 1);
	image_tiff.saveImage(imag_img, 0, 0, 2);
	return -1;
}

void clipRaster(QString inRasterPath, QString outRasterPath, long minRow, long maxRow, long minCol, long maxCol)
{
	long rownum = maxRow - minRow + 1;
	long colnum = maxCol - minCol + 1;

	gdalImage inimg(inRasterPath);
	Eigen::MatrixXd gt = inimg.gt;
	
	Landpoint lp = inimg.getLandPoint(minRow, minCol, 0);

	gt(0, 0) = lp.lon;
	gt(1, 0) = lp.lat;

	gdalImage outimg= CreategdalImageDouble(outRasterPath, rownum, colnum, inimg.band_num, gt, inimg.projection, true, true, true);

	for (long bi = 1; bi < inimg.band_num + 1; bi++) {
		Eigen::MatrixXd brasterData = inimg.getData(minRow, minCol, rownum, colnum, bi);
		outimg.saveImage(brasterData, 0, 0, bi);
		qDebug() << "writer raster band : " << bi;
	}

	qDebug() << "writer raster overring";

}

ErrorCode MergeRasterProcess(QVector<QString> filepaths, QString outfileptah, QString mainString, MERGEMODE  mergecode, bool isENVI, ShowProessAbstract* dia )
{
	// 参数检查
	if (!isExists(mainString)) {
		qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::FILENOFOUND) )<< "\t" << mainString;
		return ErrorCode::FILENOFOUND;
	}
	else {}
	gdalImage mainimg(mainString);
	QVector<gdalImage> imgdslist(filepaths.count());
	for (long i = 0; i < filepaths.count(); i++) {
		if (!isExists(filepaths[i])) {
			qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::FILENOFOUND)) << "\t" << filepaths[i];
			return ErrorCode::FILENOFOUND;
		}
		else {
			imgdslist[i] = gdalImage(filepaths[i]);
			if (imgdslist[i].band_num != mainimg.band_num) {
				qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::RASTERBAND_NOTEQUAL)) << "\t" << imgdslist[i].band_num <<" != "<< mainimg.band_num;
				return ErrorCode::RASTERBAND_NOTEQUAL;
			}
		}
	}
 
	// 检查坐标系是否统一
	long EPSGCode = GetEPSGFromRasterFile(mainString);
	long tempCode = 0;
	for (long i = 0; i < filepaths.count(); i++) {
		tempCode = GetEPSGFromRasterFile(filepaths[i]);
		if (EPSGCode != tempCode) {
			qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::EPSGCODE_NOTSAME)) << "\t" << EPSGCode <<"!="<< tempCode;
			return ErrorCode::EPSGCODE_NOTSAME;
		}
	}

	// 检查影像类型是否统一
	GDALDataType mainType = mainimg.getDataType();
	for (long i = 0; i < imgdslist.count(); i++) {
		if (mainType != imgdslist[i].getDataType()) {
			qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::RASTER_DATETYPE_NOTSAME)) << "\t" << mainType << "!=" << imgdslist[i].getDataType();
			return ErrorCode::RASTER_DATETYPE_NOTSAME;
		}
	}

	Eigen::MatrixXd maingt = mainimg.getGeoTranslation();
	Eigen::MatrixXd rgt = Eigen::MatrixXd::Zero(2,3);
	RasterExtend mainExtend = mainimg.getExtend();
	rgt(0, 1) = (mainExtend.max_x - mainExtend.min_x) / (mainimg.width - 1); //dx
	rgt(1, 2) = -1*std::abs(( (mainExtend.max_y - mainExtend.min_y) / (mainimg.height - 1)));//dy
	QVector<RasterExtend> extendlist(imgdslist.count());
	for (long i = 0; i < imgdslist.count(); i++) {
		extendlist[i] = imgdslist[i].getExtend();
		mainExtend.min_x = mainExtend.min_x < extendlist[i].min_x ? mainExtend.min_x : extendlist[i].min_x;
		mainExtend.max_x = mainExtend.max_x > extendlist[i].max_x ? mainExtend.max_x : extendlist[i].max_x;
		mainExtend.min_y = mainExtend.min_y < extendlist[i].min_y ? mainExtend.min_y : extendlist[i].min_y;
		mainExtend.max_y = mainExtend.max_y > extendlist[i].max_y ? mainExtend.max_y : extendlist[i].max_y;
	}

	rgt(0, 0) = mainExtend.min_x;
	rgt(1, 0) = mainExtend.max_y;

	// 计算数量

	long width = std::ceil((mainExtend.max_x - mainExtend.min_x) / rgt(0, 1) + 1);
	long height = std::ceil(std::abs((mainExtend.min_y - mainExtend.max_y) / rgt(1, 2)) + 1);
	OGRSpatialReference oSRS;
	if (oSRS.importFromEPSG(EPSGCode) != OGRERR_NONE) {
		qDebug() << QString::fromStdString(errorCode2errInfo(ErrorCode::EPSGCODE_NOTSUPPORT)) << "\t" << EPSGCode;
		return ErrorCode::EPSGCODE_NOTSUPPORT;
	}
	
	gdalImage resultImage = CreategdalImage(outfileptah, height, width, mainimg.band_num, rgt, EPSGCode, mainType, true, true, isENVI);
 
	QString resultMaskString = addMaskToFileName(outfileptah, QString("_MASK"));
	gdalImage maskImage = CreategdalImage(resultMaskString, height, width,1 , rgt, EPSGCode, GDT_Int32, true, true, isENVI);

	// 初始化
	long resultline = Memory1MB * 500 / 8 / resultImage.width;
	resultline = resultline < 10000 ? resultline : 10000; // 最多100行
	resultline = resultline > 0 ? resultline : 2;
	long bandnum = resultImage.band_num + 1;
	long starti = 0;
	long rasterCount = imgdslist.count();
	


	QProgressDialog progressDialog(u8"初始化影像", u8"终止", 0, resultImage.height);
	progressDialog.setWindowTitle(u8"初始化影像");
	progressDialog.setWindowModality(Qt::WindowModal);
	progressDialog.setAutoClose(true);
	progressDialog.setValue(0);
	progressDialog.setMaximum(resultImage.height);
	progressDialog.setMinimum(0);
	progressDialog.show();

	
	for (starti = 0; starti < resultImage.height; starti = starti + resultline) {
		long blocklines = resultline;
		blocklines = starti + blocklines < resultImage.height ? blocklines : resultImage.height - starti;
		for (long b = 1; b < bandnum; b++) {
			Eigen::MatrixXd data = resultImage.getData(starti, 0, blocklines, resultImage.width, b);
			Eigen::MatrixXi maskdata = maskImage.getDatai(starti, 0, blocklines, resultImage.width, b);
			data = data.array() * 0;
			maskdata = maskdata.array() * 0;
			resultImage.saveImage(data, starti, 0, b);
			maskImage.saveImage(maskdata, starti, 0, b);
		}
		if (nullptr != dia) {
			dia->showProcess(starti * 1.0 / resultImage.height, u8"初始化影像数据");
		}
		progressDialog.setValue(starti+ blocklines);
	}
	progressDialog.close();

 

	switch (mergecode)
	{
	case MERGE_GEOCODING:
		return MergeRasterInGeoCoding(imgdslist, resultImage, maskImage, dia);
	default:
		break;
	}
	

	return ErrorCode::SUCCESS;
}

ErrorCode MergeRasterInGeoCoding(QVector<gdalImage> imgdslist, gdalImage resultimg, gdalImage maskimg, ShowProessAbstract* dia)
{
	omp_set_num_threads(Paral_num_thread);
	// 逐点合并计算
	QVector<RasterExtend> extendlist(imgdslist.count());
	for (long i = 0; i < imgdslist.count(); i++) {
		extendlist[i] = imgdslist[i].getExtend();
		imgdslist[i].InitInv_gt();
	}
	
	// 分块计算
	long resultline = Memory1MB * 1000 / 8 / resultimg.width;
	resultline = resultline < 300 ? resultline : 300; // 最多100行
	
	long bandnum = resultimg.band_num+1;
	long starti = 0;
	long rasterCount = imgdslist.count();

	long processNumber = 0;
	QProgressDialog progressDialog(u8"合并影像", u8"终止", 0, resultimg.height);
	progressDialog.setWindowTitle(u8"合并影像");
	progressDialog.setWindowModality(Qt::WindowModal);
	progressDialog.setAutoClose(true);
	progressDialog.setValue(0);
	progressDialog.setMaximum(resultimg.height);
	progressDialog.setMinimum(0);
	progressDialog.show();
	omp_lock_t lock;
	omp_init_lock(&lock);

#pragma omp parallel for
	for (starti = 0; starti < resultimg.height; starti = starti + resultline) {
		long blocklines = resultline;
		blocklines = starti + blocklines < resultimg.height ? blocklines : resultimg.height - starti;

		long rid = starti;
		long cid = 0;

		Landpoint pp = {0,0,0};
		Landpoint lp = { 0,0,0 };

		for (long ir = 0; ir < rasterCount; ir++) {// 影像
			long minRid = imgdslist[ir].height;
			long maxRid = 0;

			Eigen::MatrixXd ridlist = resultimg.getData(starti, 0, blocklines, resultimg.width, 1);
			ridlist = ridlist.array() * 0;
			Eigen::MatrixXd cidlist = ridlist.array() * 0;

			for (long i = 0; i < blocklines; i++) {// 行号
				rid = starti + i;
				for (long j = 0; j < resultimg.width; j++) {// 列号
					cid = j;
					resultimg.getLandPoint(rid, cid,0,pp);
					lp = imgdslist[ir].getRow_Col(pp.lon, pp.lat); // 获取点坐标
					ridlist(i, j) = lp.lat;
					cidlist(i, j) = lp.lon;
				}
			}

			//ImageShowDialogClass* dialog = new ImageShowDialogClass;
			//dialog->show();
			//dialog->load_double_MatrixX_data(cidlist, u8"");

			//dialog->exec();

			
			if (ridlist.maxCoeff() < 0 || ridlist.minCoeff() >= imgdslist[ir].height) {
				continue;
			}

			if (cidlist.maxCoeff() < 0 || cidlist.minCoeff() >= imgdslist[ir].width) {
				continue;
			}

			minRid = std::floor(ridlist.minCoeff());
			maxRid = std::ceil(ridlist.maxCoeff());
			minRid = minRid < 0 ? 0 : minRid;
			maxRid = maxRid < imgdslist[ir].height ? maxRid : imgdslist[ir].height - 1;

			long rowlen = maxRid - minRid + 1;
			if(rowlen <= 0) {
				continue;
			}
			// 获取分配代码
			Landpoint p0{ 0,0,0 }, p11{ 0,0,0 }, p21{ 0,0,0 }, p12{ 0,0,0 }, p22{ 0,0,0 }, p{ 0,0,0 };
			

			long rowcount = 0;
			long colcount = 0;
			double ridtemp = 0, cidtemp = 0;

			long lastr = 0, nextr = 0;
			long lastc = 0, nextc = 0;

			double r0=0, c0 = 0;

			for (long b = 1; b < bandnum; b++) {
				Eigen::MatrixXd resultdata = resultimg.getData(starti, 0, blocklines, resultimg.width, b);
				Eigen::MatrixXi resultmask = maskimg.getDatai(starti, 0, blocklines, resultimg.width, b);
				Eigen::MatrixXd data = imgdslist[ir].getData(minRid, 0, rowlen, imgdslist[ir].width, b);

				double nodata = imgdslist[ir].getNoDataValue(b);
				for (long ii = 0; ii < data.rows(); ii++) {
					for (long jj = 0; jj < data.cols(); jj++) {
						if (std::abs(data(ii, jj) - nodata) < 1e-6) {
							data(ii, jj) = 0;
						}
					}
				}
				rowcount = ridlist.rows();
				colcount = ridlist.cols();
				double Bileanervalue = 0;
				for (long i = 0; i < rowcount; i++) {
					for (long j = 0; j < colcount; j++) {
						ridtemp = ridlist(i, j);
						cidtemp = cidlist(i, j);

						lastr = std::floor(ridtemp);
						nextr = std::ceil(ridtemp);
						lastc = std::floor(cidtemp);
						nextc = std::ceil(cidtemp);

						if (lastr < 0 || lastr >= imgdslist[ir].height
							|| nextr < 0 || nextr >= imgdslist[ir].height
							|| lastc < 0 || lastc >= imgdslist[ir].width
							|| nextc <0|| nextc >=imgdslist[ir].width) {
							continue;
						}
						else {}

						r0 = ridtemp - std::floor(ridtemp);
						c0 = cidtemp - std::floor(cidtemp);
 
						lastr = lastr - minRid;
						nextr = nextr - minRid;

						p0 = Landpoint{ c0,r0,0 };
						p11 = Landpoint{ 0,0,data(lastr,lastc) };
						p21 = Landpoint{ 0,1,data(nextr,lastc) };
						p12 = Landpoint{ 1,0,data(lastr,nextc) };
						p22 = Landpoint{ 1,1,data(nextr,nextc) };
						Bileanervalue = Bilinear_interpolation(p0, p11, p21, p12, p22);
						if (std::abs(Bileanervalue) < 1e-6||resultmask(i, j)>0) {
							continue;
						}
						resultdata(i,j) = resultdata(i, j)+ Bileanervalue;
						resultmask(i, j) = resultmask(i, j) + 1;
					}
				}
				resultimg.saveImage(resultdata, starti, 0, b);
				maskimg.saveImage(resultmask, starti, 0, b);
			}
		}

		omp_set_lock(&lock);
		processNumber = processNumber + blocklines;
		qDebug() << "\rprocess bar:\t" << processNumber * 100.0 / resultimg.height << " % " << "\t\t\t";
		if (nullptr != dia) {
			dia->showProcess(processNumber * 1.0 / resultimg.height, u8"合并图像");
		}
		if (progressDialog.maximum() <= processNumber) {
			processNumber = progressDialog.maximum() - 1;
		}
		progressDialog.setValue(processNumber);
		omp_unset_lock(&lock); 
	}
	omp_destroy_lock(&lock);  

	progressDialog.setWindowTitle(u8"影像掩膜");
	progressDialog.setLabelText(u8"影像掩膜");
	for (starti = 0; starti < resultimg.height; starti = starti + resultline) {
		long blocklines = resultline;
		blocklines = starti + blocklines < resultimg.height ? blocklines : resultimg.height - starti;
		for (long b = 1; b < bandnum; b++) {
			Eigen::MatrixXd data = resultimg.getData(starti, 0, blocklines, resultimg.width, b);
			Eigen::MatrixXd maskdata = maskimg.getData(starti, 0, blocklines, maskimg.width, b);
			
			for (long i = 0; i < data.rows(); i++) {
				for (long j = 0; j < data.cols(); j++) {
					if (maskdata(i, j) == 0) {
						data(i, j) = -9999;
						continue;
					}
					data(i, j) = data(i, j) / maskdata(i, j);
				}
			}

			resultimg.saveImage(data, starti, 0, b);
			maskimg.saveImage(maskdata, starti, 0, b);
		}
		if (nullptr != dia) {
			dia->showProcess((starti + blocklines) * 1.0 / resultimg.height, u8"影像掩膜");
		}
		progressDialog.setValue(starti + blocklines);
	}
	resultimg.setNoDataValue(-9999);
	progressDialog.close();
	return ErrorCode::SUCCESS;
}

bool saveEigenMatrixXd2Bin(Eigen::MatrixXd data, QString dataStrPath)
{

	Eigen::MatrixXd gt = Eigen::MatrixXd::Zero(2, 3);

	gdalImage img= CreategdalImageDouble(dataStrPath, data.rows(), data.cols(), 1, gt, "", false, true,true);
	
	img.saveImage(data, 0,0,1);

	return true;
}

gdalImageComplex::gdalImageComplex(const QString& raster_path)
{
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	this->img_path = raster_path;

	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDataset* rasterDataset = (GDALDataset*)(GDALOpen(
		raster_path.toUtf8().constData(), GA_ReadOnly)); 
	this->width				   = rasterDataset->GetRasterXSize();
	this->height			   = rasterDataset->GetRasterYSize();
	this->band_num			   = rasterDataset->GetRasterCount();

	double* gt				   = new double[6];
	rasterDataset->GetGeoTransform(gt);
	this->gt = Eigen::MatrixXd(2, 3);
	this->gt << gt[0], gt[1], gt[2], gt[3], gt[4], gt[5];

	double a		 = this->gt(0, 0);
	double b		 = this->gt(0, 1);
	double c		 = this->gt(0, 2);
	double d		 = this->gt(1, 0);
	double e		 = this->gt(1, 1);
	double f		 = this->gt(1, 2);

	this->projection = rasterDataset->GetProjectionRef();

	// 释放投影
	GDALFlushCache((GDALDatasetH)rasterDataset);
	GDALClose((GDALDatasetH)rasterDataset);
	rasterDataset = NULL; // 指矫匡拷
	this->InitInv_gt();
	delete[] gt;
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	omp_unset_lock(&lock);	 // 锟酵放伙拷斤拷
	omp_destroy_lock(&lock); // 劫伙拷斤拷
}

gdalImageComplex::~gdalImageComplex() {}

void gdalImageComplex::setData(Eigen::MatrixXcd data)
{
	this->data = data;
}

void gdalImageComplex::saveImage(Eigen::MatrixXcd data, int start_row, int start_col, int band_ids)
{



	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if(start_row + data.rows() > this->height || start_col + data.cols() > this->width) {
		QString tip = u8"file path: " + this->img_path;
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDriver*	 poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS  = nullptr;
	if(exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	} else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
								   this->band_num, GDT_CFloat64, NULL); // 斤拷锟斤拷
		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for(int i = 0; i < this->gt.rows(); i++) {
			for(int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
		//delete[] gt_ptr;
	}

	int		datarows   = data.rows();
	int		datacols   = data.cols();

	double* databuffer = new double[data.size() * 2];
	for(int i = 0; i < data.rows(); i++) {
		for(int j = 0; j < data.cols(); j++) {
			databuffer[i * data.cols() * 2 + j * 2]		= data(i, j).real();
			databuffer[i * data.cols() * 2 + j * 2 + 1] = data(i, j).imag();
		}
	}

	// poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols,
	// datarows, GDT_Float32,band_ids, num,0,0,0);
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, datacols, datarows,
											   databuffer, datacols, datarows, GDT_CFloat64, 0, 0);
	GDALFlushCache(poDstDS);
	delete databuffer;
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	omp_unset_lock(&lock);	 //
	omp_destroy_lock(&lock); //
}

void gdalImageComplex::saveImage(std::shared_ptr<std::complex<double>> data, long start_row, long start_col, long rowCount, long colCount, int band_ids)
{
	omp_lock_t lock;
	omp_init_lock(&lock);
	omp_set_lock(&lock);
	if (start_row + rowCount > this->height || start_col + colCount > this->width) {
		QString tip = u8"file path: " + this->img_path;
		qDebug() << tip;
		throw std::exception(tip.toUtf8().constData());
		return;
	}
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("ENVI");
	GDALDataset* poDstDS = nullptr;
	if (exists_test(this->img_path)) {
		poDstDS = (GDALDataset*)(GDALOpen(this->img_path.toUtf8().constData(), GA_Update));
	}
	else {
		poDstDS = poDriver->Create(this->img_path.toUtf8().constData(), this->width, this->height,
			this->band_num, GDT_CFloat64, NULL); // 斤拷锟斤拷
		poDstDS->SetProjection(this->projection.toUtf8().constData());

		double gt_ptr[6];
		for (int i = 0; i < this->gt.rows(); i++) {
			for (int j = 0; j < this->gt.cols(); j++) {
				gt_ptr[i * 3 + j] = this->gt(i, j);
			}
		}
		poDstDS->SetGeoTransform(gt_ptr);
		//delete[] gt_ptr;
	}
 
	double* databuffer = new double[rowCount * colCount * 2];
	for (long i = 0; i < rowCount; i++) {
		for (long j = 0; j < colCount; j++) {
			databuffer[i * colCount * 2 + j * 2] = data.get()[i*colCount+j].real();
			databuffer[i * colCount * 2 + j * 2 + 1] = data.get()[i * colCount + j].imag();
		}
	}

	// poDstDS->RasterIO(GF_Write,start_col, start_row, datacols, datarows, databuffer, datacols,
	// datarows, GDT_Float32,band_ids, num,0,0,0);
	poDstDS->GetRasterBand(band_ids)->RasterIO(GF_Write, start_col, start_row, colCount, rowCount,
		databuffer, colCount, rowCount, GDT_CFloat64, 0, 0);
	GDALFlushCache(poDstDS);
	delete databuffer;
	GDALClose((GDALDatasetH)poDstDS);
	// GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	omp_unset_lock(&lock);	 //
	omp_destroy_lock(&lock); //

}

Eigen::MatrixXcd gdalImageComplex::getDataComplex(int start_row, int start_col, int rows_count,
												  int cols_count, int band_ids)
{
	GDALDataset* poDataset;
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");

	// 打开TIFF文件
	poDataset = (GDALDataset*)GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly);
	if(poDataset == nullptr) {
		QMessageBox::warning(nullptr, u8"错误", u8"无法打开文件：" + this->img_path);
		qDebug() << u8"无法打开文件：" + this->img_path;
	}

	// 获取数据集的第一个波段
	GDALRasterBand* poBand;
	poBand			   = poDataset->GetRasterBand(1);

	// 读取波段信息，假设是复数类型
	int		nXSize = cols_count; poBand->GetXSize();
	int		nYSize = rows_count; poBand->GetYSize();

	double* databuffer = new double[nXSize * nYSize * 2];
	poBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, databuffer, cols_count,
					 rows_count, GDT_CFloat64, 0, 0);
	GDALClose((GDALDatasetH)poDataset);
	Eigen::MatrixXcd rasterData(nYSize, nXSize); // 使用Eigen的MatrixXcd
	for(size_t i = 0; i < nYSize; i++) {
		for(size_t j = 0; j < nXSize; j++) {
			rasterData(i, j) = std::complex<double>(databuffer[i * nXSize * 2 + j * 2],
													databuffer[i * nXSize * 2 + j * 2 + 1]);
		}
	}

	delete[] databuffer;
	return rasterData;
}

std::shared_ptr<std::complex<double>> gdalImageComplex::getDataComplexSharePtr(int start_row, int start_col, int rows_count, int cols_count, int band_ids)
{
	GDALDataset* poDataset;
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");

	// 打开TIFF文件
	poDataset = (GDALDataset*)GDALOpen(this->img_path.toUtf8().constData(), GA_ReadOnly);
	if(poDataset == nullptr) {
		QMessageBox::warning(nullptr, u8"错误", u8"无法打开文件：" + this->img_path);
		qDebug() << u8"无法打开文件：" + this->img_path;
	}

	// 获取数据集的第一个波段
	GDALRasterBand* poBand;
	poBand			   = poDataset->GetRasterBand(1);

	// 读取波段信息，假设是复数类型
 

	double* databuffer = new double[rows_count * cols_count * 2];
	poBand->RasterIO(GF_Read, start_col, start_row, cols_count, rows_count, databuffer, cols_count,
					 rows_count, GDT_CFloat64, 0, 0);
	GDALClose((GDALDatasetH)poDataset);
	
	std::shared_ptr<std::complex<double>> rasterData(new std::complex<double>[rows_count * cols_count], delArrPtr);
 
	for(size_t i = 0; i < rows_count; i++) {
		for(size_t j = 0; j < cols_count; j++) {
			rasterData.get()[i*cols_count+ j] = std::complex<double>(databuffer[i * cols_count * 2 + j * 2],
													databuffer[i * cols_count * 2 + j * 2 + 1]);
		}
	}

	delete[] databuffer;
	return rasterData;
}
 
void gdalImageComplex::saveImage()
{
	this->saveImage(this->data, this->start_row, this->start_col, this->data_band_ids);
}
void gdalImageComplex::savePreViewImage()
{
	qDebug()<<"void gdalImageComplex::savePreViewImage()";
	Eigen::MatrixXd data_abs = Eigen::MatrixXd::Zero(this->height, this->width);
	data_abs				 = (this->data.array().real().pow(2) + this->data.array().imag().pow(2))
				   .array()
				   .log10()*10.0; // 计算振幅

	double				   min_abs = data_abs.minCoeff();		 // 最大值
	double				   max_abs = data_abs.maxCoeff();		 // 最小值
	double				   delta   = (max_abs - min_abs) / 1000; // 1000分位档
	Eigen::MatrixX<size_t> data_idx =
		((data_abs.array() - min_abs).array() / delta).array().floor().cast<size_t>();

	// 初始化
	double hist[1001];
	for(size_t i = 0; i < 1001; i++) {
		hist[i] = 0; // 初始化
	}
	for(size_t i = 0; i < this->height; i++) {
		for(size_t j = 0; j < this->width; j++) {
			hist[data_idx(i, j)]++;
		}
	}

	// 统计
	size_t count	   = this->height * this->width;
	double precent	   = 0;
	size_t curCount	   = 0;
	double pre2		   = 0;
	bool   findprec_2  = true;
	double pre98	   = 0;
	bool   findprec_98 = true;
	for(size_t i = 0; i < 1001; i++) {
		precent = precent + hist[i];
		if(findprec_2 & precent / count > 0.02) {
			pre2	 = i * delta + min_abs;
			findprec_2 = false;
		}
		if(findprec_98 & precent / count > 0.98) {
			pre98		= (i-1) * delta + min_abs;
			findprec_98 = false;
		}
	}
	// 拉伸
	delta = (pre98-pre2)/200;
	data_idx=
		((data_abs.array() - pre2).array() / delta).array().floor().cast<size_t>();

	for(size_t i = 0; i < this->height; i++) {
		for(size_t j = 0; j < this->width; j++) {
			if(data_idx(i,j)<0){
				data_idx(i,j)=0;
			}
			else if(data_idx(i,j)>255){
				data_idx(i,j)=255;
			}else{

			}
		}
	}

	// 赋值
	QString	  filePath = this->img_path;
	QFile	  file(filePath);
	QFileInfo fileInfo(file);

	QString	  directory = fileInfo.absolutePath();
	qDebug() << "文件所在目录：" << directory;
	QString baseName = fileInfo.completeBaseName();
	qDebug() << "无后缀文件名：" << baseName;

	// 创建文件路径
	QString			previewImagePath = JoinPath(directory, baseName+"_preview.png");
	cv::Mat			img(this->height, this->width, CV_8U ,cv::Scalar(0));

	for(size_t i = 0; i < this->height; i++) {
		for(size_t j = 0; j < this->width; j++) {
			img.at<uchar>(i,j)= (uchar)(data_idx(i,j));
		}
	}
	//std::string outimgpath=previewImagePath.toUtf8().data();
	cv::imwrite(previewImagePath.toUtf8().data(), img);
}



 
long getProjectEPSGCodeByLon_Lat(double long, double lat, ProjectStripDelta stripState)
{
	long EPSGCode = 0;
	switch (stripState) {
	case ProjectStripDelta::Strip_3: {
		break;
	};
	case ProjectStripDelta::Strip_6: {
		break;
	}
	default: {
		EPSGCode = -1;
		break;
	}
	}
	qDebug() << QString(" EPSG code : %1").arg(EPSGCode);
	return EPSGCode;
}
long getProjectEPSGCodeByLon_Lat_inStrip3(double lon, double lat)
{
	// EPSG 4534 ~ 4554 3 度带
	// 首先判断是否是在 中国带宽范围
	// 中心经度范围 ：75E ~ 135E 实际范围 73.5E ~ 136.5E,
	// 纬度范围 3N ~ 54N，放宽到 0N~ 60N
	if (73.5 <= lon && lon <= 136.5 && 0 <= lat && lat <= 60) { // 中国境内
		long code = trunc((lon - 73.5) / 3) + 4534;
		return code;
	}
	else { // 非中国境内 使用 高斯克吕格
		bool isSouth = lat < 0; // 简单判断南北半球，这里仅为示例，实际应用可能需要更细致的逻辑
		long prefix = isSouth ? 327000 : 326000;
		// std::string prefix = isSouth ? "327" : "326";
		lon = fmod(lon + 360.0, 360.0);
		long zone = std::floor((lon + 180.0) / 3.0);
		prefix = prefix + zone;
		return prefix;
	}
	return 0;
}
long getProjectEPSGCodeByLon_Lat_inStrip6(double lon, double lat)
{
	// EPSG 4502 ~ 4512   6度带
	// 首先判断是否是在 中国带宽范围
	// 中心经度范围 ：75E ~ 135E 实际范围 72.0E ~ 138E,
	// 纬度范围 3N ~ 54N，放宽到 0N~ 60N
	if (73.5 <= lon && lon <= 136.5 && 0 <= lat && lat <= 60) { // 中国境内
		long code = trunc((lon - 72.0) / 6) + 4502;
		return code;
	}
	else { // 非中国境内 使用 UTM// 确定带号，6度带从1开始到60，每6度一个带
		int	   zone = static_cast<int>((lon + 180.0) / 6.0) + 1;
		bool   isSouth = lon < 0;				   // 判断是否在南半球
		long epsgCodeBase = isSouth ? 32700 : 32600; // 计算EPSG代码
		long prefix = static_cast<int>(epsgCodeBase + zone);
		return prefix;
	}
	return 0;
}

QString GetProjectionNameFromEPSG(long epsgCode)
{
	qDebug() << "============= GetProjectionNameFromEPSG ======================";
	OGRSpatialReference oSRS;

	// 设置EPSG代码
	if (oSRS.importFromEPSG(epsgCode) != OGRERR_NONE) {
		qDebug() << "epsgcode not  recognition";
		return "";
	}

	// 获取并输出坐标系的描述（名称）
	const char* pszName = oSRS.GetAttrValue("GEOGCS");
	if (pszName) {
		qDebug() << "Coordinate system name for EPSG " + QString::number(epsgCode)
			<< " is: " + QString::fromStdString(pszName);
		return QString::fromStdString(pszName);
	}
	else {
		qDebug() << "Unable to retrieve the name for EPSG " + QString::number(epsgCode);
		return "";
	}

	//		char*				wkt = NULL;
	//		// 转换为WKT格式
	//		oSRS.exportToWkt(&wkt);
	//
	//		qDebug() << wkt;
	//
	//		// 从WKT中解析投影名称，这里简化处理，实际可能需要更复杂的逻辑来准确提取名称
	//		std::string wktStr(wkt);
	//		long start = wktStr.find("PROJCS[\"") + 8; // 找到"PROJCS["后的第一个双引号位置
	//		// 从start位置开始找下一个双引号，这之间的内容即为投影名称
	//		int	end		 = wktStr.find('\"', start);
	//		QString projName = QString::fromStdString(wktStr.substr(start, end - start));
	//
	//		// 释放WKT字符串内存
	//		CPLFree(wkt);

	// return projName;
}
long GetEPSGFromRasterFile(QString filepath)
{
	qDebug() << "============= GetEPSGFromRasterFile ======================";
	//		QTextCodec* codec = QTextCodec::codecForLocale(); // 获取系统默认编码的文本编解码器
	//		QByteArray	byteArray = codec->fromUnicode(filepath); // 将QString转换为QByteArray
	//,这个应该会自动释放 		const char* charArray = byteArray.constData(); //
	// 获取QByteArray的const char*指针

	{
		if (QFile(filepath).exists()) {
			qDebug() << "info: the image found.\n";
		}
		else {
			return -1;
		}

		GDALAllRegister();
		CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES"); // 注册GDAL驱动
		//			qDebug()<<filepath.toLocal8Bit().constData()<<std::endl;
		// 打开影像文件
		GDALDataset* poDataset;
		poDataset = (GDALDataset*)GDALOpen(filepath.toUtf8().data(), GA_ReadOnly);
		if (NULL == poDataset) {
			qDebug() << "Error: Unable to open the image.\n";
			return -1;
		}

		// 获取影像的投影信息
		const char* pszProjection = poDataset->GetProjectionRef();

		qDebug() << QString::fromUtf8(pszProjection);

		// 创建SpatialReference对象
		OGRSpatialReference oSRS;
		if (oSRS.importFromWkt((char**)&pszProjection) != OGRERR_NONE) {
			qDebug() << ("Error: Unable to import projection information.\n");
			GDALClose(poDataset);
			return -1;
		}

		qDebug() << pszProjection ;

		const char* epscodestr = oSRS.GetAuthorityCode(nullptr);
		if (NULL == epscodestr || nullptr == epscodestr) {
			qDebug() << "EPSG code  string could not be determined from the spatial reference.";
			GDALClose(poDataset);

			return -1;
		}
		long epsgCode = atoi(epscodestr); // 获取EPSG代码

		if (epsgCode != 0) {
			GDALClose(poDataset);
			qDebug() << QString("file %1 :epsg Code %2").arg(filepath).arg(epsgCode);
			return epsgCode;
		}
		else {
			qDebug() << "EPSG code could not be determined from the spatial reference.";
			GDALClose(poDataset);

			return -1;
		}
	}
}
std::shared_ptr<PointRaster> GetCenterPointInRaster(QString filepath)
{
	qDebug() << "============= GetCenterPointInRaster ======================";
	//		QTextCodec* codec = QTextCodec::codecForLocale(); // 获取系统默认编码的文本编解码器
	//		QByteArray	byteArray = codec->fromUnicode(filepath); // 将QString转换为QByteArray
	//,这个应该会自动释放 		const char* charArray = byteArray.constData(); //
	// 获取QByteArray的const char*指针
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	// qDebug()<<filepath.toLocal8Bit().constData()<<std::endl;
	GDALDataset* poDataset = (GDALDataset*)GDALOpen(filepath.toUtf8().data(), GA_ReadOnly);
	if (nullptr == poDataset || NULL == poDataset) {
		qDebug() << "Could not open dataset";
		return nullptr; // 表示读取失败
	}

	double x, y, z;

	bool   flag = false;

	{
		double adfGeoTransform[6];
		if (poDataset->GetGeoTransform(adfGeoTransform) != CE_None) {
			qDebug() << "Failed to get GeoTransform";
			return nullptr;
		}

		double dfWidth = poDataset->GetRasterXSize();
		double dfHeight = poDataset->GetRasterYSize();

		// 计算中心点坐标（像素坐标）
		double dfCenterX = adfGeoTransform[0] + dfWidth * adfGeoTransform[1] / 2.0
			+ dfHeight * adfGeoTransform[2] / 2.0;
		double dfCenterY = adfGeoTransform[3] + dfWidth * adfGeoTransform[4] / 2.0
			+ dfHeight * adfGeoTransform[5] / 2.0;

		OGRSpatialReference oSRS;
		oSRS.importFromWkt(poDataset->GetProjectionRef());

		if (oSRS.IsGeographic()) {
			qDebug() << "Center coords (already in geographic): (" + QString::number(dfCenterX)
				+ ", " + QString::number(dfCenterY) + ")";
			flag = true;
			x = dfCenterX;
			y = dfCenterY;
		}
		else {
			// 如果不是地理坐标系，转换到WGS84
			OGRSpatialReference oSRS_WGS84;
			oSRS_WGS84.SetWellKnownGeogCS("WGS84");

			OGRCoordinateTransformation* poCT =
				OGRCreateCoordinateTransformation(&oSRS, &oSRS_WGS84);
			if (poCT == nullptr) {
				qDebug() << "Failed to create coordinate transformation";
				return nullptr;
			}

			// double dfLon, dfLat;
			if (poCT->Transform(1, &dfCenterX, &dfCenterY)) {
				qDebug() << "Center coords (transformed to WGS84): ("
					+ QString::number(dfCenterX) + ", " + QString::number(dfCenterY)
					<< ")";
				flag = true;
				x = dfCenterX;
				y = dfCenterY;
			}
			else {
				qDebug() << "Transformation failed.";
			}
			OGRCoordinateTransformation::DestroyCT(poCT);
		}
	}
	if (nullptr == poDataset || NULL == poDataset) {}
	else {
		GDALClose(poDataset);
	}

	if (flag) {
		std::shared_ptr<PointRaster> RasterCenterPoint = std::make_shared<PointRaster>();
		RasterCenterPoint->x = x;
		RasterCenterPoint->y = y;
		RasterCenterPoint->z = 0;
		return RasterCenterPoint;
	}
	else {
		return nullptr;
	}
}
CoordinateSystemType getCoordinateSystemTypeByEPSGCode(long epsg_code)
{
	OGRSpatialReference oSRS;
	if (oSRS.importFromEPSG(epsg_code) == OGRERR_NONE) {
		if (oSRS.IsGeographic()) {
			return CoordinateSystemType::GeoCoordinateSystem;
		}
		else if (oSRS.IsProjected()) {
			return CoordinateSystemType::ProjectCoordinateSystem;
		}
	}
	else {
		return CoordinateSystemType::UNKNOW;
	}
}

void ShowProessAbstract::showProcess(double precent, QString tip)
{

}

void ShowProessAbstract::showToolInfo(QString tip)
{
}


void resampleRaster(const char* inputRaster, const char* outputRaster, double targetPixelSizeX, double targetPixelSizeY) {
	// 初始化GDAL
	GDALAllRegister();
	// 打开输入栅格文件
	GDALDataset* poDataset = (GDALDataset*)GDALOpen(inputRaster, GA_ReadOnly);
	if (poDataset == nullptr) {
		std::cerr << "Failed to open raster file." << std::endl;
		return;
	}

	// 获取原始栅格的空间参考
	double adfGeoTransform[6];
	if (poDataset->GetGeoTransform(adfGeoTransform) != CE_None) {
		std::cerr << "Failed to get geotransform." << std::endl;
		GDALClose(poDataset);
		return;
	}

	// 获取原始栅格的尺寸
	int nXSize = poDataset->GetRasterXSize();
	int nYSize = poDataset->GetRasterYSize();

	// 计算目标栅格的尺寸
	double targetXSize = (adfGeoTransform[1] * nXSize) / targetPixelSizeX;
	double targetYSize = (adfGeoTransform[5] * nYSize) / targetPixelSizeY;

	// 创建目标数据集（输出栅格）
	GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	if (poDriver == nullptr) {
		std::cerr << "Failed to get GTiff driver." << std::endl;
		GDALClose(poDataset);
		return;
	}

	// 创建输出数据集
	GDALDataset* poOutDataset = poDriver->Create(outputRaster, (int)targetXSize, (int)targetYSize, poDataset->GetRasterCount(), GDT_Float32, nullptr);
	if (poOutDataset == nullptr) {
		std::cerr << "Failed to create output raster." << std::endl;
		GDALClose(poDataset);
		return;
	}

	// 设置输出数据集的地理变换（坐标系）
	double targetGeoTransform[6] = {
		adfGeoTransform[0], targetPixelSizeX, 0, adfGeoTransform[3], 0, -targetPixelSizeY
	};
	poOutDataset->SetGeoTransform(targetGeoTransform);

	// 设置输出数据集的投影信息
	poOutDataset->SetProjection(poDataset->GetProjectionRef());

	// 进行重采样
	for (int i = 0; i < poDataset->GetRasterCount(); i++) {
		GDALRasterBand* poBand = poDataset->GetRasterBand(i + 1);
		GDALRasterBand* poOutBand = poOutDataset->GetRasterBand(i + 1);

		// 使用GDAL的重采样方法，选择一个适当的重采样方式
		poOutBand->RasterIO(GF_Write, 0, 0, (int)targetXSize, (int)targetYSize,
			nullptr, (int)targetXSize, (int)targetYSize,
			poBand->GetRasterDataType(), 0, 0, nullptr);
	}

	// 关闭数据集
	GDALClose(poDataset);
	GDALClose(poOutDataset);

	qDebug() << "Resampling completed." ;
}

void transformRaster(const char* inputFile, const char* outputFile, int sourceEPSG, int targetEPSG) {
	// 初始化 GDAL 库
	GDALAllRegister();

	// 打开源栅格文件
	GDALDataset* poSrcDS = (GDALDataset*)GDALOpen(inputFile, GA_ReadOnly);
	if (poSrcDS == nullptr) {
		qDebug() << "Failed to open input file:" << inputFile;
		return;
	}

	// 获取源栅格的基本信息
	int nXSize = poSrcDS->GetRasterXSize();
	int nYSize = poSrcDS->GetRasterYSize();
	int nBands = poSrcDS->GetRasterCount();
	GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType();

	// 创建目标栅格文件
	GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	if (poDriver == nullptr) {
		qDebug() << "GTiff driver not available.";
		GDALClose(poSrcDS);
		return;
	}

	GDALDataset* poDstDS = poDriver->Create(outputFile, nXSize, nYSize, nBands, eDT, nullptr);
	if (poDstDS == nullptr) {
		qDebug() << "Failed to create output file:" << outputFile;
		GDALClose(poSrcDS);
		return;
	}

	// 设置目标栅格的空间参考系统
	OGRSpatialReference oSRS;
	oSRS.importFromEPSG(targetEPSG);

	char* pszWKT = nullptr;
	oSRS.exportToWkt(&pszWKT);
	poDstDS->SetProjection(pszWKT);
	CPLFree(pszWKT);

	// 复制元数据
	poDstDS->SetMetadata(poSrcDS->GetMetadata());

	// 复制每个波段的数据
	for (int i = 1; i <= nBands; ++i) {
		GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(i);
		GDALRasterBand* poDstBand = poDstDS->GetRasterBand(i);

		float* pafScanline = (float*)CPLMalloc(sizeof(float) * nXSize);

		for (int j = 0; j < nYSize; ++j) {
			poSrcBand->RasterIO(GF_Read, 0, j, nXSize, 1, pafScanline, nXSize, 1, GDT_Float32, 0, 0);
			poDstBand->RasterIO(GF_Write, 0, j, nXSize, 1, pafScanline, nXSize, 1, GDT_Float32, 0, 0);
		}

		CPLFree(pafScanline);
	}

	// 关闭数据集
	GDALClose(poSrcDS);
	GDALClose(poDstDS);

	qDebug() << "Raster transformation completed successfully.";
}



ErrorCode transformCoordinate(double x, double y, int sourceEPSG, int targetEPSG, Point2 &p) {
	// 创建源坐标系（原始坐标系）
	OGRSpatialReference sourceSRS;
	sourceSRS.importFromEPSG(sourceEPSG);  // 使用 EPSG 编码来指定坐标系

	// 创建目标坐标系（目标坐标系）
	OGRSpatialReference targetSRS;
	targetSRS.importFromEPSG(targetEPSG);  // WGS84 坐标系 EPSG:4326

	// 创建坐标变换对象
	OGRCoordinateTransformation* transform = OGRCreateCoordinateTransformation(&sourceSRS, &targetSRS);
	if (transform == nullptr) {
		qDebug() << "Failed to create coordinate transformation." ;
		return ErrorCode::FAIL;
	}

	// 转换坐标
	double transformedX = x;
	double transformedY = y;
	if (transform->Transform(1, &transformedX, &transformedY)) {
		qDebug() << "Original Coordinates: (" << x << ", " << y << ")" ;
		qDebug() << "Transformed Coordinates (EPSG:" << targetEPSG << "): (" << transformedX << ", " << transformedY << ")" ;
	}
	else {
		qDebug() << "Coordinate transformation failed." ;
	}

	// 清理
	delete transform;
	p.x = transformedX;
	p.y = transformedY;
	return ErrorCode::SUCCESS;

}

void cropRasterByLatLon(const char* inputFile, const char* outputFile,double minLon, double maxLon, double minLat, double maxLat) {
	// 初始化 GDAL 库
	GDALAllRegister();

	// 打开栅格数据集
	GDALDataset* poDataset = (GDALDataset*)GDALOpen(inputFile, GA_ReadOnly);
	if (poDataset == nullptr) {
		std::cerr << "Failed to open input raster." << std::endl;
		return;
	}

	// 获取栅格数据的地理参考信息
	double adfGeoTransform[6];
	if (poDataset->GetGeoTransform(adfGeoTransform) != CE_None) {
		std::cerr << "Failed to get geotransform." << std::endl;
		GDALClose(poDataset);
		return;
	}

	// 获取输入影像的投影信息
	const char* projection = poDataset->GetProjectionRef();

	// 根据经纬度计算出裁剪区域对应的栅格像素坐标
	int xMin = (int)((minLon - adfGeoTransform[0]) / adfGeoTransform[1]);
	int xMax = (int)((maxLon - adfGeoTransform[0]) / adfGeoTransform[1]);
	int yMin = (int)((maxLat - adfGeoTransform[3]) / adfGeoTransform[5]);
	int yMax = (int)((minLat - adfGeoTransform[3]) / adfGeoTransform[5]);

	// 创建裁剪区域的目标栅格数据集
	GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	if (poDriver == nullptr) {
		std::cerr << "Failed to get GTiff driver." << std::endl;
		GDALClose(poDataset);
		return;
	}

	// 创建输出栅格数据集，指定尺寸
	int width = xMax - xMin;
	int height = yMax - yMin;
	GDALDataset* poOutDataset = poDriver->Create(outputFile, width, height, poDataset->GetRasterCount(), GDT_Float32, nullptr);
	if (poOutDataset == nullptr) {
		std::cerr << "Failed to create output raster." << std::endl;
		GDALClose(poDataset);
		return;
	}

	// 设置输出栅格的投影信息和地理变换
	poOutDataset->SetProjection(projection);
	double newGeoTransform[6] = { adfGeoTransform[0] + xMin * adfGeoTransform[1], adfGeoTransform[1], 0.0, adfGeoTransform[3] + yMin * adfGeoTransform[5], 0.0, adfGeoTransform[5] };
	poOutDataset->SetGeoTransform(newGeoTransform);

	// 循环读取源数据并写入目标数据集
	for (int i = 0; i < poDataset->GetRasterCount(); ++i) {
		GDALRasterBand* poBand = poDataset->GetRasterBand(i + 1);
		GDALRasterBand* poOutBand = poOutDataset->GetRasterBand(i + 1);

		// 读取源数据
		int* pData = new int[width * height];
		poBand->RasterIO(GF_Read, xMin, yMin, width, height, pData, width, height, GDT_Int32, 0, 0);

		// 写入目标数据
		poOutBand->RasterIO(GF_Write, 0, 0, width, height, pData, width, height, GDT_Int32, 0, 0);

		delete[] pData;
	}

	qDebug() << "Raster cropped and saved to: " << outputFile ;

	// 清理
	GDALClose(poDataset);
	GDALClose(poOutDataset);
}


ErrorCode  DEM2XYZRasterAndSlopRaster(QString dempath, QString demxyzpath, QString demsloperPath)
{
	gdalImage demds(dempath);
	gdalImage demxyz = CreategdalImage(demxyzpath, demds.height, demds.width, 3, demds.gt, demds.projection, true, true);// X,Y,Z

	// 分块计算并转换为XYZ

	Eigen::MatrixXd demArr = demds.getData(0, 0, demds.height, demds.width, 1);
	Eigen::MatrixXd demR = demArr;
	Landpoint LandP{ 0,0,0 };
	Point3 GERpoint{ 0,0,0 };
	double R = 0;
	double dem_row = 0, dem_col = 0, dem_alt = 0;

	long line_invert = 1000;

	double rowidx = 0;
	double colidx = 0;
	for (int max_rows_ids = 0; max_rows_ids < demds.height; max_rows_ids = max_rows_ids + line_invert) {
		Eigen::MatrixXd demdata = demds.getData(max_rows_ids, 0, line_invert, demds.width, 1);
		Eigen::MatrixXd xyzdata_x = demdata.array() * 0;
		Eigen::MatrixXd xyzdata_y = demdata.array() * 0;
		Eigen::MatrixXd xyzdata_z = demdata.array() * 0;

		int datarows = demdata.rows();
		int datacols = demdata.cols();

		for (int i = 0; i < datarows; i++) {
			for (int j = 0; j < datacols; j++) {
				rowidx = i + max_rows_ids;
				colidx = j;
				demds.getLandPoint(rowidx, colidx, demdata(i, j), LandP); // 获取地理坐标
				LLA2XYZ(LandP, GERpoint); // 经纬度转换为地心坐标系
				xyzdata_x(i, j) = GERpoint.x;
				xyzdata_y(i, j) = GERpoint.y;
				xyzdata_z(i, j) = GERpoint.z;
			}
		}
		demxyz.saveImage(xyzdata_x, max_rows_ids, 0, 1);
		demxyz.saveImage(xyzdata_y, max_rows_ids, 0, 2);
		demxyz.saveImage(xyzdata_z, max_rows_ids, 0, 3);
	}


	// 计算坡向角
	gdalImage demsloperxyz = CreategdalImage(demsloperPath, demds.height, demds.width, 4, demds.gt, demds.projection, true, true);// X,Y,Z,cosangle

	line_invert = 1000;
	long start_ids = 0;
	long dem_rows = 0, dem_cols = 0;

	for (start_ids = 1; start_ids < demds.height; start_ids = start_ids + line_invert) {
		Eigen::MatrixXd demdata = demds.getData(start_ids - 1, 0, line_invert + 2, demxyz.width, 1);
		long startlineid = start_ids;
		Eigen::MatrixXd demsloper_x = demsloperxyz.getData(start_ids - 1, 0, line_invert + 2, demxyz.width, 1);
		Eigen::MatrixXd demsloper_y = demsloperxyz.getData(start_ids - 1, 0, line_invert + 2, demxyz.width, 2);
		Eigen::MatrixXd demsloper_z = demsloperxyz.getData(start_ids - 1, 0, line_invert + 2, demxyz.width, 3);
		Eigen::MatrixXd demsloper_angle = demsloperxyz.getData(start_ids - 1, 0, line_invert + 2, demxyz.width, 4);

		Landpoint p0, p1, p2, p3, p4, pslopeVector, pp;
		Vector3D  slopeVector;

		dem_rows = demsloper_y.rows();
		dem_cols = demsloper_y.cols();
		double sloperAngle = 0;
		Vector3D Zaxis = { 0,0,1 };

		double rowidx = 0, colidx = 0;

		for (long i = 1; i < dem_rows - 1; i++) {
			for (long j = 1; j < dem_cols - 1; j++) {
				rowidx = i + startlineid;
				colidx = j;
				demds.getLandPoint(rowidx, colidx, demdata(i, j), p0);
				demds.getLandPoint(rowidx - 1, colidx, demdata(i - 1, j), p1);
				demds.getLandPoint(rowidx, colidx - 1, demdata(i, j - 1), p2);
				demds.getLandPoint(rowidx + 1, colidx, demdata(i + 1, j), p3);
				demds.getLandPoint(rowidx, colidx + 1, demdata(i, j + 1), p4);

				pslopeVector = getSlopeVector(p0, p1, p2, p3, p4); // 地面坡向矢量
				slopeVector = { pslopeVector.lon,pslopeVector.lat,pslopeVector.ati };
				pp = LLA2XYZ(p0);
				Zaxis.x = pp.lon;
				Zaxis.y = pp.lat;
				Zaxis.z = pp.ati;
				sloperAngle = getCosAngle(slopeVector, Zaxis); // 地面坡向角

				demsloper_x(i, j) = slopeVector.x;
				demsloper_y(i, j) = slopeVector.y;
				demsloper_z(i, j) = slopeVector.z;
				demsloper_angle(i, j) = sloperAngle;
			}
		}
		demsloperxyz.saveImage(demsloper_x, start_ids - 1, 0, 1);
		demsloperxyz.saveImage(demsloper_y, start_ids - 1, 0, 2);
		demsloperxyz.saveImage(demsloper_z, start_ids - 1, 0, 3);
		demsloperxyz.saveImage(demsloper_angle, start_ids - 1, 0, 4);
	}


	return ErrorCode::SUCCESS;
}

void testOutAmpArr(QString filename, float* amp, long rowcount, long colcount)
{


	Eigen::MatrixXd h_amp_img = Eigen::MatrixXd::Zero(rowcount, colcount);

	for (long hii = 0; hii < rowcount; hii++) {
		for (long hjj = 0; hjj < colcount; hjj++) {
			h_amp_img(hii, hjj) = amp[hii * colcount + hjj];
		}
	}
	QString ampPath = getDebugDataPath(filename);
	saveEigenMatrixXd2Bin(h_amp_img, ampPath);
	qDebug() << filename.toLocal8Bit().constData() ;
	qDebug() << "max:\t" << h_amp_img.maxCoeff() ;
	qDebug() << "min:\t" << h_amp_img.minCoeff() ;
}

void testOutAmpArr(QString filename, double* amp, long rowcount, long colcount)
{


	Eigen::MatrixXd h_amp_img = Eigen::MatrixXd::Zero(rowcount, colcount);

	for (long hii = 0; hii < rowcount; hii++) {
		for (long hjj = 0; hjj < colcount; hjj++) {
			h_amp_img(hii, hjj) = amp[hii * colcount + hjj];
		}
	}
	QString ampPath = getDebugDataPath(filename);
	saveEigenMatrixXd2Bin(h_amp_img, ampPath);
	qDebug() << filename.toLocal8Bit().constData() ;
	qDebug() << "max:\t" << h_amp_img.maxCoeff() ;
	qDebug() << "min:\t" << h_amp_img.minCoeff() ;
}


void testOutClsArr(QString filename, long* amp, long rowcount, long colcount) {

	Eigen::MatrixXd h_amp_img = Eigen::MatrixXd::Zero(rowcount, colcount);

	for (long hii = 0; hii < rowcount; hii++) {
		for (long hjj = 0; hjj < colcount; hjj++) {
			h_amp_img(hii, hjj) = amp[hii * colcount + hjj];
		}
	}
	QString ampPath = getDebugDataPath(filename);
	saveEigenMatrixXd2Bin(h_amp_img, ampPath);
	qDebug() << filename.toLocal8Bit().constData() ;
	qDebug() << "max:\t" << h_amp_img.maxCoeff() ;
	qDebug() << "min:\t" << h_amp_img.minCoeff() ;

}

void testOutAntPatternTrans(QString antpatternfilename, double* antPatternArr,
	double starttheta, double deltetheta,
	double startphi, double deltaphi,
	long thetanum, long phinum)
{


	Eigen::MatrixXd antPatternMatrix(thetanum, phinum);
	for (long t = 0; t < thetanum; ++t) {
		for (long p = 0; p < phinum; ++p) {
			long index = t * phinum + p;
			if (index < thetanum * phinum) {
				antPatternMatrix(t, p) = static_cast<double>(antPatternArr[index]);  // Copy to Eigen matrix
			}
		}
	}

	Eigen::MatrixXd gt(2, 3);
	gt(0, 0) = startphi;//x
	gt(0, 1) = deltaphi;
	gt(0, 2) = 0;

	gt(1, 0) = starttheta;
	gt(1, 1) = 0;
	gt(1, 2) = deltetheta;

	QString antpatternfilepath = getDebugDataPath(antpatternfilename);
	gdalImage  ds = CreategdalImageDouble(antpatternfilepath, thetanum, phinum, 1, gt, "", true, true, true);
	ds.saveImage(antPatternMatrix, 0, 0, 1);
}


void MergeTiffs(QList<QString> inputFiles, QString outputFile) {
	GDALAllRegister();

	if (inputFiles.isEmpty()) {
		fprintf(stderr, "No input files provided.\n");
		return;
	}

	// Open the first file to determine the data type and coordinate system
	GDALDataset* poFirstDS = (GDALDataset*)GDALOpen(inputFiles.first().toUtf8().constData(), GA_ReadOnly);
	if (poFirstDS == nullptr) {
		fprintf(stderr, "Failed to open the first file %s\n", inputFiles.first().toUtf8().constData());
		return;
	}

	double adfGeoTransform[6];
	CPLErr eErr = poFirstDS->GetGeoTransform(adfGeoTransform);
	if (eErr != CE_None) {
		fprintf(stderr, "Failed to get GeoTransform for the first file %s\n", inputFiles.first().toUtf8().constData());
		GDALClose(poFirstDS);
		return;
	}

	int nXSize = 0;
	int nYSize = 0;
	double minX = std::numeric_limits<double>::max();
	double minY = std::numeric_limits<double>::max();
	double maxX = std::numeric_limits<double>::lowest();
	double maxY = std::numeric_limits<double>::lowest();
	double pixelWidth = adfGeoTransform[1];
	double pixelHeight = adfGeoTransform[5];

	// Determine the bounding box and size of the output raster
	for (const QString& inputFile : inputFiles) {
		GDALDataset* poSrcDS = (GDALDataset*)GDALOpen(inputFile.toUtf8().constData(), GA_ReadOnly);
		if (poSrcDS == nullptr) {
			fprintf(stderr, "Failed to open %s\n", inputFile.toUtf8().constData());
			continue;
		}

		double adfThisTransform[6];
		eErr = poSrcDS->GetGeoTransform(adfThisTransform);
		if (eErr != CE_None) {
			fprintf(stderr, "Failed to get GeoTransform for %s\n", inputFile.toUtf8().constData());
			GDALClose(poSrcDS);
			continue;
		}

		minX = std::min(minX, adfThisTransform[0]);
		minY = std::min(minY, adfThisTransform[3] + adfThisTransform[5] * poSrcDS->GetRasterYSize());
		maxX = std::max(maxX, adfThisTransform[0] + adfThisTransform[1] * poSrcDS->GetRasterXSize());
		maxY = std::max(maxY, adfThisTransform[3]);

		GDALClose(poSrcDS);
	}

	nXSize = static_cast<int>(std::ceil((maxX - minX) / pixelWidth));
	nYSize = static_cast<int>(std::ceil((maxY - minY) / (-pixelHeight)));

	GDALDriver* poDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
	if (poDriver == nullptr) {
		fprintf(stderr, "GTiff driver not available.\n");
		GDALClose(poFirstDS);
		return;
	}

	char** papszOptions = nullptr;
	GDALDataset* poDstDS = poDriver->Create(outputFile.toUtf8().constData(), nXSize, nYSize, 1, poFirstDS->GetRasterBand(1)->GetRasterDataType(), papszOptions);
	if (poDstDS == nullptr) {
		fprintf(stderr, "Creation of output file failed.\n");
		GDALClose(poFirstDS);
		return;
	}

	poDstDS->SetGeoTransform(adfGeoTransform);

	const OGRSpatialReference* oSRS = poFirstDS->GetSpatialRef( );
	poDstDS->SetSpatialRef(oSRS);

	float fillValue = std::numeric_limits<float>::quiet_NaN();
	void* pafScanline = CPLMalloc(GDALGetDataTypeSizeBytes(poFirstDS->GetRasterBand(1)->GetRasterDataType()) * nXSize);
	memset(pafScanline, 0, GDALGetDataTypeSizeBytes(poFirstDS->GetRasterBand(1)->GetRasterDataType()) * nXSize);

	// Initialize all pixels to NaN
	for (int iY = 0; iY < nYSize; ++iY) {
		GDALRasterBand* poBand = poDstDS->GetRasterBand(1);
		poBand->RasterIO(GF_Write, 0, iY, nXSize, 1, pafScanline, nXSize, 1, poFirstDS->GetRasterBand(1)->GetRasterDataType(), 0, 0);
	}

	CPLFree(pafScanline);

	// Read each source image and write into the destination image
	for (const QString& inputFile : inputFiles) {
		GDALDataset* poSrcDS = (GDALDataset*)GDALOpen(inputFile.toUtf8().constData(), GA_ReadOnly);
		if (poSrcDS == nullptr) {
			fprintf(stderr, "Failed to open %s\n", inputFile.toUtf8().constData());
			continue;
		}

		double adfThisTransform[6];
		poSrcDS->GetGeoTransform(adfThisTransform);

		int srcXSize = poSrcDS->GetRasterXSize();
		int srcYSize = poSrcDS->GetRasterYSize();

		int dstXOffset = static_cast<int>(std::round((adfThisTransform[0] - minX) / pixelWidth));
		int dstYOffset = static_cast<int>(std::round((maxY - adfThisTransform[3]) / (-pixelHeight)));

		GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(1);
		GDALRasterBand* poDstBand = poDstDS->GetRasterBand(1);

		void* pafBuffer = CPLMalloc(GDALGetDataTypeSizeBytes(poFirstDS->GetRasterBand(1)->GetRasterDataType()) * srcXSize * srcYSize);
		poSrcBand->RasterIO(GF_Read, 0, 0, srcXSize, srcYSize, pafBuffer, srcXSize, srcYSize, poFirstDS->GetRasterBand(1)->GetRasterDataType(), 0, 0);

		poDstBand->RasterIO(GF_Write, dstXOffset, dstYOffset, srcXSize, srcYSize, pafBuffer, srcXSize, srcYSize, poFirstDS->GetRasterBand(1)->GetRasterDataType(), 0, 0);

		CPLFree(pafBuffer);
		GDALClose(poSrcDS);
	}

	GDALClose(poDstDS);
	GDALClose(poFirstDS);

}

void ConvertCoordinateSystem(QString inRasterPath, QString outRasterPath, long outepsgcode) {
	// 注册所有GDAL驱动
	GDALAllRegister();

	// 打开输入栅格文件
	GDALDataset* srcDataset = (GDALDataset*)GDALOpen(inRasterPath.toUtf8().constData(), GA_ReadOnly);
	if (!srcDataset) {
		// 错误处理：输出文件打开失败
		// qDebug() << "无法打开输入文件：" << inRasterPath;
		return;
	}

	// 创建目标坐标系
	OGRSpatialReference targetSRS;
	if (targetSRS.importFromEPSG(outepsgcode) != OGRERR_NONE) {
		GDALClose(srcDataset);
		// qDebug() << "无效的EPSG代码：" << outepsgcode;
		return;
	}

	// 获取目标坐标系的WKT表示
	char* targetSRSWkt = nullptr;
	targetSRS.exportToWkt(&targetSRSWkt);

	// 创建重投影后的虚拟数据集（Warped VRT）
	GDALDataset* warpedVRT = (GDALDataset*)GDALAutoCreateWarpedVRT(
		srcDataset,
		nullptr,          // 输入坐标系（默认使用源数据）
		targetSRSWkt,     // 目标坐标系
		GRA_Bilinear,     // 重采样方法：双线性插值
		0.0,              // 最大误差（0表示自动计算）
		nullptr           // 其他选项
	);
	CPLFree(targetSRSWkt); // 释放WKT内存

	if (!warpedVRT) {
		GDALClose(srcDataset);
		qDebug() << u8"创建投影转换VRT失败";
		return;
	}

	// 获取输出驱动（GeoTIFF格式）
	QString filesuffer = getFileExtension(outRasterPath).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* driver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");
	if (!driver) {
		GDALClose(warpedVRT);
		GDALClose(srcDataset);
		// qDebug() << "无法获取GeoTIFF驱动";
		return;
	}

	// 创建输出栅格文件
	GDALDataset* dstDataset = driver->CreateCopy(
		outRasterPath.toUtf8().constData(), // 输出文件路径
		warpedVRT,                          // 输入数据集（VRT）
		false,                              // 是否严格复制
		nullptr,                            // 创建选项
		nullptr,                            // 进度回调
		nullptr                             // 回调参数
	);

	if (!dstDataset) {
		// qDebug() << "创建输出文件失败：" << outRasterPath;
		GDALClose(warpedVRT);
		GDALClose(srcDataset);
		return;
	}

	// 释放资源
	GDALClose(dstDataset);
	GDALClose(warpedVRT);
	GDALClose(srcDataset);
}


void ResampleByReferenceRasterB(QString pszSrcFile, QString RefrasterBPath, QString pszOutFile, GDALResampleAlg eResample) {
	GDALAllRegister();
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");
	GDALDataset* pDSrc = (GDALDataset*)GDALOpen(pszSrcFile.toLocal8Bit().constData(), GA_ReadOnly);
	if (pDSrc == NULL) {
		qDebug() << u8"do not  open In Raster file: " << pszSrcFile;
		return  ;
	}

	GDALDataset* pDRef = (GDALDataset*)GDALOpen(RefrasterBPath.toLocal8Bit().constData(), GA_ReadOnly);
	if (pDRef == NULL) {
		qDebug() << u8"do not open Ref Raster file: " << RefrasterBPath;
		return;
	}

	QString filesuffer = getFileExtension(pszOutFile).toLower();
	bool isTiff = filesuffer.contains("tif");
	GDALDriver* pDriver = isTiff ? GetGDALDriverManager()->GetDriverByName("GTiff") : GetGDALDriverManager()->GetDriverByName("ENVI");

	if (pDriver == NULL) {
		qDebug() << "not open driver";
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		return ;
	}
	int			 width = pDSrc->GetRasterXSize();
	int			 height = pDSrc->GetRasterYSize();
	int			 nBandCount = pDSrc->GetRasterCount();
	GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType();

	char* pszSrcWKT = NULL;
	pszSrcWKT = const_cast<char*>(pDSrc->GetProjectionRef());

	// 锟斤拷锟矫伙拷锟酵队帮拷锟斤拷锟轿?拷锟斤拷锟揭伙拷锟?1锟?7
	if (strlen(pszSrcWKT) <= 0) {
		OGRSpatialReference oSRS;
		oSRS.importFromEPSG(4326);
		// oSRS.SetUTM(50, true);   //锟斤拷锟斤拷锟斤拷  锟斤拷锟斤拷120锟斤拷
		// oSRS.SetWellKnownGeogCS("WGS84");
		oSRS.exportToWkt(&pszSrcWKT);
	}

	char* pdstSrcWKT = NULL;
	pdstSrcWKT = const_cast<char*>(pDRef->GetProjectionRef());

	// 锟斤拷锟矫伙拷锟酵队帮拷锟斤拷锟轿?拷锟斤拷锟揭伙拷锟?1锟?7
	if (strlen(pdstSrcWKT) <= 0)
	{
		OGRSpatialReference oSRS;
		oSRS.importFromEPSG(4326);
		// oSRS.SetUTM(50, true);   //锟斤拷锟斤拷锟斤拷  锟斤拷锟斤拷120锟斤拷
		// oSRS.SetWellKnownGeogCS("WGS84");
		oSRS.exportToWkt(&pdstSrcWKT);
	}


	int			 new_width = pDRef->GetRasterXSize();
	int			 new_height = pDRef->GetRasterYSize();
	double gt[6]  ;
	pDRef->GetGeoTransform(gt);

	// GDALDestroyGenImgProjTransformer(hTransformArg);
	qDebug() << "create init GDALDataset ";
	GDALDataset* pDDst =
		pDriver->Create(pszOutFile.toLocal8Bit().constData(), new_width, new_height, nBandCount, dataType, NULL);
	if (pDDst == NULL) {
		qDebug() << "not create init GDALDataset ";
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDRef);
		return  ;
	}

	pDDst->SetProjection(pdstSrcWKT);
	pDDst->SetGeoTransform(gt);


	qDebug() << "GDALCreateGenImgProjTransformer " << Qt::endl;
	void* hTransformArg;
	hTransformArg = GDALCreateGenImgProjTransformer((GDALDatasetH)pDSrc, pszSrcWKT, NULL, pszSrcWKT,
		FALSE, 0.0, 1);
	qDebug() << "no proj ";
	//(没锟斤拷投影锟斤拷影锟斤拷锟斤拷锟斤拷锟斤拷卟锟酵?拷锟?1锟?7)
	if (hTransformArg == NULL) {
		qDebug() << "hTransformArg create failure";
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDRef);
		return;
	}
	qDebug() << "has proj ";
	double dGeoTrans[6] = { 0 };
	int	   nNewWidth = 0, nNewHeight = 0;
	if (GDALSuggestedWarpOutput((GDALDatasetH)pDSrc, GDALGenImgProjTransform, hTransformArg,
		dGeoTrans, &nNewWidth, &nNewHeight)
		!= CE_None) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDRef);
		return  ;
	}



	GDALWarpOptions* psWo = GDALCreateWarpOptions();
	CPLSetConfigOption("GDAL_NUM_THREADS", "ALL_CPUS"); // 使用所有可用的CPU核心
	CPLSetConfigOption("GDAL_CACHEMAX", "16000");         // 设置缓存大小为500MB
	// psWo->papszWarpOptions = CSLDuplicate(NULL);
	psWo->eWorkingDataType = dataType;



	psWo->eResampleAlg = eResample;

	psWo->hSrcDS = (GDALDatasetH)pDSrc;
	psWo->hDstDS = (GDALDatasetH)pDDst;
	qDebug() << "GDALCreateGenImgProjTransformer"  ;
	psWo->pfnTransformer = GDALGenImgProjTransform;
	psWo->pTransformerArg = GDALCreateGenImgProjTransformer(
		(GDALDatasetH)pDSrc, pszSrcWKT, (GDALDatasetH)pDDst, pszSrcWKT, FALSE, 0.0, 1);
	;

	qDebug() << "GDALCreateGenImgProjTransformer has created" << Qt::endl;
	psWo->nBandCount = nBandCount;
	psWo->panSrcBands = (int*)CPLMalloc(nBandCount * sizeof(int));
	psWo->panDstBands = (int*)CPLMalloc(nBandCount * sizeof(int));
	for (int i = 0; i < nBandCount; i++) {
		psWo->panSrcBands[i] = i + 1;
		psWo->panDstBands[i] = i + 1;
	}

	GDALWarpOperation oWo;
	if (oWo.Initialize(psWo) != CE_None) {
		GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
		GDALClose((GDALDatasetH)(GDALDatasetH)pDRef);
		return ;
	}
	qDebug() << "ChunkAndWarpImage:" << new_width << "," << new_height << Qt::endl;
	oWo.ChunkAndWarpMulti(0, 0, new_width, new_height);
	GDALFlushCache(pDDst);
	qDebug() << "ChunkAndWarpImage over" << Qt::endl;
	// GDALDestroyGenImgProjTransformer(psWo->pTransformerArg);
	// GDALDestroyWarpOptions(psWo);
	GDALClose((GDALDatasetH)(GDALDatasetH)pDSrc);
	GDALClose((GDALDatasetH)(GDALDatasetH)pDDst);
	GDALClose((GDALDatasetH)(GDALDatasetH)pDRef);
	////GDALDestroy(); // or, DllMain at DLL_PROCESS_DETACH
	return ;
}



void ResampleByReferenceRasterB(QString InrasterAPath, QString RefrasterBPath, QString OutrasterCPath) {
    // 注册所有GDAL驱动
    GDALAllRegister();

    // 打开参考栅格B
    GDALDataset* refDS = (GDALDataset*)GDALOpen(RefrasterBPath.toUtf8().constData(), GA_ReadOnly);
    if (!refDS) {
        qDebug() << "无法打开参考栅格B：" << RefrasterBPath;
        return;
    }

    // 获取参考栅格的地理变换、投影和尺寸
    double geotransform[6];
    if (refDS->GetGeoTransform(geotransform) != CE_None) {
        qDebug() << "获取参考栅格的地理变换失败。";
        GDALClose(refDS);
        return;
    }

    const char* proj = refDS->GetProjectionRef();
    int cols = refDS->GetRasterXSize();
    int rows = refDS->GetRasterYSize();
    GDALClose(refDS); // 获取信息后关闭参考栅格

    // 打开输入栅格A
    GDALDataset* srcDS = (GDALDataset*)GDALOpen(InrasterAPath.toUtf8().constData(), GA_ReadOnly);
    if (!srcDS) {
        qDebug() << "无法打开输入栅格A：" << InrasterAPath;
        return;
    }

    // 获取输入栅格的波段数和数据类型
    int nBands = srcDS->GetRasterCount();
    if (nBands == 0) {
        qDebug() << "输入栅格没有波段数据。";
        GDALClose(srcDS);
        return;
    }
    GDALDataType dataType = srcDS->GetRasterBand(1)->GetRasterDataType();

    // 创建输出栅格C
    GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("GTiff");
    if (!driver) {
        qDebug() << "无法获取GeoTIFF驱动。";
        GDALClose(srcDS);
        return;
    }

    GDALDataset* dstDS = driver->Create(
        OutrasterCPath.toUtf8().constData(),
        cols,
        rows,
        nBands,
        dataType,
        nullptr
    );
    if (!dstDS) {
        qDebug() << "无法创建输出栅格：" << OutrasterCPath;
        GDALClose(srcDS);
        return;
    }

    // 设置输出栅格的地理变换和投影
    dstDS->SetGeoTransform(geotransform);
    dstDS->SetProjection(proj);

    // 配置GDAL Warp选项
    GDALWarpOptions* psWO = GDALCreateWarpOptions();
    psWO->hSrcDS = srcDS;
    psWO->hDstDS = dstDS;
    psWO->nBandCount = nBands;
    psWO->panSrcBands = (int*)CPLMalloc(nBands * sizeof(int));
    psWO->panDstBands = (int*)CPLMalloc(nBands * sizeof(int));
    for (int i = 0; i < nBands; ++i) {
        psWO->panSrcBands[i] = i + 1;
        psWO->panDstBands[i] = i + 1;
    }
    psWO->eResampleAlg = GRA_NearestNeighbour; // 使用最近邻重采样

    // 初始化坐标转换器
    psWO->pfnTransformer = GDALGenImgProjTransform;
    psWO->pTransformerArg = GDALCreateGenImgProjTransformer(
        srcDS, GDALGetProjectionRef(srcDS),
        dstDS, GDALGetProjectionRef(dstDS),
        FALSE, 0.0, 1
    );
    if (!psWO->pTransformerArg) {
        qDebug() << "创建坐标转换器失败。";
        GDALDestroyWarpOptions(psWO);
        GDALClose(srcDS);
        GDALClose(dstDS);
        return;
    }

    // 执行Warp操作
    GDALWarpOperation oWarp;
    if (oWarp.Initialize(psWO) != CE_None) {
        qDebug() << "初始化Warp操作失败。";
        GDALDestroyGenImgProjTransformer(psWO->pTransformerArg);
        GDALDestroyWarpOptions(psWO);
        GDALClose(srcDS);
        GDALClose(dstDS);
        return;
    }

    CPLErr eErr = oWarp.ChunkAndWarpImage(0, 0, cols, rows);
    if (eErr != CE_None) {
        qDebug() << "执行Warp操作失败。";
    }

    // 清理资源
    GDALDestroyGenImgProjTransformer(psWO->pTransformerArg);
    GDALDestroyWarpOptions(psWO);
    GDALClose(srcDS);
    GDALClose(dstDS);

    qDebug() << "重采样完成，结果已保存至：" << OutrasterCPath;
}


void CreateSARIntensityByLookTable(QString IntensityRasterPath,
	QString LookTableRasterPath,
	QString SARIntensityPath,
	long min_rid, long max_rid,
	long min_cid, long max_cid,
	std::function<void(long, long)> processBarShow 
)
{
	GDALAllRegister();
	constexpr size_t GB4 = size_t(1) * 1024 * 1024 * 1024; // 4GB in bytes

	// 打开输入数据集
	GDALDataset* lookDS = (GDALDataset*)GDALOpen(LookTableRasterPath.toStdString().c_str(), GA_ReadOnly);
	GDALDataset* intensityDS = (GDALDataset*)GDALOpen(IntensityRasterPath.toStdString().c_str(), GA_ReadOnly);

	// 验证数据集有效性
	if (!lookDS || !intensityDS ||
		lookDS->GetRasterXSize() != intensityDS->GetRasterXSize() ||
		lookDS->GetRasterYSize() != intensityDS->GetRasterYSize())
	{
		if (lookDS) GDALClose(lookDS);
		if (intensityDS) GDALClose(intensityDS);
		return;
	}

	// 获取栅格参数
	const int width = lookDS->GetRasterXSize();
	const int height = lookDS->GetRasterYSize();
	const int rows_sar = max_rid - min_rid + 1;
	const int cols_sar = max_cid - min_cid + 1;

	// 计算分块策略
	const size_t pixelBytes =
		GDALGetDataTypeSizeBytes(lookDS->GetRasterBand(1)->GetRasterDataType()) * 2 + // 两个波段
		GDALGetDataTypeSizeBytes(intensityDS->GetRasterBand(1)->GetRasterDataType());

	const size_t maxPixelsPerBlock = GB4 / pixelBytes;
	int blockXSize = width;
	int blockYSize = static_cast<int>(maxPixelsPerBlock / width);
	blockYSize = std::max(1, std::min(blockYSize, height));

	// 输出矩阵初始化
	std::vector<double> sarData(rows_sar * cols_sar, 0.0);

	// 分块处理
	for (int yOff = 0; yOff < height; yOff += blockYSize)
	{
		const int ySize = std::min(blockYSize, height - yOff);
		
		// 读取行号列号数据
		std::vector<long> rData(width * ySize);
		std::vector<long> cData(width * ySize);
		lookDS->GetRasterBand(1)->RasterIO(GF_Read, 0, yOff, width, ySize,
			rData.data(), width, ySize, GDT_Int32, 0, 0);
		lookDS->GetRasterBand(2)->RasterIO(GF_Read, 0, yOff, width, ySize,
			cData.data(), width, ySize, GDT_Int32, 0, 0);

		// 读取强度数据
		std::vector<float> intensity(width * ySize);
		intensityDS->GetRasterBand(1)->RasterIO(GF_Read, 0, yOff, width, ySize,
			intensity.data(), width, ySize, GDT_Float32, 0, 0);

		// 处理当前块
#pragma omp parallel for collapse(2)
		for (int y = 0; y < ySize; ++y) {
			for (int x = 0; x < width; ++x) {
				const int idx = y * width + x;
				const long r = rData[idx];
				const long c = cData[idx];

				if (r >= min_rid && r <= max_rid && c >= min_cid && c <= max_cid) {
					const int row = r - min_rid;
					const int col = c - min_cid;
#pragma omp atomic
					sarData[row * cols_sar + col] += intensity[idx];
				}
			}
		}
		if (processBarShow) {
			processBarShow(yOff, height);
		}

	}

	// 写入输出
	GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("GTiff");
	GDALDataset* outDS = driver->Create(SARIntensityPath.toStdString().c_str(),
		cols_sar, rows_sar, 1, GDT_Float64, nullptr);
	outDS->GetRasterBand(1)->RasterIO(GF_Write, 0, 0, cols_sar, rows_sar,
		sarData.data(), cols_sar, rows_sar, GDT_Float64, 0, 0);

	// 资源清理
	GDALClose(lookDS);
	GDALClose(intensityDS);
	GDALClose(outDS);
}







