Java解析图形mdb矢量mdb

news2024/11/23 18:53:05

Java解析图形mdb矢量mdb

背景:项目中需要解析图形mdb,同事积累下的代码无法读取复杂图形;终于在某位大佬的博客下发现新的
解析方法,特此整理记录下。

原理:jackcess(assess提供解析mdb属性)、esri-geometry-api(esri提供解析二进制图形数据)

Maven依赖

<dependency>
    <groupId>com.healthmarketscience.jackcess</groupId>
    <artifactId>jackcess</artifactId>
    <version>4.0.5</version>
</dependency>
<dependency>
    <groupId>com.esri.geometry</groupId>
    <artifactId>esri-geometry-api</artifactId>
    <version>1.2.1</version>
</dependency>

读取测试代码

public static void main(String[] args) {
    // 设置mdb文件路径
    String mdbFilePath = "C:\\XXX.mdb";
    File file = new File(mdbFilePath);
    MDBReaderUtils readerUtils = new MDBReaderUtils();
    MDBMsg mdbMsg = readerUtils.read(file, "DATA_TEMPLATE");// mdb中数据表名称
    String epsg = mdbMsg.getEpsg();
    List<Map<String, Object>> data = mdbMsg.getData();
    System.out.println("epsg : " + epsg); // 坐标系
    System.out.println("data : " + data.size()); // mdb数据
    for (Map<String, Object> map : data) {
        String objectid = MDBReaderUtils.getString(map.get("objectid")); // objectid
        String wkt = MDBReaderUtils.getString(map.get("wkt")); // mdb中图形wkt
        System.out.println(objectid + " -> " + wkt);
    }
}

在这里插入图片描述

读取结果

在这里插入图片描述

MDBMsg

@Data
public class MDBMsg {
    private String epsg; // 坐标系
    private List<Map<String, Object>> data; // mdb数据
}

MDBReaderUtils

@Slf4j
public class MDBReaderUtils {

    private final static Map<String, String> ESRI_EPSG_MAPPING = new HashMap<>();

    static {
        ESRI_EPSG_MAPPING.put("GCS_China_Geodetic_Coordinate_System_2000", "4490");
        ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_40", "4528");
        ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_39", "4527");
        ESRI_EPSG_MAPPING.put("CGCS2000_3_Degree_GK_Zone_41", "4529");
        ESRI_EPSG_MAPPING.put("GCS_WGS_1984", "4326");
    }

    public MDBMsg read(MultipartFile multipartFile, String tableName) {
        File file = null;
        try {
            String originalFilename = multipartFile.getOriginalFilename();
            String[] filename = originalFilename.split("\\.");
            file = File.createTempFile(filename[0], filename[1] + ".");
            multipartFile.transferTo(file);
            file.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return read(file, tableName);
    }

    public MDBMsg read(File file, String tableName) {
        MDBMsg mdbMsg = new MDBMsg();
        try (Database db = DatabaseBuilder.open(file)) {

            String epsg = getEpsg(db, tableName);
            mdbMsg.setEpsg(epsg);

            Map<String, Integer> tableFieldShapeTypeMap = getShapeFieldMap(db);
            // 打开表
            Table table = db.getTable(tableName);
            List<? extends Column> columns = table.getColumns();
            List<Map<String, Object>> data = new ArrayList<>();
            // 读取所有行
            for (Row row : table) {
                Map<String, Object> map = new HashMap<>();
                for (Column column : columns) {
                    String name = column.getName();
                    Object value = row.get(name);
                    //DataType.OLE 类型代表几何类型
                    if (value instanceof byte[] && DataType.OLE.toString().equals(column.getType().toString())) {
                        try {
                            // 如果是字节数组,尝试解析为几何对象
                            byte[] shapeBytes = (byte[]) value;
                            // 使用 Esri Geometry API 解析二进制数据
                            ByteBuffer buffer = ByteBuffer.wrap(shapeBytes).order(java.nio.ByteOrder.LITTLE_ENDIAN);
                            buffer.rewind(); // 确保从头开始读取
                            // 使用 OperatorImportFromESRIShape 解析 Shape 数据
                            OperatorImportFromESRIShape opImportFromESRIShape = OperatorImportFromESRIShape.local();
                            Geometry.Type geometryTypeFromShapeType = getGeometryTypeFromShapeType(tableName, column.getName(), tableFieldShapeTypeMap);
                            Geometry esriGeometry = opImportFromESRIShape.execute(0, geometryTypeFromShapeType ,buffer);
                            // 将 Esri 几何对象转换为 OGC 几何对象
                            OGCGeometry ogcGeometry = OGCGeometry.createFromEsriGeometry(esriGeometry, null);
                            // 输出 WKT 格式的几何数据
                            String wkt = ogcGeometry.asText();
                            map.put("wkt", wkt);
                        } catch (Exception e) {
                            System.err.println("无法解析几何数据: " + e.getMessage());
                            continue;
                        }
                    } else {
                        map.put(name, value);
                    }
                }
                data.add(map);
            }
            mdbMsg.setData(data);
        } catch (Exception e) {
            mdbMsg.setData(new ArrayList<>());
            System.err.println(e.getMessage());
        }
        return mdbMsg;
    }

    /**
     * 获取mdb某个矢量表的几何类型
     * @param tableName
     * @param fieldName
     * @param tableFieldShapeTypeMap
     * @return
     */
    private Geometry.Type getGeometryTypeFromShapeType(String tableName, String fieldName, Map<String, Integer> tableFieldShapeTypeMap) {
        if (!tableFieldShapeTypeMap.containsKey(tableName + "." + fieldName)) {
            return null;
        }
        Integer type = tableFieldShapeTypeMap.get(tableName + "." + fieldName);
        //暂时只支持点、折线、面,也大致通过真实数据推断GDB_GeomColumns表中记录的几何类型
        if (type == 1) {
            return Geometry.Type.Point;
        }
        if (type == 3) {
            return Geometry.Type.Polyline;
        }
        if (type == 4) {
            return Geometry.Type.Polygon;
        }
        return null;
    }

    private Map<String, Integer> getShapeFieldMap(Database db) {
        try {
            // 获取 GDB_GeomColumns 表
            Table table = db.getTable("GDB_GeomColumns");
            // 创建一个映射,用于存储每个几何字段的几何类型
            Map<String, Integer> geometryTypeMap = new HashMap<>();
            // 读取 GDB_GeomColumns 表中的所有行
            for (Row row : table) {
                String tableName = row.get("TableName").toString();
                String fieldName = row.get("FieldName").toString();
                int shapeType = ((Number) row.get("ShapeType")).intValue();
                // 将几何字段和几何类型存储在映射中
                geometryTypeMap.put(tableName + "." + fieldName, shapeType);
            }
            return geometryTypeMap;
        } catch (Exception e) {
            log.error(e.getMessage());
            return new HashMap<>();
        }
    }

    private String getEpsg(Database db, String tName) {
        String epsg = "";
        try {
            // 获取 GDB_GeomColumns 表
            Table colTable = db.getTable("GDB_GeomColumns");
            int srid = -1;
            // 读取 GDB_GeomColumns 表中的所有行
            for (Row row : colTable) {
                String tableName = row.get("TableName").toString();
                if (tName.equals(tableName)) {
                    srid = ((Number) row.get("SRID")).intValue();
                    break;
                }
            }
            // 获取 GDB_SpatialRefs 表
            Table refTable = db.getTable("GDB_SpatialRefs");
            // 读取 GDB_SpatialRefs 表中的所有行
            for (Row row : refTable) {
                if (srid == ((Number) row.get("SRID")).intValue()) {
                    epsg = row.get("SRTEXT").toString().split(",")[0];
                    break;
                }
            }
            for (Map.Entry<String, String> entry : ESRI_EPSG_MAPPING.entrySet()) {
                if (epsg.contains(entry.getKey())) {
                    epsg = entry.getValue();
                    break;
                }
            }
            return epsg;
        } catch (Exception e) {
            log.error(e.getMessage());
            return epsg;
        }
    }

    public static String getString(Object o) {
        return Objects.isNull(o) ? null : o.toString();
    }

    public static Double getDouble(Object o) {
        Double v = null;

        try {
            v = Double.valueOf(getString(o));
        } catch (Exception var4) {
            ;
        }

        return v;
    }

    public static Integer getInteger(Object o) {
        Integer v = null;

        try {
            v = Integer.valueOf(getString(o));
        } catch (Exception var4) {
            ;
        }

        return v;
    }

    public static Long getLong(Object o) {
        Long v = null;

        try {
            v = Long.valueOf(getString(o));
        } catch (Exception var4) {
            ;
        }

        return v;
    }

    public static BigDecimal getBigDecimal(Object o) {
        BigDecimal v = null;

        try {
            v = new BigDecimal(getString(o));
        } catch (Exception var4) {
            ;
        }

        return v;
    }

}

参考博文:https://blog.csdn.net/qq_41613913/article/details/142488569

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196753.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++模拟实现二叉搜索树

目录 1.二叉搜索树的概念 2.二叉搜索树的性能分析 3.二叉搜索树的结构和中序遍历 3.1二叉搜索树中节点的结构 3.2二叉搜索树的结构 3.3中序遍历 4.二叉搜索树的插入 5.二叉搜索树的查找 6.二叉树搜索树的删除 7. 二叉搜索树的默认成员函数 8.参考代码 9.二叉搜…

常见的图像处理算法:Canny边缘检测

一、Canny边缘检测算子的由来 Canny 边缘检测算子是一种多级检测算法。1986 年由 John F. Canny 提出&#xff0c;同时提出 了边缘检测的三大准则&#xff1a; 1、低错误率的边缘检测&#xff1a;检测算法应该精确地找到图像中的尽可能多的边缘&#xff0c;尽可能的减少漏检…

【一起学Rust | 框架篇 | Tauri2.0框架】高级概念之安全特性的权限与能力

文章目录 前言一、开发前准备1. 准备项目2. 需求分析1. 监听系统热键2. 切换窗口无边框3. 切换窗口全屏 二、安装插件三、前端实现功能四、配置权限 前言 当前时间为 2024 年 9 月&#xff0c;距离Tauri 2.0 的 RC 版本发布迄今已近一个月。从 Tauri 官方渠道可以看出&#xf…

李飞飞:我不知道什么是AGI

图片来源&#xff1a;Stanford University 你对人工通用智能&#xff08;AGI&#xff09;感到困惑吗&#xff1f;这就是 OpenAI 执着于最终以“造福全人类”的方式创造的东西。你可能想认真对待他们&#xff0c;因为他们刚筹集了 66 亿美元以更接近这个目标。 但如果你仍然在…

揭秘Sui存储基金:灵活且可持续的链上数据管理解决方案

链上数据存储的方法常常被忽视&#xff0c;因为所使用的机制通常是传统和常见的。然而&#xff0c;在去中心化网络中&#xff0c;数据存储对确保数据完整性和长期可访问性至关重要。Sui的链上存储与其他区块链有所不同。 Sui存储基金是为了解决链上数据永久存储问题而设计的核…

企业架构系列(16)ArchiMate第14节:实施和迁移视角

在企业架构中&#xff0c;为了有效地规划和管理架构的变更与实施&#xff0c;通常会使用不同的视角来描述架构的不同方面。本篇涉及到三个主要视角&#xff1a;项目视角、迁移视角以及实施与迁移视角。 一、实施和迁移视角概览 1.项目视角 元素与关系&#xff1a;关注项目本身…

“网络安全等级保护测评入门:基础概念与重要性“

网络安全等级保护测评&#xff08;简称“等保测评”&#xff09;是依据国家网络安全等级保护制度&#xff0c;对信息系统安全等级进行评估和评定的过程。它是提高信息系统安全性、保障信息安全的重要手段。以下是关于等保测评的基础概念与重要性的详细解读&#xff1a; 一、等…

【钱拿不回来了,中介说开源吧】《刚体旋转的四元数模型及捷联惯性导航系统中定向算法》

《刚体旋转的四元数模型及捷联惯性导航系统中定向算法》 1. 摘要 本文深入探讨了四元数在刚体旋转描述中的核心作用以及其在捷联惯性导航系统&#xff08;SINS&#xff09;中确定方向的算法。详细阐述了四元数的理论基础、数学性质和实际应用优势&#xff0c;包括与卡丹角和欧…

小红书AI商单变现,单月收入10000+,真猛!

AI相关的话题在这两年来一直很火爆&#xff0c;很多行业也纷纷和AI结合起来&#xff0c; 从而达到更好的变现效果&#xff0c;这也是未来的发展趋势&#xff0c; 有这个工具确实能给我们的工作和生活带来一些便利 之前也拆解过很多类似的玩法&#xff0c; 比如AI古诗词、数…

软件测试之压力测试

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 压力测试 压力测试是一种软件测试&#xff0c;用于验证软件应用程序的稳定性和可靠性。压力测试的目标是在极其沉重的负载条件下测量软件的健壮性和错误处理能力&…

GSLAM——一个通用的SLAM架构和基准

GSLAM: A General SLAM Framework and Benchmark 开源地址 摘要&#xff1a; SLAM技术最近取得了许多成功&#xff0c;并吸引了高科技公司的关注。然而&#xff0c;如何同一现有或新兴算法的界面&#xff0c;一级有效地进行关于速度、稳健性和可移植性的基准测试仍然是问题。本…

芯片干货 | 同步内置MOS升压恒压5V/2A芯片FP6276B,输入限流可调

芯片概述 FP6276B是一个具有PWM/PSM控制的电流模式增压直流-直流转换器。它的PWM电路内置40mΩ高侧开关和40mΩ低侧开关使该调节器高高效。内部补偿网络还将外部组件计数最小化到只有6个。一个内部的0.6V电压被连接到误差放大器的非反相输入作为精度参考电压。内置的软启动功能…

Llama 3.2 智能代理开发教程

构建研究代理可能很复杂&#xff0c;但使用 LangChain 和 Ollama&#xff0c;它会变得更加简单和模块化。 在本教程中&#xff0c;我们将向你展示如何基于Llama 3.2创建一个研究代理&#xff0c;该代理可以路由查询、执行网络搜索并使用工作流和 LLM 的组合生成详细响应。最后…

我的书第三次重印啦,做一波活动,参与可抽现金红包~

大家好&#xff0c;我是拭心&#xff0c;好久不见。 四月份我的《Android 性能优化入门与实战》顺利出版&#xff0c;在朋友们帮忙宣传下&#xff0c;初印的两三千册很快卖完&#xff0c;四月份第二次重印&#xff0c;五个月后&#xff0c;又迎来了第三次重印。 这样的销量算不…

如何解决Lenovo笔记本电脑很快就自动休眠,自动锁屏,需要密码登录的问题

前段时间电脑经常会很快就锁屏了&#xff0c;只要离开电脑1分钟不到&#xff0c;就自动锁屏&#xff0c;然后就要输入密码登录&#xff0c;太烦了&#xff0c;后来百度和谷歌了不少帖子和方案&#xff0c;给的建议都是调整电源选项之类的参数。 尝试了各种修改参数&#xff0c…

栈和队列--DS

1. 栈(Stack) 1.1 栈的定义 **栈是一种特殊的线性表&#xff0c;其只允许在固定的一端(栈顶)进行元素插入和删除元素操作。**进行数据插入和删除操作的一段称为栈顶&#xff0c;另一端则称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)原则。 1.2 栈的核心操…

Android 无Bug版 多语言设计方案!

出海业务为什么要做多语言&#xff1f; 1.市场扩大与本地化需求&#xff1a; 通过支持多种语言&#xff0c;出海项目可以触及更广泛的国际用户群体&#xff0c;进而扩大其市场份额。 本地化是吸引国际用户的重要策略之一&#xff0c;而语言本地化是其中的核心。使用用户的母语…

E37.【C语言】动态内存管理练习题

目录 1. 答案速查 分析 源代码分析 反汇编代码分析(底层) 2. 答案速查 分析 3. 答案速查 分析 VS逐步调试 1. 求下列代码的执行结果 #include <stdio.h> char* GetMemory(void) {char p[] "hello world";return p; }void Test(void) {char* str…

软件测试学习笔记丨allure学习指南

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32336 安装与下载 需要下载本地文件&#xff0c;并且添加到环境变量里 windows&#xff1a;下载&#xff0c;解压&#xff0c;并配置环境变量 mac&#xff1a;brew install allure 环境变量…

1688代采系统-反向海淘系统详细介绍

Onebound凡邦1688代采系统-反向海淘系统是一种专为海外买家及跨境电商提供一站式采购解决方案的平台。其核心功能和服务旨在解决跨境采购中的语言、货币等常见问题&#xff0c;并优化采购流程&#xff0c;提高采购效率。以下是对该系统的详细介绍。 一、核心功能 商品采集与展…