将点X Y转为OGC WKB十六进制字符串(Java代码和oracle函数两种方式)

WKB(well-known binary) 是WKT的二进制表示形式,解决了WKT表达方式冗余的问题,便于传输和在数据库中存储相同的信息WKB是采用二进制存储表示点线面等。

WKB比WKT的优势在于WKB是二进制,主要是解决传输和存储的效率问题,所以MySQL,Postgre数据存储Geometry类型的数据,存储的值是WKB格式的。

WKB(Well-Known Binary)是OGC定义的一种用于表示几何对象的二进制格式。

对于一个2D点(没有Z和M值)的WKB表示(小端序):

字节顺序:1字节(0x01表示小端序)

类型值:4字节(Point的类型值为1,2D点)

坐标:两个双精度浮点数(各8字节),x和y。

以一个点(Point)为例,其WKB十六进制表示为:

0101000000000000000000F03F000000000000F03F

  • 字节序‌:01(表示little-endian)
  • 几何类型‌:01000000(表示Point)
  • 坐标值‌:X坐标为0x000000000000F03F,Y坐标为0x000000000000F03F‌12

一、java代码实现点xy转为wkb十六进制字符串

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public class PointToWKB {

    // 将双精度浮点数转换为小端字节序的8字节表示
    private static String doubleToLittleEndianHex(double value) {
        ByteBuffer buffer = ByteBuffer.allocate(8);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        buffer.putDouble(value);
        return bytesToHex(buffer.array());
    }

    // 将整型转换为小端字节序的4字节表示
    private static String intToLittleEndianHex(int value) {
        ByteBuffer buffer = ByteBuffer.allocate(4);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        buffer.putInt(value);
        return bytesToHex(buffer.array());
    }

    // 字节数组转十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            hexString.append(String.format("%02x", b));
        }
        System.out.println(hexString.toString());
        return hexString.toString();
    }

    // 生成点的WKB十六进制表示
    public static String convertPointToWKBHex(double x, double y) {
        // 字节顺序标记 (小端字节序: 0x01)
        String byteOrderHex = "01";

        // 几何类型 (点: 1)
        String geomTypeHex = intToLittleEndianHex(1);

        // X坐标的十六进制表示
        String xHex = doubleToLittleEndianHex(x);

        // Y坐标的十六进制表示
        String yHex = doubleToLittleEndianHex(y);

        // 组合所有部分
        return byteOrderHex + geomTypeHex + xHex + yHex;
    }

    public static void main(String[] args) {
        double longitude = 121.387451356 ; // 经度
        double latitude = 31.12874904;   // 纬度

        // 转换为WKB十六进制字符串
        String wkbHex = convertPointToWKBHex(longitude, latitude);

        // 输出结果
        System.out.println("经度: " + longitude + ", 纬度: " + latitude);
        System.out.println("WKB十六进制字符串: " + wkbHex);


    }
}

二、oracle函数实现点xy转wkb十六进制字符串

CREATE OR REPLACE FUNCTION double_to_little_endian_hex(
    p_value IN NUMBER
) RETURN VARCHAR2
IS
    l_raw RAW(8);
BEGIN
    -- 使用 UTL_RAW 转换函数(Oracle 11g+)
    l_raw := UTL_RAW.CAST_FROM_BINARY_DOUBLE(p_value);

    -- 返回小端序十六进制表示(反转字节顺序)
    RETURN LOWER(RAWTOHEX(UTL_RAW.REVERSE(l_raw)));

EXCEPTION
    -- 处理 UTL_RAW 不可用的情况(Oracle 10g 或其他限制)
    WHEN OTHERS THEN
        -- 回退方案:手动实现 IEEE 754 双精度转换
        DECLARE
            l_hex VARCHAR2(16);
            l_val BINARY_DOUBLE := p_value;
            l_ieee RAW(8);
        BEGIN
            -- 使用 DBMS_LOB 实现转换(10g 兼容方案)
            DBMS_LOB.CREATETEMPORARY(l_ieee, TRUE);
            DBMS_LOB.WRITEAPPEND(l_ieee, 8, UTL_RAW.CAST_FROM_BINARY_DOUBLE(l_val));
            l_hex := RAWTOHEX(UTL_RAW.REVERSE(l_ieee));
            RETURN LOWER(l_hex);
        EXCEPTION
            WHEN OTHERS THEN
                -- 最终回退:返回 0 的表示
                RETURN '0000000000000000';
        END;
END double_to_little_endian_hex;



CREATE OR REPLACE FUNCTION point_to_wkb_hex(
    p_x IN NUMBER,  -- 经度/X坐标
    p_y IN NUMBER   -- 纬度/Y坐标
) RETURN VARCHAR2
IS
    -- WKB 固定前缀 (01 + 01000000)
    c_prefix CONSTANT VARCHAR2(10) := '0101000000';

    l_x_hex VARCHAR2(16);
    l_y_hex VARCHAR2(16);
BEGIN
    -- 转换经度坐标
    l_x_hex := double_to_little_endian_hex(p_x);

    -- 转换纬度坐标
    l_y_hex := double_to_little_endian_hex(p_y);

    -- 组合所有部分形成完整 WKB
    RETURN c_prefix || l_x_hex || l_y_hex;

EXCEPTION
    WHEN OTHERS THEN
        -- 返回一个有效的 WKB 错误点
        RETURN c_prefix || '000000000000F87F' || '000000000000F87F'; -- NaN点
END point_to_wkb_hex;

SELECT point_to_wkb_hex(121.387451356,31.12874904) AS wkb_hex FROM DUAL;

0101000000e5b3c500cc585e40ff3074b2f5203f40

通过postgis转换验证

SELECT ENCODE(ST_AsBinary(ST_GeomFromText('POINT(121.387451356 31.12874904)')),'hex') AS wkb;

0101000000e5b3c500cc585e40ff3074b2f5203f40

select ST_AsEWKT('0101000000e5b3c500cc585e40ff3074b2f5203f40'::geometry)

POINT(121.387451356 31.12874904)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值