Browse Source

终验收数据预处理模块第一次提交

cicv 1 tháng trước cách đây
commit
81544a84da
62 tập tin đã thay đổi với 5613 bổ sung0 xóa
  1. 16 0
      .vscode/launch.json
  2. 167 0
      README.md
  3. 146 0
      README_new.md
  4. BIN
      __pycache__/merge_data_process.cpython-313.pyc
  5. BIN
      __pycache__/merge_data_process_LST.cpython-313.pyc
  6. 297 0
      _internal/VBox.dbc
  7. 256 0
      _internal/data_map/hd_arrow.csv
  8. 14 0
      _internal/data_map/hd_crosswalks.csv
  9. 1 0
      _internal/data_map/hd_intersections.csv
  10. 5 0
      _internal/data_map/hd_lane.csv
  11. 7 0
      _internal/data_map/hd_link.csv
  12. 58 0
      _internal/data_map/hd_sign.csv
  13. 73 0
      _internal/data_map/hd_stopline.csv
  14. 30 0
      _internal/data_map/hd_trafficlight.csv
  15. BIN
      _internal/engine
  16. 35 0
      config/config.json
  17. 9 0
      core/__init__.py
  18. BIN
      core/__pycache__/__init__.cpython-310.pyc
  19. BIN
      core/__pycache__/__init__.cpython-313.pyc
  20. BIN
      core/__pycache__/config_manager.cpython-313.pyc
  21. BIN
      core/__pycache__/data_pipeline.cpython-313.pyc
  22. BIN
      core/__pycache__/db_processor.cpython-313.pyc
  23. BIN
      core/__pycache__/error_handler.cpython-313.pyc
  24. BIN
      core/__pycache__/optimized_processor.cpython-313.pyc
  25. BIN
      core/__pycache__/plugin_interface.cpython-310.pyc
  26. BIN
      core/__pycache__/plugin_interface.cpython-313.pyc
  27. BIN
      core/__pycache__/plugin_manager.cpython-313.pyc
  28. BIN
      core/__pycache__/resource_manager.cpython-313.pyc
  29. 257 0
      core/config_manager.py
  30. 295 0
      core/data_pipeline.py
  31. 152 0
      core/error_handler.py
  32. 175 0
      core/optimized_processor.py
  33. 106 0
      core/plugin_interface.py
  34. 83 0
      core/plugin_manager.py
  35. BIN
      core/processors/__pycache__/final_processor.cpython-313.pyc
  36. 24 0
      core/processors/built_in/__init__.py
  37. BIN
      core/processors/built_in/__pycache__/__init__.cpython-313.pyc
  38. BIN
      core/processors/built_in/__pycache__/base.cpython-313.pyc
  39. BIN
      core/processors/built_in/__pycache__/lst.cpython-313.pyc
  40. BIN
      core/processors/built_in/__pycache__/pgvil.cpython-313.pyc
  41. BIN
      core/processors/built_in/__pycache__/processor.cpython-313.pyc
  42. 1449 0
      core/processors/built_in/lst.py
  43. 274 0
      core/processors/built_in/pgvil.py
  44. 221 0
      core/resource_manager.py
  45. 153 0
      docs/can_plugin_guide.md
  46. 667 0
      docs/optimization_plan.md
  47. 74 0
      docs/plugin_system.md
  48. 3 0
      plugins/__init__.py
  49. BIN
      plugins/__pycache__/__init__.cpython-313.pyc
  50. BIN
      plugins/__pycache__/custom_plugin.cpython-313.pyc
  51. BIN
      plugins/__pycache__/plugin_interface.cpython-313.pyc
  52. BIN
      plugins/__pycache__/plugin_manager.cpython-313.pyc
  53. BIN
      plugins/__pycache__/radar_data_processor.cpython-313.pyc
  54. BIN
      plugins/__pycache__/resource_manager.cpython-313.pyc
  55. 195 0
      plugins/radar_data_processor.py
  56. 28 0
      resources/radar_config.xml
  57. 300 0
      run.py
  58. 1 0
      trafficlights.json
  59. 0 0
      utils/__init__.py
  60. BIN
      utils/__pycache__/__init__.cpython-313.pyc
  61. BIN
      utils/__pycache__/logging_utils.cpython-313.pyc
  62. 42 0
      utils/logging_utils.py

+ 16 - 0
.vscode/launch.json

@@ -0,0 +1,16 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+    
+        {
+            "name": "Python Debugger: Current File",
+            "type": "debugpy",
+            "request": "launch",
+            "program": "${file}",
+            "console": "integratedTerminal"
+        }
+    ]
+}

+ 167 - 0
README.md

@@ -0,0 +1,167 @@
+# 数据预处理系统 (Data Preprocessing System)
+
+## 1. 项目概述
+本项目是一个用于处理车辆数据的预处理系统,目前主要包括:
+- 路测内置数据处理 (merge_data_process_LST.py)
+- 仿真内置数据处理 (后续扩展)
+- 插件式自定义数据处理
+
+## 功能特点
+
+- 支持多种数据源处理: CAN、GNSS、雷达等
+- 插件系统支持扩展自定义数据处理
+- 并行处理优化
+- 灵活的配置管理
+- 完整的错误处理机制
+
+## 安装要求
+
+- Python 3.6+
+- 依赖包:
+  - pandas
+  - numpy
+  - cantools (CAN数据处理)
+  - bagpy (ROS包处理)
+  - pyproj (坐标投影)
+
+## 安装步骤
+
+1. 克隆或下载代码库
+2. 安装依赖:
+```bash
+pip install -r requirements.txt
+```
+
+## 使用方法
+
+### 基本用法
+```bash
+python run.py --zip-path <数据ZIP文件路径> --output-dir <输出目录>
+```
+
+### 完整参数说明
+```bash
+python run.py \
+  --zip-path <数据ZIP文件路径> \
+  --trafficlight-json <交通灯JSON文件路径> \
+  --output-dir <输出目录> \
+  --utm-zone <UTM区域> \
+  --x-offset <X偏移量> \
+  --y-offset <Y偏移量> \
+  --plugins-dir <插件目录> \
+  --resources-dir <资源目录> \
+  --config <配置文件路径> \
+  --use-parallel \
+  --batch-size 10000
+```
+
+### 打包发布
+使用 PyInstaller 打包:
+```bash
+pyinstaller --onedir --name merge_data_process_LST --clean \
+  --add-data="$(python -c 'import bagpy; from pathlib import Path; print(f"{Path(bagpy.__file__).parent}:bagpy")')" \
+  --add-binary="/path/to/engine:." \
+  --add-data="./data_map:data_map" \
+  --add-data="VBox.dbc:." \
+  merge_data_process_LST.py
+```
+
+## 文件结构分析
+必要的核心文件:
+```
+/core/ - 核心模块目录
+  __init__.py
+  plugin_interface.py - 插件接口
+  plugin_manager.py - 插件管理器
+  resource_manager.py - 资源管理器
+  error_handler.py - 错误处理
+  config_manager.py - 配置管理
+/plugins/ - 插件目录
+  __init__.py
+  radar_data_processor.py - 雷达数据处理插件
+主要文件:
+  merge_data_process_LST.py - 主要数据处理逻辑
+  run.py - 命令行入口程序
+  config.json - 配置文件
+  README.md - 项目文档
+建议移除的文件:
+  merge_data_process.py - 功能已被整合到 merge_data_process_LST.py
+  data_pipeline.py - 未被实际使用
+```
+
+## 项目结构
+```
+dataPreProcess_LST_new_win/
+├── core/ # 核心模块
+│   ├── init.py
+│   ├── plugin_interface.py # 插件接口定义
+│   ├── plugin_manager.py # 插件管理器
+│   ├── resource_manager.py # 资源管理器
+│   ├── error_handler.py # 错误处理
+│   └── config_manager.py # 配置管理
+├── plugins/ # 插件目录
+│   ├── init.py
+│   └── radar_data_processor.py # 雷达数据处理插件示例
+├── resources/ # 资源文件目录
+│   ├── radar_config.xml # 雷达插件配置
+├── merge_data_process_LST.py # 主要数据处理逻辑
+├── run.py # 命令行入口程序
+├── config.json # 系统配置文件
+└── README.md
+```
+
+## 数据处理流程
+
+### 数据加载和预处理
+- ZIP文件解压
+- 配置加载
+- 插件发现和初始化
+
+### 主要处理阶段
+- CSV数据处理
+- ROS包数据提取
+- C++引擎处理
+- 数据质量检查
+- 数据合并和后处理
+
+### 插件数据处理
+- 数据合并
+- 结果验证和保存
+
+## 插件开发
+查看 plugins/radar_data_processor.py 作为示例插件。新插件需要:
+- 继承 CustomDataProcessorPlugin
+- 实现必要方法:
+  - can_handle()
+  - get_required_columns()
+  - _process_extracted_files()
+
+## 配置说明
+系统配置文件 (config.json) 包含:
+- 处理参数 (并行、批处理等)
+- 数据库配置
+- 插件设置
+- 日志配置
+- 坐标系参数
+- 文件路径配置
+
+## 系统架构
+
+1.编译代码
+```bash
+pyinstaller --onedir --name merge_data_process_LST --clean --add-data="$(python -c 'import bagpy; from pathlib import Path; print(f"{Path(bagpy.__file__).parent}:bagpy")')" --add-binary="/home/MapToCsv/build/engine:." --add-data="./data_map:data_map" --add-data="VBox.dbc:." --add-binary="/usr/lib/libstdc++.so.6:." --add-binary="/usr/lib/libgcc_s.so.1:." --add-binary="/lib/ld-musl-x86_64.so.1:." merge_data_process_LST.py
+```
+
+2.运行代码
+    打开python文件,修改路径
+    ```python
+    input_zip = '/home/cicv/zhaoyuan/data/dataprocess_python/LeftTurnAssit.zip'
+    output_dir = '/home/cicv/zhaoyuan/data/dataprocess_python/output'
+    shpdata_path = "./modules/map/data"
+    engine_dir = "./engine"
+    ```
+    请根据用户本地存放位置进行修改
+    
+```bash
+./your_packed_app --zip_path V2I_CSAE53-2020_LeftTurnAssist_PGVIL_01_VR.zip --output_path ./output
+```

+ 146 - 0
README_new.md

@@ -0,0 +1,146 @@
+# 数据预处理系统(Data Preprocessing System)
+
+## 项目概述
+
+本项目是一个用于处理车辆数据的预处理系统,支持多种数据源和格式,包括CAN数据、GNSS数据、雷达数据等。系统采用插件架构,允许用户扩展自定义数据处理功能。
+
+## 系统架构
+
+### 核心组件
+
+```
++------------------+      +------------------+      +------------------+
+|                  |      |                  |      |                  |
+|  数据源(ZIP)    +----->+  数据处理管道     +----->+  输出(CSV)     |
+|                  |      |                  |      |                  |
++------------------+      +------------------+      +------------------+
+                                   |
+                                   v
+                          +------------------+
+                          |                  |
+                          |   插件系统       |
+                          |                  |
+                          +------------------+
+```
+
+系统由以下主要组件构成:
+
+1. **数据处理器(DataProcessor)**:负责协调整个处理流程,包括ZIP文件解析、数据提取、格式转换等。
+
+2. **插件系统**:
+   - **插件接口(PluginInterface)**:定义插件必须实现的方法。
+   - **插件管理器(PluginManager)**:负责发现、加载和管理插件。
+   - **资源管理器(ResourceManager)**:管理插件资源和验证数据格式。
+
+3. **数据处理管道**:
+   - **ZIP/CSV处理器**:处理ZIP中的数据库文件并生成CSV。
+   - **Rosbag处理器**:处理ROS包数据。
+   - **C++引擎**:执行高性能数据处理任务。
+   - **最终数据处理器**:合并、清洗和验证数据。
+
+## 插件系统
+
+### 插件接口
+
+所有插件必须实现以下接口:
+
+```python
+def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+    """判断插件是否可以处理指定文件夹中的数据"""
+    pass
+
+def process_data(self, zip_path: Path, folder_name: str, output_dir: Path) -> Optional[Path]:
+    """处理数据并返回处理后的CSV文件路径"""
+    pass
+
+def get_required_columns(self) -> Dict[str, Any]:
+    """返回插件将提供的列及其数据类型"""
+    pass
+```
+
+### 现有插件
+
+系统已包含以下插件:
+
+1. **雷达数据处理器(RadarDataProcessor)**:处理雷达数据,使用XML配置文件定义数据格式和处理参数。
+2. **文本数据处理器(TextDataProcessor)**:处理简单文本格式的传感器数据。
+
+## 数据处理流程
+
+1. **初始化配置**:创建配置对象,设置输入/输出路径、UTM区域等参数。
+2. **处理ZIP中的数据库文件**:提取并处理数据库文件,生成初始CSV文件。
+3. **处理Rosbag文件**:提取并处理ROS包数据。
+4. **运行C++预处理引擎**:执行高性能数据处理任务。
+5. **数据质量预检**:验证数据质量,检查帧丢失等问题。
+6. **最终数据处理**:合并数据、计算曲率、处理交通灯信息等。
+7. **插件数据处理**:使用插件处理自定义数据文件夹,并将结果合并到主数据文件中。
+8. **扩展后处理**:应用额外的处理/验证步骤。
+
+## 使用方法
+
+### 基本用法
+
+```bash
+python run.py --zip-path <数据ZIP文件路径> --output-dir <输出目录>
+```
+
+### 完整参数
+
+```bash
+python run.py \
+  --zip-path <数据ZIP文件路径> \
+  --trafficlight-json <交通灯JSON文件路径> \
+  --output-dir <输出目录> \
+  --utm-zone <UTM区域> \
+  --x-offset <X偏移量> \
+  --y-offset <Y偏移量> \
+  --plugins-dir <插件目录> \
+  --resources-dir <资源目录>
+```
+
+### 列出可用插件
+
+```bash
+python run.py --list-plugins
+```
+
+## 开发自定义插件
+
+1. 在 `plugins` 目录下创建新的Python文件。
+2. 导入并继承 `CustomDataProcessorPlugin` 基类。
+3. 实现所有必需的方法(`can_handle`、`process_data`、`get_required_columns`)。
+4. 如果需要配置文件,可以将其放在 `resources` 目录下。
+
+示例插件模板可参考 `plugins/data_processor_template.py`。
+
+## 系统要求
+
+- Python 3.6+
+- pandas
+- numpy
+- cantools(用于处理CAN数据)
+- bagpy(用于处理ROS包)
+- pyproj(用于坐标投影)
+
+## 编译打包
+
+使用PyInstaller打包为可执行文件:
+
+```bash
+pyinstaller --onedir --name merge_data_process_LST --clean \
+  --add-data="$(python -c 'import bagpy; from pathlib import Path; print(f"{Path(bagpy.__file__).parent}:bagpy")')" \
+  --add-binary="/path/to/engine:." \
+  --add-data="./data_map:data_map" \
+  --add-data="VBox.dbc:." \
+  merge_data_process_LST.py
+```
+
+## 代码优化建议
+
+1. **错误处理**:增强错误处理机制,提供更详细的错误信息和恢复策略。
+2. **日志系统**:引入结构化日志系统,便于调试和问题追踪。
+3. **配置管理**:使用统一的配置管理系统,支持配置文件、环境变量和命令行参数。
+4. **单元测试**:增加单元测试覆盖率,确保代码质量和稳定性。
+5. **文档完善**:为每个模块和函数添加详细的文档字符串。
+6. **性能优化**:识别性能瓶颈并进行优化,特别是大数据处理部分。
+7. **代码重构**:减少重复代码,提高模块化和可维护性。

BIN
__pycache__/merge_data_process.cpython-313.pyc


BIN
__pycache__/merge_data_process_LST.cpython-313.pyc


+ 297 - 0
_internal/VBox.dbc

@@ -0,0 +1,297 @@
+VERSION ""
+
+
+NS_ : 
+	NS_DESC_
+	CM_
+	BA_DEF_
+	BA_
+	VAL_
+	CAT_DEF_
+	CAT_
+	FILTER
+	BA_DEF_DEF_
+	EV_DATA_
+	ENVVAR_DATA_
+	SGTYPE_
+	SGTYPE_VAL_
+	BA_DEF_SGTYPE_
+	BA_SGTYPE_
+	SIG_TYPE_REF_
+	VAL_TABLE_
+	SIG_GROUP_
+	SIG_VALTYPE_
+	SIGTYPE_VALTYPE_
+	BO_TX_BU_
+	BA_DEF_REL_
+	BA_REL_
+	BA_DEF_DEF_REL_
+	BU_SG_REL_
+	BU_EV_REL_
+	BU_BO_REL_
+	SG_MUL_VAL_
+
+BS_:
+
+BU_:
+
+
+BO_ 3221225472 VECTOR__INDEPENDENT_SIG_MSG: 0 Vector__XXX
+ SG_ Speed_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Speed_long_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Speed_lat_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Speed_x_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Speed_y_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Speed_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Speed_x_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Speed_y_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Speed_long_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Speed_lat_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Rel_speed_long_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Rel_speed_lat_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Rel_speed_long_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Rel_speed_lat_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ UFO_Speed_n_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+ SG_ VUT_Speed_n_kph : 0|16@1- (0.036,0) [-1080|1080] "kph" Vector__XXX
+
+BO_ 512 DLB_00: 8 Vector__XXX
+ SG_ UTC_Date_Year : 0|8@1+ (1,2000) [2000|2255] "" Vector__XXX
+ SG_ UTC_Date_Month : 8|8@1+ (1,0) [1|12] "" Vector__XXX
+ SG_ UTC_Date_Day : 16|8@1+ (1,0) [1|31] "" Vector__XXX
+ SG_ UTC_Time_Hour : 24|8@1+ (1,0) [0|23] "" Vector__XXX
+ SG_ UTC_Time_Minute : 32|8@1+ (1,0) [0|59] "" Vector__XXX
+ SG_ UTC_Time_Second : 40|8@1+ (1,0) [0|59] "" Vector__XXX
+ SG_ UTC_Time_Millisecond : 48|16@1+ (1,0) [0|999] "" Vector__XXX
+
+BO_ 513 DLB_01: 7 Vector__XXX
+ SG_ GPS_Latitude : 0|48@1- (1E-010,0) [-90|90] "deg" Vector__XXX
+ SG_ Validity_GPS_Pos : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 514 DLB_02: 7 Vector__XXX
+ SG_ GPS_Longitude : 0|48@1- (1E-010,0) [-180|180] "deg" Vector__XXX
+ SG_ Validity_GPS_Pos : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 515 DLB_03: 7 Vector__XXX
+ SG_ Local_Pos_North : 0|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ Local_Pos_East : 24|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ Validity_Local_Pos : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 516 DLB_04: 8 Vector__XXX
+ SG_ Speed_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ Dir_Movement : 16|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ Heading : 32|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ UFO_State : 48|8@1+ (1,0) [0|20] "" Vector__XXX
+ SG_ Validity_SDH : 56|8@1+ (1,0) [0|15] "" Vector__XXX
+
+BO_ 517 DLB_05: 7 Vector__XXX
+ SG_ Local_Pos_X : 0|24@1- (0.001,0) [-8388.608|8388.607] "m" Vector__XXX
+ SG_ Local_Pos_Y : 24|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ Validity_Local_Pos_FR : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 518 DLB_06: 7 Vector__XXX
+ SG_ Acc_X : 0|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ Acc_Y : 24|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ Validity_Acc_FR : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 519 DLB_07: 7 Vector__XXX
+ SG_ Acc_Z : 0|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ Yaw_Rate : 24|24@1- (0.00057298,0) [-4500|4500] "deg/s" Vector__XXX
+ SG_ Validity_Acc_D_Yaw : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 520 DLB_08: 8 Vector__XXX
+ SG_ Deviation_Y : 0|16@1- (0.001,0) [-30|30] "m" Vector__XXX
+ SG_ Deviation_Way : 16|16@1- (0.001,0) [-30|30] "m" Vector__XXX
+ SG_ Deviation_Speed : 32|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ Deviation_Acc : 48|16@1- (0.01,0) [-300|300] "m/ss" Vector__XXX
+
+BO_ 521 DLB_09: 7 Vector__XXX
+ SG_ Dist_MP : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ VUT_Dist_MP : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_DistMP : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 522 DLB_10: 2 Vector__XXX
+ SG_ Transmission_delay : 0|16@1+ (1,0) [0|65534] "ms" Vector__XXX
+
+BO_ 523 DLB_11: 4 Vector__XXX
+ SG_ UFO_Speed_long_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ UFO_Speed_lat_mps : 16|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+
+BO_ 524 DLB_12: 8 Vector__XXX
+ SG_ UFO_Target_Heading : 0|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ UFO_Deviation_Heading : 16|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ UFO_Radius_of_turn : 32|24@1- (0.01,0) [-80000|80000] "m" Vector__XXX
+ SG_ Validity_12 : 56|8@1+ (1,0) [0|7] "" Vector__XXX
+
+BO_ 525 DLB_13: 4 Vector__XXX
+ SG_ UFO_Speed_x_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ UFO_Speed_y_mps : 16|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+
+BO_ 528 DLB_16: 8 Vector__XXX
+ SG_ SyncVehDistance_X : 0|24@1- (0.001,0) [-8388.608|8388.607] "m" Vector__XXX
+ SG_ SyncVehDistance_Y : 24|24@1- (0.001,0) [-8388.608|8388.607] "m" Vector__XXX
+ SG_ Reserved : 48|8@1+ (1,0) [0|255] "" Vector__XXX
+ SG_ Validity_SVD : 56|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 529 DLB_17: 7 Vector__XXX
+ SG_ VUT_GPS_Latitude : 0|48@1- (1E-010,0) [-90|90] "deg" Vector__XXX
+ SG_ Validity_VUT_GPS_Lat : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 530 DLB_18: 7 Vector__XXX
+ SG_ VUT_GPS_Longitude : 0|48@1- (1E-010,0) [-180|180] "deg" Vector__XXX
+ SG_ Validity_VUT_GPS_Long : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 531 DLB_19: 7 Vector__XXX
+ SG_ VUT_Local_Pos_North : 0|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ VUT_Local_Pos_East : 24|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ Validity_VUT_Local_Pos : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 532 DLB_20: 7 Vector__XXX
+ SG_ VUT_Speed_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Speed_x_mps : 16|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Speed_y_mps : 32|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ Validity_VUT_Speed : 48|8@1+ (1,0) [0|7] "" Vector__XXX
+
+BO_ 533 DLB_21: 7 Vector__XXX
+ SG_ VUT_Local_Pos_X : 0|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ VUT_Local_Pos_Y : 24|24@1- (0.001,0) [-8388.608|8388.608] "m" Vector__XXX
+ SG_ Validity_VUT_Local_Pos_XY : 48|8@1+ (1,0) [0|1] "" Vector__XXX
+
+BO_ 534 DLB_22: 7 Vector__XXX
+ SG_ VUT_Heading : 0|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ VUT_Pitch : 16|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ VUT_Roll : 32|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ Validity_VUT_HPR : 48|8@1+ (1,0) [0|7] "" Vector__XXX
+
+BO_ 535 DLB_23: 7 Vector__XXX
+ SG_ VUT_Acc_X : 0|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ VUT_Yaw_Rate : 24|24@1- (0.00057298,0) [-4500|4500] "deg/s" Vector__XXX
+ SG_ Validity_VUT_AY : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 536 DLB_24: 7 Vector__XXX
+ SG_ TimeToCollision_Abs : 0|16@1- (0.001,0) [0|32.767] "s" Vector__XXX
+ SG_ TimeToCollision_Long : 16|16@1- (0.001,0) [0|32.767] "s" Vector__XXX
+ SG_ TimeToCollision_Lat : 32|16@1- (0.001,0) [0|32.767] "s" Vector__XXX
+ SG_ Validity_TTC : 48|8@1+ (1,0) [0|7] "" Vector__XXX
+
+BO_ 537 DLB_25: 7 Vector__XXX
+ SG_ VUT_Dist_MRP_Abs : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ VUT_Dist_MIN_Abs : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_VUT_Dist_Abs : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 538 DLB_26: 7 Vector__XXX
+ SG_ VUT_Dist_MRP_X : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ VUT_Dist_MIN_X : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_VUT_Dist_X : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 539 DLB_27: 7 Vector__XXX
+ SG_ VUT_Dist_MRP_Y : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ VUT_Dist_MIN_Y : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_VUT_Dist_Y : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 540 DLB_28: 7 Vector__XXX
+ SG_ VUT_Speed_long_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Speed_lat_mps : 16|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Acc_Y : 32|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+
+BO_ 541 DLB_29: 8 Vector__XXX
+ SG_ VUT_Target_Heading : 0|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ VUT_Deviation_Heading : 16|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ VUT_Radius_of_turn : 32|24@1- (0.01,0) [-80000|80000] "m" Vector__XXX
+ SG_ Validity_32 : 56|8@1+ (1,0) [0|7] "" Vector__XXX
+
+BO_ 542 DLB_30: 8 Vector__XXX
+ SG_ UFO_Rel_speed_long_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ UFO_Rel_speed_lat_mps : 16|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Rel_speed_long_mps : 32|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Rel_speed_lat_mps : 48|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+
+BO_ 543 DLB_31: 6 Vector__XXX
+ SG_ UFO_Rel_Acc_long : 0|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ UFO_Rel_Acc_lat : 24|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+
+BO_ 544 DLB_32: 6 Vector__XXX
+ SG_ VUT_Rel_Acc_long : 0|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ VUT_Rel_Acc_lat : 24|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+
+BO_ 545 DLB_33: 7 Vector__XXX
+ SG_ UFO_Dist_MRP_long : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ UFO_Dist_MRP_lat : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_33 : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 546 DLB_34: 7 Vector__XXX
+ SG_ VUT_Dist_MRP_long : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ VUT_Dist_MRP_lat : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_34 : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 547 DLB_35: 7 Vector__XXX
+ SG_ UFO_Dist_MRP_long_th : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ UFO_Dist_MRP_lat_th : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_35 : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 548 DLB_36: 7 Vector__XXX
+ SG_ VUT_Dist_MRP_long_th : 0|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ VUT_Dist_MRP_lat_th : 24|24@1- (0.001,0) [-8000|8000] "m" Vector__XXX
+ SG_ Validity_36 : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 549 DLB_37: 7 Vector__XXX
+ SG_ VUT_Acc_Y : 0|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ VUT_Acc_Z : 24|24@1- (0.0001,0) [-800|800] "m/ss" Vector__XXX
+ SG_ Validity_VUT_Acc_YZ : 48|8@1+ (1,0) [0|3] "" Vector__XXX
+
+BO_ 550 DLB_38: 7 Vector__XXX
+ SG_ UFO_Speed_n_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ UFO_Dir_Movement_n : 16|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ UFO_Heading_n : 32|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ Validity_USDHN : 48|8@1+ (1,0) [0|15] "" Vector__XXX
+
+BO_ 551 DLB_39: 7 Vector__XXX
+ SG_ VUT_Speed_n_mps : 0|16@1- (0.01,0) [-300|300] "m/s" Vector__XXX
+ SG_ VUT_Dir_Movement_n : 16|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ VUT_Heading_n : 32|16@1- (0.01,0) [-180|180] "deg" Vector__XXX
+ SG_ Validity_VSDHN : 48|8@1+ (1,0) [0|15] "" Vector__XXX
+
+BO_ 562 DLB_50: 6 Vector__XXX
+ SG_ DR_Servo_St_Pos_Target : 0|24@1- (0.001,0) [-8000|8000] "deg" Vector__XXX
+ SG_ DR_Servo_St_Pos_Current : 24|24@1- (0.001,0) [-8000|8000] "deg" Vector__XXX
+
+BO_ 563 DLB_51: 6 Vector__XXX
+ SG_ DR_Servo_St_Speed : 0|16@1- (0.01,0) [-320|320] "deg/s" Vector__XXX
+ SG_ DR_Servo_St_Current : 16|16@1- (0.01,0) [-320|320] "A" Vector__XXX
+ SG_ DR_Steering_Moment : 32|16@1- (0.01,0) [-320|320] "Nm" Vector__XXX
+
+BO_ 564 DLB_52: 6 Vector__XXX
+ SG_ DR_Servo_Br_Pos_Target : 0|24@1- (0.001,0) [-8000|8000] "mm" Vector__XXX
+ SG_ DR_Servo_Br_Pos_Current : 24|24@1- (0.001,0) [-8000|8000] "mm" Vector__XXX
+
+BO_ 565 DLB_53: 6 Vector__XXX
+ SG_ DR_Servo_Br_Speed : 0|16@1- (0.01,0) [-320|320] "mm/s" Vector__XXX
+ SG_ DR_Servo_Br_Current : 16|16@1- (0.01,0) [-320|320] "A" Vector__XXX
+ SG_ DR_Brake_Force : 32|16@1- (0.05,0) [-1600|1600] "N" Vector__XXX
+
+BO_ 566 DLB_54: 6 Vector__XXX
+ SG_ DR_Servo_Thr_Pos_Target : 0|24@1- (0.001,0) [-8000|8000] "mm" Vector__XXX
+ SG_ DR_Servo_Thr_Pos_Current : 24|24@1- (0.001,0) [-8000|8000] "mm" Vector__XXX
+
+BO_ 567 DLB_55: 4 Vector__XXX
+ SG_ DR_Servo_Thr_Speed : 0|16@1- (0.01,0) [-320|320] "mm/s" Vector__XXX
+ SG_ DR_Servo_Thr_Current : 16|16@1- (0.01,0) [-320|320] "A" Vector__XXX
+
+BO_ 568 DLB_56: 8 Vector__XXX
+ SG_ UTC_Date_Year : 0|8@1+ (1,2000) [2000|2255] "" Vector__XXX
+ SG_ UTC_Date_Month : 8|8@1+ (1,0) [1|12] "" Vector__XXX
+ SG_ UTC_Date_Day : 16|8@1+ (1,0) [1|31] "" Vector__XXX
+ SG_ UTC_Time_Hour : 24|8@1+ (1,0) [0|23] "" Vector__XXX
+ SG_ UTC_Time_Minute : 32|8@1+ (1,0) [0|59] "" Vector__XXX
+ SG_ UTC_Time_Second : 40|8@1+ (1,0) [0|59] "" Vector__XXX
+ SG_ UTC_Time_Millisecond : 48|16@1+ (1,0) [0|999] "" Vector__XXX
+
+BO_ 569 DLB_57: 4 Vector__XXX
+ SG_ AVAD_optical_match : 0|8@1+ (1,0) [0|255] "" Vector__XXX
+ SG_ AVAD_acoustical_match : 8|8@1+ (1,0) [0|255] "" Vector__XXX
+ SG_ AVAD_color_on : 16|8@1+ (1,0) [0|255] "" Vector__XXX
+ SG_ AVAD_validity : 24|8@1+ (1,0) [0|255] "" Vector__XXX
+
+
+
+CM_ BO_ 3221225472 "This is a message for not used signals, created by Vector CANdb++ DBC OLE DB Provider.";
+

+ 256 - 0
_internal/data_map/hd_arrow.csv

@@ -0,0 +1,256 @@
+arrow_id,arrow_ref_lane,arrow_direction,arrow_coords
+61107866,30225856,"[2,3]","[[258151.871738424,4150149.822082736],[258154.563560307,4150149.997551888],[258154.550492213,4150150.215071158],[258156.446968721,4150149.997919289],[258154.596881512,4150149.505104142],[258154.579284440,4150149.767848948],[258153.035249191,4150149.649884545],[258153.556799289,4150149.089826979],[258154.338949832,4150149.134964384],[258153.213217373,4150148.733504874],[258151.799013112,4150148.982738305],[258152.655396510,4150149.035492732],[258152.127921754,4150149.598832429],[258151.883398135,4150149.589610087],[258151.871738424,4150149.822082736]]"
+61107867,30226051,"2","[[258111.781928812,4149970.343506709],[258112.890672987,4149970.753564230],[258112.925390224,4149970.598613981],[258114.703135913,4149970.864168012],[258114.751579812,4149970.703265457],[258112.957734780,4149970.438179238],[258112.989788615,4149970.282973178],[258111.781928812,4149970.343506709]]"
+61107868,30225915,"2","[[258458.674848633,4149789.203169928],[258457.230385323,4149791.517986385],[258457.045031822,4149791.403299533],[258456.375505540,4149793.129181892],[258457.618755584,4149791.758065506],[258457.430339732,4149791.641579337],[258458.886411923,4149789.317984879],[258458.674848633,4149789.203169928]]"
+61107869,30225876,"[2,3]","[[257802.589358373,4150059.575144120],[257801.371766479,4150059.212611187],[257801.356617745,4150059.428304048],[257800.452991175,4150059.368073856],[257800.726731075,4150059.009019177],[257801.232523237,4150059.051947122],[257800.430963026,4150058.772273280],[257799.625150656,4150058.954993191],[257800.101857716,4150058.965890879],[257799.802910148,4150059.319681313],[257799.601678176,4150059.307543352],[257799.587291846,4150059.494669256],[257801.343817643,4150059.590837501],[257801.330324352,4150059.796485966],[257802.589358373,4150059.575144120]]"
+61107870,30225829,"1","[[258308.375797526,4149764.392899528],[258308.353152662,4149765.162040601],[258307.435081422,4149766.010824945],[258307.375365927,4149768.964206682],[258307.610292868,4149768.962717263],[258307.670816118,4149766.695827087],[258308.346573995,4149766.072883026],[258308.329760798,4149766.801981164],[258308.673416992,4149765.620674309],[258308.375797526,4149764.392899528]]"
+61107871,30225885,"2","[[258151.975173040,4149806.968010229],[258152.404604788,4149805.762655674],[258152.227799864,4149805.741246827],[258152.485246117,4149803.991653808],[258152.321357654,4149803.966870849],[258152.068952215,4149805.719316284],[258151.913199235,4149805.700294693],[258151.975173040,4149806.968010229]]"
+61107872,30226075,"2","[[257968.762582056,4149832.290307385],[257967.550485199,4149831.816075329],[257967.534778058,4149832.015789733],[257965.746139303,4149831.763576194],[257965.734219238,4149831.919974669],[257967.519882613,4149832.173385402],[257967.503909554,4149832.366998746],[257968.762582056,4149832.290307385]]"
+61107873,30225995,"4","[[257981.261445627,4150111.449331210],[257977.591610740,4150111.265145354],[257977.254878301,4150111.220845634],[257977.136835034,4150111.128425327],[257977.039420770,4150110.993421121],[257977.008109195,4150110.857383451],[257977.039419028,4150110.710195191],[257977.142554843,4150110.554809710],[257977.300127481,4150110.441713673],[257977.540016378,4150110.401084714],[257978.292576954,4150110.430072790],[257978.272847879,4150110.658893249],[257980.145786656,4150110.390072584],[257978.302413469,4150109.955411040],[257978.313990704,4150110.192206756],[257977.436898046,4150110.149068549],[257977.220912608,4150110.217102950],[257977.057324936,4150110.330373880],[257976.923563529,4150110.464658177],[257976.824614761,4150110.627030336],[257976.791166746,4150110.801159466],[257976.802107023,4150111.019091973],[257976.890425986,4150111.185348887],[257977.013901267,4150111.321483510],[257977.154315419,4150111.425137738],[257977.351079131,4150111.505939359],[257977.469447714,4150111.515159520],[257981.242112905,4150111.722234529],[257981.261445627,4150111.449331210]]"
+61107874,30225907,"2","[[257955.603640171,4150002.788181142],[257954.453033812,4150002.357480877],[257954.429579944,4150002.534318322],[257952.620517055,4150002.281815691],[257952.604311247,4150002.433896132],[257954.413254508,4150002.697509136],[257954.385830868,4150002.887012812],[257955.603640171,4150002.788181142]]"
+61107875,30226004,"1","[[258309.559388682,4149792.004509890],[258310.385293808,4149792.052281500],[258311.141541926,4149792.972853369],[258314.124182154,4149793.098399590],[258314.137541273,4149792.860213874],[258311.855349891,4149792.760980274],[258311.328458787,4149792.086208327],[258312.032573562,4149792.119856142],[258310.886113883,4149791.746741377],[258309.559388682,4149792.004509890]]"
+61107876,30226030,"1","[[258337.911139929,4149971.217487720],[258339.131113084,4149969.320671292],[258339.908864041,4149969.140596834],[258339.552189419,4149969.732951069],[258340.425965003,4149968.917442161],[258340.808499450,4149967.648373708],[258340.404992359,4149968.320057659],[258339.228521733,4149968.635326803],[258337.691289265,4149971.091587624],[258337.911139929,4149971.217487720]]"
+61107877,30226076,"[1,2,3]","[[258132.084816095,4149783.416090597],[258130.863427452,4149783.014966144],[258130.849588871,4149783.175529407],[258130.035499428,4149783.068343507],[258130.315412564,4149782.744220008],[258130.890398039,4149782.803596105],[258130.132119953,4149782.456879272],[258129.283185278,4149782.606941552],[258129.704132511,4149782.657575940],[258129.398060126,4149782.992455705],[258129.108431737,4149782.954777267],[258129.087209956,4149783.126328725],[258129.433417522,4149783.167250291],[258129.625261714,4149783.593511738],[258129.123543502,4149783.532784442],[258129.916095556,4149783.876839323],[258130.733154182,4149783.729702488],[258130.266748949,4149783.665505602],[258130.072040853,4149783.247324307],[258130.828763793,4149783.339405587],[258130.810739992,4149783.496091975],[258132.084816095,4149783.416090597]]"
+61107878,30226004,"2","[[258368.359886981,4149794.217931906],[258365.693730057,4149794.118832976],[258365.706698644,4149793.891543510],[258363.869182649,4149794.181567576],[258365.670322045,4149794.593441904],[258365.683581775,4149794.367032534],[258368.352289325,4149794.462503222],[258368.359886981,4149794.217931906]]"
+61107879,30225923,"[1,2,3]","[[258147.187998386,4149811.199197099],[258146.749321003,4149812.400155740],[258146.922145136,4149812.421680116],[258146.788781960,4149813.261680454],[258146.474957478,4149812.991460043],[258146.520610508,4149812.414464220],[258146.145878875,4149813.217049560],[258146.279927967,4149814.064497183],[258146.351330455,4149813.602820126],[258146.698141426,4149813.883966533],[258146.650513746,4149814.179682517],[258146.827481542,4149814.209749864],[258146.874853286,4149813.886940537],[258147.283570952,4149813.681251052],[258147.210221774,4149814.206960268],[258147.562565312,4149813.359042947],[258147.457649796,4149812.578834055],[258147.390282715,4149813.042282025],[258146.968490551,4149813.245907844],[258147.084886304,4149812.440498576],[258147.282802484,4149812.463293198],[258147.187998386,4149811.199197099]]"
+61107880,30225851,"[1,2]","[[258309.433556631,4149919.214824373],[258309.693163431,4149919.365226407],[258309.875562393,4149920.143519707],[258309.214634328,4149919.755198636],[258310.070203127,4149920.642119982],[258311.339472285,4149921.010223755],[258310.665003515,4149920.615964812],[258310.476078924,4149919.823310978],[258311.737343597,4149920.556063381],[258311.616104212,4149920.752953951],[258313.406985510,4149921.406909391],[258311.969311080,4149920.144816456],[258311.851494313,4149920.343717952],[258309.559985429,4149919.004565930],[258309.433556631,4149919.214824373]]"
+61107881,30225987,"[2,3]","[[258480.885271576,4149851.835438888],[258480.936197341,4149849.007380791],[258481.160659464,4149849.008421067],[258480.860468732,4149847.266914203],[258480.461545803,4149848.997383351],[258480.686857268,4149849.003285984],[258480.667908568,4149850.605220429],[258480.099766161,4149850.030708999],[258480.110902536,4149849.224473335],[258479.775312186,4149850.452519611],[258480.066150547,4149851.728254647],[258480.085288352,4149850.978098526],[258480.656486773,4149851.502318352],[258480.650004672,4149851.834267833],[258480.885271576,4149851.835438888]]"
+61107882,30225959,"3","[[258422.115287992,4149993.639021739],[258419.596761333,4149992.187920632],[258418.511057695,4149992.509985237],[258417.829002412,4149992.116271820],[258418.692900307,4149993.028506958],[258419.873492762,4149993.312899376],[258419.309797521,4149992.979948418],[258420.067230858,4149992.749601653],[258421.992438212,4149993.856727161],[258422.115287992,4149993.639021739]]"
+61107883,30225993,"[2,3]","[[258286.864244667,4149744.466894104],[258286.261537192,4149746.267156433],[258286.508422479,4149746.287199770],[258286.337877619,4149747.713274593],[258285.817588344,4149747.089181663],[258285.902042986,4149746.329685773],[258285.436804641,4149747.516189971],[258285.607981251,4149748.709761176],[258285.710199096,4149747.991844516],[258286.224208825,4149748.607012140],[258286.177673571,4149748.955785956],[258286.426502283,4149748.987879335],[258286.747259359,4149746.304477953],[258286.989091296,4149746.327333678],[258286.864244667,4149744.466894104]]"
+61107884,30225938,"[1,2,3]","[[257948.178032348,4149877.437592455],[257948.642552284,4149876.267857169],[257948.450777171,4149876.243111657],[257948.601052001,4149875.266888352],[257948.931235142,4149875.591049820],[257948.840817957,4149876.144358985],[257949.216136673,4149875.298762220],[257949.094375123,4149874.490943722],[257949.027814169,4149874.987802575],[257948.683282994,4149874.681718277],[257948.712832922,4149874.486155096],[257948.551978316,4149874.462176527],[257948.527071747,4149874.640833274],[257948.115208765,4149874.826410029],[257948.178481597,4149874.393067173],[257947.840506395,4149875.125398447],[257947.918758934,4149876.001900950],[257948.015061419,4149875.453085535],[257948.436333564,4149875.201371265],[257948.276855171,4149876.223400477],[257948.080832138,4149876.195668562],[257948.178032348,4149877.437592455]]"
+61107885,30225831,"[1,3]","[[258283.366005124,4149791.585704674],[258283.466911350,4149790.746427949],[258284.264039571,4149790.111071970],[258284.893191455,4149790.892608922],[258284.794141204,4149791.701287856],[258285.273065146,4149790.452631792],[258285.098756709,4149789.184735526],[258285.006631102,4149789.975775611],[258284.486537273,4149789.324798634],[258284.763183507,4149787.064627333],[258284.518280657,4149787.039639557],[258284.245138575,4149789.289379742],[258283.584264701,4149789.811932124],[258283.671272574,4149789.088570337],[258283.193379341,4149790.266001585],[258283.366005124,4149791.585704674]]"
+61107886,30225829,"2","[[258349.940098732,4149759.838542526],[258348.117832327,4149759.406736568],[258348.105400043,4149759.643340271],[258345.415803872,4149759.542372765],[258345.413560655,4149759.779236047],[258348.099272960,4149759.889757114],[258348.096050875,4149760.105101505],[258349.940098732,4149759.838542526]]"
+61107887,30225887,"2","[[258273.548644879,4149926.138332746],[258273.021945829,4149928.799283140],[258272.797275400,4149928.751383695],[258272.801241555,4149930.613556858],[258273.488065836,4149928.884487552],[258273.260503851,4149928.840670534],[258273.790006078,4149926.175640287],[258273.548644879,4149926.138332746]]"
+61107888,30226017,"1","[[258284.673982124,4149730.382680682],[258283.957715781,4149730.290521224],[258283.212106385,4149729.358535476],[258280.284505804,4149728.998045175],[258280.291590479,4149729.251186983],[258282.507963547,4149729.519260565],[258283.031328501,4149730.160812909],[258282.300608561,4149730.086177832],[258283.439033828,4149730.542046662],[258284.673982124,4149730.382680682]]"
+61107889,30226025,"2","[[258368.258487316,4149909.307775895],[258369.692002320,4149907.001699036],[258369.899701028,4149907.117623415],[258370.531786863,4149905.393040575],[258369.271439122,4149906.774887259],[258369.473550095,4149906.881310860],[258368.040271506,4149909.186381277],[258368.258487316,4149909.307775895]]"
+61107890,30226033,"[2,3]","[[258310.376506703,4149837.453716903],[258307.720519483,4149837.115989001],[258307.749397807,4149836.890903023],[258305.859454891,4149837.003198192],[258307.650751460,4149837.594610056],[258307.684264502,4149837.358393720],[258309.164019736,4149837.532347711],[258308.567665131,4149838.038808319],[258307.750710576,4149837.966786551],[258308.927930779,4149838.414645058],[258310.112083191,4149838.265752951],[258309.418296202,4149838.163831756],[258310.048092470,4149837.641294947],[258310.348339209,4149837.678893299],[258310.376506703,4149837.453716903]]"
+61107891,30225929,"2","[[257822.625790874,4150003.401728494],[257823.092125818,4150002.048778193],[257822.899024148,4150002.020964415],[257823.155300445,4150000.264280345],[257822.993360352,4150000.239447379],[257822.729181020,4150001.998360630],[257822.537166667,4150001.971403781],[257822.625790874,4150003.401728494]]"
+61107892,30225998,"4","[[257979.732321413,4150142.128291299],[257975.802191595,4150141.882257522],[257975.600229356,4150141.823598811],[257975.474474305,4150141.709522192],[257975.405944395,4150141.599668312],[257975.376821316,4150141.441464278],[257975.406130057,4150141.292446006],[257975.467863223,4150141.156368566],[257975.568703771,4150141.056028927],[257975.689609174,4150140.988093368],[257975.844963392,4150140.963139488],[257976.685895945,4150141.032430286],[257976.646582594,4150141.275814910],[257978.502899570,4150141.047572538],[257976.733314726,4150140.574557850],[257976.697430111,4150140.798849975],[257975.839605664,4150140.730161401],[257975.681897502,4150140.744187894],[257975.568309671,4150140.792806809],[257975.429883310,4150140.876246138],[257975.328867183,4150140.973592021],[257975.252822801,4150141.068101495],[257975.188315793,4150141.209257699],[257975.148666260,4150141.346692265],[257975.139200150,4150141.490024406],[257975.150987464,4150141.578759023],[257975.190885903,4150141.699552691],[257975.256877529,4150141.822586518],[257975.334851186,4150141.913173000],[257975.439479909,4150141.994876403],[257975.552521280,4150142.055343151],[257975.732430262,4150142.110644612],[257979.705096080,4150142.373323672],[257979.732321413,4150142.128291299]]"
+61107893,30226074,"2","[[258021.153985447,4150062.774776763],[258020.725143303,4150063.950468597],[258020.884694308,4150063.972375848],[258020.612968828,4150065.759266536],[258020.778002461,4150065.799229707],[258021.045632938,4150063.990244279],[258021.195965077,4150064.011753118],[258021.153985447,4150062.774776763]]"
+61107894,30225888,"2","[[257823.916261979,4150060.622777371],[257825.775165253,4150060.759733382],[257825.762147171,4150060.948263284],[257826.989152311,4150060.761066677],[257825.791783718,4150060.402828951],[257825.779946580,4150060.595434055],[257823.927406381,4150060.464179578],[257823.916261979,4150060.622777371]]"
+61107895,30225830,"2","[[258434.696700096,4149753.938079917],[258432.015649932,4149753.817288424],[258432.031891411,4149753.574576801],[258430.177008098,4149753.824771496],[258431.999599096,4149754.286240979],[258432.034263163,4149754.055989776],[258434.718491559,4149754.182575671],[258434.696700096,4149753.938079917]]"
+61107896,30225834,"1","[[258278.382940324,4150075.670988318],[258280.253947032,4150076.847407162],[258280.466121890,4150077.663265074],[258279.823961072,4150077.265405535],[258280.638241036,4150078.197283169],[258281.876199366,4150078.570177447],[258281.248839598,4150078.166778835],[258281.003141166,4150077.022686823],[258278.504292668,4150075.484200943],[258278.382940324,4150075.670988318]]"
+61107897,30225827,"[1,3]","[[258109.600519959,4149966.402197667],[258109.121247034,4149966.321383120],[258108.708313612,4149965.793699041],[258109.267769787,4149965.416579123],[258109.770804272,4149965.498591369],[258109.012565382,4149965.134438626],[258108.172367162,4149965.243266310],[258108.639648634,4149965.304436877],[258108.188189889,4149965.614109667],[258106.712499373,4149965.411974162],[258106.688722863,4149965.577824465],[258108.159614057,4149965.779321947],[258108.515151903,4149966.229926051],[258107.979813767,4149966.142188469],[258108.790265747,4149966.511710120],[258109.600519959,4149966.402197667]]"
+61107898,30226067,"2","[[258168.343672828,4150142.455453244],[258168.607141343,4150139.761821333],[258168.838897537,4150139.779523148],[258168.655696543,4150137.925775911],[258168.129804452,4150139.732039607],[258168.346043433,4150139.767185767],[258168.086625752,4150142.429600733],[258168.343672828,4150142.455453244]]"
+61107899,30225842,"1","[[258181.847735743,4150116.832289960],[258183.520997209,4150115.321791546],[258184.366501224,4150115.316887627],[258183.894612206,4150115.773316889],[258184.973260969,4150115.230508860],[258185.651429639,4150114.182976580],[258185.069282605,4150114.696032985],[258183.832863472,4150114.714403769],[258181.692698937,4150116.660972133],[258181.847735743,4150116.832289960]]"
+61107900,30225996,"2","[[258343.211097248,4149810.220650779],[258345.868978702,4149810.556336288],[258345.847349901,4149810.787209292],[258347.676890037,4149810.664792775],[258345.923770664,4149810.077150889],[258345.910248168,4149810.312786660],[258343.238736781,4149809.998599828],[258343.211097248,4149810.220650779]]"
+61107901,30225930,"[1,2]","[[258197.456820112,4150156.058380501],[258197.151748995,4150156.040253161],[258196.712002720,4150155.454589255],[258197.456452652,4150155.481944151],[258196.290235998,4150155.097760107],[258195.004729790,4150155.333917710],[258195.789856288,4150155.380971720],[258196.268416563,4150155.983167964],[258194.762260435,4150155.889086059],[258194.778478894,4150155.676362441],[258192.874052441,4150155.900178572],[258194.737841955,4150156.380275221],[258194.746113502,4150156.137793890],[258197.442562510,4150156.302035337],[258197.456820112,4150156.058380501]]"
+61107902,30225994,"4","[[257981.462632104,4150107.934034163],[257977.611347551,4150107.772561780],[257977.454394134,4150107.745581780],[257977.304423196,4150107.657310801],[257977.209712665,4150107.542220399],[257977.197909669,4150107.422497985],[257977.237354839,4150107.281070909],[257977.324363942,4150107.122155853],[257977.473248230,4150106.987320786],[257977.674173585,4150106.918946804],[257978.490130207,4150106.926876673],[257978.475617363,4150107.161543189],[257980.299206854,4150106.882273118],[257978.510515433,4150106.467902151],[257978.485919895,4150106.699862967],[257977.663306101,4150106.670023928],[257977.500632275,4150106.717293283],[257977.354780302,4150106.788952982],[257977.230998700,4150106.891958839],[257977.135343559,4150107.000144614],[257977.028372357,4150107.160639716],[257976.973137461,4150107.343621431],[257976.971633624,4150107.483723180],[257976.991035865,4150107.621217818],[257977.106364417,4150107.784690158],[257977.256861313,4150107.891050090],[257977.469269314,4150107.992277815],[257981.438810442,4150108.223061936],[257981.462632104,4150107.934034163]]"
+61107903,30225983,"2","[[257977.346384261,4150099.868598170],[257980.031731661,4150099.997107595],[257979.988237295,4150100.233727451],[257981.888213877,4150099.963010532],[257980.076768119,4150099.527309057],[257980.033895061,4150099.751804325],[257977.349259242,4150099.614277614],[257977.346384261,4150099.868598170]]"
+61107904,30225920,"2","[[258136.577628697,4150074.760542373],[258136.959999859,4150072.064231720],[258137.177389301,4150072.102342647],[258137.103160346,4150070.272863306],[258136.488539522,4150071.999182987],[258136.727748304,4150072.029551500],[258136.338216845,4150074.723182436],[258136.577628697,4150074.760542373]]"
+61107905,30225902,"2","[[258235.475856990,4150107.778890256],[258237.642814169,4150106.135553818],[258237.787279965,4150106.330059798],[258239.037342240,4150104.955595843],[258237.360180162,4150105.765240634],[258237.495997294,4150105.945447806],[258235.331449175,4150107.586381865],[258235.475856990,4150107.778890256]]"
+61107906,30225934,"2","[[257728.785005038,4150039.870500099],[257728.339001991,4150041.139674485],[257728.522311595,4150041.165660716],[257728.301024337,4150042.928328476],[257728.437438455,4150042.940018854],[257728.666574575,4150041.179344039],[257728.874683246,4150041.208718056],[257728.785005038,4150039.870500099]]"
+61107907,30225929,"[1,3]","[[257815.650540552,4150047.868950068],[257815.739467570,4150047.371327458],[257816.289782054,4150046.802302708],[257816.650979327,4150047.550396124],[257816.563884821,4150048.083618606],[257816.919733526,4150047.284674156],[257816.803058617,4150046.481706646],[257816.742831401,4150046.915962281],[257816.463723470,4150046.293321093],[257816.649705485,4150044.999285503],[257816.466338882,4150044.962192106],[257816.286818707,4150046.237935420],[257815.840416592,4150046.769616467],[257815.879766609,4150046.338967111],[257815.543686336,4150047.099239722],[257815.650540552,4150047.868950068]]"
+61107908,30226026,"2","[[258364.968057514,4149907.437486471],[258366.403087483,4149905.140916931],[258366.604819185,4149905.252571699],[258367.273959682,4149903.544906078],[258366.005929144,4149904.927420557],[258366.194396559,4149905.030463793],[258364.776440298,4149907.317430140],[258364.968057514,4149907.437486471]]"
+61107909,30226006,"[2,3]","[[257755.627447430,4149976.801442915],[257756.848770901,4149977.252161656],[257756.869788594,4149977.086056881],[257757.851562279,4149977.230198602],[257757.548940785,4149977.552109389],[257757.006210839,4149977.478270697],[257757.794071415,4149977.831423277],[257758.631320356,4149977.724756024],[257758.131990953,4149977.648543561],[257758.435946899,4149977.308600749],[257758.655754760,4149977.341411515],[257758.678562838,4149977.163814515],[257756.896016169,4149976.910359609],[257756.921741198,4149976.714351295],[257755.627447430,4149976.801442915]]"
+61107910,30225923,"2","[[258126.046735370,4149954.558298179],[258126.299047953,4149952.772643826],[258126.447864960,4149952.793754441],[258126.392882235,4149951.571817896],[258126.001420385,4149952.730644554],[258126.150234169,4149952.751644188],[258125.897918390,4149954.537187573],[258126.046735370,4149954.558298179]]"
+61107911,30226057,"2","[[257940.603622259,4149831.617963613],[257938.640000337,4149831.340077849],[257938.668988038,4149831.134312643],[257937.309949804,4149831.236474020],[257938.591835625,4149831.696232764],[257938.620276431,4149831.489928115],[257940.581483332,4149831.776103202],[257940.603622259,4149831.617963613]]"
+61107912,30225936,"2","[[258372.386592024,4149778.491147692],[258374.435179264,4149778.960705827],[258374.423029074,4149778.740365322],[258377.184275865,4149778.940112219],[258377.181795883,4149778.696055577],[258374.451431095,4149778.495745517],[258374.438179007,4149778.270994253],[258372.386592024,4149778.491147692]]"
+61107913,30225998,"2","[[258156.153261085,4150152.991316797],[258153.471177781,4150152.806678742],[258153.482948983,4150152.581089127],[258151.534146487,4150152.785878484],[258153.452017547,4150153.274613112],[258153.463732104,4150153.044027045],[258156.137208895,4150153.221917818],[258156.153261085,4150152.991316797]]"
+61107914,30226073,"3","[[258442.547779988,4149784.444014549],[258444.111673209,4149781.940023391],[258443.823638437,4149780.840473439],[258444.270571104,4149780.136103621],[258443.317997382,4149781.074616955],[258443.012484343,4149782.133967565],[258443.355510788,4149781.592440265],[258443.548527662,4149782.401415549],[258442.341773173,4149784.328483409],[258442.547779988,4149784.444014549]]"
+61107915,30225934,"2","[[257799.082965205,4150063.001136802],[257800.304586864,4150063.347002804],[257800.313075640,4150063.161048126],[257802.117400456,4150063.278261642],[257802.128638669,4150063.113774390],[257800.290047330,4150062.984229620],[257800.304238055,4150062.802551800],[257799.082965205,4150063.001136802]]"
+61107916,30225917,"2","[[258465.032047770,4149793.204107830],[258463.612293746,4149795.497880661],[258463.424559984,4149795.380486032],[258462.768011771,4149797.089886331],[258464.001397061,4149795.738827328],[258463.816741769,4149795.623786876],[258465.245626640,4149793.336524329],[258465.032047770,4149793.204107830]]"
+61107917,30226053,"[1,2,3]","[[257944.417328302,4149950.568041583],[257945.484515567,4149951.025157634],[257945.511581301,4149950.808119236],[257946.494166605,4149950.949815995],[257946.194971412,4149951.292389560],[257945.671154220,4149951.229539830],[257946.490433914,4149951.558249513],[257947.326576563,4149951.398209554],[257946.814059806,4149951.355578924],[257947.093686800,4149951.034233230],[257947.344278173,4149951.072262620],[257947.367036262,4149950.883672088],[257947.117049853,4149950.848179694],[257946.948938327,4149950.443667717],[257947.349689538,4149950.475886818],[257946.588148406,4149950.141610688],[257945.727060660,4149950.287159622],[257946.280781288,4149950.346252020],[257946.534680065,4149950.772038202],[257945.527689430,4149950.625275516],[257945.547570126,4149950.453429000],[257944.417328302,4149950.568041583]]"
+61107918,30225939,"[1,3]","[[258177.236432024,4149783.558244804],[258177.315037907,4149782.902543994],[258178.091371119,4149782.234238634],[258178.740149225,4149782.932118866],[258178.664507623,4149783.692915637],[258179.132826194,4149782.503315732],[258178.935005525,4149781.322625970],[258178.847395788,4149782.028013888],[258178.312674930,4149781.437667000],[258178.589351329,4149779.206922318],[258178.347447451,4149779.184627215],[258178.067041229,4149781.439360035],[258177.432873713,4149781.921049676],[258177.496701453,4149781.256448389],[258177.023694792,4149782.397425407],[258177.236432024,4149783.558244804]]"
+61107919,30225876,"2","[[257743.074394706,4150055.653397590],[257741.901953216,4150055.324434779],[257741.887498879,4150055.497012788],[257740.086224530,4150055.378279409],[257740.079197915,4150055.541422499],[257741.859669928,4150055.657207088],[257741.826075322,4150055.832230332],[257743.074394706,4150055.653397590]]"
+61107920,30225933,"4","[[258444.032865444,4149993.450460496],[258445.591828109,4149994.368962384],[258446.598977086,4149994.952056744],[258447.445327475,4149995.421418355],[258447.523816916,4149995.481116918],[258447.563483054,4149995.536166519],[258447.593353995,4149995.622821682],[258447.608157801,4149995.696696920],[258447.606687175,4149995.774154339],[258447.589928720,4149995.828175662],[258447.572803146,4149995.869545831],[258447.509749445,4149995.975668883],[258447.486526350,4149996.005220596],[258447.424020877,4149996.057015246],[258447.341330834,4149996.102731516],[258447.233434983,4149996.140182679],[258447.141798355,4149996.152171608],[258447.031871691,4149996.156250088],[258446.917033767,4149996.128372289],[258446.771680062,4149996.064838487],[258446.186446891,4149995.709630704],[258446.282720514,4149995.512689221],[258444.549937158,4149994.910334197],[258445.957378169,4149996.108016609],[258446.055249153,4149995.920358523],[258446.751281212,4149996.335104751],[258446.901306841,4149996.391838870],[258446.986962695,4149996.396461629],[258447.217121051,4149996.404776976],[258447.320510712,4149996.376786330],[258447.397206896,4149996.341129091],[258447.559093976,4149996.257461642],[258447.661662735,4149996.161520902],[258447.754661392,4149996.046976229],[258447.817978347,4149995.925518086],[258447.848714720,4149995.776571852],[258447.838958685,4149995.632576981],[258447.827487763,4149995.524062723],[258447.735182834,4149995.366580513],[258447.691221137,4149995.319097149],[258447.588833014,4149995.238211598],[258447.527730124,4149995.198000829],[258445.727165751,4149994.160557932],[258444.151903961,4149993.229533987],[258444.032865444,4149993.450460496]]"
+61107921,30226042,"2","[[257923.893276166,4149947.547692671],[257925.324044868,4149948.037438793],[257925.353018460,4149947.846446031],[257927.134149122,4149948.112195740],[257927.155875325,4149947.952068798],[257925.372686341,4149947.673383863],[257925.402782012,4149947.493576443],[257923.893276166,4149947.547692671]]"
+61107922,30226030,"1","[[258315.131279580,4150007.603747470],[258316.287445485,4150005.726439294],[258317.099189788,4150005.525049854],[258316.741232711,4150006.134102881],[258317.639267712,4150005.273126043],[258318.000455267,4150004.092309006],[258317.608639151,4150004.721337795],[258316.455061089,4150005.010733387],[258314.927089277,4150007.471395615],[258315.131279580,4150007.603747470]]"
+61107923,30225988,"1","[[258251.520753652,4150064.268196524],[258249.440135776,4150062.983359507],[258249.230559027,4150062.153432023],[258249.834734202,4150062.520515901],[258248.976589387,4150061.566035103],[258247.822206870,4150061.269576879],[258248.405388926,4150061.636270752],[258248.743820507,4150062.833425392],[258251.392318336,4150064.476293088],[258251.520753652,4150064.268196524]]"
+61107924,30226014,"[1,2,3]","[[257904.960080507,4149995.254901887],[257903.790290438,4149994.788779879],[257903.758924608,4149994.997946616],[257902.743449578,4149994.821114343],[257903.086250633,4149994.522920087],[257903.578566399,4149994.583351076],[257902.826887893,4149994.235019680],[257902.007146665,4149994.359156458],[257902.490236437,4149994.412858360],[257902.165104611,4149994.761519452],[257901.982970009,4149994.730274952],[257901.957874740,4149994.887167935],[257902.143016897,4149994.918324961],[257902.330422734,4149995.331715881],[257901.878115653,4149995.271009903],[257902.605301152,4149995.605170310],[257903.450145240,4149995.516178801],[257902.932900835,4149995.426595271],[257902.721381008,4149995.009018632],[257903.736126580,4149995.160770508],[257903.706706824,4149995.369880648],[257904.960080507,4149995.254901887]]"
+61107925,30225934,"3","[[257736.047316376,4149991.465297495],[257735.714747899,4149992.142280573],[257735.835782062,4149992.991325476],[257735.895151751,4149992.570311197],[257736.188883684,4149993.111110876],[257736.003414970,4149994.455892728],[257736.163375220,4149994.476561027],[257736.440039670,4149992.605766764],[257735.976376172,4149991.938962132],[257736.047316376,4149991.465297495]]"
+61107926,30226056,"2","[[258315.799291452,4149773.531349730],[258313.939489109,4149773.087423909],[258313.954706473,4149773.343217352],[258311.266337501,4149773.244780106],[258311.274010988,4149773.484687625],[258313.959997346,4149773.571198635],[258313.965462201,4149773.805172569],[258315.799291452,4149773.531349730]]"
+61107927,30226032,"2","[[258029.592061908,4150029.433713686],[258030.004317501,4150028.235513503],[258029.851488606,4150028.213410623],[258030.123667053,4150026.448054816],[258029.960287268,4150026.422371223],[258029.682831994,4150028.207206427],[258029.539216907,4150028.182281129],[258029.592061908,4150029.433713686]]"
+61107928,30226041,"2","[[258488.172163926,4149847.376546552],[258488.138463511,4149850.117915556],[258487.917298313,4149850.108449310],[258488.211762246,4149851.866227383],[258488.599165733,4149850.126207829],[258488.371792481,4149850.122475103],[258488.410680011,4149847.385953694],[258488.172163926,4149847.376546552]]"
+61107929,30226005,"3","[[258440.756989273,4150017.324958067],[258440.377439206,4150014.359114311],[258439.455739642,4150013.627041742],[258439.354179410,4150012.882164722],[258439.187486985,4150014.121195388],[258439.658515842,4150015.254419654],[258439.573771699,4150014.542930530],[258440.229616459,4150015.070799418],[258440.521488414,4150017.309467458],[258440.756989273,4150017.324958067]]"
+61107930,30226056,"3","[[258372.726504930,4149776.030665424],[258375.634389475,4149776.133635555],[258376.493499670,4149775.272575863],[258377.274673210,4149775.304325836],[258376.027351311,4149774.927354535],[258374.770657209,4149775.200517409],[258375.541896271,4149775.240774642],[258374.922970832,4149775.863618322],[258372.729674851,4149775.783001657],[258372.726504930,4149776.030665424]]"
+61107931,30226072,"2","[[258445.362706601,4149786.191853198],[258446.784891394,4149783.905670226],[258446.987747508,4149784.025513496],[258447.647537364,4149782.296691852],[258446.388158643,4149783.667278105],[258446.582662258,4149783.776923293],[258445.152326714,4149786.075116068],[258445.362706601,4149786.191853198]]"
+61107932,30225943,"1","[[258179.001936310,4150142.061720566],[258179.001936310,4150142.061720566],[258178.833762787,4150144.238667988],[258178.180983695,4150144.867955859],[258178.233154382,4150144.192363577],[258177.845913819,4150145.295198099],[258178.053408417,4150146.519479074],[258178.111367055,4150145.768858256],[258179.001004658,4150145.006848129],[258179.227130539,4150142.079057959],[258179.001936310,4150142.061720566]]"
+61107933,30225843,"2","[[258179.356921551,4150114.202459826],[258181.355977195,4150112.396382818],[258181.511891194,4150112.576560662],[258182.637369746,4150111.055430731],[258181.047797857,4150112.051915040],[258181.190925999,4150112.209473091],[258179.203756940,4150114.034641849],[258179.356921551,4150114.202459826]]"
+61107934,30225912,"2","[[258116.610574510,4150045.276625678],[258117.019209433,4150044.075314889],[258116.881457559,4150044.054105163],[258117.141452211,4150042.304546161],[258116.975102905,4150042.283278886],[258116.710839781,4150044.032184450],[258116.559806463,4150044.010916397],[258116.610574510,4150045.276625678]]"
+61107935,30226000,"3","[[258306.178531143,4149993.210183695],[258307.721609232,4149990.723979803],[258307.419780937,4149989.637717762],[258307.822428170,4149988.988381667],[258306.924700270,4149989.835578050],[258306.571981231,4149990.984828364],[258306.917200958,4149990.449338981],[258307.136014731,4149991.192032550],[258305.986952020,4149993.094459352],[258306.178531143,4149993.210183695]]"
+61107936,30225976,"2","[[258125.526907042,4149985.299150274],[258125.928014181,4149984.149372919],[258125.768164488,4149984.126361558],[258126.027645559,4149982.343719726],[258125.872923586,4149982.326557081],[258125.612530783,4149984.111335720],[258125.463624033,4149984.087117842],[258125.526907042,4149985.299150274]]"
+61107937,31186583,"4","[[258382.346047568,4149912.203929991],[258380.552902029,4149915.101442690],[258380.483850859,4149915.165645353],[258380.394299443,4149915.219002996],[258380.297264763,4149915.240256901],[258380.216773999,4149915.236706590],[258380.159008318,4149915.216947067],[258380.077732830,4149915.177211185],[258380.044101619,4149915.153196942],[258380.006936539,4149915.120288718],[258379.945570587,4149915.040545609],[258379.908078932,4149914.965885090],[258379.887972162,4149914.901493608],[258379.890554056,4149914.795237128],[258379.923055138,4149914.713213708],[258380.136520414,4149914.378143684],[258380.409101014,4149914.545497945],[258381.006796828,4149912.731060128],[258379.590234743,4149914.038247607],[258379.880147229,4149914.217094178],[258379.422214211,4149914.920232939],[258379.367377564,4149915.065436270],[258379.340869348,4149915.192268506],[258379.335820546,4149915.305038565],[258379.349921332,4149915.437022990],[258379.368648208,4149915.502676280],[258379.426160409,4149915.617406768],[258379.552041625,4149915.781688585],[258379.704000907,4149915.880571559],[258379.952245559,4149915.962887257],[258380.279754701,4149915.911952407],[258380.573735979,4149915.688057397],[258382.629121507,4149912.385085453],[258382.346047568,4149912.203929991]]"
+61107938,30225904,"2","[[258102.308097679,4150111.578307747],[258104.995786581,4150111.376470022],[258105.021104096,4150111.604869368],[258106.837104396,4150111.146693634],[258104.951200207,4150110.917607378],[258104.973099249,4150111.134999181],[258102.287091853,4150111.327680393],[258102.308097679,4150111.578307747]]"
+61107939,30225889,"[2,3]","[[258267.808377005,4149801.026242739],[258266.064224876,4149800.467234481],[258266.039966343,4149800.686744152],[258264.538233786,4149800.497108333],[258265.115777803,4149799.995300391],[258265.922500407,4149800.083720381],[258264.830252156,4149799.620182714],[258263.467094382,4149799.775722875],[258264.249666147,4149799.867842872],[258263.640510555,4149800.381675706],[258263.339787625,4149800.342982055],[258263.308759197,4149800.585457404],[258266.009781990,4149800.924752227],[258265.977554370,4149801.180812757],[258267.808377005,4149801.026242739]]"
+61107940,30226051,"[1,2,3]","[[258056.158751326,4149962.156201187],[258057.367979781,4149962.581324184],[258057.380893489,4149962.425563457],[258058.219695396,4149962.555014002],[258057.923900126,4149962.883711880],[258057.401716481,4149962.828249400],[258058.230618339,4149963.150136884],[258059.038446420,4149963.030249538],[258058.560518017,4149962.980498051],[258058.853399188,4149962.633780665],[258059.150215171,4149962.681354576],[258059.169217261,4149962.515753902],[258058.868427605,4149962.474626411],[258058.694197927,4149962.057406452],[258059.203291210,4149962.110250625],[258058.365791298,4149961.769731231],[258057.553033893,4149961.893649317],[258058.025591848,4149961.959661834],[258058.178877768,4149962.375158067],[258057.394671936,4149962.263002393],[258057.407623866,4149962.102464591],[258056.158751326,4149962.156201187]]"
+61107941,30226009,"1","[[258228.099012994,4150154.710339042],[258225.846938688,4150154.577940752],[258225.348782404,4150153.956319803],[258226.088829866,4150154.002797890],[258224.933772865,4150153.591296074],[258223.653507790,4150153.834183210],[258224.412035427,4150153.895118640],[258225.140864179,4150154.780602733],[258228.078856971,4150154.955164703],[258228.099012994,4150154.710339042]]"
+61107942,30225996,"2","[[258440.467831844,4149734.954730898],[258443.110370127,4149734.904486955],[258443.147054639,4149735.143552480],[258444.980186535,4149734.753823798],[258443.115050174,4149734.421980876],[258443.153941639,4149734.669978906],[258440.463405067,4149734.728946115],[258440.467831844,4149734.954730898]]"
+61107943,30226181,"[1,2]","[[258182.928516033,4149744.635353372],[258183.479953288,4149742.893438332],[258183.266942619,4149742.869193031],[258183.592274886,4149740.231634686],[258183.351357296,4149740.206756121],[258183.320092673,4149740.474562434],[258182.689524793,4149740.860849846],[258182.769330023,4149740.151912447],[258182.321386473,4149741.271946298],[258182.473248010,4149742.507173035],[258182.577846884,4149741.731318462],[258183.212964839,4149741.346231690],[258183.030018704,4149742.844642749],[258182.786878208,4149742.816385647],[258182.928516033,4149744.635353372]]"
+61107944,30225841,"2","[[258245.717746443,4150041.307228790],[258246.587666080,4150038.771366229],[258246.812029404,4150038.839266045],[258247.022359643,4150036.957762137],[258246.127912740,4150038.633887625],[258246.339189101,4150038.699279732],[258245.490256381,4150041.235310274],[258245.717746443,4150041.307228790]]"
+61107945,30225860,"1","[[258329.185053273,4150021.897977734],[258328.023250593,4150023.785443957],[258327.201596932,4150023.974791545],[258327.574504833,4150023.368414796],[258326.641106070,4150024.200539936],[258326.356572370,4150025.316821584],[258326.719532543,4150024.739833583],[258327.824630673,4150024.558472629],[258329.384675739,4150022.037681974],[258329.185053273,4150021.897977734]]"
+61107946,30226008,"2","[[258271.521816418,4150080.583547490],[258269.234421397,4150079.153213286],[258269.351550135,4150078.967325896],[258267.593840132,4150078.268768769],[258268.984851220,4150079.552533532],[258269.106905946,4150079.362504609],[258271.401276871,4150080.776975504],[258271.521816418,4150080.583547490]]"
+61107947,30225941,"[2,3]","[[258088.029865438,4150086.457746299],[258086.837100353,4150086.044026197],[258086.814574229,4150086.185849432],[258085.856355029,4150086.047205755],[258086.138972381,4150085.713004875],[258086.871665561,4150085.810776583],[258085.924810990,4150085.429561352],[258085.214252760,4150085.557282683],[258085.599186770,4150085.609071421],[258085.227906535,4150085.960065948],[258085.029061678,4150085.932524309],[258085.004516371,4150086.105394457],[258086.790883045,4150086.360693987],[258086.767710550,4150086.504646316],[258088.029865438,4150086.457746299]]"
+61107948,30225876,"3","[[257732.147710215,4150042.130184080],[257732.637102724,4150042.820230482],[257732.575282566,4150043.266528905],[257732.905747615,4150042.520410537],[257732.764814415,4150041.678164670],[257732.715282198,4150042.181639323],[257732.403522900,4150041.593271535],[257732.593052685,4150040.269474322],[257732.420911301,4150040.243940433],[257732.147710215,4150042.130184080]]"
+61107949,30225906,"2","[[257935.705313855,4149961.435912873],[257936.195198540,4149960.225342696],[257936.000176243,4149960.198470662],[257936.263392614,4149958.408602850],[257936.111506071,4149958.385474544],[257935.838235894,4149960.173635484],[257935.662261096,4149960.147209182],[257935.705313855,4149961.435912873]]"
+61107950,30225932,"4","[[258442.179091125,4149996.577298831],[258445.414072066,4149998.466772759],[258445.526513609,4149998.543257009],[258445.618951951,4149998.650421294],[258445.688132615,4149998.810351619],[258445.691793768,4149998.924312727],[258445.676682310,4149998.980174426],[258445.609833769,4149999.108065979],[258445.578656182,4149999.144179433],[258445.524032898,4149999.189969806],[258445.441040798,4149999.243580727],[258445.335508881,4149999.270967154],[258445.241324844,4149999.286695291],[258445.001633656,4149999.218346442],[258444.318788711,4149998.815657363],[258444.421498179,4149998.602535226],[258442.658049788,4149998.008178885],[258444.091464387,4149999.237539236],[258444.197196400,4149999.040101111],[258444.877245504,4149999.425766762],[258445.019988825,4149999.487821319],[258445.150268297,4149999.520026935],[258445.388519347,4149999.520443657],[258445.496648520,4149999.487983779],[258445.655362640,4149999.413960252],[258445.753899851,4149999.334685681],[258445.812258552,4149999.268128171],[258445.910129693,4149999.086578844],[258445.936236365,4149998.958092481],[258445.929448644,4149998.748592125],[258445.907759341,4149998.666253356],[258445.834800990,4149998.513429968],[258445.779583568,4149998.444170613],[258445.678381924,4149998.349256024],[258445.590260106,4149998.284061438],[258442.296038563,4149996.351434886],[258442.179091125,4149996.577298831]]"
+61107951,30225878,"2","[[258306.508327428,4149833.810906342],[258309.194880141,4149834.167627794],[258309.161671661,4149834.383842926],[258311.025031449,4149834.252439077],[258309.250252901,4149833.708528515],[258309.227099755,4149833.923452084],[258306.535964089,4149833.585745341],[258306.508327428,4149833.810906342]]"
+61107952,30225885,"2","[[258132.880559600,4149935.956295182],[258133.286815809,4149934.782489143],[258133.131266452,4149934.767349575],[258133.368797364,4149933.021332447],[258133.213671885,4149932.996406504],[258132.981736438,4149934.743038539],[258132.823452294,4149934.719092933],[258132.880559600,4149935.956295182]]"
+61107953,30226047,"[2,3]","[[258253.040764445,4150085.235031389],[258254.461696564,4150082.933848417],[258254.655695476,4150083.056720681],[258255.330562133,4150081.306781286],[258254.069393008,4150082.683119792],[258254.263424162,4150082.807101797],[258253.410701265,4150084.124262795],[258253.220069882,4150083.385749924],[258253.619439205,4150082.727509054],[258252.705413894,4150083.537311519],[258252.328810580,4150084.784332943],[258252.707770255,4150084.206765317],[258252.933079123,4150084.932164558],[258252.837681757,4150085.110312677],[258253.040764445,4150085.235031389]]"
+61107954,30225885,"[1,2]","[[258130.976695999,4149949.830240705],[258131.378728944,4149948.675661018],[258131.227988380,4149948.655383683],[258131.515247904,4149946.865826394],[258131.332457889,4149946.842481811],[258131.284868352,4149947.151636274],[258130.876298294,4149947.386533946],[258130.944896566,4149946.883287165],[258130.606938792,4149947.665368434],[258130.688345528,4149948.453035567],[258130.774206742,4149947.983274245],[258131.201222998,4149947.752505479],[258131.070201593,4149948.633311850],[258130.909238165,4149948.608555599],[258130.976695999,4149949.830240705]]"
+61107955,30226246,"[1,3]","[[258166.198192170,4149790.791821977],[258167.030341384,4149790.914258427],[258167.655823632,4149791.700114621],[258166.915884184,4149792.313717636],[258166.099203987,4149792.236147877],[258167.246782383,4149792.699287524],[258168.493729691,4149792.508344558],[258167.775152434,4149792.446251067],[258168.427624383,4149791.905939873],[258170.627009311,4149792.202132399],[258170.669725724,4149791.950653603],[258168.453939609,4149791.668932184],[258167.957592925,4149791.037264272],[258168.650655003,4149791.120091382],[258167.500453369,4149790.633703301],[258166.198192170,4149790.791821977]]"
+61107956,30225923,"2","[[258135.178752739,4149892.781716179],[258135.438077027,4149891.026958139],[258135.583893939,4149891.048378305],[258135.534860598,4149889.823936605],[258135.122332273,4149890.980042403],[258135.292350395,4149891.008645279],[258135.016899060,4149892.759873425],[258135.178752739,4149892.781716179]]"
+61107957,30225954,"[1,2,3]","[[257952.000082305,4150006.379866045],[257953.148136671,4150006.853734927],[257953.176728434,4150006.652646096],[257954.211345095,4150006.802826492],[257953.834710408,4150007.137100175],[257953.413129092,4150007.067390002],[257954.127367368,4150007.400931521],[257954.906445522,4150007.288089493],[257954.489875926,4150007.220232780],[257954.798639852,4150006.890154045],[257954.991626457,4150006.917085623],[257955.013986555,4150006.739169294],[257954.824126896,4150006.716256343],[257954.619654318,4150006.297362999],[257955.068240998,4150006.367176529],[257954.321490587,4150006.017697823],[257953.570978756,4150006.141704696],[257953.999087938,4150006.207559787],[257954.268138847,4150006.636903971],[257953.199411189,4150006.485827279],[257953.227683486,4150006.273751907],[257952.000082305,4150006.379866045]]"
+61107958,30225944,"3","[[258181.589320039,4150142.259447650],[258181.350872256,4150145.235466322],[258182.113990056,4150146.066860010],[258182.048539056,4150146.928322968],[258182.491251021,4150145.720583136],[258182.242106617,4150144.464413607],[258182.187726678,4150145.176722725],[258181.633734205,4150144.501302908],[258181.819260449,4150142.278646464],[258181.589320039,4150142.259447650]]"
+61107959,30225905,"2","[[258044.302398778,4150015.750922386],[258043.133743989,4150015.350834688],[258043.108966918,4150015.515714762],[258041.310563932,4150015.236782292],[258041.288412441,4150015.391478782],[258043.090713465,4150015.664411288],[258043.070748069,4150015.824264465],[258044.302398778,4150015.750922386]]"
+61107960,30226047,"2","[[258213.748381515,4150147.586616954],[258215.231960010,4150145.242399093],[258215.410431383,4150145.409815736],[258216.084876012,4150143.648888384],[258214.840398772,4150144.983653905],[258215.013654100,4150145.145224341],[258213.564751086,4150147.424459372],[258213.748381515,4150147.586616954]]"
+61107961,30225875,"2","[[257942.721394236,4149913.883613957],[257943.186711925,4149912.680534171],[257942.980458901,4149912.651100670],[257943.247595254,4149910.874114553],[257943.094464913,4149910.853910017],[257942.821931297,4149912.634051948],[257942.633812254,4149912.604091147],[257942.721394236,4149913.883613957]]"
+61107962,30225955,"2","[[257928.544996648,4149986.291354772],[257928.787293634,4149984.534193755],[257928.981366287,4149984.558871815],[257928.898025079,4149983.285223281],[257928.454783243,4149984.464782279],[257928.637742500,4149984.490894208],[257928.382170866,4149986.269544387],[257928.544996648,4149986.291354772]]"
+61107963,30225998,"[1,3]","[[257992.638045388,4150142.477555156],[257990.464357515,4150142.261638231],[257989.907847821,4150141.536766317],[257990.504469115,4150141.573732339],[257989.495395189,4150141.156573715],[257988.207051345,4150141.337755714],[257988.994522398,4150141.425706769],[257989.604573643,4150142.289968476],[257988.818555244,4150142.970572654],[257988.064250761,4150142.884545098],[257989.252070499,4150143.320053121],[257990.387543301,4150143.148758353],[257989.758187107,4150143.060763820],[257990.456131021,4150142.475018834],[257992.623590398,4150142.714219197],[257992.638045388,4150142.477555156]]"
+61107964,30225852,"[2,3]","[[258310.781066471,4149916.715863360],[258313.131440275,4149918.079074578],[258312.996963141,4149918.286567781],[258314.852542026,4149918.948974508],[258313.355551235,4149917.668611153],[258313.238708898,4149917.864485478],[258311.957065493,4149917.112887502],[258312.817993159,4149916.940281011],[258313.577593181,4149917.375940544],[258312.505185787,4149916.390687919],[258311.326204083,4149916.076940695],[258311.985126769,4149916.466319789],[258311.178209563,4149916.660460481],[258310.899389111,4149916.500842214],[258310.781066471,4149916.715863360]]"
+61107965,30225924,"2","[[257901.349900454,4149998.819257521],[257902.530407732,4149999.282512870],[257902.560631113,4149999.101035546],[257904.181500129,4149999.348227215],[257904.206825284,4149999.190105794],[257902.580463500,4149998.939741799],[257902.607661273,4149998.754687194],[257901.349900454,4149998.819257521]]"
+61107966,30226056,"2","[[258349.881034096,4149774.718778404],[258348.098268022,4149774.302597419],[258348.092140735,4149774.542905504],[258345.404136397,4149774.432562409],[258345.395817024,4149774.673600549],[258348.107483390,4149774.781701803],[258348.102519670,4149775.001095225],[258349.881034096,4149774.718778404]]"
+61107967,30225852,"3","[[258293.515763857,4149906.590342212],[258296.044147178,4149908.071222217],[258297.135549322,4149907.756085161],[258297.816515607,4149908.145378523],[258296.907164211,4149907.247913392],[258295.828381620,4149906.970132866],[258296.369453673,4149907.301067520],[258295.601556515,4149907.512736219],[258293.640578840,4149906.370245269],[258293.515763857,4149906.590342212]]"
+61107968,30226009,"1","[[258250.588241390,4150139.851889441],[258249.438227721,4150141.702041395],[258248.597061674,4150141.904959562],[258248.957597770,4150141.318041462],[258248.042769854,4150142.163965710],[258247.715936667,4150143.338236083],[258248.134552273,4150142.687432581],[258249.262833017,4150142.448297188],[258250.800575645,4150139.981226333],[258250.588241390,4150139.851889441]]"
+61107969,30225912,"[1,3]","[[258113.103787855,4150068.431981923],[258112.896528344,4150069.875791192],[258112.451374768,4150070.286464749],[258112.509206016,4150069.830179345],[258112.207563984,4150070.530348606],[258112.294280349,4150071.366620712],[258112.370143416,4150070.860607802],[258112.907630542,4150070.437588077],[258113.301564084,4150070.951385208],[258113.226923647,4150071.505566464],[258113.571187161,4150070.736628818],[258113.484630309,4150069.924120810],[258113.401444170,4150070.403578912],[258113.048212643,4150069.919476138],[258113.260301842,4150068.452979547],[258113.103787855,4150068.431981923]]"
+61107970,30225947,"4","[[258179.961497236,4150131.663571009],[258179.683010554,4150135.327491330],[258179.635860405,4150135.545112105],[258179.577437113,4150135.658100370],[258179.473136016,4150135.776531029],[258179.336392678,4150135.850921342],[258179.195900060,4150135.872440761],[258179.022252021,4150135.791851570],[258178.939562499,4150135.709508384],[258178.854149699,4150135.573042740],[258178.823330683,4150135.392895947],[258178.877881876,4150134.622492841],[258179.101385558,4150134.633437367],[258178.888712265,4150132.764663488],[258178.396984550,4150134.576820036],[258178.645358907,4150134.611921416],[258178.583272128,4150135.299686122],[258178.583913946,4150135.468047787],[258178.616570709,4150135.592606785],[258178.670674320,4150135.720985457],[258178.752367757,4150135.866555729],[258178.892211973,4150135.984224354],[258179.065829174,4150136.060704892],[258179.220155458,4150136.097872177],[258179.362739187,4150136.081290102],[258179.499176887,4150136.029899912],[258179.601099412,4150135.960630768],[258179.679644768,4150135.882044588],[258179.745100051,4150135.800839846],[258179.836877860,4150135.665779491],[258179.902443281,4150135.524372259],[258179.936946117,4150135.358988048],[258180.219939297,4150131.670390616],[258179.961497236,4150131.663571009]]"
+61107971,30225920,"2","[[258146.400574711,4150008.254894844],[258146.799456669,4150005.571989332],[258147.015415452,4150005.597369297],[258146.932486204,4150003.779138809],[258146.322928110,4150005.506309540],[258146.535990378,4150005.532551132],[258146.152057790,4150008.215022309],[258146.400574711,4150008.254894844]]"
+61107972,30225919,"4","[[258141.113043167,4150070.858972062],[258140.578753429,4150074.506003053],[258140.534495210,4150074.719541573],[258140.508264109,4150074.837481369],[258140.435878611,4150074.920887007],[258140.351433993,4150075.003643420],[258140.236494150,4150075.039304175],[258140.146815342,4150075.021140036],[258140.032173724,4150074.908626305],[258139.931612482,4150074.768824792],[258139.892846511,4150074.619897194],[258139.873054621,4150074.438430454],[258139.987312175,4150073.721160083],[258140.210687585,4150073.758097536],[258140.129420037,4150071.933154415],[258139.506378741,4150073.674379595],[258139.740577674,4150073.706004445],[258139.625820166,4150074.448724111],[258139.628840075,4150074.577031936],[258139.639146364,4150074.648371870],[258139.690550568,4150074.799597900],[258139.754907258,4150074.939562831],[258139.902119484,4150075.130988670],[258140.014171979,4150075.224473790],[258140.101281795,4150075.257817933],[258140.190928355,4150075.274872321],[258140.302820927,4150075.268400140],[258140.435220885,4150075.215127460],[258140.549707113,4150075.133386321],[258140.653617335,4150075.031960094],[258140.732060851,4150074.919389470],[258140.789975727,4150074.758433973],[258141.380640963,4150070.900511268],[258141.113043167,4150070.858972062]]"
+61107973,30225913,"2","[[257759.155683736,4149973.577610684],[257757.990851101,4149973.142352282],[257757.970806403,4149973.308428735],[257756.194006526,4149973.036480254],[257756.174596664,4149973.212201260],[257757.933824815,4149973.464446496],[257757.910938825,4149973.663704261],[257759.155683736,4149973.577610684]]"
+61107974,30225995,"[1,3]","[[257993.627926778,4150111.428536567],[257991.429335085,4150111.309417512],[257990.828733251,4150110.614927454],[257991.420711530,4150110.629148494],[257990.356563536,4150110.275789389],[257989.096068804,4150110.544127810],[257989.882302857,4150110.562030599],[257990.580696317,4150111.404509042],[257989.829384854,4150112.137083674],[257989.032062985,4150112.115393725],[257990.225289817,4150112.468776073],[257991.438076496,4150112.209932924],[257990.776499041,4150112.176965555],[257991.365079623,4150111.553638258],[257993.631991493,4150111.650556377],[257993.627926778,4150111.428536567]]"
+61107975,30225833,"[1,2,3]","[[258034.268552658,4149973.142766330],[258033.885769533,4149974.331667976],[258034.021352842,4149974.348274578],[258033.906438219,4149975.207178858],[258033.569223591,4149974.857117736],[258033.631557892,4149974.376154452],[258033.282669231,4149975.162556721],[258033.409868804,4149975.981102521],[258033.470775359,4149975.505845247],[258033.818171118,4149975.822400808],[258033.777105650,4149976.151803179],[258033.942248930,4149976.155888288],[258033.998048170,4149975.766857898],[258034.420902771,4149975.551421265],[258034.350419763,4149976.099262764],[258034.676701298,4149975.345283398],[258034.578915527,4149974.475679436],[258034.499339532,4149974.990908846],[258034.087032626,4149975.151948306],[258034.188541022,4149974.380067485],[258034.362335358,4149974.401561094],[258034.268552658,4149973.142766330]]"
+61107976,30226041,"2","[[258489.103904416,4149796.915566574],[258489.058345030,4149799.599190555],[258488.827086165,4149799.592793726],[258489.159723338,4149801.418215671],[258489.527926475,4149799.605226263],[258489.300669287,4149799.602489652],[258489.343337038,4149796.922948033],[258489.103904416,4149796.915566574]]"
+61107977,30225882,"[2,3]","[[257965.284736328,4149835.086957797],[257966.477539881,4149835.552309589],[257966.495370550,4149835.358642231],[257967.484947027,4149835.515022443],[257967.174354753,4149835.843376123],[257966.738781580,4149835.804282199],[257967.430149897,4149836.142489284],[257968.130164162,4149835.968083903],[257967.757886972,4149835.937923306],[257968.039732687,4149835.604407719],[257968.255329722,4149835.644566133],[257968.277026026,4149835.459005493],[257966.508828282,4149835.185094427],[257966.526278214,4149834.978332001],[257965.284736328,4149835.086957797]]"
+61107978,30225941,"2","[[258108.798976414,4150070.276091472],[258108.997912825,4150069.012011199],[258109.153695208,4150069.035251383],[258109.091656284,4150067.811298235],[258108.687959173,4150068.960041646],[258108.845506082,4150068.986118338],[258108.646322289,4150070.253871077],[258108.798976414,4150070.276091472]]"
+61107979,30226046,"[1,2]","[[258255.435040714,4150086.721012504],[258255.595434689,4150086.464117196],[258256.335479276,4150086.363987796],[258255.991326164,4150086.966423387],[258256.886608638,4150086.136173622],[258257.243648561,4150084.934925582],[258256.834821429,4150085.578446669],[258256.079837998,4150085.691560646],[258256.853270358,4150084.460892806],[258257.071619422,4150084.593054119],[258257.744321244,4150082.808191171],[258256.455013149,4150084.212447292],[258256.652165989,4150084.337227238],[258255.231130113,4150086.601315876],[258255.435040714,4150086.721012504]]"
+61107980,30225960,"[1,2]","[[257941.161192739,4149827.896711160],[257939.776931599,4149827.368955771],[257939.749749095,4149827.581999031],[257938.091773948,4149827.344651430],[257938.067347811,4149827.518518263],[257938.164118923,4149827.530809717],[257938.360064377,4149827.942509262],[257937.944852534,4149827.888163618],[257938.632611362,4149828.236136417],[257939.426986925,4149828.100746729],[257938.957570976,4149828.036537080],[257938.717487763,4149827.611015582],[257939.725263505,4149827.756867207],[257939.699969028,4149827.967856328],[257941.161192739,4149827.896711160]]"
+61107981,30225990,"5","[[258435.046614373,4149772.422047195],[258432.764697282,4149773.738784178],[258432.632451170,4149773.577907202],[258431.150625357,4149774.782017266],[258433.002228556,4149774.159616092],[258432.883272168,4149773.944152054],[258435.217593698,4149772.605791033],[258435.046614373,4149772.422047195]]"
+61107982,30226039,"2","[[258117.233201368,4150013.359226243],[258116.791962931,4150014.526275418],[258116.967964748,4150014.553704238],[258116.690470183,4150016.325652177],[258116.846911396,4150016.350206262],[258117.125042707,4150014.575796311],[258117.277691351,4150014.597794959],[258117.233201368,4150013.359226243]]"
+61107983,30226046,"1","[[258242.238278501,4150107.571370465],[258243.417146848,4150105.684282478],[258244.241144602,4150105.505853561],[258243.865005764,4150106.107330630],[258244.751033497,4150105.269462196],[258245.215871868,4150103.963565681],[258244.755068845,4150104.673794458],[258243.574239638,4150104.990649430],[258242.048714187,4150107.451812844],[258242.238278501,4150107.571370465]]"
+61107984,30225934,"1","[[257739.753753899,4150059.298148593],[257740.253502504,4150059.340249138],[257740.796387160,4150059.918447300],[257742.715362499,4150060.029534572],[257742.718573833,4150059.863059379],[257741.294388548,4150059.766671850],[257740.900936059,4150059.367610969],[257741.301694402,4150059.381937483],[257740.547028547,4150059.128782801],[257739.753753899,4150059.298148593]]"
+61107985,31186585,"1","[[258385.342689340,4149914.060983685],[258384.151979152,4149915.984487344],[258383.345801398,4149916.158384989],[258383.698149942,4149915.593703671],[258382.788253322,4149916.430914393],[258382.462949857,4149917.576587819],[258382.860563611,4149916.942618647],[258383.983314798,4149916.703997954],[258385.561040273,4149914.193148453],[258385.342689340,4149914.060983685]]"
+61107986,30225885,"2","[[258147.580480793,4149836.026104752],[258147.325204675,4149837.813731723],[258147.168245671,4149837.789747210],[258147.227788702,4149839.010329213],[258147.630580006,4149837.851064212],[258147.497600293,4149837.832713938],[258147.750254915,4149836.046273826],[258147.580480793,4149836.026104752]]"
+61107987,30225984,"2","[[257977.523399144,4150096.411093279],[257980.206873042,4150096.511667929],[257980.169101945,4150096.741124025],[257982.014034930,4150096.468120218],[257980.257339227,4150096.024606897],[257980.219206285,4150096.272066693],[257977.527684105,4150096.168727182],[257977.523399144,4150096.411093279]]"
+61107988,30225861,"[2,3]","[[258296.067358593,4150072.307101352],[258294.615685660,4150074.617165748],[258294.424810757,4150074.498200347],[258293.733325925,4150076.267611176],[258295.046224306,4150074.873672208],[258294.815729584,4150074.737864143],[258295.640942560,4150073.436501075],[258295.836208008,4150074.224972035],[258295.385715045,4150074.942895078],[258296.326779201,4150074.073224021],[258296.695649226,4150072.864526268],[258296.322987907,4150073.451793826],[258296.111613569,4150072.690891379],[258296.268462572,4150072.430767857],[258296.067358593,4150072.307101352]]"
+61107989,30226012,"3","[[258390.028284129,4149737.774303802],[258389.638088422,4149739.002828275],[258390.028458424,4149740.135281983],[258390.018356708,4149739.408964997],[258390.704733503,4149740.060675469],[258390.700734517,4149742.262613597],[258390.952969720,4149742.262623479],[258390.943551649,4149739.360454626],[258390.034930490,4149738.485282549],[258390.028284129,4149737.774303802]]"
+61107990,30225836,"[1,2]","[[258183.947939878,4149730.841772044],[258184.076926516,4149730.033776670],[258184.700878424,4149729.672672080],[258184.512537103,4149731.119481729],[258184.279072860,4149731.101272876],[258184.397071842,4149732.969019989],[258184.960343179,4149731.174225911],[258184.742385648,4149731.162563941],[258185.096685777,4149728.495064327],[258184.856040360,4149728.455183512],[258184.819027187,4149728.747591908],[258184.173455973,4149729.169079444],[258184.262403177,4149728.506636469],[258183.792931437,4149729.562209229],[258183.947939878,4149730.841772044]]"
+61107991,30225939,"[1,3]","[[258179.037794944,4149768.985235041],[258179.133585712,4149768.238403003],[258179.917142620,4149767.629754154],[258180.535975516,4149768.406141497],[258180.436759659,4149769.217937143],[258180.901251264,4149767.997127237],[258180.716568999,4149766.912130256],[258180.636251669,4149767.548554737],[258180.139155965,4149766.851488365],[258180.425619525,4149764.628456524],[258180.185197150,4149764.590124403],[258179.898701412,4149766.812046504],[258179.245354458,4149767.319283501],[258179.299423360,4149766.660074908],[258178.866642364,4149767.777780525],[258179.037794944,4149768.985235041]]"
+61107992,30226031,"2","[[258312.571181543,4150005.956404445],[258314.009761333,4150003.661274928],[258314.205738952,4150003.779093094],[258314.833234608,4150002.113614984],[258313.612505933,4150003.410798234],[258313.812667139,4150003.535492246],[258312.372414893,4150005.834002417],[258312.571181543,4150005.956404445]]"
+61107993,30225938,"2","[[257952.014820567,4149850.792647508],[257952.513137972,4149849.591608101],[257952.293252415,4149849.559238569],[257952.556118791,4149847.760052559],[257952.386942083,4149847.736093719],[257952.120913245,4149849.530040382],[257951.938006043,4149849.505814378],[257952.014820567,4149850.792647508]]"
+61107994,30225866,"3","[[258198.517862148,4150153.017148634],[258201.422560387,4150153.215770834],[258202.284609736,4150152.442680350],[258203.073715110,4150152.486509552],[258201.892885861,4150152.083867510],[258200.644321363,4150152.317840365],[258201.351491332,4150152.369269844],[258200.761690342,4150152.923532049],[258198.537247407,4150152.779342559],[258198.517862148,4150153.017148634]]"
+61107995,30226069,"3","[[258289.850381965,4149916.111283738],[258287.337550765,4149914.632397615],[258286.242217217,4149914.943207465],[258285.540234356,4149914.546639436],[258286.459192231,4149915.430385119],[258287.574249436,4149915.725659533],[258287.003034847,4149915.378051868],[258287.787118142,4149915.181128708],[258289.732119292,4149916.325303867],[258289.850381965,4149916.111283738]]"
+61107996,30225873,"[2,4]","[[258279.283393739,4149723.806777561],[258277.442996904,4149723.894425185],[258277.469771929,4149724.127447177],[258274.877649232,4149724.743395824],[258274.899201110,4149724.991674811],[258277.072826824,4149724.464404145],[258277.094005914,4149724.657159646],[258277.060578459,4149724.771309191],[258276.976814807,4149724.905135579],[258276.912368395,4149724.957209900],[258276.793036411,4149724.979001215],[258276.766008035,4149724.761647254],[258274.980415316,4149725.553656285],[258276.870264620,4149725.470792000],[258276.845761386,4149725.221488023],[258276.962290186,4149725.203776573],[258277.008795351,4149725.186321272],[258277.053030700,4149725.160823870],[258277.097602856,4149725.116435022],[258277.160362608,4149725.042862366],[258277.224996060,4149724.936247923],[258277.283991145,4149724.809249507],[258277.316041292,4149724.684255232],[258277.289386559,4149724.412688934],[258277.545542208,4149724.349494618],[258277.571581468,4149724.599864683],[258279.283393739,4149723.806777561]]"
+61107997,30225920,"[1,2]","[[258272.144039821,4149829.160538040],[258272.505315750,4149829.193030835],[258272.932547266,4149829.816937133],[258272.230462568,4149829.737251481],[258273.317220655,4149830.203948074],[258274.574831057,4149830.032814477],[258273.773374083,4149829.915252062],[258273.378567668,4149829.304287746],[258274.818871901,4149829.494597800],[258274.790271407,4149829.695685063],[258276.665733780,4149829.599908393],[258274.905085776,4149829.027494198],[258274.882354038,4149829.226411808],[258272.172492045,4149828.893369225],[258272.144039821,4149829.160538040]]"
+61107998,30225888,"[2,3]","[[257892.637342046,4150065.004712458],[257891.463018492,4150064.616806263],[257891.450497343,4150064.819427271],[257890.433482747,4150064.750712127],[257890.753979728,4150064.391966735],[257891.182715125,4150064.421591679],[257890.476644658,4150064.158791277],[257889.703214581,4150064.322567313],[257890.110410332,4150064.372589007],[257889.839387959,4150064.712568614],[257889.638942847,4150064.700072411],[257889.625894982,4150064.878495683],[257891.435298045,4150065.003022291],[257891.417615427,4150065.201683869],[257892.637342046,4150065.004712458]]"
+61107999,30225923,"2","[[258143.252401452,4149838.365895345],[258143.529411421,4149836.570639398],[258143.703499711,4149836.599124274],[258143.624001195,4149835.328585742],[258143.161418580,4149836.517244249],[258143.342429259,4149836.546305478],[258143.065734471,4149838.340219453],[258143.252401452,4149838.365895345]]"
+61108000,30225829,"[1,3]","[[258380.249304588,4149761.775142252],[258379.494354077,4149761.740964763],[258378.719481545,4149760.895343603],[258379.538490979,4149760.162510700],[258380.325814243,4149760.183419993],[258379.097949224,4149759.830207359],[258377.883308081,4149760.100371902],[258378.610864961,4149760.130235197],[258377.970033186,4149760.779260114],[258375.763771627,4149760.700462560],[258375.741724183,4149760.947452479],[258377.934774444,4149761.022523941],[258378.574455193,4149761.718683305],[258377.912523474,4149761.704797301],[258379.053299984,4149762.049874881],[258380.249304588,4149761.775142252]]"
+61108001,30226023,"2","[[258374.707428860,4149913.136821679],[258376.148917915,4149910.806523734],[258376.341055958,4149910.926231985],[258377.010549655,4149909.209338306],[258375.764818725,4149910.567102108],[258375.956868321,4149910.686812918],[258374.500418708,4149913.020210798],[258374.707428860,4149913.136821679]]"
+61108002,30226031,"2","[[258335.324273075,4149969.618007537],[258336.755199336,4149967.324104883],[258336.933503153,4149967.433884433],[258337.600249211,4149965.720398257],[258336.343166254,4149967.083052620],[258336.535874327,4149967.194968559],[258335.110206942,4149969.480943774],[258335.324273075,4149969.618007537]]"
+61108003,30225924,"[1,2,3]","[[257837.427779471,4149989.347800802],[257838.569715007,4149989.735754045],[257838.590594790,4149989.573985306],[257839.555843931,4149989.716284685],[257839.202706825,4149990.063874957],[257838.702761349,4149989.984676847],[257839.436647845,4149990.308640821],[257840.183634212,4149990.209494649],[257839.736381133,4149990.133872759],[257840.151686588,4149989.802133930],[257840.399144086,4149989.835919532],[257840.421133176,4149989.669675766],[257840.203115299,4149989.643586041],[257839.906125808,4149989.212725364],[257840.264859885,4149989.258379161],[257839.584842137,4149988.929738049],[257838.820309398,4149989.034392830],[257839.287751571,4149989.122311364],[257839.582502538,4149989.555347458],[257838.614622898,4149989.420010885],[257838.641663086,4149989.263061042],[257837.427779471,4149989.347800802]]"
+61108004,30225997,"2","[[258442.659165815,4149730.982646382],[258445.300894522,4149731.032610464],[258445.318762913,4149731.279219283],[258447.130786111,4149730.949192062],[258445.329805022,4149730.558286795],[258445.344462904,4149730.797991458],[258442.620811159,4149730.722637384],[258442.659165815,4149730.982646382]]"
+61108005,30226024,"2","[[258371.494750402,4149911.184747955],[258372.912591677,4149908.893787698],[258373.117428899,4149909.005685673],[258373.785207243,4149907.278512116],[258372.528378578,4149908.665698507],[258372.712147868,4149908.768545042],[258371.276892001,4149911.069562727],[258371.494750402,4149911.184747955]]"
+61108006,30225830,"2","[[258416.006611680,4149771.091295492],[258414.542430755,4149773.351824318],[258414.342888111,4149773.215003212],[258413.613181537,4149775.063478502],[258414.935044108,4149773.582448718],[258414.753012189,4149773.460224748],[258416.202170014,4149771.215903662],[258416.006611680,4149771.091295492]]"
+61108007,30226066,"2","[[258172.125971648,4150142.681214842],[258172.360518093,4150139.991533344],[258172.605274060,4150140.008746512],[258172.387496060,4150138.138010677],[258171.882321078,4150139.965663804],[258172.120891164,4150139.977170028],[258171.899320197,4150142.662476083],[258172.125971648,4150142.681214842]]"
+61108008,30225958,"[1,2]","[[258404.763334395,4149980.178752726],[258404.519457657,4149980.033333817],[258404.323734876,4149979.240986956],[258404.941826027,4149979.599570041],[258404.146906106,4149978.770190489],[258402.832952671,4149978.371938094],[258403.564528101,4149978.800199364],[258403.719529328,4149979.577401031],[258402.444747712,4149978.832810764],[258402.563847094,4149978.626209673],[258400.796669372,4149977.992096261],[258402.209870991,4149979.226257402],[258402.323911158,4149979.034464192],[258404.640416938,4149980.388019174],[258404.763334395,4149980.178752726]]"
+61108009,30225913,"[1,2,3]","[[257807.506548551,4149981.175955031],[257807.018868070,4149981.104509949],[257806.800946829,4149980.674015435],[257807.789375710,4149980.818746776],[257807.757892699,4149981.023807905],[257809.035910085,4149980.928090250],[257807.840642222,4149980.447728059],[257807.808159065,4149980.654928599],[257806.820619252,4149980.507283589],[257807.199618142,4149980.150942442],[257807.641374748,4149980.195845348],[257806.879147898,4149979.892923170],[257806.072234862,4149980.010698386],[257806.547597785,4149980.072616649],[257806.245376392,4149980.420504077],[257806.069517630,4149980.398075622],[257806.044661054,4149980.560071263],[257806.223585501,4149980.584409764],[257806.422194519,4149981.005358870],[257805.999930880,4149980.945783088],[257806.698645042,4149981.265769586],[257807.506548551,4149981.175955031]]"
+61108010,30226006,"2","[[257805.452863646,4149984.456380527],[257806.573267407,4149984.928813259],[257806.605425064,4149984.716512995],[257808.409980939,4149984.999326578],[257808.428202596,4149984.846631662],[257806.628662950,4149984.562783570],[257806.652849860,4149984.380814964],[257805.452863646,4149984.456380527]]"
+61108011,30225843,"5","[[258201.683852108,4150093.563468229],[258203.068411492,4150092.287274858],[258203.289556906,4150092.098142699],[258203.458056647,4150092.016721587],[258203.868536457,4150091.832529962],[258203.963230327,4150092.038588508],[258205.486608705,4150091.006268559],[258203.713529481,4150091.397089329],[258203.793712647,4150091.618674746],[258203.364174598,4150091.805086026],[258203.163874260,4150091.891984729],[258203.076857183,4150091.968484282],[258202.863034312,4150092.156737324],[258201.501322798,4150093.363071173],[258201.683852108,4150093.563468229]]"
+61108012,30225837,"[1,2,3]","[[257819.714197959,4150002.780038286],[257819.738496777,4150002.604952761],[257820.142418673,4150002.420599573],[257820.069686052,4150002.899757674],[257820.423606362,4150002.134856883],[257820.316549581,4150001.318614445],[257820.227559450,4150001.792803151],[257819.825296373,4150002.012872337],[257819.971248307,4150001.004338715],[257820.161432862,4150001.035347234],[257820.064625981,4149999.731546211],[257819.624370431,4150000.952343140],[257819.802232890,4150000.976712794],[257819.653217246,4150001.986446248],[257819.320464080,4150001.686577667],[257819.388166654,4150001.141035479],[257819.037922289,4150001.928820684],[257819.163677925,4150002.733523241],[257819.225470913,4150002.286115977],[257819.570754030,4150002.581510448],[257819.543013773,4150002.760028173],[257819.714197959,4150002.780038286]]"
+61108013,30226037,"2","[[258138.119652914,4149788.172096245],[258136.350222262,4149787.953274832],[258136.364381540,4149787.800699219],[258135.142085039,4149787.871087558],[258136.318155176,4149788.266531923],[258136.332836523,4149788.104500293],[258138.105667716,4149788.330664509],[258138.119652914,4149788.172096245]]"
+61108014,30225886,"[1,2,3]","[[257949.008317596,4149847.112163048],[257948.522539780,4149848.354711082],[257948.716528894,4149848.382502198],[257948.547964121,4149849.405684072],[257948.228897499,4149849.034550341],[257948.275898200,4149848.592684081],[257947.956998495,4149849.326459813],[257948.059916110,4149850.073849350],[257948.127983093,4149849.668356511],[257948.458509424,4149849.989064907],[257948.430990347,4149850.163132707],[257948.609632709,4149850.192925023],[257948.642022597,4149849.991503693],[257949.053734219,4149849.825035336],[257948.997711996,4149850.264165047],[257949.319517549,4149849.560293490],[257949.217854032,4149848.719014188],[257949.153588516,4149849.188261143],[257948.717886772,4149849.461386873],[257948.881566053,4149848.410246606],[257949.085816981,4149848.443848141],[257949.008317596,4149847.112163048]]"
+61108015,30225842,"[1,2]","[[258229.097197156,4150071.297148456],[258229.229448033,4150071.110710143],[258230.176547404,4150071.122630557],[258229.753556515,4150071.729578566],[258230.725763894,4150070.956957671],[258231.145237825,4150069.768667027],[258230.649336804,4150070.444040715],[258229.691939191,4150070.455521657],[258230.644981367,4150069.084019445],[258230.846017444,4150069.235786818],[258231.590566669,4150067.507590001],[258230.276599752,4150068.803497006],[258230.462368991,4150068.941713141],[258228.892980929,4150071.136476928],[258229.097197156,4150071.297148456]]"
+61108016,30225832,"2","[[258468.233841111,4149795.219843798],[258466.795751670,4149797.522478175],[258466.593761284,4149797.395834175],[258465.934118263,4149799.108433905],[258467.175973435,4149797.762460918],[258466.995894062,4149797.649509002],[258468.440373452,4149795.344356827],[258468.233841111,4149795.219843798]]"
+61108017,30225861,"3","[[258331.334278206,4150023.231600867],[258329.766635786,4150025.731619737],[258330.022188788,4150026.843327731],[258329.606788431,4150027.532129226],[258330.549474165,4150026.681408455],[258330.950338175,4150025.409585560],[258330.524476593,4150026.085695688],[258330.342624764,4150025.246853834],[258331.532725767,4150023.355234315],[258331.334278206,4150023.231600867]]"
+61108018,30226004,"1","[[258379.804234692,4149787.095467699],[258380.240686307,4149786.466369462],[258381.490247501,4149786.197634920],[258383.131131615,4149783.790691507],[258382.946626762,4149783.653434667],[258381.677787318,4149785.503011459],[258380.774453710,4149785.682282812],[258381.171296333,4149785.091653301],[258380.234168525,4149785.909327844],[258379.804234692,4149787.095467699]]"
+61108019,30225978,"2","[[258106.896720241,4150114.745703068],[258104.033877651,4150115.013162946],[258104.013064477,4150114.799626998],[258102.428834201,4150115.242404531],[258104.076186809,4150115.494194476],[258104.058918783,4150115.265561203],[258106.923010723,4150114.974074142],[258106.896720241,4150114.745703068]]"
+61108020,30226074,"[1,2,3]","[[258025.327907301,4150034.528338599],[258025.365363744,4150034.266682005],[258025.791440395,4150034.040377310],[258025.738518071,4150034.488746111],[258026.053971459,4150033.727861377],[258025.939757844,4150032.938815667],[258025.853375737,4150033.497004695],[258025.441027914,4150033.726575567],[258025.576226640,4150032.743239424],[258025.721983480,4150032.762660009],[258025.670534016,4150031.531845680],[258025.264640992,4150032.702205020],[258025.412412994,4150032.720900608],[258025.289843130,4150033.575251799],[258024.947873588,4150033.253429813],[258025.009772243,4150032.733160597],[258024.654981557,4150033.575269609],[258024.798147933,4150034.361363351],[258024.868376503,4150033.865731426],[258025.212137429,4150034.203495258],[258025.171189613,4150034.506459928],[258025.327907301,4150034.528338599]]"
+61108021,30226046,"2","[[258216.616817634,4150149.398683226],[258218.062826899,4150147.080769812],[258218.243041116,4150147.241138550],[258218.933480028,4150145.445648750],[258217.665846701,4150146.809186865],[258217.851131927,4150146.970407915],[258216.431043604,4150149.238920300],[258216.616817634,4150149.398683226]]"
+61108022,30225977,"[1,2,3]","[[258049.618785536,4150020.491531773],[258049.256371692,4150020.447086822],[258049.091036396,4150020.009949348],[258049.563560819,4150020.077961356],[258048.818313151,4150019.743425222],[258047.986877585,4150019.845895972],[258048.535351963,4150019.937912563],[258048.658407319,4150020.348956016],[258047.871173299,4150020.236001109],[258047.894059217,4150020.073064196],[258046.686173269,4150020.141605473],[258047.836962063,4150020.542323983],[258047.855075646,4150020.413179669],[258048.689415563,4150020.544646692],[258048.383734589,4150020.868190103],[258047.886057940,4150020.802908502],[258048.581976447,4150021.152095589],[258049.441779362,4150021.029585420],[258048.994225739,4150020.961736155],[258049.290894137,4150020.623571500],[258049.595679007,4150020.671246498],[258049.618785536,4150020.491531773]]"
+61108023,30225931,"2","[[258481.436072483,4149801.300538957],[258481.484016066,4149798.613735646],[258481.714329376,4149798.624158169],[258481.389780314,4149796.790726947],[258481.016345380,4149798.612531959],[258481.245666158,4149798.616208092],[258481.186018569,4149801.299352513],[258481.436072483,4149801.300538957]]"
+61108024,30225978,"2","[[258259.807176434,4149915.015782699],[258259.184350274,4149917.643761661],[258258.965432114,4149917.589697802],[258258.879127964,4149919.529130815],[258259.643267206,4149917.755275678],[258259.421545950,4149917.705291684],[258260.047233289,4149915.075230417],[258259.807176434,4149915.015782699]]"
+61108025,30225977,"2","[[258103.117936292,4150028.537233175],[258104.316341920,4150028.925468525],[258104.320343734,4150028.801177243],[258106.098546184,4150029.073712584],[258106.121522099,4150028.916882087],[258104.349157327,4150028.638068308],[258104.359599013,4150028.494708176],[258103.117936292,4150028.537233175]]"
+61108026,30226037,"[2,3]","[[258081.664892247,4149780.875027905],[258082.804957356,4149781.256072764],[258082.818113603,4149781.102526515],[258083.662208647,4149781.215500032],[258083.355783147,4149781.559499531],[258082.900137041,4149781.515207119],[258083.662289457,4149781.870248463],[258084.462288949,4149781.693614210],[258083.993790419,4149781.627481467],[258084.308670740,4149781.300229826],[258084.590077363,4149781.335257867],[258084.613561341,4149781.165417585],[258082.837760141,4149780.934685912],[258082.847258196,4149780.792352855],[258081.664892247,4149780.875027905]]"
+61108027,30225997,"2","[[258343.680101337,4149806.784902204],[258346.332796689,4149807.115740408],[258346.307272686,4149807.352724183],[258348.167130848,4149807.225540332],[258346.384407143,4149806.630649672],[258346.369666569,4149806.891422295],[258343.707695803,4149806.561297607],[258343.680101337,4149806.784902204]]"
+61108028,30226055,"[2,3]","[[258257.018288080,4150058.930733274],[258259.293995397,4150060.339412509],[258259.165097511,4150060.534638394],[258260.886421575,4150061.190378643],[258259.550124500,4150059.940345785],[258259.423867755,4150060.141159469],[258258.138984058,4150059.332353541],[258258.864549172,4150059.078037432],[258259.562861967,4150059.510139973],[258258.726934503,4150058.656085534],[258257.501159751,4150058.254740169],[258258.090065081,4150058.614271156],[258257.368220872,4150058.856483846],[258257.154882775,4150058.726176188],[258257.018288080,4150058.930733274]]"
+61108029,30225876,"2","[[257739.775590691,4149995.014855890],[257740.263176661,4149993.768907572],[257740.054093852,4149993.739561535],[257740.342474796,4149991.954949418],[257740.187811035,4149991.936792552],[257739.909554652,4149993.695119815],[257739.723264138,4149993.658002019],[257739.775590691,4149995.014855890]]"
+61108030,30225886,"2","[[257945.037702076,4149873.861629734],[257944.576697403,4149875.091351356],[257944.777470108,4149875.121055393],[257944.509180375,4149876.885857178],[257944.671657587,4149876.907789243],[257944.929047554,4149875.142637993],[257945.123759877,4149875.170963294],[257945.037702076,4149873.861629734]]"
+61108031,30225999,"1","[[258308.372366665,4149994.561388090],[258309.509208866,4149992.707631322],[258310.310543683,4149992.537975979],[258309.955457116,4149993.111737173],[258310.924027805,4149992.225498329],[258311.294319201,4149990.998434254],[258310.828897943,4149991.720787813],[258309.648980139,4149992.005617697],[258308.179912390,4149994.439913542],[258308.372366665,4149994.561388090]]"
+61108032,30225933,"2","[[258404.576271744,4149971.107216727],[258406.930291290,4149972.493448519],[258406.820635608,4149972.695999112],[258408.555305404,4149973.302068440],[258407.153489857,4149972.085013532],[258407.046198245,4149972.283608110],[258404.690537088,4149970.910974289],[258404.576271744,4149971.107216727]]"
+61108033,30225932,"2","[[258402.842062399,4149974.332999425],[258405.203602832,4149975.700797166],[258405.088649451,4149975.903834753],[258406.814329561,4149976.502167657],[258405.434736160,4149975.279025734],[258405.319545122,4149975.492177452],[258402.968328186,4149974.117082732],[258402.842062399,4149974.332999425]]"
+61108034,30225926,"[1,2,3]","[[257939.702907773,4149910.265458858],[257939.228536124,4149911.458583791],[257939.428714606,4149911.489193466],[257939.277616402,4149912.494874365],[257938.951606700,4149912.158929740],[257939.015866599,4149911.610379457],[257938.669566793,4149912.385159627],[257938.792014296,4149913.243938793],[257938.860018854,4149912.769362648],[257939.190164443,4149913.080085405],[257939.159218428,4149913.270246877],[257939.329062832,4149913.292853107],[257939.353809356,4149913.126973885],[257939.774473711,4149912.918371440],[257939.708795410,4149913.399877279],[257940.039037768,4149912.678766140],[257939.941997336,4149911.768156415],[257939.861238737,4149912.279089778],[257939.438313724,4149912.546957735],[257939.585413659,4149911.507294918],[257939.779372330,4149911.534086980],[257939.702907773,4149910.265458858]]"
+61108035,30225905,"[1,3]","[[258098.059478670,4150023.854405292],[258099.526346331,4150024.064014368],[258099.890449519,4150024.571791685],[258099.396362241,4150024.532503939],[258100.180236642,4150024.816274094],[258101.019628939,4150024.743899125],[258100.515434988,4150024.661477090],[258100.082181817,4150024.083403461],[258100.671922672,4150023.703625398],[258101.176113450,4150023.785936469],[258100.389993014,4150023.427926415],[258099.529531648,4150023.500358377],[258100.069364715,4150023.587520242],[258099.552432430,4150023.904538881],[258098.086887450,4150023.682562713],[258098.059478670,4150023.854405292]]"
+61108036,30225957,"2","[[258152.292106826,4149777.486594701],[258152.560674546,4149775.708356208],[258152.711052783,4149775.725201556],[258152.660987591,4149774.480353480],[258152.236080071,4149775.667805385],[258152.404807168,4149775.694558120],[258152.134180119,4149777.462860261],[258152.292106826,4149777.486594701]]"
+61108037,30225875,"[1,2,3]","[[257939.636689165,4149934.689239016],[257940.112175921,4149933.467536794],[257939.925563770,4149933.431534544],[257940.067040711,4149932.429909718],[257940.383018007,4149932.795357215],[257940.282711424,4149933.386051248],[257940.687668708,4149932.430299975],[257940.543247771,4149931.668345517],[257940.477293689,4149932.173850301],[257940.134845353,4149931.866262021],[257940.163158591,4149931.643411743],[257939.992399604,4149931.622831362],[257939.963968870,4149931.844685438],[257939.562042142,4149932.030862486],[257939.622377567,4149931.569615477],[257939.278543985,4149932.340880855],[257939.393812168,4149933.135448772],[257939.479311832,4149932.607939288],[257939.889605036,4149932.386754343],[257939.744786449,4149933.410468010],[257939.544124815,4149933.384537318],[257939.636689165,4149934.689239016]]"
+61108038,30225833,"2","[[258030.134009278,4150001.598523065],[258029.725037605,4150002.833613576],[258029.876007993,4150002.858769375],[258029.624164332,4150004.629309535],[258029.785070956,4150004.655176114],[258030.029781343,4150002.879845217],[258030.184706508,4150002.903997510],[258030.134009278,4150001.598523065]]"
+61108039,30226032,"[1,3]","[[258024.256630918,4150062.590950864],[258024.343154028,4150062.147269750],[258024.852592447,4150061.785814153],[258025.229480112,4150062.291661865],[258025.185957349,4150062.856268793],[258025.477748907,4150062.088519070],[258025.382605829,4150061.175854577],[258025.303789944,4150061.622754764],[258025.026878109,4150061.288267937],[258025.259843425,4150059.772957145],[258025.086954729,4150059.752103944],[258024.857337696,4150061.245547896],[258024.433255722,4150061.534326594],[258024.474837166,4150061.082622149],[258024.176078903,4150061.817809091],[258024.256630918,4150062.590950864]]"
+61108040,30225846,"[2,3]","[[258427.462465755,4149771.734032010],[258428.905891481,4149769.481216426],[258429.095293075,4149769.613334066],[258429.825764577,4149767.821594243],[258428.507755344,4149769.203658618],[258428.700164584,4149769.335688972],[258427.906653032,4149770.565918982],[258427.664181658,4149769.739941684],[258427.934181174,4149769.327039877],[258427.196372254,4149769.978097472],[258426.767524888,4149771.125661999],[258427.145306167,4149770.543140793],[258427.405849120,4149771.369482208],[258427.262894328,4149771.596211830],[258427.462465755,4149771.734032010]]"
+61108041,30225919,"2","[[258276.095072312,4149833.488220902],[258273.394790318,4149833.171004805],[258273.418654581,4149832.947063853],[258271.522782403,4149833.062537785],[258273.336468448,4149833.635188202],[258273.366202915,4149833.406078702],[258276.061316805,4149833.746547133],[258276.095072312,4149833.488220902]]"
+61108042,30225975,"2","[[257948.127508235,4149945.740389032],[257946.823698094,4149945.305480712],[257946.804911880,4149945.469298428],[257944.989972771,4149945.237404056],[257944.974292310,4149945.401464675],[257946.776650771,4149945.648274905],[257946.759807411,4149945.811925057],[257948.127508235,4149945.740389032]]"
+61108043,30225941,"[2,3]","[[258111.972654815,4150051.022042932],[258112.246996534,4150049.260515579],[258112.399239147,4150049.280748788],[258112.329743781,4150048.043906239],[258111.910764491,4150049.215196135],[258112.077597887,4150049.237893128],[258111.922458660,4150050.211699315],[258111.604623733,4150049.815423027],[258111.682045276,4150049.262493794],[258111.305645135,4150050.074127199],[258111.456182373,4150050.843014057],[258111.513606488,4150050.445829134],[258111.840639531,4150050.844836985],[258111.818548184,4150051.001641762],[258111.972654815,4150051.022042932]]"
+61108044,30225976,"[1,2]","[[258122.006049562,4150010.187579132],[258122.428385733,4150008.900125606],[258122.268539715,4150008.877225309],[258122.516380907,4150007.138904660],[258122.360657326,4150007.120771599],[258122.335490693,4150007.302767231],[258121.902117552,4150007.585812737],[258121.953978209,4150007.170796487],[258121.614400208,4150007.979248858],[258121.728140404,4150008.752315002],[258121.821964312,4150008.191023481],[258122.244733095,4150007.920836887],[258122.109926094,4150008.860175854],[258121.968036914,4150008.836753776],[258122.006049562,4150010.187579132]]"
+61108045,31186582,"2","[[258406.453843439,4149886.707283529],[258405.035810925,4149888.967698691],[258404.821424480,4149888.840971759],[258404.175881011,4149890.559722041],[258405.421478079,4149889.203188763],[258405.250583634,4149889.101633872],[258406.671514484,4149886.843467070],[258406.453843439,4149886.707283529]]"
+61108046,30226012,"2","[[258379.461584396,4149727.055106506],[258381.298567746,4149727.456948333],[258381.305596073,4149727.238494713],[258383.985610983,4149727.393398728],[258383.990318712,4149727.137693450],[258381.322723812,4149726.989759471],[258381.332440914,4149726.760232030],[258379.461584396,4149727.055106506]]"
+61108047,30226010,"2","[[258253.201678175,4150141.336946013],[258251.746052230,4150143.656353532],[258251.553780370,4150143.534986233],[258250.871599851,4150145.255372587],[258252.177095773,4150143.887630372],[258251.961697554,4150143.753384349],[258253.414186396,4150141.472275625],[258253.201678175,4150141.336946013]]"
+61108048,30226035,"[1,2,3]","[[258156.924957730,4149771.523336054],[258157.354367372,4149770.301877702],[258157.181407413,4149770.281800888],[258157.305072622,4149769.440083416],[258157.651947096,4149769.762990376],[258157.583774023,4149770.265779912],[258157.949387038,4149769.472234725],[258157.808487337,4149768.724170436],[258157.742413366,4149769.131601995],[258157.395314789,4149768.825361850],[258157.438556363,4149768.515778761],[258157.281797421,4149768.495675555],[258157.224715767,4149768.877411134],[258156.807567359,4149769.003264277],[258156.876238710,4149768.520674773],[258156.540772410,4149769.331004138],[258156.651821732,4149770.115144406],[258156.721161834,4149769.652527846],[258157.147984604,4149769.478745145],[258157.028796444,4149770.261243977],[258156.883950600,4149770.239795070],[258156.924957730,4149771.523336054]]"
+61108049,30225830,"2","[[258298.549903106,4149808.009934895],[258300.354728285,4149808.579183443],[258300.382073784,4149808.353142331],[258303.041051156,4149808.631915443],[258303.065698709,4149808.389181315],[258300.400759039,4149808.109359549],[258300.421499088,4149807.884509841],[258298.549903106,4149808.009934895]]"
+61108050,30225845,"2","[[257889.070862198,4150068.612233208],[257890.391437577,4150068.957455213],[257890.403470452,4150068.777617567],[257892.200478467,4150068.880846325],[257892.212132966,4150068.712348740],[257890.410545146,4150068.616028397],[257890.424903724,4150068.437011658],[257889.070862198,4150068.612233208]]"
+61108051,30225937,"1","[[258382.984460928,4149724.281993769],[258384.265529179,4149724.033893245],[258383.434992434,4149723.979250951],[258382.652676453,4149723.035882851],[258379.712520270,4149722.910632183],[258379.701768138,4149723.159404520],[258381.936839080,4149723.242143668],[258382.504349405,4149723.931623747],[258381.840768720,4149723.900680504],[258382.984460928,4149724.281993769]]"
+61108052,30225984,"5","[[257996.741622934,4150098.747894543],[257998.841734219,4150098.823118372],[257999.051845454,4150098.851441097],[257999.232253352,4150098.920834375],[257999.527089496,4150099.034438363],[257999.459897653,4150099.250755003],[258001.239492955,4150099.632407456],[257999.731056958,4150098.589563707],[257999.594513646,4150098.826111938],[257999.282645985,4150098.680904174],[257999.191469954,4150098.647790763],[257999.030952665,4150098.604808958],[257997.771369052,4150098.523918519],[257996.808127990,4150098.477507248],[257996.741622934,4150098.747894543]]"
+61108053,30225860,"[1,2]","[[258296.304469608,4150066.621830468],[258296.206572570,4150066.784056693],[258295.397504864,4150066.992035090],[258295.770889745,4150066.365650332],[258294.832758256,4150067.266224377],[258294.495762669,4150068.404911926],[258294.929085554,4150067.775564902],[258295.685551130,4150067.582331060],[258294.892355539,4150068.882653285],[258294.695232002,4150068.758871223],[258294.004822485,4150070.498262203],[258295.292590412,4150069.132153853],[258295.082344535,4150069.004643285],[258296.524968914,4150066.757928830],[258296.304469608,4150066.621830468]]"
+61108054,30226076,"2","[[258075.413640119,4149776.286732501],[258077.221678861,4149776.514748730],[258077.203042798,4149776.665566454],[258078.436919234,4149776.588391212],[258077.258957435,4149776.213335233],[258077.240519026,4149776.361814765],[258075.433656953,4149776.125545242],[258075.413640119,4149776.286732501]]"
+61108055,30225922,"2","[[258303.537542596,4149805.176816804],[258301.770613608,4149804.552821100],[258301.746166728,4149804.820761979],[258299.097364674,4149804.486936919],[258299.075824121,4149804.720806431],[258301.725541158,4149805.052605677],[258301.701265629,4149805.305103044],[258303.537542596,4149805.176816804]]"
+61108056,30225912,"[1,2]","[[258044.003541541,4150084.085549552],[258045.177102534,4150084.511595251],[258045.203822114,4150084.346547617],[258046.940322916,4150084.628389818],[258046.967905875,4150084.459540751],[258046.776817293,4150084.427776073],[258046.466685798,4150083.995069706],[258046.951352911,4150084.066726813],[258046.151252552,4150083.708906312],[258045.390937959,4150083.812198309],[258045.877480836,4150083.908791340],[258046.152902252,4150084.326068426],[258045.235674041,4150084.184460727],[258045.260741125,4150084.029568399],[258044.003541541,4150084.085549552]]"
+61108057,30225916,"2","[[258461.860072985,4149791.175623467],[258460.424968495,4149793.498720061],[258460.228467316,4149793.375137917],[258459.542166765,4149795.145378734],[258460.824150119,4149793.745260798],[258460.630905852,4149793.621028801],[258462.078594154,4149791.298344606],[258461.860072985,4149791.175623467]]"
+61108058,30225955,"[1,2,3]","[[257932.590877427,4149957.845430809],[257932.126978946,4149959.005819822],[257932.328132610,4149959.036511952],[257932.176063283,4149960.020896188],[257931.841463829,4149959.657434470],[257931.900420041,4149959.246208501],[257931.576978744,4149959.930136458],[257931.681821615,4149960.801534068],[257931.752598983,4149960.321879021],[257932.086592374,4149960.603611554],[257932.058305848,4149960.781700302],[257932.228866675,4149960.804618688],[257932.261529185,4149960.606521331],[257932.684218447,4149960.443286657],[257932.626002893,4149960.846494108],[257932.948019723,4149960.116625042],[257932.845318908,4149959.343239088],[257932.766971070,4149959.806120709],[257932.340355194,4149960.047440019],[257932.489098057,4149959.058265483],[257932.707233000,4149959.094461532],[257932.590877427,4149957.845430809]]"
+61108059,30225902,"2","[[257976.144069136,4150125.427438187],[257978.849731412,4150125.597228924],[257978.835180705,4150125.821456065],[257980.670849506,4150125.598479722],[257978.874350826,4150125.134688133],[257978.858689464,4150125.366389190],[257976.159827438,4150125.183849917],[257976.144069136,4150125.427438187]]"
+61108060,30225978,"2","[[258245.445546761,4149976.376591049],[258244.833959730,4149979.010132312],[258244.609264614,4149978.961345882],[258244.542367263,4149980.818913647],[258245.272682384,4149979.115345542],[258245.074014933,4149979.069579520],[258245.679469100,4149976.429107998],[258245.445546761,4149976.376591049]]"
+61108061,30225937,"2","[[258305.035622309,4149721.260756862],[258303.168053792,4149720.848601481],[258303.190506423,4149721.082193268],[258300.465870299,4149721.006802718],[258300.488843219,4149721.255262590],[258303.204959543,4149721.326902031],[258303.224434702,4149721.552472258],[258305.035622309,4149721.260756862]]"
+61108062,30226068,"1","[[258291.173796534,4149913.788840469],[258289.236907750,4149912.649649618],[258289.014905174,4149911.849071097],[258289.584572645,4149912.164736063],[258288.828560508,4149911.352673824],[258287.568455282,4149910.998412910],[258288.226663721,4149911.384478925],[258288.552382545,4149912.518917032],[258291.049325287,4149913.996376730],[258291.173796534,4149913.788840469]]"
+61108063,30225999,"2","[[258274.557048742,4150056.586200994],[258275.993028445,4150054.287584525],[258276.171907623,4150054.405009742],[258276.894053997,4150052.673247814],[258275.622152689,4150054.052226477],[258275.793753748,4150054.159866861],[258274.359837583,4150056.459423061],[258274.557048742,4150056.586200994]]"
+61108064,30225990,"[1,2]","[[258399.700576830,4149821.184706908],[258399.534527372,4149821.442318059],[258398.781173249,4149821.542263684],[258399.154650488,4149820.948869961],[258398.234857041,4149821.765817486],[258397.809027630,4149823.038470754],[258398.283675527,4149822.291753935],[258399.058672637,4149822.177962966],[258398.263268005,4149823.440239321],[258398.061957216,4149823.309578750],[258397.306669157,4149825.112149931],[258398.665834807,4149823.699673899],[258398.459278948,4149823.562168230],[258399.901655738,4149821.307377317],[258399.700576830,4149821.184706908]]"
+61108065,30226014,"2","[[257837.962255519,4149985.373525924],[257839.826661319,4149985.650384437],[257839.797620143,4149985.820720781],[257840.991984815,4149985.743657663],[257839.867763682,4149985.346858536],[257839.847766486,4149985.490275185],[257837.986364335,4149985.207109414],[257837.962255519,4149985.373525924]]"
+61108066,31186582,"2","[[258388.184260368,4149915.867560361],[258386.773123000,4149918.112007653],[258386.567706646,4149917.986242614],[258385.887965388,4149919.746638558],[258387.160857958,4149918.351657413],[258386.980122172,4149918.243502318],[258388.397699418,4149916.001311653],[258388.184260368,4149915.867560361]]"
+61108067,30225925,"[2,3]","[[258299.333410127,4150105.004844616],[258300.551982724,4150102.573042751],[258300.769808532,4150102.687227189],[258301.257159136,4150100.894088954],[258300.121753339,4150102.357622548],[258300.338660923,4150102.473721806],[258299.606935454,4150103.915204321],[258299.334490026,4150103.185286242],[258299.706650537,4150102.458864193],[258298.876882512,4150103.334966346],[258298.618904116,4150104.536223518],[258298.921495345,4150103.981090204],[258299.208061886,4150104.715596321],[258299.123168389,4150104.877444961],[258299.333410127,4150105.004844616]]"
+61108068,30225926,"2","[[257936.622058755,4149931.008663532],[257936.152048407,4149932.278632817],[257936.343976636,4149932.302596014],[257936.075077732,4149934.070637254],[257936.229885159,4149934.090681791],[257936.500321483,4149932.320707679],[257936.703915761,4149932.353106095],[257936.622058755,4149931.008663532]]"
+61108069,30225959,"[2,3]","[[258403.366339253,4149982.876613576],[258401.014405086,4149981.504205987],[258401.139004861,4149981.298000568],[258399.373080566,4149980.667405304],[258400.781125942,4149981.906936069],[258400.898826255,4149981.707039664],[258402.184816184,4149982.456524587],[258401.425029801,4149982.700380525],[258400.753297084,4149982.317697772],[258401.714991385,4149983.262301633],[258402.833780739,4149983.528048956],[258402.187409921,4149983.149850217],[258403.007039797,4149982.936356266],[258403.252272336,4149983.082735393],[258403.366339253,4149982.876613576]]"
+61108070,30226070,"2","[[258451.734378479,4149790.175590345],[258453.172757513,4149787.904377148],[258453.379409235,4149788.026887136],[258454.026778329,4149786.287986028],[258452.750172059,4149787.653739884],[258452.959661122,4149787.782498436],[258451.530555780,4149790.049888395],[258451.734378479,4149790.175590345]]"
+61108071,30226047,"3","[[258240.134392018,4150106.122164079],[258241.695007816,4150103.619441031],[258241.405635197,4150102.547702244],[258241.815840388,4150101.854159270],[258240.901397993,4150102.679969321],[258240.533133964,4150103.936634432],[258240.925806443,4150103.288694535],[258241.118229011,4150104.113233451],[258239.940165245,4150106.003630471],[258240.134392018,4150106.122164079]]"
+61108072,30225986,"[2,3]","[[258296.573092197,4150091.406557132],[258294.273747205,4150089.948574303],[258294.406944906,4150089.764219918],[258292.646304595,4150089.098730335],[258294.027841021,4150090.397879317],[258294.161051426,4150090.180426094],[258295.505587780,4150091.010273858],[258294.749809172,4150091.257578388],[258294.082529935,4150090.857448408],[258294.907382317,4150091.741927108],[258296.141167399,4150092.141934174],[258295.508538546,4150091.730801741],[258296.258505104,4150091.490663373],[258296.448351815,4150091.607770476],[258296.573092197,4150091.406557132]]"
+61108073,30225851,"1","[[258292.313770754,4149908.734437246],[258292.179510453,4149908.961583663],[258294.100992255,4149910.079342064],[258294.342204990,4149910.861591909],[258293.840556960,4149910.601707286],[258294.583727217,4149911.404479853],[258295.798622143,4149911.735397290],[258295.140919937,4149911.333211057],[258294.804263008,4149910.184873576],[258292.313770754,4149908.734437246]]"
+61108074,30225941,"2","[[258039.759389592,4150079.134734788],[258038.557078280,4150078.718633156],[258038.522737607,4150078.871240493],[258036.726448881,4150078.618905126],[258036.688730424,4150078.786271762],[258038.481418199,4150079.039600345],[258038.447320828,4150079.197531919],[258039.759389592,4150079.134734788]]"
+61108075,30225887,"[2,3]","[[258248.787417251,4150042.411287149],[258247.897897647,4150044.930725205],[258247.682194663,4150044.880566979],[258247.407381058,4150046.733510875],[258248.357534582,4150045.064208786],[258248.136818571,4150045.015195761],[258248.661813033,4150043.494189768],[258249.247621007,4150044.195124348],[258248.949977971,4150045.063884901],[258249.676231687,4150044.016295324],[258249.732117365,4150042.849561438],[258249.511316972,4150043.456078375],[258248.916518604,4150042.756515567],[258249.022604077,4150042.473874579],[258248.787417251,4150042.411287149]]"
+61108076,30225835,"2","[[258280.082609222,4150072.977640473],[258282.361684145,4150074.411107013],[258282.237635871,4150074.651396649],[258283.940838717,4150075.271681269],[258282.600575421,4150074.031201154],[258282.481174008,4150074.221152798],[258280.202010604,4150072.787688792],[258280.082609222,4150072.977640473]]"
+61108077,30225936,"2","[[258345.297158410,4149777.557694019],[258347.080517701,4149777.979077369],[258347.089809466,4149777.759336169],[258349.788492968,4149777.850265933],[258349.792092135,4149777.614362910],[258347.096055903,4149777.523134156],[258347.108339192,4149777.302750774],[258345.297158410,4149777.557694019]]"
+61108078,30225831,"[1,3]","[[258286.033894301,4149770.363883178],[258286.152342164,4149769.558528494],[258286.925314486,4149768.941867473],[258287.553394480,4149769.686449973],[258287.470922019,4149770.453218861],[258287.951033943,4149769.217967934],[258287.765156236,4149768.066918560],[258287.674181499,4149768.760406884],[258287.153819967,4149768.145979027],[258287.443623889,4149765.902863742],[258287.207783163,4149765.869837913],[258286.925560461,4149768.099626987],[258286.273532053,4149768.618923303],[258286.350889770,4149767.947377648],[258285.881851305,4149769.048691598],[258286.033894301,4149770.363883178]]"
+61108079,30226061,"2","[[258235.086249688,4150070.169447835],[258233.562683142,4150072.420857672],[258233.375856837,4150072.273675611],[258232.583087067,4150073.966286975],[258233.937553317,4150072.690084904],[258233.770035290,4150072.552338214],[258235.288081397,4150070.315083416],[258235.086249688,4150070.169447835]]"
+61108080,30226000,"2","[[258271.781372610,4150054.722105330],[258273.202634801,4150052.431912701],[258273.395780278,4150052.558919751],[258274.131314697,4150050.754685186],[258272.803588922,4150052.159387337],[258272.999975424,4150052.291298351],[258271.564766092,4150054.582895665],[258271.781372610,4150054.722105330]]"
+61108081,30226065,"1","[[258181.606569550,4149729.205878746],[258181.473217107,4149727.946456735],[258181.357126725,4149728.704651969],[258180.405967089,4149729.392473878],[258179.985276032,4149732.569264288],[258180.219777885,4149732.617098227],[258180.546695021,4149730.070681151],[258181.223478069,4149729.623407273],[258181.124224695,4149730.312028688],[258181.606569550,4149729.205878746]]"
+61108082,30225982,"2","[[257977.164996931,4150103.346222654],[257979.854643208,4150103.485602771],[257979.801661678,4150103.706504542],[257981.744943482,4150103.445413156],[257979.899476334,4150103.008812793],[257979.849850802,4150103.241612437],[257977.160680554,4150103.085113846],[257977.164996931,4150103.346222654]]"
+61108083,30225904,"2","[[258241.151450991,4149980.061389768],[258241.754577799,4149977.413988118],[258241.968249440,4149977.461206465],[258242.039531239,4149975.614396043],[258241.304177510,4149977.318221854],[258241.522804219,4149977.362297423],[258240.905438678,4149980.004114924],[258241.151450991,4149980.061389768]]"
+61108084,31186583,"1","[[258400.455224750,4149882.971324621],[258399.274248202,4149884.864443321],[258398.474070624,4149885.068264661],[258398.820677395,4149884.479537904],[258397.929686685,4149885.321640188],[258397.553583418,4149886.510770999],[258397.992954239,4149885.839049303],[258399.149659396,4149885.531693758],[258400.659160423,4149883.097910497],[258400.455224750,4149882.971324621]]"
+61108085,30225856,"2","[[257975.489473186,4150137.910969895],[257978.172023193,4150138.077655782],[257978.151437417,4150138.310499655],[257980.033818672,4150138.077390271],[257978.182862892,4150137.600965595],[257978.199567960,4150137.843609949],[257975.503504025,4150137.684092197],[257975.489473186,4150137.910969895]]"
+61108086,30226012,"[2,3]","[[258300.287317109,4149724.627158537],[258302.149640063,4149725.038576970],[258302.168150077,4149724.785691711],[258303.642047375,4149724.839529051],[258303.076815470,4149725.472925699],[258302.222641215,4149725.454963954],[258303.523111835,4149725.832492254],[258304.669228570,4149725.525654732],[258303.960709713,4149725.502131138],[258304.556075876,4149724.863750121],[258304.808566345,4149724.872524450],[258304.791241803,4149724.650890252],[258302.194318629,4149724.555686365],[258302.213101938,4149724.300016455],[258300.287317109,4149724.627158537]]"
+61108087,31186584,"3","[[258409.263835710,4149888.487239164],[258407.724015420,4149890.941004496],[258408.000794775,4149892.049210293],[258407.589165584,4149892.715905698],[258408.501543260,4149891.854191030],[258408.810810438,4149890.762852673],[258408.474830449,4149891.287628313],[258408.292700270,4149890.487778478],[258409.469218649,4149888.614893919],[258409.263835710,4149888.487239164]]"
+61108088,30226004,"[1,2]","[[258305.355765278,4149780.852204117],[258305.160126458,4149779.547830064],[258305.060992869,4149780.375059453],[258304.369434727,4149780.938596670],[258304.511774725,4149779.461916449],[258304.743685247,4149779.484616392],[258304.561030948,4149777.648624227],[258304.024611447,4149779.448071367],[258304.262941162,4149779.441818156],[258304.015649897,4149782.139968115],[258304.254938526,4149782.142350407],[258304.279994605,4149781.828298400],[258304.998719738,4149781.236871670],[258304.929551195,4149781.955716659],[258305.355765278,4149780.852204117]]"
+61108089,30225919,"[2,3]","[[258152.717444033,4149986.233901124],[258152.317697438,4149988.859741793],[258152.097590001,4149988.828706616],[258152.156036769,4149990.727617886],[258152.770554724,4149988.936439140],[258152.572053498,4149988.905553686],[258152.769889622,4149987.472238425],[258153.258911677,4149988.181199390],[258153.165143754,4149988.820681165],[258153.654437695,4149987.750312025],[258153.505324391,4149986.494013432],[258153.388998321,4149987.207233873],[258152.896366981,4149986.566018662],[258152.941255676,4149986.267494352],[258152.717444033,4149986.233901124]]"
+61108090,30225853,"2","[[257736.089562006,4149974.151039455],[257734.325437995,4149973.891832837],[257734.356344224,4149973.706558405],[257732.889959418,4149973.760787466],[257734.285551964,4149974.249192727],[257734.313637028,4149974.049117127],[257736.066475177,4149974.306875092],[257736.089562006,4149974.151039455]]"
+61108091,30225958,"1","[[258423.494544134,4149991.260223640],[258421.575431618,4149990.143480050],[258421.355995653,4149989.342380295],[258421.955001853,4149989.680970732],[258421.065743644,4149988.800903656],[258419.916810585,4149988.478717457],[258420.589921125,4149988.887573833],[258420.893900793,4149990.017981646],[258423.370153352,4149991.473642086],[258423.494544134,4149991.260223640]]"
+61108092,30225827,"2","[[258049.026672363,4149957.076287213],[258050.827919298,4149957.352140755],[258050.803766454,4149957.505007178],[258052.061613168,4149957.458450610],[258050.877877538,4149957.036252608],[258050.855407742,4149957.198288831],[258049.047675680,4149956.918625293],[258049.026672363,4149957.076287213]]"
+61108093,31186584,"3","[[258391.082781853,4149917.650604439],[258389.529685626,4149920.122419323],[258389.802677571,4149921.228180042],[258389.375685227,4149921.929753770],[258390.351703472,4149921.009766694],[258390.727410978,4149919.773553707],[258390.297165376,4149920.448454279],[258390.108315888,4149919.652020727],[258391.290412813,4149917.776416373],[258391.082781853,4149917.650604439]]"
+61108094,30225993,"[2,3]","[[258284.203435366,4149765.585547345],[258283.603081294,4149767.341758592],[258283.851796701,4149767.369967741],[258283.671126032,4149768.843651990],[258283.147868802,4149768.254521016],[258283.237418003,4149767.493655353],[258282.766179996,4149768.665561948],[258282.956952685,4149769.817468752],[258283.046172552,4149769.161128218],[258283.555038334,4149769.754675526],[258283.519635150,4149770.044704059],[258283.762893514,4149770.077070122],[258284.095879971,4149767.397200712],[258284.321782716,4149767.432514246],[258284.203435366,4149765.585547345]]"
+61108095,30225898,"[1,2,3]","[[257927.814655417,4149942.779863415],[257926.622514264,4149942.303391922],[257926.589404766,4149942.519606551],[257925.611161087,4149942.350684929],[257925.919807223,4149942.016499137],[257926.441659634,4149942.093954862],[257925.631810432,4149941.742536827],[257924.791539446,4149941.879374470],[257925.302697701,4149941.936149076],[257925.011001369,4149942.265621356],[257924.761430447,4149942.223120170],[257924.736787628,4149942.392550666],[257924.984602877,4149942.441655979],[257925.142471933,4149942.844021946],[257924.742812792,4149942.800665214],[257925.494786404,4149943.155987610],[257926.359582601,4149943.034430755],[257925.807715799,4149942.959958192],[257925.565033769,4149942.533291008],[257926.568235535,4149942.701931101],[257926.543644320,4149942.873137192],[257927.814655417,4149942.779863415]]"
+61108096,30225937,"2","[[258398.223887710,4149741.531135409],[258398.481085757,4149739.685709463],[258398.259448671,4149739.702804423],[258398.126869075,4149737.016795290],[258397.874911816,4149737.056872840],[258398.010802283,4149739.719683639],[258397.795122509,4149739.734606484],[258398.223887710,4149741.531135409]]"
+61108097,30225965,"[1,2,3]","[[258034.433590565,4149996.418349214],[258034.356916222,4149996.893287364],[258033.939957339,4149997.070900348],[258034.016578217,4149996.475342889],[258033.659372782,4149997.246659487],[258033.789757195,4149998.071221508],[258033.853808708,4149997.646298083],[258034.276876404,4149997.435186842],[258034.167144682,4149998.201309031],[258034.016317527,4149998.178037155],[258034.071018656,4149999.423306892],[258034.471762050,4149998.273645715],[258034.312830427,4149998.248721247],[258034.447852732,4149997.362798016],[258034.778479551,4149997.760365972],[258034.724053546,4149998.220995923],[258035.054314809,4149997.430359114],[258034.951778696,4149996.567890561],[258034.876579364,4149997.142303590],[258034.542855316,4149996.769149756],[258034.595746766,4149996.441513921],[258034.433590565,4149996.418349214]]"
+61108098,30225936,"[1,2]","[[258313.146906129,4149776.007992155],[258313.901186471,4149776.064841017],[258314.446044928,4149776.733315966],[258312.982436451,4149776.688952759],[258312.973306622,4149776.465969948],[258311.111830919,4149776.717604925],[258312.966273257,4149777.153799814],[258312.971774148,4149776.919396442],[258315.658400497,4149777.027991979],[258315.650725372,4149776.784974591],[258315.395283647,4149776.778173907],[258314.840499073,4149776.087995502],[258315.535990356,4149776.105122722],[258314.358728329,4149775.759780196],[258313.146906129,4149776.007992155]]"
+61108099,30225829,"2","[[258319.013591270,4149758.813297702],[258317.126441623,4149758.357614132],[258317.118781162,4149758.606074822],[258314.400125579,4149758.513624638],[258314.390128052,4149758.757821511],[258317.113492448,4149758.841693768],[258317.113301909,4149759.069945243],[258319.013591270,4149758.813297702]]"
+61108100,30225845,"[1,2]","[[257823.539247536,4150064.808280753],[257824.782345242,4150065.155968930],[257824.791263258,4150064.963448750],[257826.581330505,4150065.077528091],[257826.585580480,4150064.922351896],[257826.385257180,4150064.907965486],[257826.157683410,4150064.501631352],[257826.674177612,4150064.538140635],[257825.826001545,4150064.268928365],[257824.992155494,4150064.413142954],[257825.541353031,4150064.478245093],[257825.831254049,4150064.872436435],[257824.799041125,4150064.801727901],[257824.812214146,4150064.618524803],[257823.539247536,4150064.808280753]]"
+61108101,30225913,"2","[[257733.661265176,4149969.952544262],[257735.459279457,4149970.186773510],[257735.443463769,4149970.355170493],[257736.667726974,4149970.268003646],[257735.503798077,4149969.860822469],[257735.478733781,4149970.036930262],[257733.680719469,4149969.802701008],[257733.661265176,4149969.952544262]]"
+61108102,30225887,"3","[[258254.858902382,4150019.221963972],[258254.307120090,4150022.100895775],[258254.947931263,4150023.022148671],[258254.804376645,4150023.761370474],[258255.344597905,4150022.685308442],[258255.275574935,4150021.430459558],[258255.113074353,4150022.142242265],[258254.677996909,4150021.415604501],[258255.099549088,4150019.268288089],[258254.858902382,4150019.221963972]]"
+61108103,30225912,"2","[[258084.518712744,4150089.860202703],[258085.729857045,4150090.272721875],[258085.746426147,4150090.133071003],[258087.518734708,4150090.379893681],[258087.542303801,4150090.206940846],[258085.771886418,4150089.958175026],[258085.790285456,4150089.814472491],[258084.518712744,4150089.860202703]]"
+61108104,30226054,"2","[[258255.261953580,4150061.696926854],[258257.535701898,4150063.138760947],[258257.402852552,4150063.335101246],[258259.160261895,4150063.992680900],[258257.774883629,4150062.759734436],[258257.671207474,4150062.930237019],[258255.399376170,4150061.487347593],[258255.261953580,4150061.696926854]]"
+61108105,30226005,"2","[[258268.024575259,4150120.491023661],[258268.720842897,4150123.133120081],[258268.502425470,4150123.193664744],[258269.308237360,4150124.904045470],[258269.180072218,4150122.993609413],[258268.955343214,4150123.071553010],[258268.274244915,4150120.454895049],[258268.024575259,4150120.491023661]]"
+61108106,30226071,"2","[[258448.543892946,4149788.189742764],[258449.946402839,4149785.893690827],[258450.151787432,4149786.021346659],[258450.787334105,4149784.317441666],[258449.558512639,4149785.642713390],[258449.758703894,4149785.771408452],[258448.341318056,4149788.058229117],[258448.543892946,4149788.189742764]]"
+61108107,30225989,"3","[[258250.063807026,4150066.597526472],[258247.561569576,4150065.021939592],[258246.471134736,4150065.320840847],[258245.821111455,4150064.896222383],[258246.727762473,4150065.899163933],[258247.822494203,4150066.144485705],[258247.275412752,4150065.810619369],[258248.030788691,4150065.613414311],[258249.951050110,4150066.787618857],[258250.063807026,4150066.597526472]]"
+61108108,30226050,"2","[[257959.592345064,4149893.783486486],[257958.376568673,4149893.349903536],[257958.342817797,4149893.547143791],[257956.547738898,4149893.277016217],[257956.522559543,4149893.428024692],[257958.322356546,4149893.689907035],[257958.287224718,4149893.876191615],[257959.592345064,4149893.783486486]]"
+61108109,31186585,"2","[[258403.240313794,4149884.732008853],[258401.825651762,4149887.007876367],[258401.627668914,4149886.888115015],[258400.973527816,4149888.609558619],[258402.212510934,4149887.244775597],[258402.021719229,4149887.131802847],[258403.440476146,4149884.856705072],[258403.240313794,4149884.732008853]]"
+61108110,30226065,"[2,3]","[[258262.693619207,4149727.687310860],[258260.924249391,4149727.111041684],[258260.899829587,4149727.358545314],[258259.401023484,4149727.160383204],[258259.898281152,4149726.625364789],[258260.788964152,4149726.735892904],[258259.576107504,4149726.271859030],[258258.275838201,4149726.434902653],[258259.052361432,4149726.528864369],[258258.494246532,4149727.038327175],[258258.230227618,4149727.007564223],[258258.194885067,4149727.247832383],[258260.868914329,4149727.589688336],[258260.842871472,4149727.833129557],[258262.693619207,4149727.687310860]]"
+61108111,30225965,"2","[[258038.641181675,4149967.465771947],[258038.343594298,4149969.246526669],[258038.168329210,4149969.217078758],[258038.233829962,4149970.450150129],[258038.647134381,4149969.290905529],[258038.498252803,4149969.267576983],[258038.803911091,4149967.490364011],[258038.641181675,4149967.465771947]]"
+61108112,30226039,"[2,3]","[[258120.721864229,4149991.656295225],[258120.990536013,4149989.882271554],[258121.135320204,4149989.901722109],[258121.086399839,4149988.681275351],[258120.689059496,4149989.841828308],[258120.833784254,4149989.862280203],[258120.705740382,4149990.741889732],[258120.354034641,4149990.417014864],[258120.402205235,4149989.948126391],[258120.059986351,4149990.677907689],[258120.180965981,4149991.453318037],[258120.244292079,4149991.055073230],[258120.616238511,4149991.357479380],[258120.573644513,4149991.634389927],[258120.721864229,4149991.656295225]]"
+61108113,30225906,"[1,2,3]","[[257931.951828084,4149986.730189219],[257932.419286735,4149985.634449732],[257932.235000655,4149985.608376308],[257932.388892956,4149984.589285440],[257932.732308715,4149984.905841742],[257932.657986730,4149985.400594214],[257933.012474296,4149984.651787598],[257932.892062222,4149983.856925013],[257932.834996823,4149984.327073673],[257932.474287358,4149984.000357645],[257932.500166618,4149983.827781273],[257932.339344964,4149983.807911769],[257932.317563805,4149983.981368590],[257931.899470718,4149984.177790434],[257931.962793554,4149983.685357058],[257931.636667933,4149984.441335910],[257931.716765690,4149985.268581245],[257931.801548801,4149984.780410828],[257932.225841413,4149984.544490254],[257932.068543559,4149985.589559245],[257931.865476725,4149985.560033496],[257931.951828084,4149986.730189219]]"
+61108114,30225902,"2","[[258055.199442547,4150130.739606942],[258057.894044341,4150130.912854458],[258057.875782479,4150131.152627747],[258059.678693056,4150130.929621397],[258057.929061088,4150130.433240611],[258057.912851706,4150130.676619517],[258055.215065420,4150130.503464554],[258055.199442547,4150130.739606942]]"
+61108115,30226007,"1","[[258273.233409252,4150077.919840245],[258271.318385749,4150076.745922941],[258271.137992748,4150075.920923142],[258271.714506909,4150076.298919004],[258270.895897626,4150075.422257951],[258269.758267641,4150075.053226808],[258270.348434341,4150075.422718086],[258270.597547876,4150076.580705379],[258273.102945612,4150078.128217494],[258273.233409252,4150077.919840245]]"
+61108116,30225837,"2","[[257813.539928428,4150044.494100606],[257813.085193655,4150045.682665179],[257813.262795686,4150045.716372008],[257812.996581771,4150047.463016503],[257813.172364915,4150047.498109082],[257813.438475542,4150045.747913384],[257813.575952888,4150045.777900618],[257813.539928428,4150044.494100606]]"
+61108118,30225860,"2","[[258357.917431896,4149975.077441679],[258356.488375381,4149977.371841451],[258356.283753579,4149977.264269407],[258355.638795736,4149978.969013391],[258356.890454709,4149977.605519847],[258356.692700395,4149977.496637748],[258358.116942109,4149975.213262504],[258357.917431896,4149975.077441679]]"
+61108119,30225999,"1","[[258327.079047743,4149964.649045324],[258328.236734314,4149962.756701213],[258329.098414279,4149962.536981110],[258328.719491173,4149963.143643209],[258329.571198665,4149962.360872668],[258329.990339345,4149961.099404212],[258329.557664499,4149961.778821789],[258328.431013423,4149962.007900670],[258326.861728027,4149964.518851402],[258327.079047743,4149964.649045324]]"
+61108120,30225861,"2","[[258360.835785863,4149976.992070238],[258359.391257485,4149979.336010932],[258359.194046074,4149979.209230975],[258358.531248959,4149980.927709728],[258359.798280858,4149979.575321499],[258359.608460291,4149979.462210558],[258361.046203507,4149977.125464193],[258360.835785863,4149976.992070238]]"
+61108121,30226000,"[2,3]","[[258324.772386647,4149963.211367939],[258326.195801023,4149960.927122287],[258326.409502865,4149961.039428121],[258327.064785475,4149959.303171538],[258325.800577201,4149960.679584771],[258325.996438122,4149960.796407040],[258325.196252580,4149962.066939383],[258325.001874526,4149961.275443292],[258325.378651644,4149960.661957061],[258324.441929683,4149961.541493536],[258324.127280695,4149962.660426429],[258324.511569261,4149962.061716331],[258324.723799710,4149962.818596037],[258324.559904498,4149963.077035150],[258324.772386647,4149963.211367939]]"

+ 14 - 0
_internal/data_map/hd_crosswalks.csv

@@ -0,0 +1,14 @@
+cross_id,cross_coords
+63100914,"[[257940.208681223,4149942.208638771],[257939.626713985,4149946.180396347],[257939.437278933,4149947.459977665],[257938.842729881,4149951.525732443],[257940.819221934,4149951.811794157],[257941.020924995,4149950.579615803],[257941.437146454,4149947.666945132],[257941.557577942,4149946.818430040],[257941.700720201,4149945.843635488],[257942.190313728,4149942.491774770],[257940.208681223,4149942.208638771]]"
+63100915,"[[258277.885556088,4149795.808285161],[258282.098834799,4149796.352023277],[258283.203397263,4149796.492662296],[258285.302324592,4149796.756592792],[258285.684516984,4149793.783406169],[258281.772810093,4149793.255788899],[258278.268672326,4149792.802972338],[258277.885556088,4149795.808285161]]"
+63100916,"[[257933.988312614,4149940.496129821],[257936.338740511,4149940.851175352],[257937.259787476,4149940.992550321],[257939.336770160,4149941.306122582],[257939.631421609,4149939.327634300],[257937.591108154,4149938.993336393],[257934.290039513,4149938.517435502],[257933.988312614,4149940.496129821]]"
+63100917,"[[258315.280774345,4149840.287857207],[258315.415678256,4149839.277770048],[258315.840870385,4149836.132624410],[258316.184579383,4149833.163222614],[258313.201847882,4149832.777889955],[258312.760670267,4149836.583025269],[258312.299744749,4149839.924467234],[258315.280774345,4149840.287857207]]"
+63100918,"[[257931.521650921,4149953.384781525],[257933.671011747,4149953.675699623],[257935.841834086,4149953.967882340],[257937.839672756,4149954.232996930],[257938.138431038,4149952.240505432],[257935.067081441,4149951.821456034],[257931.805933084,4149951.378604889],[257931.521650921,4149953.384781525]]"
+63100919,"[[258378.878291073,4149976.251641201],[258372.211039601,4149972.406052591],[258364.408094041,4149967.935354800],[258356.204622672,4149963.257374476],[258352.857055983,4149961.342656276],[258349.253168705,4149959.277885051],[258348.354603412,4149958.760734058],[258345.605221259,4149957.180629487],[258343.923393566,4149956.214620223],[258333.385646392,4149950.273935698],[258329.064149099,4149947.802058734],[258322.918232863,4149944.319892352],[258320.925939248,4149947.474328229],[258321.259358172,4149949.078474998],[258325.591860208,4149951.587791888],[258329.864422724,4149954.008663306],[258335.417614131,4149957.137405955],[258336.458516224,4149957.388412520],[258336.988280314,4149957.619715995],[258337.341173949,4149957.857709280],[258337.668281467,4149958.134547719],[258338.071890602,4149958.551999442],[258338.547469282,4149958.905163387],[258341.995886344,4149960.902471210],[258346.557360866,4149963.522994540],[258350.109341582,4149965.583829016],[258361.501205027,4149972.121944584],[258369.619173854,4149976.746099455],[258374.028064769,4149979.243781100],[258377.293172569,4149978.705507605],[258378.878291073,4149976.251641201]]"
+63100920,"[[258342.784840413,4149761.311764650],[258342.899257964,4149757.909189953],[258339.395636628,4149757.785539101],[258339.291438481,4149761.189372253],[258342.784840413,4149761.311764650]]"
+63100921,"[[257931.340941968,4149940.969076253],[257930.655780767,4149945.559935555],[257930.157604167,4149948.832632590],[257929.945324569,4149950.233832749],[257931.946083032,4149950.544510473],[257932.133884048,4149949.193559015],[257932.671928783,4149945.580831194],[257933.289522250,4149941.251172106],[257931.340941968,4149940.969076253]]"
+63100922,"[[258284.687940594,4149742.233740957],[258287.760002767,4149742.620914998],[258292.021304996,4149743.155935209],[258292.402205182,4149740.159351602],[258288.064347441,4149739.613114598],[258285.071610977,4149739.235077147],[258284.687940594,4149742.233740957]]"
+63100923,"[[258342.257426003,4149778.155517141],[258342.333189324,4149775.922283550],[258342.405688295,4149773.738237040],[258338.921255485,4149773.628801994],[258338.772136876,4149778.025670542],[258342.257426003,4149778.155517141]]"
+63100924,"[[258318.721685874,4149937.693091814],[258321.496995256,4149932.383848923],[258322.917145659,4149929.736947850],[258324.298805162,4149927.096829100],[258326.343246014,4149923.152404598],[258322.031542958,4149920.658587399],[258318.744908760,4149926.826241336],[258318.122975505,4149928.006631335],[258316.183436894,4149931.688334129],[258314.388238851,4149935.121051489],[258318.721685874,4149937.693091814]]"
+63100925,"[[258356.642914006,4149911.226792058],[258353.922375844,4149915.550918529],[258357.484327158,4149917.750303703],[258365.039773136,4149922.717773222],[258368.517480070,4149925.025456442],[258372.310709512,4149927.540343836],[258376.011851967,4149929.945060106],[258378.197911927,4149931.363816351],[258381.095808127,4149933.259609490],[258383.446988609,4149934.797637760],[258386.121339746,4149936.547090719],[258388.834300071,4149932.324600874],[258384.502324291,4149929.479143259],[258380.238352406,4149926.679917541],[258378.725609277,4149925.683003252],[258372.797022267,4149921.772876146],[258368.578389207,4149919.010880550],[258365.985245326,4149917.314387422],[258360.049300952,4149913.444022470],[258356.642914006,4149911.226792058]]"
+63100926,"[[258394.835994324,4149962.460675410],[258392.912339550,4149965.500809903],[258390.383611266,4149969.506255312],[258389.994137514,4149970.127770530],[258388.762186703,4149972.082015525],[258387.677906672,4149973.810503815],[258385.562190875,4149977.184755969],[258388.926866404,4149979.128200684],[258390.076980478,4149979.353718885],[258391.583348622,4149977.001880494],[258393.194258809,4149974.454304184],[258394.220521967,4149972.825463082],[258394.729665542,4149972.023098212],[258396.334391645,4149969.503358241],[258398.999215462,4149965.285044863],[258397.449753275,4149963.989641718],[258394.835994324,4149962.460675410]]"

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
_internal/data_map/hd_intersections.csv


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 5 - 0
_internal/data_map/hd_lane.csv


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 7 - 0
_internal/data_map/hd_link.csv


+ 58 - 0
_internal/data_map/hd_sign.csv

@@ -0,0 +1,58 @@
+sign_id,sign_type,sign_type1,sign_ref_link,sign_coords
+47103954,3,146,20164044,"[[258435.534539280,4149860.326471922],[258435.499503375,4149860.333375251],[258436.506810821,4149860.945787056],[258436.541849942,4149860.938994704],[258435.534539280,4149860.326471922]]"
+47103955,4,118,20163092,"[[258156.498786481,4150144.556928761],[258156.496234369,4150144.606206406],[258156.494674726,4150144.634796410],[258156.494400114,4150144.640579967],[258156.495312404,4150144.623226724],[258156.497355385,4150144.583848999],[258156.500432752,4150144.525226312],[258156.504303538,4150144.451253074],[258156.508673784,4150144.367046991],[258156.513268878,4150144.278391622],[258156.517817434,4150144.191181500],[258156.521962831,4150144.111424704],[258156.525512467,4150144.044680270],[258156.528061355,4150143.995291652],[258156.529532544,4150143.966704218],[258156.529807154,4150143.960920659],[258156.528898088,4150143.978384878],[258156.526855106,4150144.017762604],[258156.523777738,4150144.076385290],[258156.519992185,4150144.150244984],[258156.515533483,4150144.234453636],[258156.510941611,4150144.323219980],[258156.506393058,4150144.410430101],[258156.502244437,4150144.490075923],[258156.498786481,4150144.556928761]]"
+47103956,3,154,20163124,"[[258002.178296015,4150119.806895872],[258002.174337739,4150119.003871106],[258002.157545845,4150119.007913508],[258002.154496458,4150119.825692047],[258002.178296015,4150119.806895872]]"
+47103957,1,4,20163222,"[[258331.146767285,4150072.139673858],[258330.704786783,4150072.150728945],[258331.622117292,4150072.137535075],[258331.146767285,4150072.139673858]]"
+47103958,3,146,20163196,"[[258444.600041442,4149728.365423520],[258443.948965292,4149728.338222083],[258443.949174972,4149728.357652976],[258444.594695005,4149728.358137069],[258444.600041442,4149728.365423520]]"
+47103959,2,48,20163205,"[[258233.295055772,4150160.133288150],[258233.504503574,4150160.193734731],[258233.800729682,4150160.279205817],[258234.010177479,4150160.339652410],[258234.010177479,4150160.339652410],[258233.800729682,4150160.279205817],[258233.504503574,4150160.193734731],[258233.295055772,4150160.133288150],[258233.295055772,4150160.133288150]]"
+47103960,3,146,20163082,"[[258211.758963012,4150079.333893311],[258212.974401254,4150080.510125685],[258212.974492934,4150080.510234090],[258211.759054693,4150079.334001717],[258211.758963012,4150079.333893311],[258211.758963012,4150079.333893311]]"
+47103961,2,71,20163099,"[[258195.261328663,4150150.017375127],[258195.260684095,4150149.973854885],[258195.260420748,4150149.955647254],[258195.260574083,4150149.963972959],[258195.261036300,4150149.998168719],[258195.261919835,4150150.056009893],[258195.263108627,4150150.133501373],[258195.264536389,4150150.225313788],[258195.266025805,4150150.325343501],[258195.267550681,4150150.426593941],[258195.269002824,4150150.522293055],[258195.270192017,4150150.605893308],[258195.271215992,4150150.671616286],[258195.271857336,4150150.715025552],[258195.272120681,4150150.733233184],[258195.271970572,4150150.725018452],[258195.271505130,4150150.690711719],[258195.270624819,4150150.632981519],[258195.269436024,4150150.555490038],[258195.268093496,4150150.463564080],[258195.266607304,4150150.363645342],[258195.265082427,4150150.262394901],[258195.263630285,4150150.166695788],[258195.262352637,4150150.083098105],[258195.261328663,4150150.017375127]]"
+47103962,3,204,20163172,"[[258297.316902682,4150083.722553039],[258296.935386731,4150084.404263969],[258296.935478410,4150084.404372376],[258297.317082818,4150083.722658878],[258297.316902682,4150083.722553039],[258297.316902682,4150083.722553039]]"
+47103963,3,146,20163921,"[[258296.820316418,4149842.496756968],[258298.067916513,4149842.816396486],[258298.077389229,4149842.807235955],[258296.850177753,4149842.479340711],[258296.820316418,4149842.496756968]]"
+47103964,1,40,20163126,"[[258107.198719491,4150110.895720760],[258107.210669408,4150110.984006451],[258107.223523701,4150111.079041063],[258107.236476124,4150111.174406028],[258107.248543521,4150111.263687926],[258107.259014555,4150111.340687569],[258107.267118457,4150111.400207120],[258107.272208391,4150111.438266896],[258107.274115272,4150111.452095090],[258107.272547933,4150111.440811614],[258107.267797545,4150111.405296554],[258107.260020287,4150111.347877818],[258107.249771316,4150111.272426686],[258107.237824625,4150111.184251970],[258107.224970332,4150111.089217359],[258107.212014684,4150110.993741418],[258107.199950511,4150110.904570496],[258107.189479476,4150110.827570853],[258107.181464029,4150110.768048732],[258107.176285639,4150110.729991525],[258107.174378758,4150110.716163331],[258107.175946095,4150110.727446809],[258107.180784941,4150110.762959298],[258107.188562200,4150110.820378033],[258107.198719491,4150110.895720760]]"
+47103965,4,106,20163072,"[[258431.765862600,4149758.288933817],[258431.809530148,4149758.304882273],[258431.831008475,4149758.312811279],[258431.828859676,4149758.311985086],[258431.803178654,4149758.302623074],[258431.755750708,4149758.285228783],[258431.689802255,4149758.261152474],[258431.609804589,4149758.231930428],[258431.521214951,4149758.199514583],[258431.430030993,4149758.166174409],[258431.342604210,4149758.134169097],[258431.264755342,4149758.105773246],[258431.201846725,4149758.082719415],[258431.158090713,4149758.066773532],[258431.136615607,4149758.058955500],[258431.138761187,4149758.059670718],[258431.164442210,4149758.069032728],[258431.211870159,4149758.086427016],[258431.277818614,4149758.110503322],[258431.357819501,4149758.139836340],[258431.446405920,4149758.172141206],[258431.537589880,4149758.205481383],[258431.625016659,4149758.237486697],[258431.702868744,4149758.265993524],[258431.765862600,4149758.288933817]]"
+47103966,2,82,20163184,"[[258242.429110458,4149984.288099111],[258242.421798924,4149984.286312224],[258242.397456634,4149984.280355079],[258242.357691935,4149984.270736308],[258242.305351584,4149984.257928573],[258242.243914435,4149984.242830461],[258242.177488210,4149984.226655491],[258242.110704932,4149984.210379822],[258242.048111388,4149984.195093158],[258241.993985770,4149984.181781933],[258241.951901835,4149984.171564110],[258241.924883256,4149984.164907212],[258241.914630062,4149984.162428281],[258241.921941597,4149984.164215167],[258241.946283888,4149984.170172310],[258241.986051810,4149984.179902053],[258242.038392163,4149984.192709787],[258242.099826089,4149984.207696923],[258242.166252315,4149984.223871892],[258242.233038816,4149984.240258536],[258242.295632359,4149984.255545202],[258242.349754752,4149984.268745454],[258242.391841909,4149984.279074254],[258242.418857265,4149984.285620179],[258242.429110458,4149984.288099111]]"
+47103967,2,82,20163126,"[[258107.286350956,4150111.937110502],[258107.296697603,4150112.028108438],[258107.307670358,4150112.125419106],[258107.318721890,4150112.222394276],[258107.328954281,4150112.312506984],[258107.337656188,4150112.389558037],[258107.344322215,4150112.448341893],[258107.348479209,4150112.484762747],[258107.349794080,4150112.496497837],[258107.348241023,4150112.482659360],[258107.343845841,4150112.444135118],[258107.336951301,4150112.383580803],[258107.328119013,4150112.305089641],[258107.317775591,4150112.214202680],[258107.306714381,4150112.116894584],[258107.295751302,4150112.019916841],[258107.285518913,4150111.929804136],[258107.276725322,4150111.852644677],[258107.270062520,4150111.793971797],[258107.265902300,4150111.757439966],[258107.264590655,4150111.745815852],[258107.266232169,4150111.759651759],[258107.270538897,4150111.798178570],[258107.277433435,4150111.858732886],[258107.286350956,4150111.937110502]]"
+47103968,2,76,20163126,"[[258107.558947858,4150115.099649743],[258107.550912603,4150115.033352995],[258107.545420009,4150114.987530098],[258107.542740514,4150114.965394191],[258107.543096183,4150114.968493784],[258107.546480566,4150114.996606926],[258107.552661919,4150115.047852181],[258107.561271682,4150115.118686058],[258107.571640439,4150115.204352046],[258107.583063302,4150115.298872911],[258107.594825707,4150115.395938493],[258107.606023279,4150115.488799872],[258107.616033142,4150115.571255293],[258107.624071622,4150115.637663016],[258107.629652671,4150115.683483342],[258107.632328941,4150115.705508274],[258107.631884816,4150115.702411252],[258107.628500436,4150115.674298109],[258107.622319078,4150115.623052854],[258107.613709318,4150115.552218979],[258107.603343787,4150115.466663964],[258107.591920926,4150115.372143099],[258107.580158519,4150115.275077517],[258107.568960946,4150115.182216139],[258107.558947858,4150115.099649743]]"
+47103969,3,146,20163074,"[[258471.137870795,4149800.347250077],[258471.124605624,4149800.366072312],[258472.268375225,4149800.778049358],[258472.261498945,4149800.757701207],[258471.137870795,4149800.347250077]]"
+47103970,4,117,20163190,"[[258481.276434321,4149842.858757141],[258480.356769198,4149842.841123284],[258480.346040416,4149842.858872305],[258481.259116362,4149842.884361055],[258481.276434321,4149842.858757141]]"
+47103971,2,49,20163242,"[[258467.652319358,4149815.961975859],[258467.707561768,4149815.415693393],[258467.498199185,4149816.466033435],[258467.652319358,4149815.961975859]]"
+47103972,3,146,20163192,"[[258434.678331808,4149778.610140048],[258433.457100285,4149777.905639881],[258433.495948920,4149777.966044491],[258434.664741758,4149778.578102414],[258434.678331808,4149778.610140048]]"
+47103973,3,146,20163172,"[[258297.412942406,4150083.539055556],[258296.829688521,4150084.575269022],[258296.824989368,4150084.611613861],[258297.386818907,4150083.572357238],[258297.412942406,4150083.539055556]]"
+47103974,1,44,20163082,"[[258187.307409586,4150102.648800504],[258187.005463247,4150102.342136957],[258187.584895019,4150103.000268981],[258187.307409586,4150102.648800504]]"
+47103975,3,146,20163219,"[[258358.545472208,4149846.904069385],[258358.535172316,4149846.903035550],[258358.420920532,4149848.091009314],[258358.424148928,4149848.101578182],[258358.545472208,4149846.904069385]]"
+47103976,1,21,20163126,"[[258107.445716349,4150113.198664436],[258107.351919421,4150112.761557481],[258107.435781292,4150113.636675595],[258107.445716349,4150113.198664436]]"
+47103977,2,90,20163184,"[[258241.200858779,4149984.000006229],[258241.191142776,4149983.997733833],[258241.163963395,4149983.991636953],[258241.121184690,4149983.981883585],[258241.065659865,4149983.969168348],[258241.001224823,4149983.954490518],[258240.932246217,4149983.938833963],[258240.863444524,4149983.923172268],[258240.799454994,4149983.908592570],[258240.744735954,4149983.896187137],[258240.703025186,4149983.886624894],[258240.677002198,4149983.880716566],[258240.668625950,4149983.878849536],[258240.678338730,4149983.881010954],[258240.705521335,4149983.887218809],[258240.748388498,4149983.896969606],[258240.803913325,4149983.909684841],[258240.868345142,4149983.924251694],[258240.937326973,4149983.940019224],[258241.006128666,4149983.955680919],[258241.070026516,4149983.970152213],[258241.124748777,4149983.982668623],[258241.166544778,4149983.992117325],[258241.192479309,4149983.998028222],[258241.200858779,4149984.000006229]]"
+47103978,4,130,20163666,"[[257833.223730760,4149981.828437617],[257833.235039807,4149981.836772004],[257833.364399677,4149981.058190343],[257833.356269323,4149981.070866616],[257833.223730760,4149981.828437617]]"
+47103979,4,98,20163116,"[[258258.699394262,4150022.141827293],[258258.747919239,4150022.151302784],[258258.772494548,4150022.156142513],[258258.771515075,4150022.155948822],[258258.745069274,4150022.150719139],[258258.694853944,4150022.140959532],[258258.624426707,4150022.127233095],[258258.538508020,4150022.110513425],[258258.442883050,4150022.091854268],[258258.344231197,4150022.072616605],[258258.249228649,4150022.054050442],[258258.164200979,4150022.037527037],[258258.095107041,4150022.023984019],[258258.046673744,4150022.014616938],[258258.022009974,4150022.009779781],[258258.022989447,4150022.009973472],[258258.049520486,4150022.015089608],[258258.099650584,4150022.024962754],[258258.170166280,4150022.038686619],[258258.256084969,4150022.055406285],[258258.351621483,4150022.074068009],[258258.450273333,4150022.093305673],[258258.545364339,4150022.111869269],[258258.630303551,4150022.128395247],[258258.699394262,4150022.141827293]]"
+47103980,4,106,20163074,"[[258471.409913506,4149800.782853296],[258471.396178241,4149800.785473179],[258471.406656610,4149800.783503134],[258471.440814632,4149800.776847585],[258471.496191548,4149800.766133270],[258471.569176622,4149800.752020294],[258471.654573290,4149800.735436911],[258471.746837591,4149800.717543587],[258471.839367269,4149800.699642563],[258471.926084389,4149800.682798734],[258472.001005913,4149800.668296373],[258472.059023731,4149800.657061167],[258472.096176493,4149800.649874458],[258472.110000219,4149800.647252009],[258472.099433393,4149800.649224619],[258472.065275368,4149800.655880166],[258472.009898451,4149800.666594476],[258471.937001836,4149800.680704881],[258471.851516707,4149800.697290828],[258471.759340865,4149800.715181585],[258471.666722725,4149800.733085176],[258471.580005606,4149800.749929009],[258471.505084088,4149800.764431373],[258471.447066269,4149800.775666583],[258471.409913506,4149800.782853296]]"
+47103981,1,7,20163187,"[[257979.142351973,4150093.901509788],[257977.502441065,4150093.300104395],[257977.508575052,4150093.334468505],[257979.181893369,4150093.897361229],[257979.142351973,4150093.901509788]]"
+47103982,4,98,20163099,"[[258195.411472254,4150149.160893629],[258195.406211034,4150149.202252991],[258195.397974350,4150149.266134689],[258195.387521027,4150149.348184991],[258195.375312283,4150149.442948133],[258195.362393073,4150149.543729629],[258195.349631430,4150149.643840134],[258195.337715259,4150149.736484468],[258195.327695956,4150149.815190100],[258195.320041188,4150149.874723209],[258195.315427774,4150149.910954587],[258195.314050158,4150149.921435074],[258195.316065907,4150149.905493679],[258195.321418804,4150149.864242721],[258195.329563808,4150149.800252621],[258195.340105587,4150149.718199746],[258195.352229096,4150149.623550151],[258195.365145082,4150149.522657680],[258195.377995180,4150149.422544605],[258195.389822898,4150149.329902839],[258195.399930659,4150149.251194639],[258195.407496974,4150149.191664100],[258195.412198842,4150149.155430152],[258195.413488004,4150149.144952234],[258195.411472254,4150149.160893629]]"
+47103983,2,78,20163739,"[[258349.149955554,4149917.284070808],[258349.187776606,4149917.309073990],[258349.244013610,4149917.346315450],[258349.315054141,4149917.393345479],[258349.395844675,4149917.446867652],[258349.480968180,4149917.503262892],[258349.564644137,4149917.558589469],[258349.641101691,4149917.609238578],[258349.705103951,4149917.651696979],[258349.752403184,4149917.682978062],[258349.779753681,4149917.701065745],[258349.785262384,4149917.704793228],[258349.768470898,4149917.693618480],[258349.730649848,4149917.668615293],[258349.674412848,4149917.631373832],[258349.603372321,4149917.584343800],[258349.522581792,4149917.530821625],[258349.437458286,4149917.474426384],[258349.353870784,4149917.419097240],[258349.277413227,4149917.368448135],[258349.213322505,4149917.325992305],[258349.166023267,4149917.294711225],[258349.138672770,4149917.276623542],[258349.133164064,4149917.272896059],[258349.149955554,4149917.284070808]]"
+47103984,3,146,20163116,"[[258258.012563304,4150022.019828173],[258258.032667417,4150022.023131720],[258258.621481434,4150022.147755272],[258258.601288865,4150022.144454292],[258258.012563304,4150022.019828173]]"
+47103985,3,146,20163116,"[[258262.258960749,4150008.815835591],[258260.599045937,4150008.552604753],[258260.580319808,4150008.572363466],[258262.248889168,4150008.810463578],[258262.258960749,4150008.815835591]]"
+47103986,4,130,20164040,"[[258426.692373874,4149877.060076935],[258426.704878950,4149877.066933489],[258427.489889805,4149877.292279499],[258427.471826230,4149877.283029675],[258426.692373874,4149877.060076935]]"
+47103987,2,90,20163126,"[[258107.477570092,4150114.066297357],[258107.470932165,4150113.996294730],[258107.466204808,4150113.946340048],[258107.463661683,4150113.919757422],[258107.463534526,4150113.918428290],[258107.465823339,4150113.942352653],[258107.470306058,4150113.989981999],[258107.476800704,4150114.058100621],[258107.484726318,4150114.141949437],[258107.493564600,4150114.235878997],[258107.502863132,4150114.333460456],[258107.511812447,4150114.428164274],[258107.519865216,4150114.513342221],[258107.526414685,4150114.583347419],[258107.531142042,4150114.633302102],[258107.533685168,4150114.659884728],[258107.533812324,4150114.661213859],[258107.531523511,4150114.637289496],[258107.527040792,4150114.589660151],[258107.520634604,4150114.521538958],[258107.512708990,4150114.437690142],[258107.503782250,4150114.343763152],[258107.494572177,4150114.246179123],[258107.485622862,4150114.151475305],[258107.477570092,4150114.066297357]]"
+47103988,2,76,20163184,"[[258240.580922995,4149983.858627640],[258240.570758257,4149983.856146140],[258240.543297387,4149983.849502094],[258240.500410885,4149983.839085448],[258240.445128868,4149983.825585681],[258240.381021872,4149983.810009778],[258240.312633455,4149983.793336468],[258240.244513635,4149983.776766426],[258240.181300882,4149983.761497759],[258240.127443854,4149983.748289814],[258240.086431073,4149983.738374095],[258240.061197756,4149983.732220697],[258240.053352254,4149983.730338252],[258240.063516992,4149983.732819751],[258240.090977863,4149983.739463796],[258240.133775909,4149983.749883008],[258240.189146384,4149983.763380205],[258240.253253384,4149983.778956105],[258240.321641799,4149983.795629415],[258240.389761618,4149983.812199458],[258240.452885914,4149983.827470695],[258240.506831398,4149983.840676074],[258240.547844177,4149983.850591795],[258240.573077493,4149983.856745194],[258240.580922995,4149983.858627640]]"
+47103989,2,85,20163739,"[[258349.849177663,4149917.744255305],[258349.832386175,4149917.733080554],[258349.837894880,4149917.736808040],[258349.865245376,4149917.754895723],[258349.912544606,4149917.786176807],[258349.976635324,4149917.828632642],[258350.053092872,4149917.879281754],[258350.136680364,4149917.934610905],[258350.221803861,4149917.991006152],[258350.302594380,4149918.044528333],[258350.373634899,4149918.091558370],[258350.429871893,4149918.128799838],[258350.467692937,4149918.153803026],[258350.484484423,4149918.164977778],[258350.478975721,4149918.161250292],[258350.451625225,4149918.143162606],[258350.404325999,4149918.111881519],[258350.340323746,4149918.069423113],[258350.263866201,4149918.018774000],[258350.180190253,4149917.963447416],[258350.095066756,4149917.907052169],[258350.014276234,4149917.853529990],[258349.943235708,4149917.806499955],[258349.886998712,4149917.769258491],[258349.849177663,4149917.744255305]]"
+47103990,3,146,20163162,"[[258374.030854997,4149866.281310313],[258375.538808725,4149867.021350931],[258375.574845868,4149866.997091588],[258374.038372255,4149866.277982194],[258374.030854997,4149866.281310313]]"
+47103991,4,117,20163226,"[[258488.137290341,4149842.796430047],[258489.063461018,4149842.809433282],[258489.083751741,4149842.742869959],[258488.160524106,4149842.721451205],[258488.137290341,4149842.796430047]]"
+47103992,3,146,20163731,"[[258314.430378586,4149930.717845228],[258313.682613155,4149931.821031093],[258313.758466272,4149931.875251627],[258314.512412938,4149930.780660723],[258314.430378586,4149930.717845228]]"
+47103993,4,106,20163196,"[[258443.929018378,4149728.340355831],[258443.997578586,4149728.350695048],[258444.082502407,4149728.363558297],[258444.177919265,4149728.378005239],[258444.277427831,4149728.393110934],[258444.374178031,4149728.407741326],[258444.461594833,4149728.421087584],[258444.533801228,4149728.431987415],[258444.585732443,4149728.439810303],[258444.613922436,4149728.444101477],[258444.616323741,4149728.444476073],[258444.593024818,4149728.440931525],[258444.545450689,4149728.433759689],[258444.476887263,4149728.423309492],[258444.391963446,4149728.410446240],[258444.296546587,4149728.395999295],[258444.197038021,4149728.380893601],[258444.100199361,4149728.366265776],[258444.012874237,4149728.353027931],[258443.940667840,4149728.342128105],[258443.888733403,4149728.334194245],[258443.860543410,4149728.329903075],[258443.858053645,4149728.329531045],[258443.881441028,4149728.333073024],[258443.929018378,4149728.340355831]]"
+47103994,1,21,20163184,"[[258241.248402007,4149984.021394502],[258241.802220243,4149984.145034245],[258241.522931194,4149984.075952954],[258241.248402007,4149984.021394502]]"
+47103995,2,86,20163184,"[[258077.937783851,4150119.058111796],[258077.936906457,4150119.006601323],[258077.935622178,4150118.934999205],[258077.934072933,4150118.848188346],[258077.932432890,4150118.752161406],[258077.930712212,4150118.653360089],[258077.929019193,4150118.558556448],[258077.927629362,4150118.474184473],[258077.926445069,4150118.406022585],[258077.925601788,4150118.358731738],[258077.925193045,4150118.335530217],[258077.925175549,4150118.337974241],[258077.925722981,4150118.365947695],[258077.926597149,4150118.417347192],[258077.927881428,4150118.488949311],[258077.929342217,4150118.575762740],[258077.931070716,4150118.671787108],[258077.932702938,4150118.770590997],[258077.934395957,4150118.865394638],[258077.935874246,4150118.949764044],[258077.937058537,4150119.017925933],[258077.937901821,4150119.065216778],[258077.938310559,4150119.088418300],[258077.938239600,4150119.085976846],[258077.937783851,4150119.058111796]]"
+47103996,2,84,20163240,"[[258351.490789641,4149972.491066064],[258351.423786936,4149972.455025692],[258351.344462581,4149972.412345696],[258351.258305910,4149972.366087711],[258351.171156875,4149972.319192124],[258351.088956770,4149972.275040652],[258351.017365408,4149972.236467845],[258350.961158022,4149972.206333929],[258350.924193061,4149972.186415059],[258350.909084119,4149972.178301390],[258350.916728658,4149972.182411144],[258350.946766407,4149972.198532642],[258350.996950484,4149972.225509357],[258351.063953190,4149972.261549726],[258351.143277550,4149972.304229720],[258351.229434221,4149972.350487704],[258351.316583255,4149972.397383293],[258351.398783357,4149972.441534766],[258351.470374718,4149972.480107577],[258351.526582098,4149972.510241495],[258351.563547056,4149972.530160367],[258351.578655997,4149972.538274037],[258351.571011458,4149972.534164282],[258351.540973714,4149972.518042783],[258351.490789641,4149972.491066064]]"
+47103997,1,4,20163156,"[[258402.913217886,4150002.703060277],[258402.767952224,4150002.264335120],[258402.948219086,4150003.225732593],[258402.913217886,4150002.703060277]]"
+47103998,3,146,20163116,"[[258278.077687143,4149927.134384695],[258276.900424323,4149926.937769866],[258276.906404674,4149926.948592003],[258278.065659738,4149927.128736244],[258278.077687143,4149927.134384695]]"
+47103999,4,131,20163149,"[[258441.196445638,4149989.342822982],[258441.675114948,4149988.689177746],[258441.668825279,4149988.655484374],[258441.195127187,4149989.306541843],[258441.196445638,4149989.342822982]]"
+47104000,4,154,20163184,"[[258077.917878841,4150118.339741278],[258077.947245688,4150119.121701417],[258077.971747251,4150119.151422181],[258077.933112659,4150118.339964933],[258077.917878841,4150118.339741278]]"
+47104001,4,130,20163666,"[[257833.080012643,4149981.787857841],[257833.099827820,4149981.778173702],[257833.214198972,4149981.038235877],[257833.206698145,4149981.042119374],[257833.080012643,4149981.787857841]]"
+47104002,4,98,20163116,"[[258254.489941611,4150036.785089009],[258254.466347250,4150036.777444089],[258254.467955588,4150036.777952722],[258254.494858313,4150036.786723316],[258254.544998347,4150036.803038132],[258254.615155790,4150036.825768927],[258254.700331929,4150036.853505913],[258254.794981193,4150036.884299841],[258254.892401631,4150036.916012908],[258254.986156657,4150036.946499602],[258255.069724452,4150036.973727957],[258255.137382534,4150036.995753864],[258255.184662937,4150037.011152113],[258255.208257299,4150037.018797036],[258255.206648958,4150037.018288403],[258255.179746238,4150037.009517807],[258255.129606204,4150036.993202986],[258255.059445543,4150036.970361212],[258254.974269407,4150036.942624222],[258254.879623366,4150036.911941268],[258254.782202930,4150036.880228200],[258254.688447902,4150036.849741509],[258254.604880104,4150036.822513156],[258254.537222017,4150036.800487257],[258254.489941611,4150036.785089009]]"
+47104003,3,146,20163072,"[[258431.247138163,4149758.081405132],[258431.246821654,4149758.091854753],[258431.802863260,4149758.297856283],[258431.797208074,4149758.292133758],[258431.247138163,4149758.081405132]]"
+47104004,1,82,20163184,"[[258243.076343011,4149984.436570928],[258243.067164199,4149984.434505067],[258243.040957855,4149984.428379920],[258242.999600922,4149984.418807388],[258242.945943381,4149984.406371113],[258242.883552539,4149984.391967106],[258242.816703369,4149984.376470826],[258242.749942655,4149984.360971978],[258242.687817185,4149984.346560265],[258242.634605154,4149984.334222122],[258242.593873868,4149984.324853559],[258242.568470088,4149984.318927242],[258242.560090616,4149984.316949234],[258242.569272650,4149984.319126070],[258242.595475774,4149984.325140241],[258242.636832706,4149984.334712769],[258242.690493471,4149984.347260017],[258242.752884313,4149984.361664025],[258242.819821943,4149984.377157735],[258242.886494200,4149984.392659152],[258242.948619669,4149984.407070866],[258243.001831699,4149984.419409012],[258243.042562983,4149984.428777577],[258243.067966763,4149984.434703895],[258243.076343011,4149984.436570928]]"
+47104005,9,146,20163074,"[[258472.069229099,4149800.670093279],[258472.067635804,4149800.633486926],[258471.482752507,4149800.778962853],[258471.466483453,4149800.816309603],[258472.069229099,4149800.670093279]]"
+47104006,4,98,20163242,"[[258467.559765560,4149816.421485764],[258467.562446266,4149816.407080155],[258467.570150648,4149816.364428471],[258467.582523345,4149816.296539871],[258467.598628422,4149816.207773179],[258467.617410988,4149816.104489903],[258467.637563648,4149815.993503153],[258467.657716308,4149815.882516402],[258467.676492436,4149815.779011176],[258467.692679537,4149815.690019968],[258467.705039357,4149815.621687468],[258467.712910998,4149815.578697726],[258467.715578825,4149815.563848218],[258467.712986577,4149815.578251259],[258467.705193735,4149815.620905510],[258467.692824257,4149815.688905085],[258467.676715953,4149815.777560802],[258467.657936608,4149815.880955052],[258467.637872408,4149815.991939236],[258467.617631287,4149816.102928553],[258467.598855161,4149816.206433779],[258467.582668065,4149816.295424987],[258467.570305026,4149816.363646513],[258467.562525067,4149816.406744664],[258467.559765560,4149816.421485764]]"
+47104007,2,82,20163096,"[[258355.756971986,4149974.897140350],[258355.703823742,4149974.868694698],[258355.634669101,4149974.831717147],[258355.554273635,4149974.788735002],[258355.467851643,4149974.742484679],[258355.381609784,4149974.696340196],[258355.301214315,4149974.653358053],[258355.232148130,4149974.616377938],[258355.179268474,4149974.588035559],[258355.145997950,4149974.570341864],[258355.134753900,4149974.564226295],[258355.146178085,4149974.570447703],[258355.179628747,4149974.588247238],[258355.232688540,4149974.616695455],[258355.301843185,4149974.653673003],[258355.382330332,4149974.696763554],[258355.468660647,4149974.742905468],[258355.554990959,4149974.789047385],[258355.635389649,4149974.832140503],[258355.704364150,4149974.869012215],[258355.757332261,4149974.897352029],[258355.790517548,4149974.915159269],[258355.801846829,4149974.921161296],[258355.790337410,4149974.915053429],[258355.756971986,4149974.897140350]]"
+47104008,3,146,20163240,"[[258351.635338970,4149972.593939925],[258352.677043725,4149973.192902930],[258352.704206220,4149973.146576285],[258351.645255452,4149972.548224998],[258351.635338970,4149972.593939925]]"
+47104009,3,146,20163096,"[[258353.980566202,4149973.917881078],[258355.038593110,4149974.508817859],[258355.056977113,4149974.492512440],[258354.002199108,4149973.903702714],[258353.980566202,4149973.917881078]]"
+47104010,3,146,20163116,"[[258255.108874696,4150036.986585610],[258254.451966350,4150036.788302200],[258254.452058031,4150036.788410607],[258255.108963154,4150036.986583040],[258255.108874696,4150036.986585610],[258255.108874696,4150036.986585610]]"

+ 73 - 0
_internal/data_map/hd_stopline.csv

@@ -0,0 +1,73 @@
+stopline_id,stopline_ref_link,stopline_ref_lane,stopline_color,stopline_type,stopline_coords
+44100584,20163204,"[30226007,30226008]",1,1,"[[258269.489246269,4150073.115226852],[258267.631877010,4150076.069725602],[258265.283884196,4150079.835613316]]"
+44100585,20163236,"[30226054,30226055]",1,1,"[[258259.232095554,4150066.088127263],[258261.110833129,4150063.143890802],[258264.420056534,4150057.916189935]]"
+44100586,20163233,"30226051",1,2,"[[258048.182596606,4149959.043749651],[258047.456393551,4149963.546599193]]"
+44100587,20163211,"30226017",1,1,"[[258285.646831735,4149731.874740554],[258286.116532336,4149728.429970939]]"
+44100588,20163220,"30226034",1,1,"[[257953.472685465,4149894.768230699],[257952.964683957,4149897.794859784]]"
+44100589,20163128,"30225906",1,1,"[[257929.874710239,4149989.355510266],[257933.476866891,4149989.865191602]]"
+44100590,20163198,"[30225999,30226000]",1,1,"[[258332.422117757,4149960.025077075],[258329.360354644,4149958.288221294],[258321.734563332,4149953.989682954]]"
+44100591,20163069,"30225827",1,2,"[[258115.519719339,4149968.803214826],[258116.403728174,4149962.661410535]]"
+44100592,20163155,"30225939",1,1,"[[258176.119131971,4149784.695168970],[258182.124233629,4149785.359407499]]"
+44100593,20163092,"30225856",1,1,"[[258157.455570037,4150151.398625588],[258157.704128354,4150147.987810492]]"
+44100594,20163114,"30225885",1,2,"[[258127.852337968,4149956.352241359],[258131.820746460,4149956.953327517]]"
+44100595,20163183,"30225977",1,2,"[[258040.562909349,4150017.338280493],[258039.913270752,4150020.819848914]]"
+44100596,20163139,"31186584",1,1,"[[258386.459716111,4149922.574397726],[258389.615639349,4149924.474699976]]"
+44100597,20163108,"30225876",1,1,"[[257805.160773592,4150061.279319978],[257805.601963086,4150057.839221269]]"
+44100598,20163225,"30226039",1,2,"[[258123.827356761,4149982.267707341],[258119.150637201,4149981.643113555]]"
+44100599,20163221,"30226035",1,2,"[[258154.237624455,4149778.052503022],[258157.946112289,4149778.608734617]]"
+44100600,20163141,"30225923",1,2,"[[258150.420647838,4149802.913513629],[258146.967835554,4149802.493692098]]"
+44100601,20163217,"[30226030,30226031]",1,1,"[[258343.219039372,4149966.650637164],[258340.262239328,4149964.787333343],[258337.297708702,4149962.932251841]]"
+44100602,20163113,"30225884",1,3,"[[258229.194475616,4150158.839821836],[258232.194313648,4150160.640745637]]"
+44100603,20163115,"30225886",1,1,"[[257950.981495358,4149845.057657587],[257947.843038493,4149844.591237158]]"
+44100604,20163096,"30225861",1,1,"[[258291.908625318,4150076.441883805],[258294.880496255,4150078.306730236]]"
+44100605,20163113,"30225883",1,3,"[[258222.951069705,4150162.223507303],[258225.989315590,4150163.972110556]]"
+44100606,20163208,"30226013",1,2,"[[258176.610589347,4149742.087476979],[258177.675619856,4149733.110175343]]"
+44100607,20163223,"30226037",1,2,"[[258074.983697389,4149778.299799179],[258074.391903867,4149782.853271225]]"
+44100608,20163122,"30225898",1,1,"[[257929.564910700,4149945.661520787],[257930.318187159,4149940.846542486]]"
+44100609,20163171,"30225960",1,1,"[[257943.749208585,4149830.319843501],[257944.281983583,4149826.781021237]]"
+44100610,20163112,"30225882",1,1,"[[257962.695759894,4149833.269950673],[257962.260712094,4149836.388310429]]"
+44100611,20163107,"30225875",1,1,"[[257937.576687624,4149937.191327703],[257940.604426566,4149937.669291396]]"
+44100612,20163076,"[30225834,30225835]",1,1,"[[258282.077197869,4150080.449287275],[258283.959716835,4150077.497949121],[258286.338471988,4150073.724065692]]"
+44100613,20163159,"[30225943,30225944]",1,1,"[[258176.494829307,4150147.180747348],[258180.010930126,4150147.468003390],[258183.527566953,4150147.743249892]]"
+44100614,20163218,"30226032",1,2,"[[258022.104025228,4150068.841512314],[258027.167843848,4150069.614846040]]"
+44100615,20163116,"30225887",1,1,"[[258245.846785998,4150046.579356216],[258249.592556972,4150047.951224371]]"
+44100616,20163164,"30225951",1,2,"[[258163.923962573,4149740.541192541],[258162.786794429,4149749.201603483]]"
+44100617,20163242,"30226063",1,2,"[[258467.490565913,4149806.881048527],[258465.552481297,4149809.972337505],[258462.631019952,4149814.649117273]]"
+44100618,20163075,"30225833",1,2,"[[258036.921011818,4149966.756728101],[258031.577301641,4149966.020619805]]"
+44100619,20163133,"30225913",1,1,"[[257811.533498643,4149983.237412090],[257812.067821653,4149979.748178125]]"
+44100620,20163194,"30225993",1,1,"[[258288.255641880,4149743.856601154],[258284.936143566,4149743.457840872]]"
+44100621,20163170,"[30225958,30225959]",1,1,"[[258399.906605951,4149975.068171219],[258398.214901028,4149978.135559457],[258396.412222971,4149981.396651672]]"
+44100622,20163235,"30226053",1,1,"[[257943.552068759,4149947.817809646],[257942.842616784,4149952.657390980]]"
+44100623,20163248,"30226074",1,2,"[[258028.432079884,4150025.129080599],[258025.230759177,4150024.638584931]]"
+44100624,20163167,"30225955",1,1,"[[257934.745324031,4149955.306384577],[257931.582902837,4149954.778693712]]"
+44100625,20163135,"[31186583,31186585,31186582]",1,1,"[[258376.687032263,4149916.775944382],[258379.875587994,4149918.668743027],[258383.118490700,4149920.594729781],[258386.323157652,4149922.496725996]]"
+44100626,20163143,"30225925",1,1,"[[258302.988285534,4150100.448750802],[258299.929280121,4150098.893870407]]"
+44100627,20163209,"30226014",1,1,"[[257908.249807355,4149997.734138903],[257908.774015566,4149994.148467158]]"
+44100628,20163126,"30225904",1,1,"[[258259.286735545,4149908.548151053],[258255.458241881,4149907.625283616]]"
+44100629,20163078,"30225837",1,1,"[[257821.819479275,4149997.791870835],[257818.776199506,4149997.421474146]]"
+44100630,20163096,"30225860",1,1,"[[258291.627798182,4150070.395907112],[258294.576411468,4150072.252432385]]"
+44100631,20163189,"30225986",1,1,"[[258292.372820199,4150087.330017243],[258290.177177992,4150090.915873837]]"
+44100632,20163154,"30225938",1,1,"[[257945.987164684,4149880.019009677],[257949.139419747,4149880.488470321]]"
+44100633,20163182,"30225976",1,2,"[[258118.693975883,4150017.743316239],[258122.692257819,4150018.401505750]]"
+44100634,20163999,"[30226046,30226047]",1,1,"[[258260.119054005,4150082.956696442],[258257.158070030,4150081.055448371],[258254.207384985,4150079.194886499]]"
+44100635,20163105,"30225873",1,2,"[[258284.655518251,4149724.572329049],[258283.964507532,4149721.230568219]]"
+44100636,20163109,"30225877",1,3,"[[258373.922509055,4149856.009170648],[258367.725373917,4149852.584766479]]"
+44100637,20163146,"30225929",1,1,"[[257814.521576445,4150048.976391553],[257817.080363181,4150049.373210174]]"
+44100638,20163073,"30225831",1,1,"[[258282.355092747,4149792.160960338],[258285.724558316,4149792.592032126]]"
+44100639,20163132,"30225912",1,2,"[[258035.714254673,4150080.649790779],[258035.234961672,4150083.884722718]]"
+44100640,20163176,"30225966",1,1,"[[258165.248551053,4149789.730491533],[258164.744905378,4149793.077629584]]"
+44100641,20163250,"30226076",1,2,"[[258138.645275213,4149786.230781236],[258139.192660549,4149782.649458841]]"
+44100642,20163142,"30225924",1,1,"[[257835.549111259,4149987.031684212],[257834.813698958,4149990.587076645]]"
+44100643,20163082,"[30225842,30225843]",1,1,"[[258233.829163402,4150068.568140252],[258230.330941073,4150065.980439473]]"
+44100644,20163175,"30225965",1,2,"[[258031.390251843,4150005.709097522],[258035.680193220,4150006.294792491]]"
+44100645,20163127,"30225905",1,2,"[[258107.202174773,4150027.065726256],[258107.867993857,4150023.558149159]]"
+44100646,20163166,"30225954",1,1,"[[257949.295420104,4150004.011107436],[257948.764335179,4150007.567875266]]"
+44100647,20163203,"30226006",1,1,"[[257753.541109750,4149974.864467816],[257753.006625033,4149978.350380023]]"
+44100648,20163089,"[30225851,30225852]",1,1,"[[258314.189183722,4149924.261431701],[258315.993320680,4149921.267620335],[258317.930583030,4149918.053249510]]"
+44100649,20163081,"30225841",1,1,"[[258272.525821093,4149921.177830382],[258268.700724786,4149920.393028188]]"
+44100650,20163085,"30225846",1,1,"[[258433.495823496,4149769.296932070],[258429.243003370,4149765.141873790]]"
+44100651,20163144,"30225926",1,1,"[[257941.744957514,4149907.733349424],[257938.619206971,4149907.255568908]]"
+44100652,20163157,"30225941",1,2,"[[258115.031577775,4150041.625582837],[258111.392808324,4150041.112780164]]"
+44100653,20163191,"[30225988,30225989]",1,1,"[[258247.450352732,4150059.241710397],[258245.814419092,4150062.364383105],[258243.182714019,4150067.402257374]]"
+44100654,20163147,"30225930",1,1,"[[258191.895108756,4150153.825752146],[258191.645444680,4150157.232487756]]"
+44100655,20163152,"30225936",1,1,"[[258307.794592199,4149774.816568234],[258307.659696192,4149777.778574734]]"

+ 30 - 0
_internal/data_map/hd_trafficlight.csv

@@ -0,0 +1,30 @@
+trafficlight_id,trafficlight_ref_link,trafficlight_ref_lane,trafficlight_type,trafficlight_head,trafficlight_coords
+48100015,20163096,"",1,"2","[[258278.982434002,4150096.644118029],[258278.976476981,4150096.646290257],[258279.441054913,4150096.934794777],[258279.447011932,4150096.932622550],[258278.982434002,4150096.644118029]]"
+48100016,20163204,"",1,"1","[[258253.756081967,4150068.709667493],[258253.858526906,4150068.722352914],[258254.082388392,4150068.413300223],[258253.979851769,4150068.400506394],[258253.756081967,4150068.709667493]]"
+48100017,20164040,"",1,"2","[[258357.350668559,4149975.651458707],[258357.366335349,4149975.690988601],[258358.727435075,4149976.456724204],[258358.722790318,4149976.421761365],[258357.350668559,4149975.651458707]]"
+48100018,20163198,"",1,"1","[[258353.325773619,4149920.019532894],[258353.341513403,4149919.997528675],[258352.011206435,4149919.213239469],[258352.009143439,4149919.224517282],[258353.325773619,4149920.019532894]]"
+48100019,20163170,"",1,"1","[[258315.918393355,4149928.923423350],[258315.599238218,4149929.298660761],[258315.612100410,4149929.372703298],[258315.949776081,4149928.976713678],[258315.918393355,4149928.923423350]]"
+48100020,20163189,"",1,"2","[[258283.054349699,4150086.111848883],[258283.064359829,4150086.142546360],[258283.318664837,4150085.735536402],[258283.308654710,4150085.704838924],[258283.054349699,4150086.111848883]]"
+48100021,20163089,"",1,"1","[[258392.030738395,4149967.266953603],[258392.071079271,4149967.290328856],[258392.335056865,4149966.773972942],[258392.303310268,4149966.735576120],[258392.030738395,4149967.266953603]]"
+48100022,20163198,"",1,"2","[[258351.868798714,4149919.077427067],[258351.875789326,4149919.059008885],[258350.593872983,4149918.297861289],[258350.590057204,4149918.315854102],[258351.868798714,4149919.077427067]]"
+48100023,20163159,"",1,"1","[[258178.827676817,4150157.757140618],[258178.827313157,4150157.778143188],[258179.221284790,4150157.830339789],[258179.221559993,4150157.809339788],[258178.827676817,4150157.757140618]]"
+48100024,20163147,"",1,"[1,2]","[[258159.945479822,4150152.492171268],[258159.966933361,4150152.109249033],[258159.897745079,4150152.229547577],[258159.876203090,4150152.612472382],[258159.945479822,4150152.492171268]]"
+48100025,20163076,"",1,"2","[[258295.333340735,4150086.487005655],[258295.489384426,4150086.089402454],[258295.493856223,4150086.042179486],[258295.337815753,4150086.439893661],[258295.333340735,4150086.487005655]]"
+48100026,20163999,"",1,"1","[[258271.049985869,4150057.522728054],[258271.052002568,4150057.491570253],[258270.628377989,4150057.235419467],[258270.626358068,4150057.266466292],[258271.049985869,4150057.522728054]]"
+48100027,20163096,"",1,"2","[[258279.826438161,4150097.157625074],[258279.823129390,4150097.177824592],[258280.302819289,4150097.474553667],[258280.306131284,4150097.454465122],[258279.826438161,4150097.157625074]]"
+48100028,20163189,"",1,"1","[[258284.015487872,4150084.711018174],[258283.957497338,4150084.710925070],[258283.698422723,4150085.130513202],[258283.756501712,4150085.130603736],[258284.015487872,4150084.711018174]]"
+48100029,20163236,"",1,"1","[[258269.799348554,4150068.995901942],[258270.002185715,4150068.609156851],[258269.927272201,4150068.632990785],[258269.721301568,4150068.981952450],[258269.799348554,4150068.995901942]]"
+48100030,20164039,"",1,"1","[[258348.240511472,4149970.514992458],[258349.557281594,4149971.290676946],[258349.593019498,4149971.240880355],[258348.276157696,4149970.465087454],[258348.240511472,4149970.514992458]]"
+48100031,20163999,"",1,"2","[[258270.150131041,4150057.018951524],[258270.172517470,4150056.997198359],[258269.760506112,4150056.735490129],[258269.738119686,4150056.757243296],[258270.150131041,4150057.018951524]]"
+48100032,20163204,"",1,"2","[[258253.407504700,4150069.607896536],[258253.657763511,4150069.247540916],[258253.559787285,4150069.193630290],[258253.323417276,4150069.517040938],[258253.407504700,4150069.607896536]]"
+48100033,20163217,"",1,"[1,2]","[[258355.432573281,4149921.318298024],[258355.447014243,4149921.312547525],[258354.151417785,4149920.543688548],[258354.153832460,4149920.556724542],[258355.432573281,4149921.318298024]]"
+48100034,20163076,"",2,"1","[[258294.796019863,4150087.330625253],[258295.014860639,4150086.952301596],[258294.944267569,4150086.862719809],[258294.763290008,4150087.252272623],[258294.796019863,4150087.330625253]]"
+48100035,20163999,"",1,"2","[[258268.934215684,4150056.329094918],[258269.351043615,4150056.555454458],[258269.266651537,4150056.451057170],[258268.849823602,4150056.224697635],[258268.934215684,4150056.329094918]]"
+48100036,20163096,"",2,"1","[[258278.493398362,4150096.467614612],[258278.584759606,4150096.412648137],[258278.131770166,4150096.108590721],[258278.040408918,4150096.163557202],[258278.493398362,4150096.467614612]]"
+48100037,20163236,"",1,"2","[[258270.376261255,4150068.000521734],[258270.419235147,4150067.971284435],[258270.634465118,4150067.627163054],[258270.609544266,4150067.653099366],[258270.376261255,4150068.000521734]]"
+48100038,20164040,"",1,"1","[[258355.955595618,4149974.877379770],[258355.971259196,4149974.916798688],[258357.332454086,4149975.682753458],[258357.327809323,4149975.647790618],[258355.955595618,4149974.877379770]]"
+48100039,20163089,"",1,"2","[[258392.881659658,4149965.715729477],[258392.935914920,4149965.718264258],[258393.200030651,4149965.194462779],[258393.138282733,4149965.205251557],[258392.881659658,4149965.715729477]]"
+48100040,20163092,"",1,"2","[[258195.032290965,4150151.958291780],[258195.082421916,4150151.526332816],[258194.948569375,4150151.535663661],[258194.898435207,4150151.967511652],[258195.032290965,4150151.958291780]]"
+48100041,20163170,"",1,"2","[[258314.849734685,4149930.418224048],[258314.525187826,4149930.812055442],[258314.591923577,4149930.805341886],[258314.901055309,4149930.426396978],[258314.849734685,4149930.418224048]]"
+48100042,20163159,"",1,"1","[[258178.233785310,4150157.682985005],[258177.879244164,4150157.631975339],[258177.783046757,4150157.691082007],[258178.137587899,4150157.742091670],[258178.233785310,4150157.682985005]]"
+48100043,20164039,"",1,"2","[[258349.626111732,4149971.334772261],[258350.770028476,4149971.996298286],[258350.788933284,4149971.973535760],[258349.664223528,4149971.321004048],[258349.626111732,4149971.334772261]]"

BIN
_internal/engine


+ 35 - 0
config/config.json

@@ -0,0 +1,35 @@
+{
+  "processing": {
+    "use_parallel": true,
+    "max_workers": null,
+    "batch_size": 10000,
+    "use_vectorized": true
+  },
+  "database": {
+    "batch_query_size": 10000,
+    "use_parallel_query": true,
+    "max_db_workers": null
+  },
+  "plugins": {
+    "enabled": true,
+    "auto_discover": true
+  },
+  "logging": {
+    "level": "INFO",
+    "log_to_file": true,
+    "log_dir": "logs"
+  },
+  "coordinates": {
+    "utm_zone": 51,
+    "x_offset": 0.0,
+    "y_offset": 0.0
+  },
+  "paths": {
+    "resources_dir": "resources",
+    "plugins_dir": "plugins",
+    "output_dir": "output",
+    "engine_path": "_internal/engine",
+    "map_path": "_internal/data_map",
+    "dbc_path": "_internal/VBox.dbc"
+  }
+}

+ 9 - 0
core/__init__.py

@@ -0,0 +1,9 @@
+"""
+核心组件包,包含插件系统的基础设施
+"""
+
+from .plugin_interface import CustomDataProcessorPlugin
+from .plugin_manager import PluginManager
+from .resource_manager import ResourceManager
+
+__all__ = ['CustomDataProcessorPlugin', 'PluginManager', 'ResourceManager']

BIN
core/__pycache__/__init__.cpython-310.pyc


BIN
core/__pycache__/__init__.cpython-313.pyc


BIN
core/__pycache__/config_manager.cpython-313.pyc


BIN
core/__pycache__/data_pipeline.cpython-313.pyc


BIN
core/__pycache__/db_processor.cpython-313.pyc


BIN
core/__pycache__/error_handler.cpython-313.pyc


BIN
core/__pycache__/optimized_processor.cpython-313.pyc


BIN
core/__pycache__/plugin_interface.cpython-310.pyc


BIN
core/__pycache__/plugin_interface.cpython-313.pyc


BIN
core/__pycache__/plugin_manager.cpython-313.pyc


BIN
core/__pycache__/resource_manager.cpython-313.pyc


+ 257 - 0
core/config_manager.py

@@ -0,0 +1,257 @@
+import json
+import os
+from pathlib import Path
+from typing import Dict, Any, Optional, Union, List
+import yaml
+
+# 全局配置字典
+_CONFIG: Dict[str, Any] = {}
+
+# 默认配置
+DEFAULT_CONFIG = {
+    # 数据处理配置
+    "processing": {
+        "use_parallel": True,
+        "max_workers": None,  # None表示使用CPU核心数
+        "batch_size": 10000,
+        "use_vectorized": True
+    },
+    # 数据库配置
+    "database": {
+        "batch_query_size": 10000,
+        "use_parallel_query": True,
+        "max_db_workers": None
+    },
+    # 插件配置
+    "plugins": {
+        "enabled": True,
+        "auto_discover": True
+    },
+    # 日志配置
+    "logging": {
+        "level": "INFO",
+        "log_to_file": True,
+        "log_dir": "logs"
+    },
+    # 坐标系配置
+    "coordinates": {
+        "utm_zone": 51,
+        "x_offset": 0.0,
+        "y_offset": 0.0
+    },
+    # 文件路径配置
+    "paths": {
+        "resources_dir": "resources",
+        "plugins_dir": "plugins",
+        "output_dir": "output",
+        "engine_path": "_internal/engine",
+        "map_path": "_internal/data_map",
+        "dbc_path": "_internal/VBox.dbc"
+    }
+}
+
+
+def load_config(config_path: Optional[Union[str, Path]] = None) -> Dict[str, Any]:
+    """加载配置文件
+    
+    Args:
+        config_path: 配置文件路径,支持JSON和YAML格式
+        
+    Returns:
+        配置字典
+    """
+    global _CONFIG
+    
+    # 首先使用默认配置
+    _CONFIG = DEFAULT_CONFIG.copy()
+    
+    if config_path is None:
+        # 尝试查找默认配置文件
+        default_paths = [
+            Path("config.json"),
+            Path("config.yaml"),
+            Path("config.yml"),
+            Path("config/config.json"),
+            Path("config/config.yaml"),
+            Path("config/config.yml")
+        ]
+        
+        for path in default_paths:
+            if path.exists():
+                config_path = path
+                break
+    
+    if config_path is None:
+        print("未找到配置文件,使用默认配置")
+        return _CONFIG
+    
+    # 确保config_path是Path对象
+    if isinstance(config_path, str):
+        config_path = Path(config_path)
+    
+    if not config_path.exists():
+        print(f"配置文件不存在: {config_path},使用默认配置")
+        return _CONFIG
+    
+    try:
+        # 根据文件扩展名选择解析方法
+        suffix = config_path.suffix.lower()
+        
+        if suffix in [".yaml", ".yml"]:
+            with open(config_path, "r", encoding="utf-8") as f:
+                user_config = yaml.safe_load(f)
+        elif suffix == ".json":
+            with open(config_path, "r", encoding="utf-8") as f:
+                user_config = json.load(f)
+        else:
+            print(f"不支持的配置文件格式: {suffix},使用默认配置")
+            return _CONFIG
+        
+        # 递归合并配置
+        _CONFIG = _merge_configs(_CONFIG, user_config)
+        print(f"成功加载配置文件: {config_path}")
+        
+    except Exception as e:
+        print(f"加载配置文件失败: {e}")
+    
+    return _CONFIG
+
+
+def _merge_configs(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
+    """递归合并配置字典
+    
+    Args:
+        base: 基础配置
+        override: 覆盖配置
+        
+    Returns:
+        合并后的配置
+    """
+    result = base.copy()
+    
+    for key, value in override.items():
+        # 如果两个都是字典,递归合并
+        if key in result and isinstance(result[key], dict) and isinstance(value, dict):
+            result[key] = _merge_configs(result[key], value)
+        else:
+            # 否则直接覆盖
+            result[key] = value
+    
+    return result
+
+
+def get_config(section: Optional[str] = None) -> Any:
+    """获取配置
+    
+    Args:
+        section: 配置节名称,如果为None则返回整个配置字典
+        
+    Returns:
+        配置值或配置字典
+    """
+    global _CONFIG
+    
+    # 如果配置为空,加载默认配置
+    if not _CONFIG:
+        _CONFIG = DEFAULT_CONFIG.copy()
+    
+    if section is None:
+        return _CONFIG
+    
+    # 支持点号分隔的多级配置访问,如 "database.batch_query_size"
+    if "." in section:
+        parts = section.split(".")
+        current = _CONFIG
+        for part in parts:
+            if part in current:
+                current = current[part]
+            else:
+                print(f"配置节不存在: {section}")
+                return None
+        return current
+    
+    # 单级配置访问
+    return _CONFIG.get(section)
+
+
+def set_config(section: str, value: Any) -> None:
+    """设置配置
+    
+    Args:
+        section: 配置节名称,支持点号分隔的多级配置
+        value: 配置值
+    """
+    global _CONFIG
+    
+    # 如果配置为空,加载默认配置
+    if not _CONFIG:
+        _CONFIG = DEFAULT_CONFIG.copy()
+    
+    # 支持点号分隔的多级配置设置
+    if "." in section:
+        parts = section.split(".")
+        current = _CONFIG
+        
+        # 遍历到倒数第二级
+        for part in parts[:-1]:
+            # 如果中间节点不存在或不是字典,创建新字典
+            if part not in current or not isinstance(current[part], dict):
+                current[part] = {}
+            current = current[part]
+        
+        # 设置最后一级的值
+        current[parts[-1]] = value
+    else:
+        # 单级配置设置
+        _CONFIG[section] = value
+
+
+def save_config(config_path: Union[str, Path], format: str = "json") -> bool:
+    """保存配置到文件
+    
+    Args:
+        config_path: 配置文件路径
+        format: 文件格式,支持 "json" 和 "yaml"
+        
+    Returns:
+        是否保存成功
+    """
+    global _CONFIG
+    
+    # 确保config_path是Path对象
+    if isinstance(config_path, str):
+        config_path = Path(config_path)
+    
+    # 确保目录存在
+    config_path.parent.mkdir(parents=True, exist_ok=True)
+    
+    try:
+        # 根据格式选择保存方法
+        if format.lower() == "yaml":
+            with open(config_path, "w", encoding="utf-8") as f:
+                yaml.dump(_CONFIG, f, default_flow_style=False, sort_keys=False)
+        else:  # 默认使用JSON
+            with open(config_path, "w", encoding="utf-8") as f:
+                json.dump(_CONFIG, f, indent=2, ensure_ascii=False)
+        
+        print(f"配置已保存到: {config_path}")
+        return True
+        
+    except Exception as e:
+        print(f"保存配置失败: {e}")
+        return False
+
+
+def update_config(new_config: Dict[str, Any]) -> None:
+    """更新全局配置
+    
+    Args:
+        new_config: 新的配置字典,将与现有配置合并
+    """
+    global _CONFIG
+    _CONFIG = _merge_configs(_CONFIG, new_config)
+    print("配置已更新")
+
+
+# 初始化时加载配置
+load_config()

+ 295 - 0
core/data_pipeline.py

@@ -0,0 +1,295 @@
+from pathlib import Path
+from typing import Dict, Any, List, Callable, Optional, Union, Tuple
+import pandas as pd
+import numpy as np
+import concurrent.futures
+import time
+import os
+import traceback
+
+from core.error_handler import ProcessingError, ErrorHandler
+
+class DataPipeline:
+    """数据处理管道,提供高效的数据处理流程"""
+    
+    def __init__(self, name: str = "default_pipeline"):
+        self.name = name
+        self.steps = []
+        print(f"初始化流水线 '{name}'")
+        
+    def add_step(self, name: str, func: Callable) -> 'DataPipeline':
+        """添加处理步骤
+        
+        Args:
+            name: 步骤名称
+            func: 处理函数,接收一个DataFrame和可选参数,返回处理后的DataFrame
+            
+        Returns:
+            当前管道实例,支持链式调用
+        """
+        self.steps.append((name, func))
+        print(f"添加处理步骤: {name}")
+        return self
+    
+    @ErrorHandler.measure_performance
+    def process(self, data: pd.DataFrame, **kwargs) -> pd.DataFrame:
+        """执行所有处理步骤
+        
+        Args:
+            data: 输入数据
+            **kwargs: 传递给处理函数的额外参数
+            
+        Returns:
+            处理后的数据
+        """
+        result = data.copy()
+        
+        for name, func in self.steps:
+            start_time = time.time()
+            print(f"开始执行步骤: {name}")
+            
+            try:
+                # 执行处理步骤
+                result = func(result, **kwargs)
+                
+                # 记录处理时间和结果信息
+                elapsed = time.time() - start_time
+                print(f"步骤 {name} 在 {elapsed:.2f} 秒内完成,结果行数: {len(result)}")
+                
+            except Exception as e:
+                print(f"步骤 {name} 失败: {e}")
+                traceback.print_exc()
+                raise ProcessingError(f"处理步骤 {name} 失败: {e}")
+        
+        return result
+    
+    @ErrorHandler.measure_performance
+    def process_batch(self, data: pd.DataFrame, batch_size: int = 10000, **kwargs) -> pd.DataFrame:
+        """分批处理数据
+        
+        Args:
+            data: 输入数据
+            batch_size: 批次大小
+            **kwargs: 传递给处理函数的额外参数
+            
+        Returns:
+            处理后的数据
+        """
+        if len(data) <= batch_size:
+            return self.process(data, **kwargs)
+        
+        print(f"开始分批处理数据,总行数: {len(data)},批次大小: {batch_size}")
+        
+        # 计算批次数
+        num_batches = (len(data) + batch_size - 1) // batch_size
+        results = []
+        
+        for i in range(num_batches):
+            start_idx = i * batch_size
+            end_idx = min((i + 1) * batch_size, len(data))
+            batch = data.iloc[start_idx:end_idx].copy()
+            
+            print(f"处理批次 {i+1}/{num_batches},行数: {len(batch)}")
+            batch_result = self.process(batch, **kwargs)
+            results.append(batch_result)
+        
+        # 合并结果
+        result = pd.concat(results, ignore_index=True)
+        print(f"分批处理完成,总行数: {len(result)}")
+        
+        return result
+    
+    @ErrorHandler.measure_performance
+    def process_files_parallel(self, file_paths: List[Path], read_func: Callable[[Path], pd.DataFrame], 
+                             write_func: Callable[[pd.DataFrame, Path], None], output_dir: Path, 
+                             max_workers: Optional[int] = None, **kwargs) -> List[Path]:
+        """并行处理多个文件
+        
+        Args:
+            file_paths: 输入文件路径列表
+            read_func: 读取文件的函数,接收文件路径,返回DataFrame
+            write_func: 写入文件的函数,接收DataFrame和输出路径
+            output_dir: 输出目录
+            max_workers: 最大工作线程数
+            **kwargs: 传递给处理函数的额外参数
+            
+        Returns:
+            处理后的文件路径列表
+        """
+        if max_workers is None or max_workers <= 1 or len(file_paths) <= 1:
+            return self.process_files_sequential(file_paths, read_func, write_func, output_dir, **kwargs)
+        
+        print(f"开始并行处理{len(file_paths)}个文件")
+        output_paths = []
+        
+        # 确保输出目录存在
+        output_dir.mkdir(parents=True, exist_ok=True)
+        
+        # 定义处理单个文件的函数
+        def process_file(file_path):
+            try:
+                # 读取文件
+                data = read_func(file_path)
+                
+                # 处理数据
+                processed_data = self.process(data, **kwargs)
+                
+                # 确定输出路径
+                output_path = output_dir / f"processed_{file_path.name}"
+                
+                # 写入结果
+                write_func(processed_data, output_path)
+                
+                print(f"文件处理完成: {file_path.name} -> {output_path.name}")
+                return output_path
+                
+            except Exception as e:
+                print(f"处理文件失败: {file_path}: {e}")
+                traceback.print_exc()
+                return None
+        
+        # 使用线程池并行处理文件
+        with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
+            futures = {executor.submit(process_file, file_path): file_path for file_path in file_paths}
+            
+            for future in concurrent.futures.as_completed(futures):
+                file_path = futures[future]
+                try:
+                    output_path = future.result()
+                    if output_path:
+                        output_paths.append(output_path)
+                except Exception as e:
+                    print(f"获取处理结果失败: {file_path}: {e}")
+                    traceback.print_exc()
+        
+        print(f"并行处理完成,成功处理: {len(output_paths)}/{len(file_paths)}个文件")
+        return output_paths
+    
+    def process_files_sequential(self, file_paths: List[Path], read_func: Callable[[Path], pd.DataFrame], 
+                               write_func: Callable[[pd.DataFrame, Path], None], output_dir: Path, 
+                               **kwargs) -> List[Path]:
+        """顺序处理多个文件
+        
+        Args:
+            file_paths: 输入文件路径列表
+            read_func: 读取文件的函数,接收文件路径,返回DataFrame
+            write_func: 写入文件的函数,接收DataFrame和输出路径
+            output_dir: 输出目录
+            **kwargs: 传递给处理函数的额外参数
+            
+        Returns:
+            处理后的文件路径列表
+        """
+        print(f"开始顺序处理{len(file_paths)}个文件")
+        output_paths = []
+        
+        # 确保输出目录存在
+        output_dir.mkdir(parents=True, exist_ok=True)
+        
+        for file_path in file_paths:
+            try:
+                # 读取文件
+                data = read_func(file_path)
+                
+                # 处理数据
+                processed_data = self.process(data, **kwargs)
+                
+                # 确定输出路径
+                output_path = output_dir / f"processed_{file_path.name}"
+                
+                # 写入结果
+                write_func(processed_data, output_path)
+                
+                print(f"文件处理完成: {file_path.name} -> {output_path.name}")
+                output_paths.append(output_path)
+                
+            except Exception as e:
+                print(f"处理文件失败: {file_path}: {e}")
+                traceback.print_exc()
+        
+        print(f"顺序处理完成,成功处理: {len(output_paths)}/{len(file_paths)}个文件")
+        return output_paths
+    
+    @staticmethod
+    def create_csv_reader(usecols: Optional[List[str]] = None, dtype: Optional[Dict[str, Any]] = None, 
+                         **pandas_kwargs) -> Callable[[Path], pd.DataFrame]:
+        """创建CSV文件读取函数
+        
+        Args:
+            usecols: 需要读取的列
+            dtype: 列的数据类型
+            **pandas_kwargs: 传递给pd.read_csv的额外参数
+            
+        Returns:
+            读取函数
+        """
+        def read_csv(file_path: Path) -> pd.DataFrame:
+            return pd.read_csv(file_path, usecols=usecols, dtype=dtype, **pandas_kwargs)
+        return read_csv
+    
+    @staticmethod
+    def create_csv_writer(index: bool = False, **pandas_kwargs) -> Callable[[pd.DataFrame, Path], None]:
+        """创建CSV文件写入函数
+        
+        Args:
+            index: 是否写入索引
+            **pandas_kwargs: 传递给pd.to_csv的额外参数
+            
+        Returns:
+            写入函数
+        """
+        def write_csv(data: pd.DataFrame, file_path: Path) -> None:
+            data.to_csv(file_path, index=index, **pandas_kwargs)
+        return write_csv
+    
+    @staticmethod
+    def create_filter_step(filter_func: Callable[[pd.DataFrame], pd.Series], name: str = "filter_data") -> Tuple[str, Callable]:
+        """创建数据过滤步骤
+        
+        Args:
+            filter_func: 过滤函数,接收DataFrame返回布尔Series
+            name: 步骤名称
+            
+        Returns:
+            处理步骤元组(名称, 函数)
+        """
+        def filter_step(data: pd.DataFrame, **kwargs) -> pd.DataFrame:
+            mask = filter_func(data)
+            filtered_data = data[mask].copy()
+            print(f"过滤前行数: {len(data)}, 过滤后行数: {len(filtered_data)}, 过滤掉: {len(data) - len(filtered_data)}行")
+            return filtered_data
+        return (name, filter_step)
+    
+    @staticmethod
+    def create_transform_step(transform_func: Callable[[pd.DataFrame], pd.DataFrame], name: str = "transform_data") -> Tuple[str, Callable]:
+        """创建数据转换步骤
+        
+        Args:
+            transform_func: 转换函数,接收DataFrame返回转换后的DataFrame
+            name: 步骤名称
+            
+        Returns:
+            处理步骤元组(名称, 函数)
+        """
+        def transform_step(data: pd.DataFrame, **kwargs) -> pd.DataFrame:
+            result = transform_func(data)
+            print(f"转换完成: {name}, 输入行数: {len(data)}, 输出行数: {len(result)}")
+            return result
+        return (name, transform_step)
+    
+    @staticmethod
+    def create_column_mapping_step(mapping: Dict[str, str], name: str = "map_columns") -> Tuple[str, Callable]:
+        """创建列映射步骤
+        
+        Args:
+            mapping: 列名映射字典,键为原列名,值为新列名
+            name: 步骤名称
+            
+        Returns:
+            处理步骤元组(名称, 函数)
+        """
+        def map_columns(data: pd.DataFrame, **kwargs) -> pd.DataFrame:
+            result = data.rename(columns=mapping)
+            print(f"列映射完成,映射了 {len(mapping)} 列")
+            return result
+        return (name, map_columns)

+ 152 - 0
core/error_handler.py

@@ -0,0 +1,152 @@
+import sys
+import traceback
+from typing import Callable, Any, Optional, Dict, List, Type, Union
+from functools import wraps
+import time
+
+class ProcessingError(Exception):
+    """数据处理错误的基类"""
+    def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
+        self.message = message
+        self.details = details or {}
+        super().__init__(message)
+
+class DataValidationError(ProcessingError):
+    """数据验证错误"""
+    pass
+
+class ResourceNotFoundError(ProcessingError):
+    """资源未找到错误"""
+    pass
+
+class PluginError(ProcessingError):
+    """插件相关错误"""
+    pass
+
+class ConfigurationError(ProcessingError):
+    """配置错误"""
+    pass
+
+class EngineExecutionError(ProcessingError):
+    """引擎执行错误"""
+    pass
+
+class ErrorHandler:
+    """错误处理器,提供统一的异常处理机制"""
+    
+    @staticmethod
+    def handle_exceptions(func: Callable) -> Callable:
+        """装饰器:用于处理函数执行期间的异常"""
+        @wraps(func)
+        def wrapper(*args, **kwargs):
+            try:
+                return func(*args, **kwargs)
+            except Exception as e:
+                ErrorHandler.handle_exception(e, {"function": func.__name__})
+                raise
+        return wrapper
+
+    @staticmethod
+    def handle_exception(exc: Exception, context: Optional[Dict[str, Any]] = None) -> None:
+        """处理异常,记录日志并提供上下文信息"""
+        context = context or {}
+        
+        # 获取异常的堆栈跟踪
+        exc_type, exc_value, exc_traceback = sys.exc_info()
+        stack_trace = traceback.format_exception(exc_type, exc_value, exc_traceback)
+        
+        # 打印异常信息
+        error_message = f"异常: {type(exc).__name__}: {str(exc)}"
+        print(error_message)
+        
+        # 打印上下文信息
+        if context:
+            print(f"上下文信息: {context}")
+        
+        # 打印堆栈跟踪
+        print("堆栈跟踪:\n" + "".join(stack_trace))
+    
+    @staticmethod
+    def retry(max_attempts: int = 3, delay: float = 1.0, backoff: float = 2.0, 
+              exceptions: Union[Type[Exception], List[Type[Exception]]] = Exception):
+        """重试装饰器,用于自动重试可能失败的操作
+        
+        Args:
+            max_attempts: 最大尝试次数
+            delay: 初始延迟时间(秒)
+            backoff: 延迟时间的增长因子
+            exceptions: 需要捕获的异常类型
+        """
+        def decorator(func):
+            @wraps(func)
+            def wrapper(*args, **kwargs):
+                attempt = 1
+                current_delay = delay
+                
+                while attempt <= max_attempts:
+                    try:
+                        return func(*args, **kwargs)
+                    except exceptions as e:
+                        if attempt == max_attempts:
+                            print(f"重试{max_attempts}次后失败: {func.__name__}")
+                            raise
+                        
+                        print(f"尝试 {attempt}/{max_attempts} 失败: {func.__name__}, 错误: {e}")
+                        print(f"将在 {current_delay:.2f} 秒后重试...")
+                        
+                        time.sleep(current_delay)
+                        attempt += 1
+                        current_delay *= backoff
+            
+            return wrapper
+        return decorator
+    
+    @staticmethod
+    def validate_input(validator: Callable[[Any], bool], error_message: str = "输入验证失败"):
+        """输入验证装饰器,用于验证函数输入参数
+        
+        Args:
+            validator: 验证函数,接收函数的所有参数并返回布尔值
+            error_message: 验证失败时的错误消息
+        """
+        def decorator(func):
+            @wraps(func)
+            def wrapper(*args, **kwargs):
+                if not validator(*args, **kwargs):
+                    raise DataValidationError(error_message)
+                return func(*args, **kwargs)
+            return wrapper
+        return decorator
+    
+    @staticmethod
+    def measure_performance(func):
+        """性能测量装饰器,用于记录函数执行时间"""
+        @wraps(func)
+        def wrapper(*args, **kwargs):
+            start_time = time.time()
+            result = func(*args, **kwargs)
+            end_time = time.time()
+            execution_time = end_time - start_time
+            print(f"函数 {func.__name__} 执行时间: {execution_time:.4f} 秒")
+            return result
+        return wrapper
+    
+    @staticmethod
+    def safe_execute(fallback_value: Any = None, log_exception: bool = True):
+        """安全执行装饰器,捕获异常并返回默认值
+        
+        Args:
+            fallback_value: 发生异常时返回的默认值
+            log_exception: 是否记录异常信息
+        """
+        def decorator(func):
+            @wraps(func)
+            def wrapper(*args, **kwargs):
+                try:
+                    return func(*args, **kwargs)
+                except Exception as e:
+                    if log_exception:
+                        print(f"函数 {func.__name__} 执行失败: {e}")
+                    return fallback_value
+            return wrapper
+        return decorator

+ 175 - 0
core/optimized_processor.py

@@ -0,0 +1,175 @@
+from pathlib import Path
+from typing import Optional
+import traceback
+
+from .processors.built_in.lst import ZipCSVProcessor, RosbagProcessor, Config
+# from .processors.final_processor import FinalDataProcessor
+from core.processors.built_in.lst import data_precheck, run_cpp_engine, FinalDataProcessor
+
+
+
+def process_lst_data(
+    zip_data_path: Path,
+    output_base_dir: Path,
+    trafficlight_json_path: Optional[Path] = None,
+    utm_zone: int = 51,
+    x_offset: float = 0.0,
+    y_offset: float = 0.0,
+    continue_to_iterate: bool = False,
+) -> Optional[Path]:
+    """
+    Processes LST data using an optimized pipeline.
+
+    Args:
+        zip_data_path: Path to the input ZIP file
+        output_base_dir: Base directory for output
+        trafficlight_json_path: Optional path to traffic light JSON file
+        utm_zone: UTM zone for coordinate projection
+        x_offset: X offset for C++ engine
+        y_offset: Y offset for C++ engine
+        continue_to_iterate: Flag to control iteration continuation
+
+    Returns:
+        Path to the final merged_ObjState.csv file if successful, None otherwise
+    """
+    print(f"Starting LST data processing for: {zip_data_path.name}")
+    
+    # Validate input paths
+    if not zip_data_path.exists():
+        print(f"Error: Input ZIP file not found: {zip_data_path}")
+        return None
+        
+    if not trafficlight_json_path:
+        print(f"Warning: Traffic light JSON file not found: {trafficlight_json_path}")
+        trafficlight_json_path = None
+
+    try:
+        # Initialize configuration
+        config = Config(
+            zip_path=zip_data_path.resolve(),
+            output_path=output_base_dir.resolve(),
+            json_path=trafficlight_json_path.resolve() if trafficlight_json_path else None,
+            dbc_path=Path("_internal/VBox.dbc").resolve(),
+            engine_path=Path("_internal/engine").resolve(),
+            map_path=Path("_internal/data_map").resolve(),
+            utm_zone=utm_zone,
+            x_offset=x_offset,
+            y_offset=y_offset
+        )
+
+        # Process built-in data types
+        print("Processing built-in data types...")
+        zip_processor = ZipCSVProcessor(config)
+        zip_processor.process_zip()
+
+        # Process rosbag data if available
+        rosbag_processor = RosbagProcessor(config)
+        rosbag_processor.process_zip_for_rosbags()
+
+        # Run C++ engine for additional processing
+        if not run_cpp_engine(config):
+            raise RuntimeError("C++ engine execution failed")
+
+        # Validate processed data
+        if not data_precheck(config.output_dir):
+            raise ValueError("Data quality pre-check failed")
+
+        # Final processing of built-in data
+        print("Processing and merging built-in data...")
+        final_processor = FinalDataProcessor(config)
+        
+        if not final_processor.process():
+            raise RuntimeError("Final data processing failed")
+
+        final_csv_path = config.output_dir / "merged_ObjState.csv"
+
+        
+        return final_csv_path
+
+    except Exception as e:
+        print(f"Error: Processing failed for {zip_data_path.name}: {str(e)}")
+        print(f"Debug: Stacktrace: {traceback.format_exc()}")
+        return None
+
+
+def process_pgvil_data(
+    zip_data_path: Path,
+    output_base_dir: Path,
+    utm_zone: int = 51,
+    x_offset: float = 0.0,
+    y_offset: float = 0.0
+) -> Optional[Path]:
+    """处理PGVIL数据
+    
+    Args:
+        zip_data_path: ZIP数据文件路径
+        output_base_dir: 输出基础目录
+        utm_zone: UTM坐标系区域
+        x_offset: X坐标偏移量
+        y_offset: Y坐标偏移量
+        
+    Returns:
+        Optional[Path]: 处理后的CSV文件路径,处理失败则返回None
+    """
+    try:
+        # 确保输出目录存在
+        output_base_dir.mkdir(parents=True, exist_ok=True)
+        
+        # 解压ZIP文件
+        if not extract_zip_file(zip_data_path, output_base_dir):
+            return None
+            
+        # 查找所有PGVIL数据文件
+        pgvil_files = []
+        for root, _, files in os.walk(output_base_dir):
+            for file in files:
+                if file.lower().endswith(('.csv', '.json')):
+                    pgvil_files.append(Path(root) / file)
+                    
+        if not pgvil_files:
+            print(f"在 {output_base_dir} 中未找到PGVIL数据文件")
+            return None
+            
+        print(f"找到 {len(pgvil_files)} 个PGVIL数据文件")
+        
+        # 处理所有PGVIL文件
+        all_data = []
+        for pgvil_file in pgvil_files:
+            try:
+                # 读取PGVIL文件
+                if pgvil_file.suffix.lower() == '.csv':
+                    df = pd.read_csv(pgvil_file)
+                elif pgvil_file.suffix.lower() == '.json':
+                    with open(pgvil_file, 'r') as f:
+                        data = json.load(f)
+                    df = pd.DataFrame(data)
+                    
+                # 确保必要的列存在
+                required_cols = ['simTime', 'simFrame', 'playerId']
+                for col in required_cols:
+                    if col not in df.columns:
+                        df[col] = 0  # 添加默认值
+                        
+                all_data.append(df)
+                print(f"成功处理文件: {pgvil_file}")
+            except Exception as e:
+                print(f"处理文件 {pgvil_file} 时出错: {e}")
+        
+        if not all_data:
+            print("没有成功处理任何PGVIL文件")
+            return None
+            
+        # 合并所有数据
+        combined_df = pd.concat(all_data, ignore_index=True)
+        
+        # 保存处理后的数据
+        output_path = output_base_dir / "processed_pgvil_data.csv"
+        combined_df.to_csv(output_path, index=False)
+        print(f"成功处理所有PGVIL数据,结果保存到: {output_path}")
+        return output_path
+        
+    except Exception as e:
+        print(f"处理PGVIL数据时出错: {e}")
+        import traceback
+        traceback.print_exc()
+        return None

+ 106 - 0
core/plugin_interface.py

@@ -0,0 +1,106 @@
+from abc import ABC, abstractmethod
+from pathlib import Path
+import pandas as pd
+from typing import Dict, Any, Optional, Tuple
+import tempfile
+import zipfile
+
+class CustomDataProcessorPlugin(ABC):
+    """自定义数据处理插件的基类,提供通用方法"""
+    
+    @abstractmethod
+    def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+        """检查是否可以处理指定的数据文件夹"""
+        pass
+    
+    @abstractmethod
+    def get_required_columns(self) -> Dict[str, Any]:
+        """返回必需的列和它们的类型"""
+        pass
+
+    def process_data(self, zip_path: Path, folder_name: str, output_dir: Path) -> Optional[pd.DataFrame]:
+        """处理数据的主方法,返回处理后的DataFrame"""
+        try:
+            with tempfile.TemporaryDirectory() as temp_dir:
+                temp_path = Path(temp_dir)
+                
+                # 提取数据文件
+                csv_files = self._extract_files(zip_path, folder_name, temp_path)
+                if not csv_files:
+                    return None
+                
+                # 处理数据
+                df = self._process_extracted_files(csv_files)
+                if df is None or df.empty:
+                    return None
+                
+                return df
+                
+        except Exception as e:
+            print(f"处理数据时发生错误: {e}")
+            import traceback
+            traceback.print_exc()
+            return None
+
+    def _extract_files(self, zip_path: Path, folder_name: str, temp_path: Path) -> list:
+        """从ZIP文件中提取数据文件,不限制文件格式"""
+        try:
+            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
+                # 获取指定文件夹下的所有文件,不限制格式
+                files = [name for name in zip_ref.namelist() 
+                        if name.startswith(f"{folder_name}/")]
+                
+                if not files:
+                    print(f"在{folder_name}中未找到数据文件")
+                    return []
+                    
+                # 解压所有文件
+                for file_name in files:
+                    zip_ref.extract(file_name, temp_path)
+                
+                # 返回解压后的所有文件路径
+                return list(temp_path.glob(f"{folder_name}/*"))
+                
+        except Exception as e:
+            print(f"提取文件时发生错误: {e}")
+            return []
+
+    @abstractmethod
+    def _process_extracted_files(self, file_paths: list) -> Optional[pd.DataFrame]:
+        """处理提取的文件"""
+        pass
+
+    def _validate_data(self, df: pd.DataFrame) -> bool:
+        """验证数据是否满足要求"""
+        required_cols = self.get_required_columns()
+        
+        # 检查必需列是否存在
+        missing_cols = [col for col in required_cols.keys() if col not in df.columns]
+        if missing_cols:
+            print(f"错误:缺少必需列: {missing_cols}")
+            return False
+            
+        # 检查数据类型
+        for col, dtype in required_cols.items():
+            try:
+                df[col] = df[col].astype(dtype)
+            except Exception as e:
+                print(f"错误:列 {col} 的数据类型转换失败: {e}")
+                return False
+                
+        return True
+
+    def _preprocess_data(self, df: pd.DataFrame) -> pd.DataFrame:
+        """数据预处理的通用方法"""
+        # 移除重复行
+        df = df.drop_duplicates()
+        
+        # 确保时间戳列的精度为3位
+        if 'simTime' in df.columns:
+            df['simTime'] = df['simTime'].round(3)
+        
+        # 按时间排序
+        if 'simTime' in df.columns:
+            df.sort_values('simTime', inplace=True)
+            
+        return df

+ 83 - 0
core/plugin_manager.py

@@ -0,0 +1,83 @@
+import importlib
+import inspect
+from pathlib import Path
+from typing import Dict, List, Type, Optional
+import sys
+
+from .plugin_interface import CustomDataProcessorPlugin
+
+class PluginManager:
+    """Manages the discovery and loading of data processor plugins."""
+    
+    def __init__(self, plugin_dir: Path):
+        self.plugin_dir = plugin_dir
+        self.plugins: Dict[str, Type[CustomDataProcessorPlugin]] = {}
+        self._load_plugins()
+    
+    def _load_plugins(self) -> None:
+        """发现并加载插件目录中的所有插件"""
+        if not self.plugin_dir.exists():
+            print(f"未找到插件目录: {self.plugin_dir}")
+            return
+            
+        # 将插件目录添加到Python路径
+        sys.path.insert(0, str(self.plugin_dir.parent))
+        
+        try:
+            # 查找插件目录中的Python文件
+            for plugin_file in self.plugin_dir.glob("*.py"):
+                if plugin_file.name == "__init__.py":
+                    continue
+                    
+                try:
+                    # 修改模块导入方式,直接使用文件名
+                    module_name = f"plugins.{plugin_file.stem}"
+                    print(f"尝试加载插件模块: {module_name}")
+                        
+                    module = importlib.import_module(module_name)
+                    
+                    # 在模块中查找插件类
+                    for name, obj in inspect.getmembers(module):
+                        if (inspect.isclass(obj) 
+                            and issubclass(obj, CustomDataProcessorPlugin) 
+                            and obj != CustomDataProcessorPlugin):
+                            # 从类名中获取关键词(移除DataProcessor或Processor后缀)
+                            keyword = name.lower().replace('dataprocessor', '').replace('processor', '')
+                            self.plugins[keyword] = obj
+                            print(f"成功加载插件: {name}, 关键词: {keyword}")
+                            
+                except ImportError as e:
+                    print(f"导入插件 {plugin_file.name} 失败: {e}")
+                except Exception as e:
+                    print(f"加载插件 {plugin_file.name} 时出错: {e}")
+                    
+        finally:
+            # 从Python路径中移除插件目录
+            if str(self.plugin_dir.parent) in sys.path:
+                sys.path.remove(str(self.plugin_dir.parent))
+            
+    def get_plugins(self) -> List[Type[CustomDataProcessorPlugin]]:
+        """Returns a list of all loaded plugin classes."""
+        return list(self.plugins.values())
+    
+    def find_plugin_by_folder_name(self, folder_name: str) -> Optional[Type[CustomDataProcessorPlugin]]:
+        """根据文件夹名称查找匹配的插件"""
+        folder_name = folder_name.lower()
+        for keyword, plugin_class in self.plugins.items():
+            if keyword in folder_name:
+                return plugin_class
+        return None
+    
+    def get_plugin_for_data(self, zip_path: Path, folder_name: str) -> Type[CustomDataProcessorPlugin]:
+        """查找能处理给定数据的插件"""
+        # 首先通过文件夹名称匹配插件
+        plugin_class = self.find_plugin_by_folder_name(folder_name)
+        if plugin_class:
+            try:
+                plugin = plugin_class()
+                if plugin.can_handle(zip_path, folder_name):
+                    return plugin_class
+            except Exception as e:
+                print(f"检查插件 {plugin_class.__name__} 时出错: {e}")
+                
+        return None

BIN
core/processors/__pycache__/final_processor.cpython-313.pyc


+ 24 - 0
core/processors/built_in/__init__.py

@@ -0,0 +1,24 @@
+
+from .lst import (
+    ZipCSVProcessor, 
+    RosbagProcessor, 
+    FinalDataProcessor,
+    Config,
+    run_cpp_engine,
+    data_precheck,
+    get_base_path
+)
+
+
+
+__all__ = [
+   
+    'ZipCSVProcessor',
+    'RosbagProcessor',
+    'FinalDataProcessor',
+
+    'Config',
+    'run_cpp_engine',
+    'data_precheck',
+    'get_base_path'
+]

BIN
core/processors/built_in/__pycache__/__init__.cpython-313.pyc


BIN
core/processors/built_in/__pycache__/base.cpython-313.pyc


BIN
core/processors/built_in/__pycache__/lst.cpython-313.pyc


BIN
core/processors/built_in/__pycache__/pgvil.cpython-313.pyc


BIN
core/processors/built_in/__pycache__/processor.cpython-313.pyc


+ 1449 - 0
core/processors/built_in/lst.py

@@ -0,0 +1,1449 @@
+import zipfile
+import sqlite3
+import csv
+import tempfile
+from pathlib import Path
+from typing import List, Dict, Tuple, Optional, Any, NamedTuple
+import cantools
+import os
+import subprocess
+import numpy as np
+import pandas as pd
+from collections import Counter
+from datetime import datetime
+import argparse
+import sys
+from pyproj import Proj
+from bagpy.bagreader import bagreader
+import shutil
+import json
+from dataclasses import dataclass, field
+
+# --- Constants ---
+PLAYER_ID_EGO = 1
+PLAYER_ID_OBJ = 2
+DEFAULT_TYPE = 1
+OUTPUT_CSV_OBJSTATE = "ObjState.csv"
+OUTPUT_CSV_TEMP_OBJSTATE = "ObjState_temp_intermediate.csv" # Should be eliminated
+OUTPUT_CSV_EGOSTATE = "EgoState.csv" # Not used in final merge? Check logic if needed.
+OUTPUT_CSV_MERGED = "merged_ObjState.csv"
+OUTPUT_CSV_OBU = "OBUdata.csv"
+OUTPUT_CSV_LANEMAP = "LaneMap.csv"
+OUTPUT_CSV_EGOMAP = "EgoMap.csv"
+OUTPUT_CSV_FUNCTION = "Function.csv"
+ROADMARK_CSV = "RoadMark.csv"
+
+# --- Configuration Class ---
+@dataclass
+class Config:
+    """Holds configuration paths and settings."""
+    zip_path: Path
+    output_path: Path
+    json_path: Optional[Path]  # Make json_path optional
+    dbc_path: Optional[Path] = None
+    engine_path: Optional[Path] = None
+    map_path: Optional[Path] = None
+    utm_zone: int = 51 # Example UTM zone
+    x_offset: float = 0.0
+    y_offset: float = 0.0
+
+    # Derived paths
+    output_dir: Path = field(init=False)
+
+    def __post_init__(self):
+        # Use output_path directly as output_dir to avoid nested directories
+        self.output_dir = self.output_path
+        self.output_dir.mkdir(parents=True, exist_ok=True)
+
+
+# --- Zip/CSV Processing ---
+class ZipCSVProcessor:
+    """Processes DB files within a ZIP archive to generate CSV data."""
+
+    # Define column mappings more clearly
+    EGO_COLS_NEW = [
+        "simTime", "simFrame", "playerId", "v", "speedX", "speedY",
+        "posH", "speedH", "posX", "posY", "accelX", "accelY",
+        "travelDist", "composite_v", "relative_dist", "type" # Added type
+    ]
+    OBJ_COLS_OLD_SUFFIXED = [
+        "v_obj", "speedX_obj", "speedY_obj", "posH_obj", "speedH_obj",
+        "posX_obj", "posY_obj", "accelX_obj", "accelY_obj", "travelDist_obj"
+    ]
+    OBJ_COLS_MAPPING = {old: new for old, new in zip(OBJ_COLS_OLD_SUFFIXED, EGO_COLS_NEW[3:13])} # Map suffixed cols to standard names
+
+    def __init__(self, config: Config):
+        self.config = config
+        self.dbc = self._load_dbc(config.dbc_path)
+        self.projection = Proj(proj='utm', zone=config.utm_zone, ellps='WGS84', preserve_units='m')
+        self._init_table_config()
+        self._init_keyword_mapping()
+
+    def _load_dbc(self, dbc_path: Optional[Path]) -> Optional[cantools.db.Database]:
+        if not dbc_path or not dbc_path.exists():
+            print("DBC path not provided or file not found.")
+            return None
+        try:
+            return cantools.db.load_file(dbc_path)
+        except Exception as e:
+            print(f"DBC loading failed: {e}")
+            return None
+
+    def _init_table_config(self):
+        """Initializes configurations for different table types."""
+        self.table_config = {
+            "gnss_table": self._get_gnss_config(),
+            "can_table": self._get_can_config()
+        }
+
+    def _get_gnss_config(self):
+        # Keep relevant columns, adjust mapping as needed
+        return {
+            "output_columns": self.EGO_COLS_NEW, # Use the standard ego columns + type
+            "mapping": { # Map output columns to source DB columns/signals
+                "simTime": ("second", "usecond"),
+                "simFrame": "ID",
+                "v": "speed",
+                "speedY": "y_speed",
+                "speedX": "x_speed",
+                "posH": "yaw",
+                "speedH": "yaw_rate",
+                "posX": "latitude_dd",  # Source before projection
+                "posY": "longitude_dd", # Source before projection
+                "accelX": "x_acceleration",
+                "accelY": "y_acceleration",
+                "travelDist": "total_distance",
+                # composite_v/relative_dist might not be direct fields in GNSS, handle later if needed
+                "composite_v": "speed", # Placeholder, adjust if needed
+                "relative_dist": None,  # Placeholder, likely not in GNSS data
+                "type": None # Will be set later
+            },
+            "db_columns": ["ID", "second", "usecond", "speed", "y_speed", "x_speed",
+                           "yaw", "yaw_rate", "latitude_dd", "longitude_dd",
+                           "x_acceleration", "y_acceleration", "total_distance"] # Actual cols to SELECT
+        }
+
+    def _get_can_config(self):
+        # Define columns needed from DB/CAN signals for both EGO and OBJ
+        return {
+             "mapping": { # Map unified output columns to CAN signals or direct fields
+                 # EGO mappings (VUT = Vehicle Under Test)
+                "simTime": ("second", "usecond"),
+                "simFrame": "ID",
+                "canid": "canid", # Keep CAN ID for reference if needed
+                "v": "VUT_Speed_mps",
+                "speedX": "VUT_Speed_x_mps",
+                "speedY": "VUT_Speed_y_mps",
+                "speedH": "VUT_Yaw_Rate",
+                "posX": "VUT_GPS_Latitude",   # Source before projection
+                "posY": "VUT_GPS_Longitude",  # Source before projection
+                "posH": "VUT_Heading",
+                "accelX": "VUT_Acc_X",
+                "accelY": "VUT_Acc_Y",
+                # OBJ mappings (UFO = Unidentified Flying Object / Other Vehicle)
+                "v_obj": "Speed_mps",
+                "speedX_obj": "UFO_Speed_x_mps",
+                "speedY_obj": "UFO_Speed_y_mps",
+                "speedH_obj": "Yaw_Rate",
+                "posX_obj": "GPS_Latitude",    # Source before projection
+                "posY_obj": "GPS_Longitude",   # Source before projection
+                "posH_obj": "Heading",
+                "accelX_obj": "Acc_X",
+                "accelY_obj": "Acc_Y",
+                # Relative Mappings
+                "composite_v": "VUT_Rel_speed_long_mps",
+                "relative_dist": "VUT_Dist_MRP_Abs",
+                # travelDist often calculated, not direct CAN signal
+                "travelDist": None, # Placeholder
+                "travelDist_obj": None # Placeholder
+             },
+             "db_columns": ["ID", "second", "usecond", "timestamp", "canid", "len", "frame"] # Core DB columns
+        }
+
+    def _init_keyword_mapping(self):
+        """Maps keywords in filenames to table configurations and output CSV names."""
+        self.keyword_mapping = {
+            "gnss": ("gnss_table", OUTPUT_CSV_OBJSTATE), # GNSS likely represents ego, writing to ObjState first? Revisit logic if needed.
+            "can2": ("can_table", OUTPUT_CSV_OBJSTATE), # Process CAN data into the combined ObjState file
+        }
+
+    def process_zip(self) -> None:
+        """Extracts and processes DB files from the configured ZIP path."""
+        print(f"Processing ZIP: {self.config.zip_path}")
+        output_dir = self.config.output_dir # Already created in Config
+
+        try:
+            with zipfile.ZipFile(self.config.zip_path, "r") as zip_ref:
+                db_files_to_process = []
+                for file_info in zip_ref.infolist():
+                    # Check if it's a DB file in the CANdata directory
+                    if 'CANdata/' in file_info.filename and file_info.filename.endswith('.db'):
+                         # Check if the filename contains any of the keywords
+                        match = self._match_keyword(file_info.filename)
+                        if match:
+                            table_type, csv_name = match
+                            db_files_to_process.append((file_info, table_type, csv_name))
+
+                if not db_files_to_process:
+                    print("No relevant DB files found in CANdata/ matching keywords.")
+                    return
+
+                # Process matched DB files
+                with tempfile.TemporaryDirectory() as tmp_dir_str:
+                    tmp_dir = Path(tmp_dir_str)
+                    for file_info, table_type, csv_name in db_files_to_process:
+                        print(f"Processing DB: {file_info.filename} for table type {table_type}")
+                        extracted_path = tmp_dir / Path(file_info.filename).name
+                        try:
+                            # Extract the specific DB file
+                            with zip_ref.open(file_info.filename) as source, open(extracted_path, "wb") as target:
+                                shutil.copyfileobj(source, target)
+
+                            # Process the extracted DB file
+                            self._process_db_file(extracted_path, output_dir, table_type, csv_name)
+
+                        except (sqlite3.Error, pd.errors.EmptyDataError, FileNotFoundError, KeyError) as e:
+                             print(f"Error processing DB file {file_info.filename}: {e}")
+                        except Exception as e:
+                            print(f"Unexpected error processing DB file {file_info.filename}: {e}")
+                        finally:
+                            if extracted_path.exists():
+                                extracted_path.unlink() # Clean up extracted file
+
+        except zipfile.BadZipFile:
+            print(f"Error: Bad ZIP file: {self.config.zip_path}")
+        except FileNotFoundError:
+            print(f"Error: ZIP file not found: {self.config.zip_path}")
+        except Exception as e:
+            print(f"An error occurred during ZIP processing: {e}")
+
+
+    def _match_keyword(self, filename: str) -> Optional[Tuple[str, str]]:
+        """Finds the first matching keyword configuration for a filename."""
+        for keyword, (table_type, csv_name) in self.keyword_mapping.items():
+            if keyword in filename:
+                return table_type, csv_name
+        return None
+
+    def _process_db_file(
+        self, db_path: Path, output_dir: Path, table_type: str, csv_name: str
+    ) -> None:
+        """Connects to SQLite DB and processes the specified table type."""
+        output_csv_path = output_dir / csv_name
+        try:
+            # Use URI for read-only connection
+            conn_str = f"file:{db_path}?mode=ro"
+            with sqlite3.connect(conn_str, uri=True) as conn:
+                cursor = conn.cursor()
+                if not self._check_table_exists(cursor, table_type):
+                     print(f"Table '{table_type}' does not exist in {db_path.name}. Skipping.")
+                     return
+                if self._check_table_empty(cursor, table_type):
+                    print(f"Table '{table_type}' in {db_path.name} is empty. Skipping.")
+                    return
+
+                print(f"Exporting data from table '{table_type}' to {output_csv_path}")
+                if table_type == "can_table":
+                    self._process_can_table_optimized(cursor, output_csv_path)
+                elif table_type == "gnss_table":
+                     # Pass output_path directly, avoid intermediate steps
+                    self._process_gnss_table(cursor, output_csv_path)
+                else:
+                    print(f"Warning: No specific processor for table type '{table_type}'. Skipping.")
+
+        except sqlite3.OperationalError as e:
+             print(f"Database operational error for {db_path.name}: {e}. Check file integrity/permissions.")
+        except sqlite3.DatabaseError as e:
+            print(f"Database error connecting to {db_path.name}: {e}")
+        except Exception as e:
+            print(f"Unexpected error processing DB {db_path.name}: {e}")
+
+    def _check_table_exists(self, cursor, table_name: str) -> bool:
+        """Checks if a table exists in the database."""
+        try:
+            cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?;", (table_name,))
+            return cursor.fetchone() is not None
+        except sqlite3.Error as e:
+            print(f"Error checking existence of table {table_name}: {e}")
+            return False # Assume not exists on error
+
+
+    def _check_table_empty(self, cursor, table_name: str) -> bool:
+        """Checks if a table is empty."""
+        try:
+            cursor.execute(f"SELECT COUNT(*) FROM {table_name}") # Use COUNT(*) for efficiency
+            count = cursor.fetchone()[0]
+            return count == 0
+        except sqlite3.Error as e:
+            # If error occurs (e.g., table doesn't exist after check - race condition?), treat as problematic/empty
+            print(f"Error checking if table {table_name} is empty: {e}")
+            return True
+
+    def _process_gnss_table(self, cursor, output_path: Path) -> None:
+        """Processes gnss_table data and writes directly to CSV."""
+        config = self.table_config["gnss_table"]
+        db_columns = config["db_columns"]
+        output_columns = config["output_columns"]
+        mapping = config["mapping"]
+
+        try:
+            cursor.execute(f"SELECT {', '.join(db_columns)} FROM gnss_table")
+            rows = cursor.fetchall()
+            if not rows:
+                print("No data found in gnss_table.")
+                return
+
+            processed_data = []
+            for row in rows:
+                row_dict = dict(zip(db_columns, row))
+                record = {}
+
+                # Calculate simTime
+                record["simTime"] = round(row_dict.get("second", 0) + row_dict.get("usecond", 0) / 1e6, 2)
+
+                # Map other columns
+                for out_col in output_columns:
+                    if out_col == "simTime": continue # Already handled
+                    if out_col == "playerId":
+                         record[out_col] = PLAYER_ID_EGO # Assuming GNSS is ego
+                         continue
+                    if out_col == "type":
+                         record[out_col] = DEFAULT_TYPE
+                         continue
+
+                    source_info = mapping.get(out_col)
+                    if source_info is None:
+                         record[out_col] = 0.0 # Or np.nan if preferred
+                    elif isinstance(source_info, tuple):
+                         # This case was only for simTime, handled above
+                         record[out_col] = 0.0
+                    else: # Direct mapping from db_columns
+                         raw_value = row_dict.get(source_info)
+                         if raw_value is not None:
+                              # Handle projection for position columns
+                             if out_col == "posX":
+                                 # Assuming source_info = "latitude_dd"
+                                 lat = row_dict.get(mapping["posX"])
+                                 lon = row_dict.get(mapping["posY"])
+                                 if lat is not None and lon is not None:
+                                     proj_x, _ = self.projection(lon, lat)
+                                     record[out_col] = round(proj_x, 6)
+                                 else:
+                                     record[out_col] = 0.0
+                             elif out_col == "posY":
+                                 # Assuming source_info = "longitude_dd"
+                                 lat = row_dict.get(mapping["posX"])
+                                 lon = row_dict.get(mapping["posY"])
+                                 if lat is not None and lon is not None:
+                                     _, proj_y = self.projection(lon, lat)
+                                     record[out_col] = round(proj_y, 6)
+                                 else:
+                                     record[out_col] = 0.0
+                             elif out_col in ["composite_v", "relative_dist"]:
+                                 # Handle these based on source if available, else default
+                                 record[out_col] = round(float(raw_value), 3) if source_info else 0.0
+                             else:
+                                 # General case: round numeric values
+                                 try:
+                                      record[out_col] = round(float(raw_value), 3)
+                                 except (ValueError, TypeError):
+                                      record[out_col] = raw_value # Keep as is if not numeric
+                         else:
+                            record[out_col] = 0.0 # Default for missing source data
+
+                processed_data.append(record)
+
+            if processed_data:
+                df_final = pd.DataFrame(processed_data)[output_columns] # Ensure column order
+                df_final.to_csv(output_path, index=False, encoding="utf-8")
+                print(f"Successfully wrote GNSS data to {output_path}")
+            else:
+                 print("No processable records found in gnss_table.")
+
+        except sqlite3.Error as e:
+            print(f"SQL error during GNSS processing: {e}")
+        except Exception as e:
+            print(f"Unexpected error during GNSS processing: {e}")
+
+
+    def _process_can_table_optimized(self, cursor, output_path: Path) -> None:
+        """Processes CAN data directly into the final merged DataFrame format."""
+        config = self.table_config["can_table"]
+        db_columns = config["db_columns"]
+        mapping = config["mapping"]
+
+        try:
+            cursor.execute(f"SELECT {', '.join(db_columns)} FROM can_table")
+            rows = cursor.fetchall()
+            if not rows:
+                print("No data found in can_table.")
+                return
+
+            all_records = []
+            for row in rows:
+                row_dict = dict(zip(db_columns, row))
+                # Decode CAN frame if DBC is available
+                decoded_signals = self._decode_can_frame(row_dict)
+                # Create a unified record combining DB fields and decoded signals
+                record = self._create_unified_can_record(row_dict, decoded_signals, mapping)
+                if record: # Only add if parsing was successful
+                     all_records.append(record)
+
+            if not all_records:
+                print("No CAN records could be successfully processed.")
+                return
+
+            # Convert raw records to DataFrame for easier manipulation
+            df_raw = pd.DataFrame(all_records)
+
+            # Separate EGO and OBJ data based on available columns
+            df_ego = self._extract_vehicle_data(df_raw, PLAYER_ID_EGO)
+            df_obj = self._extract_vehicle_data(df_raw, PLAYER_ID_OBJ)
+
+            # Project coordinates
+            df_ego = self._project_coordinates(df_ego, 'posX', 'posY')
+            df_obj = self._project_coordinates(df_obj, 'posX', 'posY') # Use same column names after extraction
+
+             # Add calculated/default columns
+            df_ego['type'] = DEFAULT_TYPE
+            df_obj['type'] = DEFAULT_TYPE
+            # Note: travelDist is often calculated later or not available directly
+
+            # Ensure both have the same columns before merging
+            final_columns = self.EGO_COLS_NEW # Target columns
+            df_ego = df_ego.reindex(columns=final_columns)
+            df_obj = df_obj.reindex(columns=final_columns)
+
+            # Merge EGO and OBJ dataframes
+            df_merged = pd.concat([df_ego, df_obj], ignore_index=True)
+
+            # Sort and clean up
+            df_merged.sort_values(by=["simTime", "simFrame", "playerId"], inplace=True)
+            df_merged.reset_index(drop=True, inplace=True)
+
+            # Fill potential NaNs introduced by reindexing or missing data
+            # Choose appropriate fill strategy (e.g., 0, forward fill, or leave as NaN)
+            df_merged.fillna(0.0, inplace=True) # Example: fill with 0.0
+
+            # Save the final merged DataFrame
+            df_merged.to_csv(output_path, index=False, encoding="utf-8")
+            print(f"Successfully processed CAN data and wrote merged output to {output_path}")
+
+        except sqlite3.Error as e:
+            print(f"SQL error during CAN processing: {e}")
+        except KeyError as e:
+             print(f"Key error during CAN processing - mapping issue? Missing key: {e}")
+        except Exception as e:
+            print(f"Unexpected error during CAN processing: {e}")
+            import traceback
+            traceback.print_exc() # Print detailed traceback for debugging
+
+
+    def _decode_can_frame(self, row_dict: Dict) -> Dict[str, Any]:
+        """Decodes CAN frame using DBC file if available."""
+        decoded_signals = {}
+        if self.dbc and 'canid' in row_dict and 'frame' in row_dict and 'len' in row_dict:
+            can_id = row_dict['canid']
+            frame_bytes = bytes(row_dict['frame'][:row_dict['len']]) # Ensure correct length
+            try:
+                message_def = self.dbc.get_message_by_frame_id(can_id)
+                decoded_signals = message_def.decode(frame_bytes, decode_choices=False, allow_truncated=True) # Allow truncated
+            except KeyError:
+                # Optional: print(f"Warning: CAN ID 0x{can_id:X} not found in DBC.")
+                pass # Ignore unknown IDs silently
+            except ValueError as e:
+                 print(f"Warning: Decoding ValueError for CAN ID 0x{can_id:X} (length {row_dict['len']}, data: {frame_bytes.hex()}): {e}")
+            except Exception as e:
+                print(f"Warning: Error decoding CAN ID 0x{can_id:X}: {e}")
+        return decoded_signals
+
+    def _create_unified_can_record(self, row_dict: Dict, decoded_signals: Dict, mapping: Dict) -> Optional[Dict[str, Any]]:
+        """Creates a single record combining DB fields and decoded signals based on mapping."""
+        record = {}
+        try:
+            # Handle time and frame ID first
+            record["simTime"] = round(row_dict.get("second", 0) + row_dict.get("usecond", 0) / 1e6, 2)
+            record["simFrame"] = row_dict.get("ID")
+            record["canid"] = f"0x{row_dict.get('canid', 0):X}" # Store CAN ID if needed
+
+            # Populate record using the mapping config
+            for target_col, source_info in mapping.items():
+                if target_col in ["simTime", "simFrame", "canid"]: continue # Already handled
+                if isinstance(source_info, tuple): continue # Should only be time
+
+                # source_info is now the signal name (or None)
+                signal_name = source_info
+                if signal_name and signal_name in decoded_signals:
+                    # Value from decoded CAN signal
+                    raw_value = decoded_signals[signal_name]
+                    try:
+                        # Apply scaling/offset if needed (cantools handles this)
+                        # Round appropriately, especially for floats
+                        if isinstance(raw_value, (int, float)):
+                            # Be cautious with lat/lon precision before projection
+                            if "Latitude" in target_col or "Longitude" in target_col:
+                                record[target_col] = float(raw_value) # Keep precision for projection
+                            else:
+                                record[target_col] = round(float(raw_value), 6)
+                        else:
+                             record[target_col] = raw_value # Keep non-numeric as is (e.g., enums)
+                    except (ValueError, TypeError):
+                        record[target_col] = raw_value # Assign raw value if conversion fails
+                # If signal not found or source_info is None, leave it empty for now
+                # Will be filled later or during DataFrame processing
+
+            return record
+
+        except Exception as e:
+             print(f"Error creating unified record for row {row_dict.get('ID')}: {e}")
+             return None
+
+
+    def _extract_vehicle_data(self, df_raw: pd.DataFrame, player_id: int) -> pd.DataFrame:
+        """Extracts and renames columns for a specific vehicle (EGO or OBJ)."""
+        df_vehicle = pd.DataFrame()
+        df_vehicle["simTime"] = df_raw["simTime"]
+        df_vehicle["simFrame"] = df_raw["simFrame"]
+        df_vehicle["playerId"] = player_id
+
+        if player_id == PLAYER_ID_EGO:
+            # Select EGO columns (not ending in _obj) + relative columns
+            ego_cols = {target: source for target, source in self.table_config['can_table']['mapping'].items()
+                        if source and not isinstance(source, tuple) and not target.endswith('_obj')}
+            rename_map = {}
+            select_cols_raw = []
+            for target_col, source_info in ego_cols.items():
+                 if source_info: # Mapped signal/field name in df_raw
+                    select_cols_raw.append(target_col) # Column names in df_raw are already target names
+                    rename_map[target_col] = target_col # No rename needed here
+
+            # Include relative speed and distance for ego frame
+            relative_cols = ["composite_v", "relative_dist"]
+            select_cols_raw.extend(relative_cols)
+            for col in relative_cols:
+                 rename_map[col] = col
+
+            # Select and rename
+            df_vehicle_temp = df_raw[list(set(select_cols_raw) & set(df_raw.columns))] # Select available columns
+            df_vehicle = pd.concat([df_vehicle, df_vehicle_temp], axis=1)
+
+
+        elif player_id == PLAYER_ID_OBJ:
+            # Select OBJ columns (ending in _obj)
+            obj_cols = {target: source for target, source in self.table_config['can_table']['mapping'].items()
+                        if source and not isinstance(source, tuple) and target.endswith('_obj')}
+            rename_map = {}
+            select_cols_raw = []
+            for target_col, source_info in obj_cols.items():
+                if source_info:
+                     select_cols_raw.append(target_col) # Original _obj column name
+                     # Map from VUT_XXX_obj -> VUT_XXX
+                     rename_map[target_col] = self.OBJ_COLS_MAPPING.get(target_col, target_col) # Rename to standard name
+
+            # Select and rename
+            df_vehicle_temp = df_raw[list(set(select_cols_raw) & set(df_raw.columns))] # Select available columns
+            df_vehicle_temp.rename(columns=rename_map, inplace=True)
+            df_vehicle = pd.concat([df_vehicle, df_vehicle_temp], axis=1)
+
+            # Copy relative speed/distance from ego calculation (assuming it's relative *to* ego)
+            if "composite_v" in df_raw.columns:
+                df_vehicle["composite_v"] = df_raw["composite_v"]
+            if "relative_dist" in df_raw.columns:
+                df_vehicle["relative_dist"] = df_raw["relative_dist"]
+
+
+        # Drop rows where essential position data might be missing after selection/renaming
+        # Adjust required columns as necessary
+        required_pos = ['posX', 'posY', 'posH']
+        df_vehicle.dropna(subset=[col for col in required_pos if col in df_vehicle.columns], inplace=True)
+
+        return df_vehicle
+
+    def _project_coordinates(self, df: pd.DataFrame, lat_col: str, lon_col: str) -> pd.DataFrame:
+        """Applies UTM projection to latitude and longitude columns."""
+        if lat_col in df.columns and lon_col in df.columns:
+            # Ensure data is numeric and handle potential errors/missing values
+            lat = pd.to_numeric(df[lat_col], errors='coerce')
+            lon = pd.to_numeric(df[lon_col], errors='coerce')
+            valid_coords = lat.notna() & lon.notna()
+
+            if valid_coords.any():
+                x, y = self.projection(lon[valid_coords].values, lat[valid_coords].values)
+                # Update DataFrame, assign NaN where original coords were invalid
+                df.loc[valid_coords, lat_col] = np.round(x, 6) # Overwrite latitude col with X
+                df.loc[valid_coords, lon_col] = np.round(y, 6) # Overwrite longitude col with Y
+                df.loc[~valid_coords, [lat_col, lon_col]] = np.nan # Set invalid coords to NaN
+            else:
+                 # No valid coordinates found, set columns to NaN or handle as needed
+                 df[lat_col] = np.nan
+                 df[lon_col] = np.nan
+
+             # Rename columns AFTER projection for clarity
+            df.rename(columns={lat_col: 'posX', lon_col: 'posY'}, inplace=True)
+        else:
+            # Ensure columns exist even if projection didn't happen
+            if 'posX' not in df.columns: df['posX'] = np.nan
+            if 'posY' not in df.columns: df['posY'] = np.nan
+            print(f"Warning: Latitude ('{lat_col}') or Longitude ('{lon_col}') columns not found for projection.")
+
+        return df
+
+
+# --- Polynomial Fitting (Largely unchanged, minor cleanup) ---
+class PolynomialCurvatureFitting:
+    """Calculates curvature and its derivative using polynomial fitting."""
+    def __init__(self, lane_map_path: Path, degree: int = 3):
+        self.lane_map_path = lane_map_path
+        self.degree = degree
+        self.data = self._load_data()
+        if self.data is not None:
+            self.points = self.data[["centerLine_x", "centerLine_y"]].values
+            self.x_data, self.y_data = self.points[:, 0], self.points[:, 1]
+        else:
+            self.points = np.empty((0, 2))
+            self.x_data, self.y_data = np.array([]), np.array([])
+
+    def _load_data(self) -> Optional[pd.DataFrame]:
+        """Loads lane map data safely."""
+        if not self.lane_map_path.exists() or self.lane_map_path.stat().st_size == 0:
+            print(f"Warning: LaneMap file not found or empty: {self.lane_map_path}")
+            return None
+        try:
+            return pd.read_csv(self.lane_map_path)
+        except pd.errors.EmptyDataError:
+            print(f"Warning: LaneMap file is empty: {self.lane_map_path}")
+            return None
+        except Exception as e:
+            print(f"Error reading LaneMap file {self.lane_map_path}: {e}")
+            return None
+
+    def curvature(self, coefficients: np.ndarray, x: float) -> float:
+        """Computes curvature of the polynomial at x."""
+        if len(coefficients) < 3: # Need at least degree 2 for curvature
+             return 0.0
+        first_deriv_coeffs = np.polyder(coefficients)
+        second_deriv_coeffs = np.polyder(first_deriv_coeffs)
+        dy_dx = np.polyval(first_deriv_coeffs, x)
+        d2y_dx2 = np.polyval(second_deriv_coeffs, x)
+        denominator = (1 + dy_dx**2)**1.5
+        return np.abs(d2y_dx2) / denominator if denominator != 0 else np.inf
+
+    def curvature_derivative(self, coefficients: np.ndarray, x: float) -> float:
+        """Computes the derivative of curvature with respect to x."""
+        if len(coefficients) < 4: # Need at least degree 3 for derivative of curvature
+             return 0.0
+        first_deriv_coeffs = np.polyder(coefficients)
+        second_deriv_coeffs = np.polyder(first_deriv_coeffs)
+        third_deriv_coeffs = np.polyder(second_deriv_coeffs)
+
+        dy_dx = np.polyval(first_deriv_coeffs, x)
+        d2y_dx2 = np.polyval(second_deriv_coeffs, x)
+        d3y_dx3 = np.polyval(third_deriv_coeffs, x)
+
+        denominator = (1 + dy_dx**2)**2.5 # Note the power is 2.5 or 5/2
+        if denominator == 0:
+            return np.inf
+
+        numerator = d3y_dx3 * (1 + dy_dx**2) - 3 * dy_dx * d2y_dx2 * d2y_dx2 # Corrected term order? Verify formula
+        # Standard formula: (d3y_dx3*(1 + dy_dx**2) - 3*dy_dx*(d2y_dx2**2)) / ((1 + dy_dx**2)**(5/2)) * sign(d2y_dx2)
+        # Let's stick to the provided calculation logic but ensure denominator is correct
+        # The provided formula in the original code seems to be for dk/ds (arc length), not dk/dx.
+        # Re-implementing dk/dx based on standard calculus:
+        term1 = d3y_dx3 * (1 + dy_dx**2)**(3/2)
+        term2 = d2y_dx2 * (3/2) * (1 + dy_dx**2)**(1/2) * (2 * dy_dx * d2y_dx2) # Chain rule
+        numerator_dk_dx = term1 - term2
+        denominator_dk_dx = (1 + dy_dx**2)**3
+
+        if denominator_dk_dx == 0:
+             return np.inf
+
+        # Take absolute value or not? Original didn't. Let's omit abs() for derivative.
+        return numerator_dk_dx / denominator_dk_dx
+        # dk_dx = (d3y_dx3 * (1 + dy_dx ** 2) - 3 * dy_dx * d2y_dx2 ** 2) / (
+        #         (1 + dy_dx ** 2) ** (5/2) # Original had power 3 ?? Double check this formula source
+        # ) * np.sign(d2y_dx2) # Need sign of curvature
+        # return dk_dx
+
+    def polynomial_fit(
+        self, x_window: np.ndarray, y_window: np.ndarray
+    ) -> Tuple[Optional[np.ndarray], Optional[np.poly1d]]:
+        """Performs polynomial fitting, handling potential rank warnings."""
+        if len(x_window) <= self.degree:
+            print(f"Warning: Window size {len(x_window)} is <= degree {self.degree}. Cannot fit.")
+            return None, None
+        try:
+            # Use warnings context manager if needed, but RankWarning often indicates insufficient data variability
+            # with warnings.catch_warnings():
+            #     warnings.filterwarnings('error', category=np.RankWarning) # Or ignore
+            coefficients = np.polyfit(x_window, y_window, self.degree)
+            return coefficients, np.poly1d(coefficients)
+        except np.RankWarning:
+             print(f"Warning: Rank deficient fitting for window. Check data variability.")
+             # Attempt lower degree fit? Or return None? For now, return None.
+             # try:
+             #      coefficients = np.polyfit(x_window, y_window, len(x_window) - 1)
+             #      return coefficients, np.poly1d(coefficients)
+             # except:
+             return None, None
+        except Exception as e:
+             print(f"Error during polynomial fit: {e}")
+             return None, None
+
+
+    def find_best_window(self, point: Tuple[float, float], window_size: int) -> Optional[int]:
+        """Finds the start index of the window whose center is closest to the point."""
+        if len(self.x_data) < window_size:
+            print("Warning: Not enough data points for the specified window size.")
+            return None
+
+        x_point, y_point = point
+        min_dist_sq = np.inf
+        best_start_index = -1
+
+        # Calculate window centers more efficiently
+        # Use rolling mean if window_size is large, otherwise simple loop is fine
+        num_windows = len(self.x_data) - window_size + 1
+        if num_windows <= 0: return None
+
+        for start in range(num_windows):
+            x_center = np.mean(self.x_data[start : start + window_size])
+            y_center = np.mean(self.y_data[start : start + window_size])
+            dist_sq = (x_point - x_center)**2 + (y_point - y_center)**2
+            if dist_sq < min_dist_sq:
+                min_dist_sq = dist_sq
+                best_start_index = start
+
+        return best_start_index if best_start_index != -1 else None
+
+
+    def find_projection(
+        self,
+        x_target: float,
+        y_target: float,
+        polynomial: np.poly1d,
+        x_range: Tuple[float, float],
+        search_points: int = 100, # Number of points instead of step size
+    ) -> Optional[Tuple[float, float, float]]:
+        """Finds the approximate closest point on the polynomial within the x_range."""
+        if x_range[1] <= x_range[0]: return None # Invalid range
+
+        x_values = np.linspace(x_range[0], x_range[1], search_points)
+        y_values = polynomial(x_values)
+        distances_sq = (x_target - x_values)**2 + (y_target - y_values)**2
+
+        if len(distances_sq) == 0: return None
+
+        min_idx = np.argmin(distances_sq)
+        min_distance = np.sqrt(distances_sq[min_idx])
+
+        return x_values[min_idx], y_values[min_idx], min_distance
+
+    def fit_and_project(
+        self, points: np.ndarray, window_size: int
+    ) -> List[Dict[str, Any]]:
+        """Fits polynomial and calculates curvature for each point in the input array."""
+        if self.data is None or len(self.x_data) < window_size:
+            print("Insufficient LaneMap data for fitting.")
+            # Return default values for all points
+            return [
+                {
+                    "projection": (np.nan, np.nan),
+                    "curvHor": np.nan,
+                    "curvHorDot": np.nan,
+                    "laneOffset": np.nan,
+                }
+            ] * len(points)
+
+        results = []
+        if points.ndim != 2 or points.shape[1] != 2:
+             raise ValueError("Input points must be a 2D numpy array with shape (n, 2).")
+
+        for x_target, y_target in points:
+            result = { # Default result
+                "projection": (np.nan, np.nan),
+                "curvHor": np.nan,
+                "curvHorDot": np.nan,
+                "laneOffset": np.nan,
+            }
+
+            best_start = self.find_best_window((x_target, y_target), window_size)
+            if best_start is None:
+                results.append(result)
+                continue
+
+            x_window = self.x_data[best_start : best_start + window_size]
+            y_window = self.y_data[best_start : best_start + window_size]
+
+            coefficients, polynomial = self.polynomial_fit(x_window, y_window)
+            if coefficients is None or polynomial is None:
+                results.append(result)
+                continue
+
+            x_min, x_max = np.min(x_window), np.max(x_window)
+            projection_result = self.find_projection(
+                x_target, y_target, polynomial, (x_min, x_max)
+            )
+
+            if projection_result is None:
+                results.append(result)
+                continue
+
+            proj_x, proj_y, min_distance = projection_result
+
+            curv_hor = self.curvature(coefficients, proj_x)
+            curv_hor_dot = self.curvature_derivative(coefficients, proj_x)
+
+            result = {
+                "projection": (round(proj_x, 6), round(proj_y, 6)),
+                "curvHor": round(curv_hor, 6),
+                "curvHorDot": round(curv_hor_dot, 6),
+                "laneOffset": round(min_distance, 6),
+            }
+            results.append(result)
+
+        return results
+
+
+# --- Data Quality Analyzer (Optimized) ---
+class DataQualityAnalyzer:
+    """Analyzes data quality metrics, focusing on frame loss."""
+
+    def __init__(self, df: Optional[pd.DataFrame] = None):
+        self.df = df if df is not None and not df.empty else pd.DataFrame() # Ensure df is DataFrame
+
+    def analyze_frame_loss(self) -> Dict[str, Any]:
+        """Analyzes frame loss characteristics."""
+        metrics = {
+            "total_frames_data": 0,
+            "unique_frames_count": 0,
+            "min_frame": np.nan,
+            "max_frame": np.nan,
+            "expected_frames": 0,
+            "dropped_frames_count": 0,
+            "loss_rate": np.nan,
+            "max_consecutive_loss": 0,
+            "max_loss_start_frame": np.nan,
+            "max_loss_end_frame": np.nan,
+            "loss_intervals_distribution": {},
+            "valid": False, # Indicate if analysis was possible
+            "message": ""
+        }
+
+        if self.df.empty or 'simFrame' not in self.df.columns:
+            metrics["message"] = "DataFrame is empty or 'simFrame' column is missing."
+            return metrics
+
+        # Drop rows with NaN simFrame and ensure integer type
+        frames_series = self.df['simFrame'].dropna().astype(int)
+        metrics["total_frames_data"] = len(frames_series)
+
+        if frames_series.empty:
+            metrics["message"] = "No valid 'simFrame' data found after dropping NaN."
+            return metrics
+
+        unique_frames = sorted(frames_series.unique())
+        metrics["unique_frames_count"] = len(unique_frames)
+
+        if metrics["unique_frames_count"] < 2:
+            metrics["message"] = "Less than two unique frames; cannot analyze loss."
+            metrics["valid"] = True # Data exists, just not enough to analyze loss
+            if metrics["unique_frames_count"] == 1:
+                 metrics["min_frame"] = unique_frames[0]
+                 metrics["max_frame"] = unique_frames[0]
+                 metrics["expected_frames"] = 1
+            return metrics
+
+        metrics["min_frame"] = unique_frames[0]
+        metrics["max_frame"] = unique_frames[-1]
+        metrics["expected_frames"] = metrics["max_frame"] - metrics["min_frame"] + 1
+
+        # Calculate differences between consecutive unique frames
+        frame_diffs = np.diff(unique_frames)
+        # Gaps are where diff > 1. The number of lost frames in a gap is diff - 1.
+        gaps = frame_diffs[frame_diffs > 1]
+        lost_frames_in_gaps = gaps - 1
+
+        metrics["dropped_frames_count"] = int(lost_frames_in_gaps.sum())
+
+        if metrics["expected_frames"] > 0:
+            metrics["loss_rate"] = round(metrics["dropped_frames_count"] / metrics["expected_frames"], 4)
+        else:
+             metrics["loss_rate"] = 0.0 # Avoid division by zero if min_frame == max_frame (already handled)
+
+
+        if len(lost_frames_in_gaps) > 0:
+            metrics["max_consecutive_loss"] = int(lost_frames_in_gaps.max())
+            # Find where the max loss occurred
+            max_loss_indices = np.where(frame_diffs == metrics["max_consecutive_loss"] + 1)[0]
+            # Get the first occurrence start/end frames
+            max_loss_idx = max_loss_indices[0]
+            metrics["max_loss_start_frame"] = unique_frames[max_loss_idx]
+            metrics["max_loss_end_frame"] = unique_frames[max_loss_idx + 1]
+
+            # Count distribution of loss interval lengths
+            loss_counts = Counter(lost_frames_in_gaps)
+            metrics["loss_intervals_distribution"] = {int(k): int(v) for k, v in loss_counts.items()}
+        else:
+            metrics["max_consecutive_loss"] = 0
+
+        metrics["valid"] = True
+        metrics["message"] = "Frame loss analysis complete."
+        return metrics
+
+
+def get_all_csv_files(path: Path) -> List[Path]:
+    """Gets all CSV files in path, excluding specific ones."""
+    excluded_files = {OUTPUT_CSV_LANEMAP, ROADMARK_CSV}
+    return [
+        file_path
+        for file_path in path.rglob("*.csv") # Recursive search
+        if file_path.is_file() and file_path.name not in excluded_files
+    ]
+
+
+def run_frame_loss_analysis_on_folder(path: Path) -> Dict[str, Dict[str, Any]]:
+    """Runs frame loss analysis on all relevant CSV files in a folder."""
+    analysis_results = {}
+    csv_files = get_all_csv_files(path)
+
+    if not csv_files:
+        print(f"No relevant CSV files found in {path}")
+        return analysis_results
+
+    for file_path in csv_files:
+        file_name = file_path.name
+        if file_name in {OUTPUT_CSV_FUNCTION, OUTPUT_CSV_OBU}: # Skip specific files if needed
+            print(f"Skipping frame analysis for: {file_name}")
+            continue
+
+        print(f"Analyzing frame loss for: {file_name}")
+        if file_path.stat().st_size == 0:
+            print(f"File {file_name} is empty. Skipping analysis.")
+            analysis_results[file_name] = {"valid": False, "message": "File is empty."}
+            continue
+
+        try:
+            # Read only necessary column if possible, handle errors
+            df = pd.read_csv(file_path, usecols=['simFrame'], index_col=False,
+                             on_bad_lines='warn') # 'warn' or 'skip'
+            analyzer = DataQualityAnalyzer(df)
+            metrics = analyzer.analyze_frame_loss()
+            analysis_results[file_name] = metrics
+
+            # Optionally print a summary here
+            if metrics["valid"]:
+                 print(f"  Loss Rate: {metrics.get('loss_rate', np.nan)*100:.2f}%, "
+                       f"Dropped: {metrics.get('dropped_frames_count', 'N/A')}, "
+                       f"Max Gap: {metrics.get('max_consecutive_loss', 'N/A')}")
+            else:
+                 print(f"  Analysis failed: {metrics.get('message')}")
+
+
+        except pd.errors.EmptyDataError:
+            print(f"File {file_name} contains no data after reading.")
+            analysis_results[file_name] = {"valid": False, "message": "Empty data after read."}
+        except ValueError as ve: # Handle case where simFrame might not be present
+            print(f"ValueError processing file {file_name}: {ve}. Is 'simFrame' column present?")
+            analysis_results[file_name] = {"valid": False, "message": f"ValueError: {ve}"}
+        except Exception as e:
+            print(f"Unexpected error processing file {file_name}: {e}")
+            analysis_results[file_name] = {"valid": False, "message": f"Unexpected error: {e}"}
+
+    return analysis_results
+
+
+def data_precheck(output_dir: Path, max_allowed_loss_rate: float = 0.20) -> bool:
+    """Checks data quality, focusing on frame loss rate."""
+    print(f"--- Running Data Quality Precheck on: {output_dir} ---")
+    if not output_dir.exists() or not output_dir.is_dir():
+        print(f"Error: Output directory does not exist: {output_dir}")
+        return False
+
+    try:
+        frame_loss_results = run_frame_loss_analysis_on_folder(output_dir)
+    except Exception as e:
+        print(f"Critical error during frame loss analysis: {e}")
+        return False # Treat critical error as failure
+
+    if not frame_loss_results:
+         print("Warning: No files were analyzed for frame loss.")
+         # Decide if this is a failure or just a warning. Let's treat it as OK for now.
+         return True
+
+    all_checks_passed = True
+    for file_name, metrics in frame_loss_results.items():
+        if metrics.get("valid", False):
+            loss_rate = metrics.get("loss_rate", np.nan)
+            if pd.isna(loss_rate):
+                 print(f"  {file_name}: Loss rate could not be calculated.")
+                 # Decide if NaN loss rate is acceptable.
+            elif loss_rate > max_allowed_loss_rate:
+                print(f"  FAIL: {file_name} - Frame loss rate ({loss_rate*100:.2f}%) exceeds threshold ({max_allowed_loss_rate*100:.1f}%).")
+                all_checks_passed = False
+            else:
+                print(f"  PASS: {file_name} - Frame loss rate ({loss_rate*100:.2f}%) is acceptable.")
+        else:
+            print(f"  WARN: {file_name} - Frame loss analysis could not be completed ({metrics.get('message', 'Unknown reason')}).")
+            # Decide if inability to analyze is a failure. Let's allow it for now.
+
+    print(f"--- Data Quality Precheck {'PASSED' if all_checks_passed else 'FAILED'} ---")
+    return all_checks_passed
+
+
+# --- Final Preprocessing Step ---
+class FinalDataProcessor:
+    """Merges processed CSVs, adds curvature, and handles traffic lights."""
+
+    def __init__(self, config: Config):
+        self.config = config
+        self.output_dir = config.output_dir
+
+    def process(self) -> bool:
+        """执行最终数据合并和处理步骤。"""
+        print("--- Starting Final Data Processing ---")
+        try:
+            # 1. Load main object state data
+            obj_state_path = self.output_dir / OUTPUT_CSV_OBJSTATE
+            lane_map_path = self.output_dir / OUTPUT_CSV_LANEMAP
+
+            if not obj_state_path.exists():
+                print(f"Error: Required input file not found: {obj_state_path}")
+                return False
+                
+            # Load and process data
+            df_object = pd.read_csv(obj_state_path, dtype={"simTime": float}, low_memory=False)
+            
+            # Process and merge data
+            df_merged = self._merge_optional_data(df_object)
+            
+            # Save final merged file directly to output directory
+            merged_csv_path = self.output_dir / OUTPUT_CSV_MERGED
+            print(f'merged_csv_path:{merged_csv_path}')
+            df_merged.to_csv(merged_csv_path, index=False, float_format='%.6f')
+            print(f"Successfully created final merged file: {merged_csv_path}")
+            
+            # Clean up intermediate files
+            if obj_state_path.exists():
+                obj_state_path.unlink()
+            
+            print("--- Final Data Processing Finished ---")
+            return True
+            
+        except Exception as e:
+            print(f"An unexpected error occurred during final data processing: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+
+    def _merge_optional_data(self, df_object: pd.DataFrame) -> pd.DataFrame:
+        """加载和合并可选数据"""
+        df_merged = df_object.copy()
+
+        # --- 合并 EgoMap ---
+        egomap_path = self.output_dir / OUTPUT_CSV_EGOMAP
+        if egomap_path.exists() and egomap_path.stat().st_size > 0:
+            try:
+                df_ego = pd.read_csv(egomap_path, dtype={"simTime": float})
+                # 删除 simFrame 列,因为使用主数据的 simFrame
+                if 'simFrame' in df_ego.columns:
+                    df_ego = df_ego.drop(columns=['simFrame'])
+                
+                # 按时间和ID排序
+                df_ego.sort_values(['simTime', 'playerId'], inplace=True)
+                df_merged.sort_values(['simTime', 'playerId'], inplace=True)
+                
+                # 使用 merge_asof 进行就近合并,不包括 simFrame
+                df_merged = pd.merge_asof(
+                    df_merged,
+                    df_ego,
+                    on='simTime',
+                    by='playerId',
+                    direction='nearest',
+                    tolerance=0.01  # 10ms tolerance
+                )
+                print("EgoMap data merged.")
+            except Exception as e:
+                print(f"Warning: Could not merge EgoMap data from {egomap_path}: {e}")
+
+        # --- Merge Function ---
+        function_path = self.output_dir / OUTPUT_CSV_FUNCTION
+        if function_path.exists() and function_path.stat().st_size > 0:
+             try:
+                df_function = pd.read_csv(function_path, dtype={"timestamp": float}, low_memory=False).drop_duplicates()
+                # 删除 simFrame 列
+                if 'simFrame' in df_function.columns:
+                    df_function = df_function.drop(columns=['simFrame'])
+
+                if 'simTime' in df_function.columns:
+                    df_function['simTime'] = df_function['simTime'].round(2)
+
+                    common_cols = list(set(df_merged.columns) & set(df_function.columns) - {'simTime'})
+                    df_function.drop(columns=common_cols, inplace=True, errors='ignore')
+
+                    df_merged = pd.merge(df_merged, df_function, on=["simTime"], how="left")
+                    print("Function data merged.")
+                else:
+                    print("Warning: 'simTime' column not found in Function.csv. Cannot merge.")
+             except Exception as e:
+                print(f"Warning: Could not merge Function data from {function_path}: {e}")
+        else:
+            print("Function data not found or empty, skipping merge.")
+
+        # --- Merge OBU ---
+        obu_path = self.output_dir / OUTPUT_CSV_OBU
+        if obu_path.exists() and obu_path.stat().st_size > 0:
+             try:
+                df_obu = pd.read_csv(obu_path, dtype={"simTime": float}, low_memory=False).drop_duplicates()
+                # 删除 simFrame 列
+                if 'simFrame' in df_obu.columns:
+                    df_obu = df_obu.drop(columns=['simFrame'])
+
+                df_obu['simTime'] = df_obu['simTime'].round(2)
+
+                common_cols = list(set(df_merged.columns) & set(df_obu.columns) - {'simTime'})
+                df_obu.drop(columns=common_cols, inplace=True, errors='ignore')
+
+                df_merged = pd.merge(df_merged, df_obu, on=["simTime"], how="left")
+                print("OBU data merged.")
+             except Exception as e:
+                print(f"Warning: Could not merge OBU data from {obu_path}: {e}")
+        else:
+            print("OBU data not found or empty, skipping merge.")
+
+        return df_merged
+
+
+    def _process_trafficlight_data(self) -> pd.DataFrame:
+        """Processes traffic light JSON data if available."""
+        # Check if json_path is provided and exists
+        if not self.config.json_path:
+            print("No traffic light JSON file provided. Skipping traffic light processing.")
+            return pd.DataFrame()
+
+        if not self.config.json_path.exists():
+            print("Traffic light JSON file not found. Skipping traffic light processing.")
+            return pd.DataFrame()
+
+        print(f"Processing traffic light data from: {self.config.json_path}")
+        valid_trafficlights = []
+        try:
+            with open(self.config.json_path, 'r', encoding='utf-8') as f:
+                # Read the whole file, assuming it's a JSON array or JSON objects per line
+                try:
+                    # Attempt to read as a single JSON array
+                    raw_data = json.load(f)
+                    if not isinstance(raw_data, list):
+                         raw_data = [raw_data] # Handle case of single JSON object
+                except json.JSONDecodeError:
+                    # If fails, assume JSON objects per line
+                    f.seek(0) # Reset file pointer
+                    raw_data = [json.loads(line) for line in f if line.strip()]
+
+            for entry in raw_data:
+                # Normalize entry if it's a string containing JSON
+                if isinstance(entry, str):
+                    try:
+                        entry = json.loads(entry)
+                    except json.JSONDecodeError:
+                        print(f"Warning: Skipping invalid JSON string in traffic light data: {entry[:100]}...")
+                        continue
+
+                # Safely extract data using .get()
+                intersections = entry.get('intersections', [])
+                if not isinstance(intersections, list): continue # Skip if not a list
+
+                for intersection in intersections:
+                     if not isinstance(intersection, dict): continue
+                     timestamp_ms = intersection.get('intersectionTimestamp', 0)
+                     sim_time = round(int(timestamp_ms) / 1000, 2) # Convert ms to s and round
+
+                     phases = intersection.get('phases', [])
+                     if not isinstance(phases, list): continue
+
+                     for phase in phases:
+                         if not isinstance(phase, dict): continue
+                         phase_id = phase.get('phaseId', 0)
+
+                         phase_states = phase.get('phaseStates', [])
+                         if not isinstance(phase_states, list): continue
+
+                         for phase_state in phase_states:
+                             if not isinstance(phase_state, dict): continue
+                             # Check for startTime == 0 as per original logic
+                             if phase_state.get('startTime') == 0:
+                                 light_state = phase_state.get('light', 0) # Extract light state
+                                 data = {
+                                     'simTime': sim_time,
+                                     'phaseId': phase_id,
+                                     'stateMask': light_state,
+                                     # Add playerId for merging - assume applies to ego
+                                     'playerId': PLAYER_ID_EGO
+                                 }
+                                 valid_trafficlights.append(data)
+
+            if not valid_trafficlights:
+                print("No valid traffic light states (with startTime=0) found in JSON.")
+                return pd.DataFrame()
+
+            df_trafficlights = pd.DataFrame(valid_trafficlights)
+            # Drop duplicates based on relevant fields
+            df_trafficlights.drop_duplicates(subset=['simTime', 'playerId', 'phaseId', 'stateMask'], keep='first', inplace=True)
+            print(f"Processed {len(df_trafficlights)} unique traffic light state entries.")
+            return df_trafficlights
+
+        except json.JSONDecodeError as e:
+            print(f"Error decoding traffic light JSON file {self.config.json_path}: {e}")
+            return pd.DataFrame()
+        except Exception as e:
+            print(f"Unexpected error processing traffic light data: {e}")
+            return pd.DataFrame()
+
+
+# --- Rosbag Processing ---
+class RosbagProcessor:
+    """Extracts data from Rosbag files within a ZIP archive."""
+
+    # Mapping from filename parts to rostopics
+    ROSTOPIC_MAP = {
+        ('V2I', 'HazardousLocationW'): "/HazardousLocationWarning",
+        ('V2C', 'OtherVehicleRedLightViolationW'): "/c2v/GoThroughRadLight",
+        ('V2I', 'LeftTurnAssist'): "/LeftTurnAssistant",
+        ('V2V', 'LeftTurnAssist'): "/V2VLeftTurnAssistant",
+        ('V2I', 'RedLightViolationW'): "/SignalViolationWarning",
+        ('V2C', 'AbnormalVehicleW'): "/c2v/AbnormalVehicleWarnning",
+        ('V2C', 'SignalLightReminder'): "/c2v/TrafficLightInfo",
+        ('V2C', 'VulnerableRoadUserCollisionW'): "/c2v/VulnerableObject",
+        ('V2C', 'EmergencyVehiclesPriority'): "/c2v/EmergencyVehiclesPriority",
+        ('V2C', 'LitterW'): "/c2v/RoadSpillageWarning",
+        ('V2V', 'ForwardCollisionW'): "/V2VForwardCollisionWarning",
+        ('V2C', 'VisibilityW'): "/c2v/VisibilityWarinning",
+        ('V2V', 'EmergencyBrakeW'): "/V2VEmergencyBrakeWarning",
+        ('V2I', 'GreenLightOptimalSpeedAdvisory'): "/GreenLightOptimalSpeedAdvisory", # Check exact topic name
+        ('V2C', 'DynamicSpeedLimitingInformation'): "/c2v/DynamicSpeedLimit",
+        ('V2C', 'TrafficJamW'): "/c2v/TrafficJam",
+        ('V2C', 'DrivingLaneRecommendation'): "/c2v/LaneGuidance",
+        ('V2C', 'RampMerge'): "/c2v/RampMerging",
+        ('V2I', 'CooperativeIntersectionPassing'): "/CooperativeIntersectionPassing",
+        ('V2I', 'IntersectionCollisionW'): "/IntersectionCollisionWarning",
+        ('V2V', 'IntersectionCollisionW'): "/V2VIntersectionCollisionWarning",
+        ('V2V', 'BlindSpotW'): "/V2VBlindSpotWarning",
+        ('V2I', 'SpeedLimitW'): "/SpeedLimit",
+        ('V2I', 'VulnerableRoadUserCollisionW'): "/VulnerableRoadUserCollisionWarning",
+        ('V2I', 'CooperativeLaneChange'): "/CooperativeLaneChange",
+        ('V2V', 'CooperativeLaneChange'): "/V2VCooperativeLaneChange",
+        ('V2I', 'CooperativeVehicleMerge'): "/CooperativeVehicleMerge",
+        ('V2V', 'AbnormalVehicleW'): "/V2VAbnormalVehicleWarning",
+        ('V2V', 'ControlLossW'): "/V2VVehicleLossControlWarning",
+        ('V2V', 'EmergencyVehicleW'): '/V2VEmergencyVehicleWarning',
+        ('V2I', 'InVehicleSignage'): "/InVehicleSign",
+        ('V2V', 'DoNotPassW'): "/V2VDoNotPassWarning",
+        ('V2I', 'TrafficJamW'): "/TrafficJamWarning",
+        # Add more mappings as needed
+    }
+
+    def __init__(self, config: Config):
+        self.config = config
+        self.output_dir = config.output_dir
+
+    def _get_target_rostopic(self, zip_filename: str) -> Optional[str]:
+        """Determines the target rostopic based on keywords in the filename."""
+        for (kw1, kw2), topic in self.ROSTOPIC_MAP.items():
+            if kw1 in zip_filename and kw2 in zip_filename:
+                print(f"Identified target topic '{topic}' for {zip_filename}")
+                return topic
+        print(f"Warning: No specific rostopic mapping found for {zip_filename}.")
+        return None
+
+    def process_zip_for_rosbags(self) -> None:
+        """Finds, extracts, and processes rosbags from the ZIP file."""
+        print(f"--- Processing Rosbags in {self.config.zip_path} ---")
+        target_rostopic = self._get_target_rostopic(self.config.zip_path.stem)
+        if not target_rostopic:
+            print("Skipping Rosbag processing as no target topic was identified.")
+            return
+
+        with tempfile.TemporaryDirectory() as tmp_dir_str:
+            tmp_dir = Path(tmp_dir_str)
+            bag_files_extracted = []
+            try:
+                with zipfile.ZipFile(self.config.zip_path, 'r') as zip_ref:
+                    for member in zip_ref.infolist():
+                        # Extract Rosbag files
+                        if 'Rosbag/' in member.filename and member.filename.endswith('.bag'):
+                            try:
+                                extracted_path = Path(zip_ref.extract(member, path=tmp_dir))
+                                bag_files_extracted.append(extracted_path)
+                                print(f"Extracted Rosbag: {extracted_path.name}")
+                            except Exception as e:
+                                print(f"Error extracting Rosbag {member.filename}: {e}")
+
+                        # Extract HMIdata CSV files directly to output
+                        elif 'HMIdata/' in member.filename and member.filename.endswith('.csv'):
+                             try:
+                                 target_path = self.output_dir / Path(member.filename).name
+                                 with zip_ref.open(member) as source, open(target_path, "wb") as target:
+                                     shutil.copyfileobj(source, target)
+                                 print(f"Extracted HMI data: {target_path.name}")
+                             except Exception as e:
+                                 print(f"Error extracting HMI data {member.filename}: {e}")
+
+            except zipfile.BadZipFile:
+                print(f"Error: Bad ZIP file provided: {self.config.zip_path}")
+                return
+            except FileNotFoundError:
+                 print(f"Error: ZIP file not found: {self.config.zip_path}")
+                 return
+
+            if not bag_files_extracted:
+                 print("No Rosbag files found in the archive.")
+                 # Attempt extraction of HMI/RDB anyway if needed (already done above)
+                 return
+
+            # Process extracted bag files
+            for bag_path in bag_files_extracted:
+                print(f"Processing bag file: {bag_path.name}")
+                self._convert_bag_topic_to_csv(bag_path, target_rostopic)
+
+        print("--- Rosbag Processing Finished ---")
+
+    def _convert_bag_topic_to_csv(self, bag_file_path: Path, target_topic: str) -> None:
+        """Converts a specific topic from a single bag file to CSV."""
+        output_csv_path = self.output_dir / OUTPUT_CSV_OBU # Standard name for OBU data
+
+        try:
+            # Check if bagpy can handle Path object, else convert to str
+            bag_reader = bagreader(str(bag_file_path), verbose=False)
+
+            # Check if topic exists
+            available_topics = bag_reader.topic_table['Topics'].tolist() if hasattr(bag_reader, 'topic_table') and bag_reader.topic_table is not None else []
+            if target_topic not in available_topics:
+                print(f"Target topic '{target_topic}' not found in {bag_file_path.name}. Available: {available_topics}")
+                # Clean up temporary bagpy-generated files if possible
+                if hasattr(bag_reader, 'data_folder') and Path(bag_reader.data_folder).exists():
+                     shutil.rmtree(bag_reader.data_folder, ignore_errors=True)
+                return
+
+            # Extract message data to a temporary CSV created by bagpy
+            temp_csv_path_str = bag_reader.message_by_topic(target_topic)
+            temp_csv_path = Path(temp_csv_path_str)
+
+
+            if not temp_csv_path.exists() or temp_csv_path.stat().st_size == 0:
+                print(f"Warning: Bagpy generated an empty or non-existent CSV for topic '{target_topic}' from {bag_file_path.name}.")
+                return # Skip if empty
+
+            # Read the temporary CSV, process, and save to final location
+            df = pd.read_csv(temp_csv_path)
+
+            if df.empty:
+                print(f"Warning: Bagpy CSV for topic '{target_topic}' is empty after reading.")
+                return
+
+            # Clean columns: Drop 'Time', rename '*timestamp' -> 'simTime'
+            if 'Time' in df.columns:
+                df.drop(columns=['Time'], inplace=True)
+
+            rename_dict = {}
+            for col in df.columns:
+                if col.endswith('.timestamp'): # More specific match
+                    rename_dict[col] = 'simTime'
+                elif col.endswith('event_type'): # As per original code
+                    rename_dict[col] = 'event_Type'
+                # Add other renames if necessary
+
+            df.rename(columns=rename_dict, inplace=True)
+
+            # Ensure simTime is float and rounded (optional, do if needed for merging)
+            if 'simTime' in df.columns:
+                df['simTime'] = pd.to_numeric(df['simTime'], errors='coerce').round(2) # Example rounding
+
+            # Save processed data
+            df.to_csv(output_csv_path, index=False, float_format='%.6f')
+            print(f"Saved processed OBU data to: {output_csv_path}")
+
+        except ValueError as ve:
+             # Catch potential Bagpy internal errors if topic doesn't contain messages
+             print(f"ValueError processing bag {bag_file_path.name} (Topic: {target_topic}): {ve}. Topic might be empty.")
+        except ImportError as ie:
+             print(f"ImportError during bag processing: {ie}. Ensure all ROS dependencies are installed if needed by bagpy.")
+        except Exception as e:
+            print(f"Error processing bag file {bag_file_path.name} (Topic: {target_topic}): {e}")
+            import traceback
+            traceback.print_exc() # More details on unexpected errors
+        finally:
+            # Clean up temporary files/folders created by bagpy
+             if 'temp_csv_path' in locals() and temp_csv_path.exists():
+                 try:
+                    temp_csv_path.unlink() # Delete the specific CSV
+                 except OSError as ose:
+                      print(f"Warning: Could not delete bagpy temp csv {temp_csv_path}: {ose}")
+
+             if 'bag_reader' in locals() and hasattr(bag_reader, 'data_folder'):
+                 bagpy_folder = Path(bag_reader.data_folder)
+                 if bagpy_folder.exists() and bagpy_folder.is_dir():
+                     try:
+                        shutil.rmtree(bagpy_folder, ignore_errors=True) # Delete the folder bagpy made
+                     except OSError as ose:
+                          print(f"Warning: Could not delete bagpy temp folder {bagpy_folder}: {ose}")
+
+
+# --- Utility Functions ---
+def get_base_path() -> Path:
+    """Gets the base path of the script or executable."""
+    if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
+        # Running in a PyInstaller bundle
+        return Path(sys._MEIPASS)
+    else:
+        # Running as a normal script
+        return Path(__file__).parent.resolve()
+
+
+def run_cpp_engine(config: Config):
+    """Runs the external C++ preprocessing engine."""
+    if not config.engine_path or not config.map_path:
+        print("C++ engine path or map path not configured. Skipping C++ engine execution.")
+        return True # Return True assuming it's optional or handled elsewhere
+
+    engine_cmd = [
+        str(config.engine_path),
+        str(config.map_path),
+        str(config.output_dir),
+        str(config.x_offset),
+        str(config.y_offset)
+    ]
+
+    print(f"--- Running C++ Preprocessing Engine ---")
+    print(f"Command: {' '.join(engine_cmd)}")
+
+    try:
+        result = subprocess.run(
+            engine_cmd,
+            check=True,          # Raise exception on non-zero exit code
+            capture_output=True, # Capture stdout/stderr
+            text=True,           # Decode output as text
+            cwd=config.engine_path.parent # Run from the engine's directory? Or script's? Adjust if needed.
+        )
+        print("C++ Engine Output:")
+        print(result.stdout)
+        if result.stderr:
+            print("C++ Engine Error Output:")
+            print(result.stderr)
+        print("--- C++ Engine Finished Successfully ---")
+        return True
+    except FileNotFoundError:
+         print(f"Error: C++ engine executable not found at {config.engine_path}.")
+         return False
+    except subprocess.CalledProcessError as e:
+        print(f"Error: C++ engine failed with exit code {e.returncode}.")
+        print("C++ Engine Output (stdout):")
+        print(e.stdout)
+        print("C++ Engine Output (stderr):")
+        print(e.stderr)
+        return False
+    except Exception as e:
+        print(f"An unexpected error occurred while running the C++ engine: {e}")
+        return False
+
+
+if __name__ == "__main__":
+    pass

+ 274 - 0
core/processors/built_in/pgvil.py

@@ -0,0 +1,274 @@
+from pathlib import Path
+from typing import Dict, Any, Optional
+import pandas as pd
+import numpy as np
+from pyproj import Proj
+
+from core.processors.built_in.base import BaseDataProcessor
+
+class PGVILDataProcessor(BaseDataProcessor):
+    """处理仿真内置数据的处理器"""
+    
+    def __init__(self):
+        super().__init__("pgvil_processor")
+        self.required_columns = {
+            'simTime': float,
+            'simFrame': int,
+            'playerId': int,
+            'v': float,
+            'speedX': float,
+            'speedY': float,
+            'posH': float,
+            'speedH': float,
+            'posX': float,
+            'posY': float,
+            'accelX': float,
+            'accelY': float
+        }
+        # 初始化UTM投影
+        self.projection = Proj(proj='utm', zone=51, ellps='WGS84', preserve_units='m')
+        
+    def process_data(self, 
+                    input_path: Path,
+                    output_path: Path,
+                    **kwargs) -> Optional[Path]:
+        """处理PGVIL数据
+        
+        Args:
+            input_path: 输入文件路径
+            output_path: 输出目录路径
+            **kwargs: 额外参数
+                - utm_zone: UTM区域
+                - x_offset: X偏移
+                - y_offset: Y偏移
+        
+        Returns:
+            处理后的文件路径
+        """
+        try:
+            # 读取数据
+            df = pd.read_csv(input_path)
+            if df.empty:
+                print(f"输入文件为空: {input_path}")
+                return None
+                
+            # 基本数据清理
+            df = self._clean_data(df)
+            
+            # 坐标转换
+            utm_zone = kwargs.get('utm_zone', 51)
+            x_offset = kwargs.get('x_offset', 0.0)
+            y_offset = kwargs.get('y_offset', 0.0)
+            
+            df = self._process_coordinates(df, utm_zone, x_offset, y_offset)
+            
+            # 计算额外字段
+            df = self._calculate_additional_fields(df)
+            
+            # 确保输出目录存在
+            output_path.parent.mkdir(parents=True, exist_ok=True)
+            
+            # 保存处理后的数据
+            df.to_csv(output_path, index=False)
+            print(f"数据处理完成,已保存至: {output_path}")
+            
+            return output_path
+            
+        except Exception as e:
+            print(f"处理PGVIL数据时出错: {e}")
+            import traceback
+            traceback.print_exc()
+            return None
+    
+    def _clean_data(self, df: pd.DataFrame) -> pd.DataFrame:
+        """清理数据"""
+        # 删除重复行
+        df = df.drop_duplicates()
+        
+        # 确保所需列存在
+        for col, dtype in self.required_columns.items():
+            if col not in df.columns:
+                df[col] = 0 if dtype in (int, float) else ''
+            else:
+                df[col] = df[col].astype(dtype)
+        
+        # 处理空值
+        numeric_cols = [col for col, dtype in self.required_columns.items() 
+                       if dtype in (int, float)]
+        df[numeric_cols] = df[numeric_cols].fillna(0)
+        
+        # 按时间和ID排序
+        df.sort_values(['simTime', 'simFrame', 'playerId'], inplace=True)
+        
+        return df
+    
+    def _process_coordinates(self, 
+                           df: pd.DataFrame, 
+                           utm_zone: int,
+                           x_offset: float,
+                           y_offset: float) -> pd.DataFrame:
+        """处理坐标数据"""
+        if 'lat' in df.columns and 'lon' in df.columns:
+            # 原始经纬度转UTM
+            projection = Proj(proj='utm', zone=utm_zone, ellps='WGS84', preserve_units='m')
+            x, y = projection(df['lon'].values, df['lat'].values)
+            
+            # 应用偏移
+            df['posX'] = x + x_offset
+            df['posY'] = y + y_offset
+        
+        return df
+    
+    def _calculate_additional_fields(self, df: pd.DataFrame) -> pd.DataFrame:
+        """计算额外的字段"""
+        # 示例:计算合成速度
+        if all(col in df.columns for col in ['speedX', 'speedY']):
+            df['v'] = np.sqrt(df['speedX']**2 + df['speedY']**2)
+        
+        # 示例:计算行驶距离
+        if 'v' in df.columns and 'simTime' in df.columns:
+            df['travelDist'] = df.sort_values('simTime').groupby('playerId')['v'].cumsum() * df['simTime'].diff()
+        
+        return df
+    
+    def validate_output(self, output_path: Path) -> bool:
+        """验证输出数据
+        
+        Args:
+            output_path: 输出文件路径
+            
+        Returns:
+            验证是否通过
+        """
+        try:
+            if not output_path.exists():
+                print(f"输出文件不存在: {output_path}")
+                return False
+                
+            df = pd.read_csv(output_path)
+            
+            # 验证所需列
+            missing_cols = [col for col in self.required_columns.keys() 
+                          if col not in df.columns]
+            if missing_cols:
+                print(f"缺少必需列: {missing_cols}")
+                return False
+            
+            # 验证数据类型
+            for col, dtype in self.required_columns.items():
+                if df[col].dtype != dtype:
+                    print(f"列 {col} 的数据类型错误,应为 {dtype}")
+                    return False
+            
+            # 验证数值范围
+            if df['simTime'].min() < 0:
+                print("simTime存在负值")
+                return False
+            
+            if df['simFrame'].min() <= 0:
+                print("simFrame存在非正值")
+                return False
+            
+            return True
+            
+        except Exception as e:
+            print(f"验证输出数据时出错: {e}")
+            return False
+
+from typing import Dict, Optional
+from pathlib import Path
+import pandas as pd
+
+from .base import BaseProcessor
+from core.error_handler import ErrorHandler
+from core.config_manager import get_config
+
+class Config:
+    """PGVIL处理器配置类"""
+    def __init__(self,
+                output_dir: Path,
+                data_dir: Path):
+        self.output_dir = output_dir
+        self.data_dir = data_dir
+
+class PGVILProcessor(BaseProcessor):
+    """PGVIL数据处理器,实现PGVIL特有的处理逻辑"""
+    
+    def __init__(self, config: Config):
+        super().__init__(config.output_dir)
+        self.config = config
+        
+    @ErrorHandler.measure_performance
+    def process_built_in_data(self) -> Dict[str, Path]:
+        """实现PGVIL特有的内置数据处理逻辑
+        
+        处理顺序:
+        1. 处理CAN数据
+        2. 处理传感器数据
+        3. 处理其他PGVIL特有数据
+        4. 合并内置数据
+        
+        Returns:
+            处理结果文件路径字典
+        """
+        result_files = {}
+        
+        # 1. 处理CAN数据
+        print("1. 处理CAN数据...")
+        can_results = self._process_can_data()
+        if can_results:
+            result_files.update(can_results)
+        else:
+            print("警告: CAN数据处理失败或无数据")
+            
+        # 2. 处理传感器数据
+        print("\n2. 处理传感器数据...")
+        sensor_results = self._process_sensor_data()
+        if sensor_results:
+            result_files.update(sensor_results)
+        else:
+            print("警告: 传感器数据处理失败或无数据")
+            
+        # 3. 处理其他PGVIL特有数据
+        print("\n3. 处理其他PGVIL数据...")
+        other_results = self._process_other_data()
+        if other_results:
+            result_files.update(other_results)
+            
+        # 4. 合并内置数据
+        print("\n4. 合并内置数据...")
+        if not self._merge_built_in_data(result_files):
+            print("警告: 内置数据合并失败")
+            
+        return result_files
+        
+    def _process_can_data(self) -> Dict[str, Path]:
+        """处理CAN数据"""
+        # TODO: 实现CAN数据处理逻辑
+        return {}
+        
+    def _process_sensor_data(self) -> Dict[str, Path]:
+        """处理传感器数据"""
+        # TODO: 实现传感器数据处理逻辑
+        return {}
+        
+    def _process_other_data(self) -> Dict[str, Path]:
+        """处理其他PGVIL特有数据"""
+        # TODO: 实现其他数据处理逻辑
+        return {}
+        
+    def _merge_built_in_data(self, result_files: Dict[str, Path]) -> bool:
+        """合并PGVIL内置数据
+        
+        Args:
+            result_files: 处理结果文件路径字典
+            
+        Returns:
+            合并是否成功
+        """
+        try:
+            # 实现PGVIL特有的数据合并逻辑
+            return True
+        except Exception as e:
+            print(f"内置数据合并失败: {e}")
+            return False

+ 221 - 0
core/resource_manager.py

@@ -0,0 +1,221 @@
+import zipfile
+from pathlib import Path
+import pandas as pd
+from typing import List, Optional
+import shutil
+
+class ResourceManager:
+    """管理插件资源和数据验证"""
+    
+    # 内置处理器类型及其对应的关键词
+    BUILT_IN_PROCESSORS = {
+        "lst": ["rosbag", "gnss", "can", "hmi"],
+        "pgvil": ["pgvil", "acu", "radar"]  # pgvil处理器支持的数据类型
+    }
+    
+    def __init__(self, resources_dir: Path):
+        self.resources_dir = resources_dir
+        if not self.resources_dir.exists():
+            self.resources_dir.mkdir(parents=True)
+            
+    def list_zip_folders(self, zip_path: Path, processor_type: str = "lst") -> List[str]:
+        """列出ZIP文件中的顶层文件夹,排除内置处理器的关键词文件夹
+        
+        Args:
+            zip_path: ZIP文件路径
+            processor_type: 内置处理器类型,可选 "lst" 或 "pgvil"
+            
+        Returns:
+            不包含内置处理器关键词的文件夹列表
+        """
+        folders = set()
+        built_in_keywords = self.BUILT_IN_PROCESSORS.get(processor_type, [])
+        
+        try:
+            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
+                for name in zip_ref.namelist():
+                    parts = Path(name).parts
+                    if len(parts) > 1:  # 至少包含一个文件夹
+                        folder = parts[0].lower()
+                        # 只返回不包含内置处理器关键词的文件夹
+                        if not any(keyword in folder for keyword in built_in_keywords):
+                            folders.add(parts[0])
+                            
+        except Exception as e:
+            print(f"读取ZIP文件出错: {e}")
+            return []
+            
+        return list(folders)
+        
+    def list_rosbag_files(self, zip_path: Path) -> List[str]:
+        """列出ZIP文件中的所有Rosbag文件"""
+        rosbag_files = set()
+        try:
+            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
+                for name in zip_ref.namelist():
+                    if 'Rosbag/' in name and name.endswith('.bag'):
+                        rosbag_files.add(name)
+        except Exception as e:
+            print(f"读取ZIP文件中的Rosbag失败: {e}")
+            return []
+        return list(rosbag_files)
+
+    def is_rosbag_file(self, zip_path: Path) -> bool:
+        """检查ZIP文件中是否包含Rosbag数据"""
+        try:
+            with zipfile.ZipFile(zip_path, 'r') as zip_ref:
+                # 查找任何包含'rosbag'关键词且扩展名为.bag的文件
+                for name in zip_ref.namelist():
+                    if 'rosbag' in name.lower() and name.endswith('.bag'):
+                        return True
+            return False
+            
+        except Exception as e:
+            print(f"检查Rosbag文件失败: {e}")
+            return False
+
+    def validate_rosbag_output(self, output_path: Path) -> bool:
+        """验证Rosbag处理后的输出文件是否有效"""
+        try:
+            if not output_path.exists():
+                print(f"错误:输出文件不存在: {output_path}")
+                return False
+
+            df = pd.read_csv(output_path)
+            
+            # Rosbag数据必需列
+            required_columns = ['simTime', 'event_Type']
+            
+            # 检查必需列
+            missing_cols = [col for col in required_columns if col not in df.columns]
+            if missing_cols:
+                print(f"错误:缺少必需列: {missing_cols}")
+                return False
+
+            # 检查simTime列的有效性
+            if df['simTime'].isna().any():
+                print("错误:simTime列包含空值")
+                return False
+
+            return True
+            
+        except Exception as e:
+            print(f"验证Rosbag输出时出错: {e}")
+            return False
+            
+    def validate_plugin_output(self, output_path: Path) -> bool:
+        """验证插件输出文件是否有效"""
+        try:
+            if not output_path.exists():
+                print(f"错误:输出文件不存在: {output_path}")
+                return False
+
+            df = pd.read_csv(output_path)
+            required_columns = ['simTime', 'playerId', 'simFrame']
+            
+            # 检查必需列是否存在
+            missing_cols = [col for col in required_columns if col not in df.columns]
+            if missing_cols:
+                print(f"错误:缺少必需列: {missing_cols}")
+                return False
+                
+            # 检查空值
+            for col in required_columns:
+                if df[col].isna().any():
+                    print(f"错误:{col} 包含空值")
+                    return False
+            
+            return True
+            
+        except Exception as e:
+            print(f"验证输出文件时出错: {e}")
+            return False
+
+    def validate_plugin_df(self, df: pd.DataFrame) -> bool:
+        """验证插件输出的DataFrame是否符合要求"""
+        try:
+            required_columns = ['simTime', 'simFrame', 'playerId']
+            
+            missing_cols = [col for col in required_columns if col not in df.columns]
+            if missing_cols:
+                print(f"错误:缺少必需列: {missing_cols}")
+                return False
+                
+            if df['playerId'].isna().any():
+                print("错误:playerId 包含空值")
+                return False
+            if df['simTime'].isna().any():
+                print("错误:simTime 包含空值")
+                return False
+            if df['simFrame'].isna().any():
+                print("错误:simFrame 包含空值")
+                return False
+                
+            return True
+            
+        except Exception as e:
+            print(f"验证DataFrame时出错: {e}")
+            return False
+            
+    def merge_plugin_data(self, main_file: Path, plugin_file: Path, output_file: Path) -> bool:
+        try:
+            df_main = pd.read_csv(main_file)
+            df_plugin = pd.read_csv(plugin_file)
+            
+            print(f"主数据形状: {df_main.shape}")
+            print(f"插件数据形状: {df_plugin.shape}")
+            
+            # 只保留需要的列进行合并
+            merge_columns = ['simTime', 'playerId']
+            
+            # 确保时间戳精度匹配
+            df_main['simTime'] = df_main['simTime'].round(3)
+            df_plugin['simTime'] = df_plugin['simTime'].round(3)
+            
+            # 按时间排序
+            df_main.sort_values(['simTime', 'playerId'], inplace=True)
+            df_plugin.sort_values(['simTime', 'playerId'], inplace=True)
+
+            # 使用 merge_asof 进行基于时间的合并,只使用 simTime 和 playerId
+            df_merged = pd.merge_asof(
+                df_main,
+                df_plugin.drop('simFrame', axis=1, errors='ignore'),  # 删除插件数据中的 simFrame
+                on='simTime',
+                by=['playerId'],
+                direction='nearest',
+                tolerance=0.01  # 100ms的容差
+            )
+            
+            print(f"合并后的数据形状: {df_merged.shape}")
+            print(f"从插件添加的列: {[col for col in df_plugin.columns if col not in merge_columns and col != 'simFrame']}")
+            
+            df_merged.to_csv(output_file, index=False)
+            print(f"成功合并数据到: {output_file}")
+            
+            return True
+            
+        except Exception as e:
+            print(f"合并插件数据时出错: {e}")
+            import traceback
+            traceback.print_exc()
+            return False
+            
+    def copy_resource(self, resource_name: str, target_dir: Path) -> Optional[Path]:
+        """复制资源文件到目标目录"""
+        source_path = self.resources_dir / resource_name
+        if not source_path.exists():
+            return None
+            
+        try:
+            # 创建目标目录(如果不存在)
+            target_dir.mkdir(parents=True, exist_ok=True)
+            
+            # 复制文件
+            target_path = target_dir / resource_name
+            shutil.copy2(source_path, target_path)
+            
+            return target_path
+            
+        except Exception as e:
+            print(f"Error copying resource {resource_name}: {e}")
+            return None

+ 153 - 0
docs/can_plugin_guide.md

@@ -0,0 +1,153 @@
+# CAN数据处理插件开发指南
+
+## 1. 概述
+本指南将帮助您创建自定义的CAN数据处理插件,以处理特定格式的CAN数据并将其集成到数据处理流程中。
+
+## 2. 快速开始
+
+### 2.1 准备工作
+1. 将您的DBC文件放在 `resources` 目录下
+2. 复制 `plugins/can_plugin_template.py` 为新文件,例如 `my_can_plugin.py`
+
+### 2.2 基本配置
+在您的插件文件中修改以下内容:
+
+```python
+class MyCanProcessor(CustomDataProcessorPlugin):  # 修改类名
+    def __init__(self):
+        self.dbc = None
+        self.custom_dbc_path = Path("resources/my_custom.dbc")  # 修改为您的DBC文件路径
+        self._load_dbc()
+```
+
+### 2.3 数据文件夹识别
+修改 `can_handle` 方法以匹配您的数据文件夹命名规则:
+
+```python
+def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+    return folder_name.startswith('my_can_data_')  # 修改为您的文件夹前缀
+```
+
+### 2.4 定义输出列
+在 `get_required_columns` 方法中定义您需要的输出列:
+
+```python
+def get_required_columns(self) -> Dict[str, Any]:
+    return {
+        'simTime': float,      # 必需列
+        'playerId': int,       # 必需列
+        'my_signal_1': float,  # 自定义列
+        'my_signal_2': float,  # 自定义列
+    }
+```
+
+## 3. 数据处理配置
+
+### 3.1 DBC文件要求
+- DBC文件必须包含完整的CAN消息和信号定义
+- 确保信号有正确的比例因子和偏移量
+- 建议包含信号的单位信息
+
+### 3.2 信号映射示例
+在 `_process_can_data` 方法中映射CAN信号到输出列:
+
+```python
+record = {
+    'simTime': timestamp,
+    'playerId': 1,
+    'my_signal_1': decoded.get('CAN_Signal_Name_1', 0.0),
+    'my_signal_2': decoded.get('CAN_Signal_Name_2', 0.0),
+}
+```
+
+## 4. 输入数据格式要求
+
+### 4.1 ZIP文件结构
+```
+your_data.zip/
+    my_can_data_folder/      # 您的CAN数据文件夹
+        can_data_1.csv       # CAN数据文件
+        can_data_2.csv
+        ...
+```
+
+### 4.2 CAN数据文件格式
+CSV文件必须包含以下列:
+- `timestamp`: 时间戳 (秒)
+- `can_id`: CAN消息ID (十六进制或十进制)
+- `data`: CAN数据 (十六进制字符串)
+
+示例:
+```csv
+timestamp,can_id,data
+1.234,0x123,0123456789ABCDEF
+1.235,0x456,FEDCBA9876543210
+```
+
+## 5. 调试技巧
+
+### 5.1 验证DBC文件加载
+运行插件时会自动打印可用的CAN消息和信号列表,确保:
+- 所有预期的消息ID都列出
+- 信号名称正确
+
+### 5.2 数据处理验证
+1. 使用小数据集进行测试
+2. 检查输出CSV文件中的数据类型和值范围
+3. 确认时间戳的连续性和合理性
+
+### 5.3 常见问题解决
+1. DBC文件未找到
+   - 检查文件路径是否正确
+   - 确认文件在resources目录下
+
+2. 信号解码失败
+   - 验证CAN ID是否匹配
+   - 检查数据长度是否符合DBC定义
+
+3. 数据类型错误
+   - 确保所有输出列都有正确的数据类型转换
+   - 检查是否处理了所有可能的空值情况
+
+## 6. 示例
+
+### 6.1 完整的插件示例
+参考 `plugins/can_plugin_template.py` 中的示例实现。
+
+### 6.2 自定义数据处理示例
+```python
+# 添加自定义数据处理逻辑
+def _process_can_data(self, can_file: Path) -> pd.DataFrame:
+    df = pd.read_csv(can_file)
+    processed_data = []
+    
+    for _, row in df.iterrows():
+        decoded = self._decode_can_message(row['can_id'], bytes.fromhex(row['data']))
+        if decoded:
+            # 添加您的自定义处理逻辑
+            speed = decoded.get('Vehicle_Speed', 0) * 3.6  # 转换为km/h
+            record = {
+                'simTime': row['timestamp'],
+                'playerId': 1,
+                'vehicle_speed': speed
+            }
+            processed_data.append(record)
+            
+    return pd.DataFrame(processed_data)
+```
+
+## 7. 注意事项
+
+1. 必需字段
+   - 确保输出数据包含 `simTime` 和 `playerId`
+   - 这些字段用于数据合并和同步
+
+2. 数据质量
+   - 处理异常值和无效数据
+   - 确保时间戳的单调递增
+   - 合理处理丢失的数据点
+
+3. 性能优化
+   - 考虑批量处理大量数据
+   - 使用适当的数据结构减少内存使用
+   - 添加进度提示以监控长时间运行的处理

+ 667 - 0
docs/optimization_plan.md

@@ -0,0 +1,667 @@
+# 数据预处理系统优化方案
+
+## 概述
+
+通过对当前数据预处理系统的代码分析,我们发现了多个可以优化的方面,包括性能瓶颈、代码结构、错误处理和文档完善等。本文档提供了一个全面的优化方案,旨在提高系统的性能、可维护性和可扩展性。
+
+## 1. 性能优化
+
+### 1.1 数据处理流程优化
+
+#### 当前问题
+- `merge_data_process_LST.py` 中的数据处理流程存在多次不必要的数据转换和中间文件生成
+- 大量使用循环处理数据,而非利用 pandas 的向量化操作
+- 数据库查询未优化,可能导致内存使用过高
+
+#### 优化建议
+
+1. **减少中间文件生成**
+   - 移除 `OUTPUT_CSV_TEMP_OBJSTATE` 等临时文件,直接在内存中处理数据
+   - 使用 pandas 的 `pipe()` 方法创建数据处理管道,减少中间 DataFrame 的创建
+
+2. **利用 pandas 向量化操作**
+   - 将 `_process_gnss_table` 和 `_process_can_table_optimized` 中的循环替换为向量化操作
+   - 示例代码:
+   ```python
+   # 替换这样的循环处理:
+   processed_data = []
+   for row in rows:
+       row_dict = dict(zip(db_columns, row))
+       record = {}
+       # 处理每行数据...
+       processed_data.append(record)
+   df_final = pd.DataFrame(processed_data)
+   
+   # 使用向量化操作:
+   df = pd.DataFrame(rows, columns=db_columns)
+   df['simTime'] = (df['second'] + df['usecond'] / 1e6).round(2)
+   df['playerId'] = PLAYER_ID_EGO
+   # 其他列的向量化处理...
+   ```
+
+3. **优化数据库查询**
+   - 使用分批查询处理大型数据库,避免一次性加载所有数据
+   - 示例代码:
+   ```python
+   def _process_db_file_in_batches(self, db_path, output_dir, table_type, csv_name, batch_size=10000):
+       output_csv_path = output_dir / csv_name
+       with sqlite3.connect(f"file:{db_path}?mode=ro", uri=True) as conn:
+           # 获取总行数
+           cursor = conn.cursor()
+           cursor.execute(f"SELECT COUNT(*) FROM {table_type}")
+           total_rows = cursor.fetchone()[0]
+           
+           # 分批处理
+           with open(output_csv_path, 'w', newline='') as f:
+               writer = None  # 将在第一批数据后初始化
+               
+               for offset in range(0, total_rows, batch_size):
+                   query = f"SELECT {', '.join(db_columns)} FROM {table_type} LIMIT {batch_size} OFFSET {offset}"
+                   cursor.execute(query)
+                   batch_rows = cursor.fetchall()
+                   
+                   # 处理这一批数据
+                   batch_df = self._process_batch(batch_rows, db_columns)
+                   
+                   # 写入CSV(第一批包含表头)
+                   if offset == 0:
+                       batch_df.to_csv(f, index=False)
+                   else:
+                       batch_df.to_csv(f, index=False, header=False)
+   ```
+
+4. **并行处理**
+   - 使用 `concurrent.futures` 或 `multiprocessing` 并行处理独立的数据文件
+   - 示例代码:
+   ```python
+   from concurrent.futures import ProcessPoolExecutor
+   
+   def process_zip_parallel(self):
+       with zipfile.ZipFile(self.config.zip_path, "r") as zip_ref:
+           db_files_to_process = []
+           # 找出需要处理的文件...
+           
+           with tempfile.TemporaryDirectory() as tmp_dir_str:
+               tmp_dir = Path(tmp_dir_str)
+               # 提取所有文件
+               for file_info, table_type, csv_name in db_files_to_process:
+                   extracted_path = tmp_dir / Path(file_info.filename).name
+                   with zip_ref.open(file_info.filename) as source, open(extracted_path, "wb") as target:
+                       shutil.copyfileobj(source, target)
+               
+               # 并行处理文件
+               with ProcessPoolExecutor(max_workers=min(os.cpu_count(), len(db_files_to_process))) as executor:
+                   futures = []
+                   for file_info, table_type, csv_name in db_files_to_process:
+                       extracted_path = tmp_dir / Path(file_info.filename).name
+                       futures.append(executor.submit(
+                           self._process_db_file, extracted_path, self.config.output_dir, table_type, csv_name
+                       ))
+                   
+                   # 等待所有任务完成
+                   for future in futures:
+                       future.result()
+   ```
+
+### 1.2 内存优化
+
+#### 当前问题
+- 处理大型数据集时可能导致内存溢出
+- 多次创建完整的 DataFrame 副本
+
+#### 优化建议
+
+1. **使用迭代器和生成器**
+   - 对于大型文件处理,使用 pandas 的 `chunksize` 参数分块读取
+   - 示例代码:
+   ```python
+   def merge_large_csv_files(self, file1, file2, output_file, on_columns, chunksize=10000):
+       # 打开输出文件
+       with open(output_file, 'w', newline='') as f_out:
+           # 读取第一个文件的表头
+           df1_header = pd.read_csv(file1, nrows=0)
+           df2_header = pd.read_csv(file2, nrows=0)
+           
+           # 创建合并后的表头
+           merged_columns = list(df1_header.columns)
+           for col in df2_header.columns:
+               if col not in on_columns and col not in merged_columns:
+                   merged_columns.append(col)
+           
+           # 写入表头
+           writer = csv.writer(f_out)
+           writer.writerow(merged_columns)
+           
+           # 分块读取和处理第一个文件
+           for df1_chunk in pd.read_csv(file1, chunksize=chunksize):
+               # 对于每个块,读取第二个文件并合并
+               for df2_chunk in pd.read_csv(file2, chunksize=chunksize):
+                   merged_chunk = pd.merge(df1_chunk, df2_chunk, on=on_columns, how='outer')
+                   # 只写入数据,不写入表头
+                   merged_chunk.to_csv(f_out, mode='a', header=False, index=False)
+   ```
+
+2. **减少 DataFrame 复制**
+   - 使用 `inplace=True` 参数进行原地操作
+   - 使用 `.loc` 或 `.iloc` 进行赋值而不是创建新的 DataFrame
+   - 示例代码:
+   ```python
+   # 替换这样的代码:
+   df_new = df[some_condition]
+   df_new['new_column'] = some_value
+   
+   # 使用这样的代码:
+   df.loc[some_condition, 'new_column'] = some_value
+   ```
+
+## 2. 代码结构优化
+
+### 2.1 插件系统重构
+
+#### 当前问题
+- 插件加载机制不够灵活,无法动态配置
+- 插件接口定义较为简单,缺乏高级功能(如进度报告、取消操作等)
+- 缺少插件版本控制和依赖管理
+
+#### 优化建议
+
+1. **增强插件接口**
+   - 添加进度报告和取消操作的支持
+   - 添加插件元数据(作者、版本、依赖等)
+   - 示例代码:
+   ```python
+   from abc import ABC, abstractmethod
+   from pathlib import Path
+   import pandas as pd
+   from typing import Dict, Any, Optional, Callable
+   
+   class PluginMetadata:
+       """插件元数据类"""
+       def __init__(self, name: str, version: str, author: str, description: str, dependencies: Dict[str, str] = None):
+           self.name = name
+           self.version = version
+           self.author = author
+           self.description = description
+           self.dependencies = dependencies or {}
+   
+   class CustomDataProcessorPlugin(ABC):
+       """增强的插件接口"""
+       
+       @abstractmethod
+       def get_metadata(self) -> PluginMetadata:
+           """返回插件元数据"""
+           pass
+       
+       @abstractmethod
+       def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+           """检查是否可以处理该数据"""
+           pass
+       
+       @abstractmethod
+       def process_data(self, zip_path: Path, folder_name: str, output_dir: Path, 
+                        progress_callback: Optional[Callable[[float, str], None]] = None,
+                        cancel_check: Optional[Callable[[], bool]] = None) -> Optional[Path]:
+           """处理数据并支持进度报告和取消"""
+           pass
+       
+       @abstractmethod
+       def get_required_columns(self) -> Dict[str, Any]:
+           """返回插件提供的列和类型"""
+           pass
+       
+       def validate_dependencies(self) -> bool:
+           """验证插件依赖是否满足"""
+           metadata = self.get_metadata()
+           for package, version in metadata.dependencies.items():
+               try:
+                   import importlib
+                   module = importlib.import_module(package)
+                   if hasattr(module, '__version__') and module.__version__ < version:
+                       print(f"警告: {package} 版本 {module.__version__} 低于所需的 {version}")
+                       return False
+               except ImportError:
+                   print(f"错误: 缺少依赖 {package} {version}")
+                   return False
+           return True
+   ```
+
+2. **改进插件管理器**
+   - 支持插件热加载和卸载
+   - 添加插件配置和优先级管理
+   - 示例代码:
+   ```python
+   class EnhancedPluginManager:
+       """增强的插件管理器"""
+       
+       def __init__(self, plugin_dir: Path, config_file: Optional[Path] = None):
+           self.plugin_dir = plugin_dir
+           self.config_file = config_file
+           self.plugins: Dict[str, Type[CustomDataProcessorPlugin]] = {}
+           self.plugin_instances: Dict[str, CustomDataProcessorPlugin] = {}
+           self.plugin_configs: Dict[str, Dict[str, Any]] = {}
+           self.plugin_priorities: Dict[str, int] = {}
+           
+           self._load_plugin_configs()
+           self._load_plugins()
+       
+       def _load_plugin_configs(self):
+           """加载插件配置"""
+           if not self.config_file or not self.config_file.exists():
+               return
+               
+           try:
+               import yaml
+               with open(self.config_file, 'r') as f:
+                   config = yaml.safe_load(f)
+                   
+               if 'plugins' in config:
+                   for plugin_name, plugin_config in config['plugins'].items():
+                       self.plugin_configs[plugin_name] = plugin_config
+                       if 'priority' in plugin_config:
+                           self.plugin_priorities[plugin_name] = plugin_config['priority']
+                       if 'enabled' in plugin_config and not plugin_config['enabled']:
+                           print(f"插件 {plugin_name} 已禁用")
+           except Exception as e:
+               print(f"加载插件配置失败: {e}")
+       
+       def reload_plugins(self):
+           """重新加载所有插件"""
+           self.plugins.clear()
+           self.plugin_instances.clear()
+           self._load_plugins()
+       
+       def get_sorted_plugins(self) -> List[str]:
+           """按优先级返回排序后的插件名称"""
+           return sorted(self.plugins.keys(), 
+                         key=lambda name: self.plugin_priorities.get(name, 0),
+                         reverse=True)
+   ```
+
+### 2.2 模块化重构
+
+#### 当前问题
+- `merge_data_process_LST.py` 文件过大,包含多个职责
+- 配置管理分散在多个地方
+- 错误处理不一致
+
+#### 优化建议
+
+1. **拆分大型模块**
+   - 将 `ZipCSVProcessor` 拆分为多个专注于单一职责的类
+   - 创建专门的配置管理模块
+   - 示例结构:
+   ```
+   core/
+     __init__.py
+     config.py          # 配置管理
+     plugin_interface.py
+     plugin_manager.py
+     resource_manager.py
+   processors/
+     __init__.py
+     base_processor.py  # 处理器基类
+     zip_processor.py   # ZIP文件处理
+     db_processor.py    # 数据库处理
+     gnss_processor.py  # GNSS数据处理
+     can_processor.py   # CAN数据处理
+     merge_processor.py # 数据合并处理
+   utils/
+     __init__.py
+     logging_utils.py   # 日志工具
+     error_utils.py     # 错误处理工具
+     projection_utils.py # 坐标投影工具
+   ```
+
+2. **统一配置管理**
+   - 创建集中式配置管理类
+   - 支持从文件、环境变量和命令行加载配置
+   - 示例代码:
+   ```python
+   import os
+   import argparse
+   import yaml
+   from pathlib import Path
+   from typing import Any, Dict, Optional
+   
+   class ConfigManager:
+       """统一配置管理类"""
+       
+       def __init__(self):
+           self.config: Dict[str, Any] = {}
+           self.config_file: Optional[Path] = None
+       
+       def load_defaults(self):
+           """加载默认配置"""
+           self.config = {
+               'zip_path': None,
+               'output_dir': Path('output'),
+               'utm_zone': 51,
+               'x_offset': 0.0,
+               'y_offset': 0.0,
+               'plugins_dir': Path('plugins'),
+               'resources_dir': Path('resources'),
+               'log_level': 'INFO',
+           }
+       
+       def load_from_file(self, config_file: Path):
+           """从YAML文件加载配置"""
+           if not config_file.exists():
+               print(f"配置文件不存在: {config_file}")
+               return
+               
+           try:
+               with open(config_file, 'r') as f:
+                   file_config = yaml.safe_load(f)
+                   self.config.update(file_config)
+               self.config_file = config_file
+               print(f"已加载配置文件: {config_file}")
+           except Exception as e:
+               print(f"加载配置文件失败: {e}")
+       
+       def load_from_env(self, prefix: str = 'DATA_PROCESS_'):
+           """从环境变量加载配置"""
+           for key, value in os.environ.items():
+               if key.startswith(prefix):
+                   config_key = key[len(prefix):].lower()
+                   self.config[config_key] = value
+       
+       def load_from_args(self, args: argparse.Namespace):
+           """从命令行参数加载配置"""
+           for key, value in vars(args).items():
+               if value is not None:  # 只覆盖非None值
+                   self.config[key] = value
+       
+       def get(self, key: str, default: Any = None) -> Any:
+           """获取配置项"""
+           return self.config.get(key, default)
+       
+       def set(self, key: str, value: Any):
+           """设置配置项"""
+           self.config[key] = value
+       
+       def save(self, file_path: Optional[Path] = None):
+           """保存配置到文件"""
+           save_path = file_path or self.config_file
+           if not save_path:
+               print("未指定配置文件路径")
+               return False
+               
+           try:
+               with open(save_path, 'w') as f:
+                   yaml.dump(self.config, f, default_flow_style=False)
+               print(f"配置已保存到: {save_path}")
+               return True
+           except Exception as e:
+               print(f"保存配置失败: {e}")
+               return False
+   ```
+
+## 3. 错误处理和日志改进
+
+### 3.1 结构化日志系统
+
+#### 当前问题
+- 使用简单的 `print` 语句输出日志,难以过滤和分析
+- 缺乏日志级别和上下文信息
+- 无法将日志输出到文件或其他目标
+
+#### 优化建议
+
+1. **引入 logging 模块**
+   - 创建结构化的日志系统
+   - 支持不同的日志级别和格式
+   - 示例代码:
+   ```python
+   import logging
+   import sys
+   from pathlib import Path
+   from typing import Optional
+   
+   class LoggingManager:
+       """日志管理类"""
+       
+       def __init__(self):
+           self.logger = logging.getLogger('data_processor')
+           self.log_file: Optional[Path] = None
+           self.log_level = logging.INFO
+           self._configure_default_logger()
+       
+       def _configure_default_logger(self):
+           """配置默认日志器"""
+           self.logger.setLevel(logging.DEBUG)  # 设置最低级别
+           
+           # 创建控制台处理器
+           console_handler = logging.StreamHandler(sys.stdout)
+           console_handler.setLevel(self.log_level)
+           
+           # 设置格式
+           formatter = logging.Formatter(
+               '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
+           )
+           console_handler.setFormatter(formatter)
+           
+           # 添加处理器
+           self.logger.addHandler(console_handler)
+       
+       def set_log_level(self, level: str):
+           """设置日志级别"""
+           level_map = {
+               'DEBUG': logging.DEBUG,
+               'INFO': logging.INFO,
+               'WARNING': logging.WARNING,
+               'ERROR': logging.ERROR,
+               'CRITICAL': logging.CRITICAL
+           }
+           
+           if level.upper() in level_map:
+               self.log_level = level_map[level.upper()]
+               for handler in self.logger.handlers:
+                   if isinstance(handler, logging.StreamHandler) and handler.stream == sys.stdout:
+                       handler.setLevel(self.log_level)
+           else:
+               self.logger.warning(f"未知的日志级别: {level},使用默认级别 INFO")
+       
+       def add_file_handler(self, log_file: Path):
+           """添加文件处理器"""
+           try:
+               # 确保目录存在
+               log_file.parent.mkdir(parents=True, exist_ok=True)
+               
+               # 创建文件处理器
+               file_handler = logging.FileHandler(log_file, encoding='utf-8')
+               file_handler.setLevel(logging.DEBUG)  # 文件记录所有级别
+               
+               # 设置格式
+               formatter = logging.Formatter(
+                   '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
+               )
+               file_handler.setFormatter(formatter)
+               
+               # 添加处理器
+               self.logger.addHandler(file_handler)
+               self.log_file = log_file
+               self.logger.info(f"日志文件已设置为: {log_file}")
+           except Exception as e:
+               self.logger.error(f"设置日志文件失败: {e}")
+       
+       def get_logger(self, name: Optional[str] = None):
+           """获取命名日志器"""
+           if name:
+               return logging.getLogger(f"data_processor.{name}")
+           return self.logger
+   ```
+
+2. **在代码中使用结构化日志**
+   - 替换所有 `print` 语句为适当的日志调用
+   - 添加上下文信息和错误详情
+   - 示例代码:
+   ```python
+   # 创建日志管理器实例
+   logging_manager = LoggingManager()
+   
+   # 在主模块中配置
+   def configure_logging(args):
+       logging_manager.set_log_level(args.log_level)
+       if args.log_file:
+           logging_manager.add_file_handler(Path(args.log_file))
+   
+   # 在各个模块中使用
+   class ZipProcessor:
+       def __init__(self, config):
+           self.config = config
+           self.logger = logging_manager.get_logger('zip_processor')
+       
+       def process_zip(self):
+           self.logger.info(f"开始处理ZIP文件: {self.config.zip_path}")
+           try:
+               # 处理逻辑...
+               self.logger.debug(f"找到 {len(db_files)} 个数据库文件")
+           except zipfile.BadZipFile:
+               self.logger.error(f"无效的ZIP文件: {self.config.zip_path}")
+           except Exception as e:
+               self.logger.exception(f"处理ZIP文件时发生错误: {e}")
+   ```
+
+### 3.2 增强错误处理
+
+#### 当前问题
+- 错误处理不一致,有些地方捕获异常但没有提供足够的上下文
+- 缺少错误恢复机制
+- 用户无法轻松理解错误原因
+
+#### 优化建议
+
+1. **创建自定义异常类**
+   - 定义特定于应用程序的异常类型
+   - 提供更多上下文信息
+   - 示例代码:
+   ```python
+   class DataProcessError(Exception):
+       """数据处理错误的基类"""
+       pass
+   
+   class ConfigError(DataProcessError):
+       """配置错误"""
+       pass
+   
+   class DatabaseError(DataProcessError):
+       """数据库操作错误"""
+       pass
+   
+   class PluginError(DataProcessError):
+       """插件相关错误"""
+       pass
+   
+   class FileProcessError(DataProcessError):
+       """文件处理错误"""
+       def __init__(self, file_path, message, original_error=None):
+           self.file_path = file_path
+           self.original_error = original_error
+           super().__init__(f"处理文件 {file_path} 时出错: {message}")
+   ```
+
+2. **统一错误处理策略**
+   - 创建错误处理工具类
+   - 实现错误恢复和重试机制
+   - 示例代码:
+   ```python
+   import time
+   from functools import wraps
+   from typing import Callable, TypeVar, Any, Optional
+   
+   T = TypeVar('T')
+   
+   class ErrorHandler:
+       """错误处理工具类"""
+       
+       @staticmethod
+       def retry(max_attempts: int = 3, delay: float = 1.0, 
+                 backoff: float = 2.0, exceptions: tuple = (Exception,),
+                 logger: Optional[logging.Logger] = None):
+           """重试装饰器"""
+           def decorator(func: Callable[..., T]) -> Callable[..., T]:
+               @wraps(func)
+               def wrapper(*args, **kwargs) -> T:
+                   attempt = 1
+                   current_delay = delay
+                   
+                   while attempt <= max_attempts:
+                       try:
+                           return func(*args, **kwargs)
+                       except exceptions as e:
+                           if logger:
+                               logger.warning(
+                                   f"尝试 {attempt}/{max_attempts} 失败: {e}. "
+                                   f"{'重试中...' if attempt < max_attempts else '放弃.'}"
+                               )
+                           
+                           if attempt == max_attempts:
+                               raise
+                           
+                           time.sleep(current_delay)
+                           current_delay *= backoff
+                           attempt += 1
+               
+               return wrapper
+           return decorator
+       
+       @staticmethod
+       def safe_operation(default_value: Any = None, 
+                         logger: Optional[logging.Logger] = None):
+           """安全操作装饰器,出错时返回默认值"""
+           def decorator(func: Callable[..., T]) -> Callable[..., Optional[T]]:
+               @wraps(func)
+               def wrapper(*args, **kwargs) -> Optional[T]:
+                   try:
+                       return func(*args, **kwargs)
+                   except Exception as e:
+                       if logger:
+                           logger.error(f"操作失败: {e}")
+                       return default_value
+               
+               return wrapper
+           return decorator
+   ```
+
+## 4. 测试和文档完善
+
+### 4.1 单元测试
+
+#### 当前问题
+- 缺少自动化测试
+- 难以验证代码更改的影响
+
+#### 优化建议
+
+1. **创建测试框架**
+   - 使用 pytest 或 unittest 创建测试框架
+   - 为核心功能编写单元测试
+   - 示例代码:
+   ```python
+   # tests/test_config_manager.py
+   import pytest
+   import tempfile
+   from pathlib import Path
+   import os
+   from core.config import ConfigManager
+   
+   class TestConfigManager:
+       def setup_method(self):
+           self.config_manager = ConfigManager()
+           self.config_manager.load_defaults()
+       
+       def test_defaults(self):
+           assert self.config_manager.get('utm_zone') == 51
+           assert self.config_manager.get('x_offset') == 0.0
+           assert self.config_manager.get('output_dir') == Path('output')
+       
+       def test_load_from_file(self):
+           with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
+               f.write("utm_zone: 52\nx_offset: 1.5\n")
+               temp_path = Path(f.name)
+           
+           try:
+               self.config_manager.load_from_file(temp_path)
+               assert self.config_manager.get('utm_zone') == 52
+               assert self.config_manager.get('x_offset') == 1.5
+               # 未覆盖的值应保

+ 74 - 0
docs/plugin_system.md

@@ -0,0 +1,74 @@
+# LST数据处理插件系统
+
+本插件系统允许用户为自定义数据格式开发数据处理插件。插件处理的结果将被合并到主数据文件中。
+
+## 插件系统概述
+
+LST数据处理插件系统提供了一种灵活的方式来扩展数据处理功能,无需修改主程序代码。用户可以开发处理特定数据格式的插件,系统会自动加载并执行这些插件,并将处理结果合并到最终的数据文件中。
+
+## 开发新插件
+
+要创建新的数据处理插件,需要:
+
+1. 在 `plugins` 目录下创建新的 Python 文件
+2. 导入并继承 `CustomDataProcessorPlugin` 基类
+3. 实现所有必需的方法
+
+### 插件接口
+
+每个插件必须实现以下方法:
+
+```python
+def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+    """判断插件是否可以处理指定文件夹中的数据"""
+    pass
+
+def process_data(self, zip_path: Path, folder_name: str, output_dir: Path) -> Optional[pd.DataFrame]:
+    """处理数据并返回处理后的DataFrame"""
+    pass
+
+def get_required_columns(self) -> Dict[str, Any]:
+    """返回插件将提供的列及其数据类型"""
+    pass
+```
+以下是一个处理自定义数据的示例插件:
+‘’‘
+from pathlib import Path
+from typing import Dict, Any, Optional
+import pandas as pd
+from plugins.plugin_interface import CustomDataProcessorPlugin
+
+class MyCustomDataProcessor(CustomDataProcessorPlugin):
+    def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+        """判断插件是否可以处理指定文件夹中的数据"""
+        return folder_name.startswith('my_custom_data_')
+        
+    def get_required_columns(self) -> Dict[str, Any]:
+        """返回插件将提供的列及其数据类型"""
+        return {
+            'simTime': float,      # 必需
+            'simFrame': int,       # 必需
+            'playerId': int,       # 必需
+            'customField1': str,   # 自定义字段
+            'customField2': float  # 自定义字段
+        }
+        
+    def process_data(self, zip_path: Path, folder_name: str, output_dir: Path) -> Optional[pd.DataFrame]:
+        """处理数据并返回处理后的DataFrame"""
+        try:
+            # 1. 从zip中提取数据
+            # 2. 处理数据
+            # 3. 创建包含必需列的DataFrame
+            df = pd.DataFrame({
+                'simTime': [...],
+                'simFrame': [...],
+                'playerId': [...],
+                'customField1': [...],
+                'customField2': [...]
+            })
+            return df
+        except Exception as e:
+            print(f"处理数据时出错: {e}")
+            return None
+
+‘’‘

+ 3 - 0
plugins/__init__.py

@@ -0,0 +1,3 @@
+"""
+插件包,包含所有自定义数据处理器的具体实现
+"""

BIN
plugins/__pycache__/__init__.cpython-313.pyc


BIN
plugins/__pycache__/custom_plugin.cpython-313.pyc


BIN
plugins/__pycache__/plugin_interface.cpython-313.pyc


BIN
plugins/__pycache__/plugin_manager.cpython-313.pyc


BIN
plugins/__pycache__/radar_data_processor.cpython-313.pyc


BIN
plugins/__pycache__/resource_manager.cpython-313.pyc


+ 195 - 0
plugins/radar_data_processor.py

@@ -0,0 +1,195 @@
+"""
+基于XML配置的雷达数据处理器示例
+使用XML配置文件来定义数据格式和处理参数
+示例数据格式(CSV):
+1234567.89,1,15.6,12.3,30.5,-15.2
+1234567.90,2,25.1,8.7,-15.3,-12.8
+"""
+
+from pathlib import Path
+import pandas as pd
+from typing import Dict, Any, Optional
+import tempfile
+import zipfile
+import xml.etree.ElementTree as ET
+import numpy as np
+
+from core.plugin_interface import CustomDataProcessorPlugin
+
+class RadarDataProcessor(CustomDataProcessorPlugin):
+    """处理雷达数据的插件,使用XML配置文件"""
+    
+    def __init__(self):
+        """初始化插件,加载XML配置文件"""
+        self.config = None
+        self.config_path = Path("resources/radar_config.xml")
+        self.field_map = {}
+        self.delimiter = ','
+        self.processing_params = {}
+        self.columns = ['simTime', 'target_id', 'distance', 'velocity', 'angle', 'rcs']  # 移除 frame
+        self._load_config()
+    
+    def _load_config(self):
+        """加载并解析XML配置文件"""
+        try:
+            if not self.config_path.exists():
+                print(f"配置文件未找到: {self.config_path}")
+                return
+                
+            tree = ET.parse(self.config_path)
+            root = tree.getroot()
+            
+            # 解析字段配置
+            fields = root.find('./DataFormat/Fields')
+            if fields is not None:
+                for field in fields.findall('Field'):
+                    name = field.get('name')
+                    column = int(field.get('column'))
+                    dtype = field.get('type')
+                    self.field_map[column] = {
+                        'name': name,
+                        'type': dtype,
+                        'unit': field.get('unit', '')
+                    }
+            
+            # 解析分隔符
+            delimiter = root.find('./DataFormat/Delimiter')
+            if delimiter is not None:
+                self.delimiter = delimiter.text
+            
+            # 解析处理参数
+            processing = root.find('./Processing')
+            if processing is not None:
+                # 解析时间格式
+                time_format = processing.find('TimeFormat')
+                if time_format is not None:
+                    self.processing_params['time_format'] = time_format.text
+                
+                # 解析角度范围
+                angle_range = processing.find('AngleRange')
+                if angle_range is not None:
+                    self.processing_params['angle_min'] = float(angle_range.find('Min').text)
+                    self.processing_params['angle_max'] = float(angle_range.find('Max').text)
+                
+                # 解析距离范围
+                distance_range = processing.find('DistanceRange')
+                if distance_range is not None:
+                    self.processing_params['distance_min'] = float(distance_range.find('Min').text)
+                    self.processing_params['distance_max'] = float(distance_range.find('Max').text)
+                
+                # 解析过滤器参数
+                filters = processing.find('Filters')
+                if filters is not None:
+                    min_rcs = filters.find('MinRCS')
+                    if min_rcs is not None:
+                        self.processing_params['min_rcs'] = float(min_rcs.text)
+            
+            print(f"成功加载雷达配置文件: {self.config_path}")
+            
+        except Exception as e:
+            print(f"加载配置文件失败: {e}")
+            import traceback
+            traceback.print_exc()
+    
+    def can_handle(self, zip_path: Path, folder_name: str) -> bool:
+        """检查是否是雷达数据文件夹"""
+        # 修改判断逻辑,使其更灵活地匹配雷达数据文件夹
+        return 'radar' in folder_name.lower()
+    
+    def get_required_columns(self) -> Dict[str, Any]:
+        """定义输出数据的列和类型"""
+        return {
+            'simTime': float,      # 必需列
+            'playerId': int,       # 必需列
+            'simFrame': int,       # 必需列
+            'radar_distance': float,  # 雷达距离
+            'radar_velocity': float,  # 雷达速度
+            'radar_angle': float,     # 雷达角度
+            'radar_rcs': float,       # 雷达RCS
+        }
+    
+    def _convert_timestamp(self, timestamp: float) -> float:
+        """根据配置转换时间戳格式"""
+        time_format = self.processing_params.get('time_format', 'unix_timestamp')
+        if time_format == 'unix_timestamp':
+            return timestamp
+        # 添加其他时间格式的转换if需要
+        return timestamp
+    
+    def _filter_data(self, df: pd.DataFrame) -> pd.DataFrame:
+        """根据配置的参数过滤数据"""
+        if df.empty:
+            return df
+            
+        # 角度范围过滤
+        angle_min = self.processing_params.get('angle_min', -float('inf'))
+        angle_max = self.processing_params.get('angle_max', float('inf'))
+        df = df[df['angle'].between(angle_min, angle_max)]
+        
+        # 距离范围过滤
+        distance_min = self.processing_params.get('distance_min', 0)
+        distance_max = self.processing_params.get('distance_max', float('inf'))
+        df = df[df['distance'].between(distance_min, distance_max)]
+        
+        # RCS过滤
+        min_rcs = self.processing_params.get('min_rcs', -float('inf'))
+        df = df[df['rcs'] >= min_rcs]
+        
+        return df
+
+    def _process_extracted_files(self, file_paths: list) -> Optional[pd.DataFrame]:
+        """处理提取的雷达数据文件,直接存储到输出目录"""
+        all_data = []
+        frame_counter = 1
+        
+        for file_path in file_paths:
+            try:
+                if file_path.suffix.lower() == '.csv':
+                    # Read and process data
+                    df = pd.read_csv(file_path, delimiter=self.delimiter, header=None)
+                    if df.empty:
+                        continue
+                        
+                    df = df.iloc[:, :6]
+                    df.columns = ['simTime', 'target_id', 'distance', 'velocity', 'angle', 'rcs']
+                    
+                    # Add frame numbers and process data
+                    df['simFrame'] = range(frame_counter, frame_counter + len(df))
+                    frame_counter += len(df)
+                    
+                    # Round values for consistency
+                    for col in ['simTime', 'distance', 'velocity', 'angle', 'rcs']:
+                        df[col] = df[col].round(3)
+
+                    df['playerId'] = 1
+
+                    # Filter and rename columns
+                    filtered_df = self._filter_data(df)
+                    if not filtered_df.empty:
+                        filtered_df = filtered_df.rename(columns={
+                            'distance': 'radar_distance',
+                            'velocity': 'radar_velocity',
+                            'angle': 'radar_angle',
+                            'rcs': 'radar_rcs'
+                        })
+                        all_data.append(filtered_df)
+                        
+            except Exception as e:
+                print(f"处理文件失败: {file_path}: {e}")
+                continue
+                    
+        if not all_data:
+            return None
+        
+        # Merge all data and sort by time
+        final_df = pd.concat(all_data, ignore_index=True)
+        final_df.sort_values('simTime', inplace=True)
+        final_df['simFrame'] = range(1, len(final_df) + 1)
+        
+        # Ensure correct data types
+        for col, dtype in self.get_required_columns().items():
+            if col in final_df.columns:
+                final_df[col] = final_df[col].astype(dtype)
+        
+        final_df.reset_index(drop=True, inplace=True)
+        return final_df

+ 28 - 0
resources/radar_config.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RadarConfig>
+    <DataFormat>
+        <Fields>
+            <Field name="timestamp" type="float" column="0" />
+            <Field name="target_id" type="int" column="1" />
+            <Field name="distance" type="float" column="2" unit="m" />
+            <Field name="velocity" type="float" column="3" unit="m/s" />
+            <Field name="angle" type="float" column="4" unit="deg" />
+            <Field name="rcs" type="float" column="5" unit="dBsm" />
+        </Fields>
+        <Delimiter>,</Delimiter>
+    </DataFormat>
+    <Processing>
+        <TimeFormat>unix_timestamp</TimeFormat>
+        <AngleRange>
+            <Min>-60</Min>
+            <Max>60</Max>
+        </AngleRange>
+        <DistanceRange>
+            <Min>0</Min>
+            <Max>200</Max>
+        </DistanceRange>
+        <Filters>
+            <MinRCS>-20</MinRCS>
+        </Filters>
+    </Processing>
+</RadarConfig>

+ 300 - 0
run.py

@@ -0,0 +1,300 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+LST数据处理系统入口文件
+支持多种数据格式和插件扩展
+"""
+
+import argparse
+import sys
+import traceback
+from pathlib import Path
+
+from core.config_manager import load_config, update_config
+from core.optimized_processor import process_lst_data, process_pgvil_data  # 新增导入
+from core.plugin_manager import PluginManager
+from core.resource_manager import ResourceManager
+
+
+def parse_arguments():
+    """解析命令行参数"""
+    parser = argparse.ArgumentParser(
+        description='数据处理系统,支持多种数据格式和插件扩展'
+    )
+
+    # 新增数据类型参数
+    parser.add_argument(
+        '--data-type',
+        type=str,
+        choices=['lst', 'pgvil'],
+        default='lst',
+        help='要处理的数据类型 (lst 或 pgvil)'
+    )
+    
+    # 定义参数
+    parser.add_argument(
+        '--zip-path',
+        type=Path,
+        default=Path('V2I_CSAE53-2020_HazardousLocationW_LST_02-01.zip'),
+        help='输入的ZIP数据文件路径'
+    )
+
+    parser.add_argument(
+        '--trafficlight-json',
+        type=Path,
+        default=None,
+        help='交通信号灯JSON配置文件路径'
+    )
+
+    parser.add_argument(
+        '--output-dir',
+        type=Path,
+        default=Path('output'),
+        help='输出目录的基础路径'
+    )
+
+    parser.add_argument(
+        '--utm-zone',
+        type=int,
+        default=51,
+        help='UTM坐标系区域 (默认: 51)'
+    )
+
+    parser.add_argument(
+        '--x-offset',
+        type=float,
+        default=0.0,
+        help='X坐标偏移量'
+    )
+                       
+    parser.add_argument(
+        '--y-offset',
+        type=float,
+        default=0.0,
+        help='Y坐标偏移量'
+    )
+                       
+    parser.add_argument(
+        '--config',
+        type=Path,
+        default=Path('config/config.json'),
+        help='配置文件路径'
+    )
+
+    parser.add_argument(
+        '--plugins-dir',
+        type=Path,
+        default=Path('plugins'),
+        help='插件目录路径'
+    )
+                       
+    parser.add_argument(
+        '--resources-dir',
+        type=Path,
+        default=Path('resources'),
+        help='资源文件目录路径'
+    )
+
+    parser.add_argument(
+        '--use-parallel',
+        action='store_true',
+        help='启用并行处理'
+    )
+                       
+    parser.add_argument(
+        '--no-parallel',
+        action='store_true',
+        help='禁用并行处理'
+    )
+                       
+    parser.add_argument(
+        '--max-workers',
+        type=int,
+        default=None,
+        help='并行处理的最大工作线程数'
+    )
+                       
+    parser.add_argument(
+        '--batch-size',
+        type=int,
+        default=10000,
+        help='处理大数据集时的批处理大小'
+    )
+                       
+    parser.add_argument(
+        '--log-level',
+        type=str,
+        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
+        default='INFO',
+        help='日志级别'
+    )
+                       
+    parser.add_argument(
+        '--log-dir',
+        type=Path,
+        default=Path('logs'),
+        help='日志文件目录'
+    )
+                       
+    parser.add_argument(
+        '--no-log-file',
+        action='store_true',
+        help='禁用文件日志'
+    )
+
+    return parser.parse_args()
+
+
+def setup_config(args):
+    """设置配置"""
+    # 根据ZIP文件名创建输出目录
+    zip_name = args.zip_path.stem
+    output_dir = args.output_dir / zip_name
+    output_dir.mkdir(parents=True, exist_ok=True)
+    
+    print(f"输出目录: {output_dir}")
+
+    # 加载配置
+    config = load_config(args.config)
+    
+    # 更新配置中的输出目录为包含zip名称的子目录
+    config['paths']['output_dir'] = str(output_dir)
+    config['paths']['data_dir'] = str(output_dir)  # 确保数据也输出到同一目录
+    config['paths']['temp_dir'] = str(output_dir)  # 确保临时文件也在同一目录
+    
+    # 使用命令行参数覆盖配置文件中的设置
+    if args.use_parallel and args.no_parallel:
+        print("警告: 同时指定了 --use-parallel 和 --no-parallel,将使用 --use-parallel")
+        config['processing']['use_parallel'] = True
+    elif args.use_parallel:
+        config['processing']['use_parallel'] = True
+    elif args.no_parallel:
+        config['processing']['use_parallel'] = False
+        
+    if args.max_workers is not None:
+        config['processing']['max_workers'] = args.max_workers
+        
+    if args.batch_size != 10000:  # 不等于默认值
+        config['processing']['batch_size'] = args.batch_size
+        
+    # 更新日志配置
+    config['logging']['level'] = args.log_level
+    config['logging']['log_dir'] = str(args.log_dir)
+    config['logging']['log_to_file'] = not args.no_log_file
+    
+    # 更新坐标系配置
+    config['coordinates']['utm_zone'] = args.utm_zone
+    config['coordinates']['x_offset'] = args.x_offset
+    config['coordinates']['y_offset'] = args.y_offset
+    
+    # 更新路径配置
+    config['paths']['plugins_dir'] = str(args.plugins_dir)
+    config['paths']['resources_dir'] = str(args.resources_dir)
+    
+    # 应用更新后的配置
+    update_config(config)
+    
+    return output_dir
+
+
+def process_plugins(args, output_dir, final_csv_path):
+    """处理插件数据"""
+    # 初始化插件处理管理器
+    plugin_manager = PluginManager(args.plugins_dir)
+    resource_manager = ResourceManager(args.resources_dir)
+
+    # 处理自定义数据
+    print("处理并合并自定义数据...")
+    folders = resource_manager.list_zip_folders(args.zip_path)
+    
+    for folder in folders:
+        plugin = plugin_manager.get_plugin_for_data(args.zip_path, folder)
+        if not plugin:
+            print(f"未找到文件夹的插件: {folder}")
+            continue
+
+        print(f"使用插件 '{plugin.__name__}' 处理文件夹 '{folder}'")
+        plugin_instance = plugin()
+        plugin_output = plugin_instance.process_data(
+            args.zip_path,
+            folder,
+            output_dir
+        )
+        
+        if plugin_output is not None and not plugin_output.empty:
+            output_file = output_dir / f"{folder}_processed.csv"
+            print(f'插件输出文件: {output_file}')
+            plugin_output.to_csv(output_file, index=False)
+            
+            if not resource_manager.validate_plugin_output(output_file):
+                print(f"警告: 插件输出验证失败: {folder}")
+                continue
+                
+            # 合并自定义数据与主数据文件
+            print(f"合并 {folder} 数据...")
+            if resource_manager.merge_plugin_data(
+                final_csv_path,
+                output_file,
+                final_csv_path
+            ):
+                print(f"成功合并 {folder} 数据")
+            else:
+                print(f"警告: 合并 {folder} 数据失败")
+        else:
+            print(f"警告: 插件处理失败: {folder}")
+
+
+def main():
+    """主函数"""
+    args = parse_arguments()
+
+    try:
+        # 设置配置
+        output_dir = setup_config(args)
+        
+        print("开始数据处理流程")
+        print(f"从以下位置加载配置: {args.config}")
+        
+        # 根据数据类型选择处理流程
+        if args.data_type == 'lst':
+            final_csv_path = process_lst_data(
+                zip_data_path=args.zip_path,
+                output_base_dir=output_dir,
+                trafficlight_json_path=args.trafficlight_json, 
+                utm_zone=args.utm_zone,
+                x_offset=args.x_offset,
+                y_offset=args.y_offset
+            )
+        elif args.data_type == 'pgvil':
+            final_csv_path = process_pgvil_data(
+                zip_data_path=args.zip_path,
+                output_base_dir=output_dir,
+                utm_zone=args.utm_zone,
+                x_offset=args.x_offset,
+                y_offset=args.y_offset
+            )
+        else:
+            print(f"不支持的数据类型: {args.data_type}")
+            sys.exit(1)
+            
+        if not final_csv_path:
+            print(f"{args.data_type}内置数据处理失败")
+            sys.exit(1)
+            
+        print(f"\n{args.data_type}内置处理流程成功完成!")
+        
+        # 处理插件数据
+        process_plugins(args, output_dir, final_csv_path)
+
+        print("LST数据处理成功完成")
+        print(f"所有处理结果已保存到: {output_dir}")
+        sys.exit(0)
+
+    except Exception as e:
+        print(f"\n处理过程中出现错误: {e}")
+        traceback.print_exc()
+        sys.exit(1)
+
+
+if __name__ == "__main__":
+    main()

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1 - 0
trafficlights.json


+ 0 - 0
utils/__init__.py


BIN
utils/__pycache__/__init__.cpython-313.pyc


BIN
utils/__pycache__/logging_utils.cpython-313.pyc


+ 42 - 0
utils/logging_utils.py

@@ -0,0 +1,42 @@
+from datetime import datetime
+
+def print_with_level(level, message):
+    """打印带有时间戳和级别的消息"""
+    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+    print(f"{timestamp} - {level} - {message}")
+
+def debug(message):
+    print_with_level("DEBUG", message)
+
+def info(message):
+    print_with_level("INFO", message)
+
+def warning(message):
+    print_with_level("WARNING", message)
+
+def error(message):
+    print_with_level("ERROR", message)
+
+def critical(message):
+    print_with_level("CRITICAL", message)
+
+def exception(message):
+    """打印异常信息"""
+    import traceback
+    print_with_level("ERROR", f"{message}\n{traceback.format_exc()}")
+
+# 兼容性函数
+def get_logger(name=None, level=None, log_dir=None, log_to_file=True):
+    """返回一个模拟logger的对象,实际上只是打印到控制台"""
+    return type('Logger', (), {
+        'debug': debug,
+        'info': info,
+        'warning': warning,
+        'error': error,
+        'critical': critical,
+        'exception': exception
+    })()
+
+def set_global_level(level):
+    """为了保持兼容性,这个函数实际上不做任何事"""
+    pass

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác