关于栅格数据中换算行列号和坐标系的说明

在进行栅格数据行列号和坐标系换算时需要注意以下两点:
1、栅格数据的行列号索引值一般以0开始;
2、坐标系方向与栅格行列索引方向是否相同。

一、将XY表示的坐标系值转换成对应栅格的行列号索引值:

// 栅格数据总行数
int rowCount = 100;
// 栅格数据总列数
int columnCount = 100;
// 栅格数据最小X坐标
double minX = 0;
// 栅格数据最小Y坐标
double minY = 0;
// 栅格数据最大X坐标
double maxX = 1000;
// 栅格数据最大Y坐标
double maxY = 1000;
// 需要换算的X坐标
double x = 400;
// 需要换算的Y坐标
double y = 400;
// 计算X轴方向每个栅格的坐标跨度(与栅格列相对应)
double dx = (maxX - minX) / (double)columnCount;
// 计算指定x坐标对应的栅格列索引值(坐标系X轴方向与栅格列索引方向相同)
int columnIndex = (int)((x - minX) / dx);
// 计算Y轴方向每个栅格的坐标跨度(与栅格行相对应)
double dy = (maxY - minY) / (double)rowCount;
// 计算指定y坐标对应的栅格行索引值(坐标系Y轴方向与栅格行索引方向相反)
int rowIndex = rowCount - (int)((y - minY) / dy) - 1;

二、将栅格的行列号索引值转换成以XY表示的坐标系值:

// 栅格数据总行数
int rowCount = 100;
// 栅格数据总列数
int columnCount = 100;
// 栅格数据最小X坐标
double minX = 0;
// 栅格数据最小Y坐标
double minY = 0;
// 栅格数据最大X坐标
double maxX = 1000;
// 栅格数据最大Y坐标
double maxY = 1000;
// 需要换算的栅格行索引值
int rowIndex = 40;
// 需要换算的栅格列索引值
int columnIndex = 40;
// 计算X轴方向每个栅格的坐标跨度(与栅格列相对应)
double dx = (maxX - minX) / (double)columnCount;
// 计算指定栅格列索引值对应的x坐标(坐标系X轴方向与栅格列索引方向相同,并取栅格的中心点作为栅格x坐标)
double x = (columnIndex + 0.5) * dx + minX;
// 计算Y轴方向每个栅格的坐标跨度(与栅格行相对应)
double dy = (maxY - minY) / (double)rowCount;
// 计算指定栅格行索引值对应的y坐标(坐标系Y轴方向与栅格行索引方向相反,并取栅格的中心点作为栅格y坐标)
double y = (rowCount - rowIndex - 0.5) * dy + minY;

关于C#中读取HDF4文件数据的说明

HDF4也被称为HDF(Hierarchical Data Format),可以存储不同类型的图像和数码数据的文件格式,并且可以在不同类型的机器上传输,同时还有统一处理这种文件格式的函数库。随着技术的发展,现存在两个完全不同的HDF文件版本:HDF4和HDF5,其中HDF4是第一个HDF版本。我们可以通过访问HDF4的官方网站(http://www.hdfgroup.org/products/hdf4/)查看其详细介绍。
csharp-read-hdf4-1
如果只是需要查看HDF4文件数据的话,我们可以从官网上下载并安装HDFView(一个简单的HDF文件查看工具):
csharp-read-hdf4-2
但是如果需要通过编程手段读写HDF4文件数据的话,我们就必须先从官网上下载并安装HDF4的函数库,然后再编程调用该函数库来实现对其的读写。
以下介绍如何通过C#方式读取HDF4文件的属性和数据。

一、安装HDF4函数库:
在HDF4官网下载页(http://www.hdfgroup.org/release4/obtain.html)下载并安装HDF4函数库。官网提供了多个系统平台的编译版本,在这里我们选择“Windows (32-bit)”平台:
csharp-read-hdf4-3
如在安装过程中发现环境变量无法写入,我们可以忽略设置环境变量选项。

二、引用HDF4函数库:
从官网中我们可以发现,现在的HDF4函数库只有提供C++和Fortran访问的版本,要想在C#程序中使用的话,我们需要通过DllImport方式引入。HDF4的函数库主要包含在hdf.dll和mfhdf.dll这两个库中,而常用来读取HDF4中数据的SD接口则在mdhdf.dll库中。

// 定义HDF4 SD接口函数库的文件位置
public const string MFHDF4_DLL = @"C:\Program Files (x86)\HDF_Group\HDF\4.2.11\bin\mfhdf.dll";

// 引入SDstart方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDstart", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDstart(string filename, int access_mode);

// 引入SDfindattr方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDfindattr", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDfindattr(int obj_id, string attr_name);

// 引入SDreadattr方法(字符串类型属性)
[DllImport(MFHDF4_DLL, EntryPoint = "SDreadattr", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDreadattr(int obj_id, int attr_index, StringBuilder attr_buffer);

// 引入SDreadattr方法(单精度浮点类型属性)
[DllImport(MFHDF4_DLL, EntryPoint = "SDreadattr", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDreadattr(int obj_id, int attr_index, float[] attr_buffer);

// 引入SDnametoindex方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDnametoindex", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDnametoindex(int sd_id, string sds_name);

// 引入SDselect方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDselect", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDselect(int sd_id, int sds_index);

// 引入SDgetinfo方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDgetinfo", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDgetinfo(int sds_id, StringBuilder sds_name, int[] rank, int[] dimsizes, int[] ntype, int[] num_attrs);

// 引入SDreaddata方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDreaddata", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDreaddata(int sds_id, int[] start, int[] stride, int[] edge, short[,] buffer);

// 引入SDendaccess方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDendaccess", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDendaccess(int sds_id);

// 引入SDend方法
[DllImport(MFHDF4_DLL, EntryPoint = "SDend", CallingConvention = CallingConvention.Cdecl)]
public static extern int SDend(int sd_id);

以上我们通过DllImport的方式引入读取HDF4文件所需要用到的相关SD接口函数,其中EntryPoint属性为对应的函数名称,CallingConvention属性必须设置为CallingConvention.Cdecl。由于个别函数返回的数据是通过指针引用在函数参数中的,因此我们需要通过StringBuilder来接收字符串数据,通过值类型数组(如float[]、int[]、short[]等)来接收数值型数据和数组型数据(不能通过ref或out参数返回)。

三、读取HDF4属性和数据:

// 要读取的HDF4文件
string hdf4File = "C:/test.hdf";
// 字符串类型属性
string sensor;
// 单精度浮点类型属性
float slope;
// 数据行数
int row;
// 数据列数
int column;
// 数据集数据
short[,] data;
// 函数调用状态
int status;
// 只读方式打开HDF4文件
int sd_id = SDstart(hdf4File, 1);
if (sd_id != -1)
{
    // 查找属性Sensor的索引号
    int attr_index = SDfindattr(sd_id, "Sensor");
    if (attr_index != -1)
    {
        // 读取Sensor属性,通过StringBuilder接收字符串数据
        StringBuilder buffer = new StringBuilder();
        status = SDreadattr(sd_id, attr_index, buffer);
        if (status != -1)
        {
            sensor = buffer.ToString();
        }
    }
    // 查找属性Slope的索引号
    attr_index = SDfindattr(sd_id, "Slope");
    if (attr_index != -1)
    {
        // 读取Slope属性,通过float[]接收单精度浮点数据
        float[] buffer = new float[1];
        status = SDreadattr(sd_id, attr_index, buffer);
        if (status != -1)
        {
            slope = buffer[0];
        }
    }
    // 查找数据集DATA的索引号
    int sds_indes = SDnametoindex(sd_id, "DATA");
    // 选中数据集
    int sds_id = SDselect(sd_id, sds_indes);
    if (sds_id != -1)
    {
        // 数据集名称
        StringBuilder sds_name = new StringBuilder();
        // 秩数
        int[] rank = new int[1];
        // 行列数
        int[] dimsizes = new int[2];
        // 数据类型
        int[] ntype = new int[1];
        // 属性数目
        int[] num_attrs = new int[1];
        // 读取数据集信息
        status = SDgetinfo(sds_id, sds_name, rank, dimsizes, ntype, num_attrs);
        if (status != -1)
        {
            row = dimsizes[0];
            column = dimsizes[1];
            // 读取数据集所有数据
            short[,] buffer = new short[row, column];
            status = SDreaddata(sds_id, new int[] { 0, 0 }, null, new int[] { row, column }, buffer);
            if (status != -1)
            {
                data = buffer;
            }
        }
        // 结束数据集访问
        status = SDendaccess(sds_id);
    }
    // 关闭HDF4文件
    status = SDend(sd_id);
}

从以上方法中可以看出,虽然HDF4官方并没有提供可直接让C#访问的类库,但我们还是可以基于DllImport这种静态函数引入的方式对其进行访问。

更多信息请参阅:The HDF Group – Information, Support, and Software

关于ArcGIS开发中计算两个几何对象之间距离的说明

在ArcGIS的二次开发中我们可以通过接口“IProximityOperator”的“ReturnDistance”方法来计算一个几何对象与另一个几何对象之间的距离。该接口被BezierCurve、CircularArc、EllipticArc、Envelope、GeoEllipse、GeoPolygon、GeoPolyline、MultiPatch、Multipoint、Point、Polygon、Polyline等几何对象实现。

// 定义用于计算的几何对象
IPoint point1 = new PointClass();
point1.X = 120;
point1.Y = 30;
// 定义计算距离的几何对象
IPoint point2 = new PointClass();
point2.X = 110;
point2.Y = 35;
// 获取IProximityOperator接口
IProximityOperator proximityOperator = point1 as IProximityOperator;
// 计算并返回几何对象point1到point2的距离
return proximityOperator.ReturnDistance(point2);