logoSpatial Topology

IMDF 格式的 GeoJSON

使用 python 或 ChatGPT 將 GeoJSON 轉換成 IMDF 格式

將 GeoJSON 轉換成 IMDF 格式

轉換前再來複習一下 IMDF 格式的 GeoJSON 長什麼樣子:

unit_3F.geojson
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "1781b56b-0f31-47c7-ab06-e1dccdc5bc66",
      "feature_type": "unit",
      "properties": {
        "category": "room",
        "restriction": null,
        "accessibility": null,
        "name": {"en": "Electrical Substation Room", "zh": "變電機械"},
        "alt_name": null,
        "level_id": "2a59caed-8774-459a-8c4a-9b344530f52d",
        "display_point": {
          "type": "Point",
          "coordinates": [121.5157129, 25.1227997]
        }
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [121.5158181, 25.1228286],
            [121.5158037, 25.1228279],
            [121.5157679, 25.1228263],
            // ...
            [121.5158239, 25.1228288],
            [121.5158239, 25.1228289],
            [121.5158181, 25.1228286]
          ]
        ]
      }
    },
    // ...
  ]
}
unit_3F.geojson
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "polygon/1",
      "properties": {
          "id": "polygon/1"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [121.51585576187, 25.12280734062],
            [121.51588158151, 25.12280856371],
            [121.51588293238, 25.12278518661],
            [121.51585711274, 25.12278396352],
            [121.51585576187, 25.12280734062]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "id": "polygon/2",
      "properties": {
        "id": "polygon/2"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [121.51577082241, 25.12274772282],
            [121.51580148958, 25.12274917554],
            [121.51580487456, 25.12269059823],
            [121.51577420739, 25.12268914551],
            [121.51577082241, 25.12274772282]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "id": "polygon/3",
      "properties": {
        "id": "polygon/3"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [121.51564830902, 25.12276841409],
            [121.51569480425, 25.12277061659],
            [121.51569650191, 25.12274123847],
            [121.51565000668, 25.12273903597],
            [121.51564830902, 25.12276841409]
          ]
        ]
      }
    },
    // ...
  ]
}

要注意填寫的欄位包含以下幾個:

PropTypeDefault
geometry?
polygon
-
display_point?
point
e.g. [121.5158815, 25.1228118]
level_id?
string
e.g. "b2c99096-281b-4d6e-b8c9-8042a264609b"
alt_name?
string
e.g. { "en": "Lift", "zh": "升降梯" }
name?
string
e.g. { "en": "Elevator", "zh": "電梯" }
accessibility?
array
null, ["wheelchair", "hearing_impaired",...]
restriction?
string
null
category?
string
e.g. room, restroom, elevator, etc.
id?
string
uuid v4

如何轉換成 IMDF 格式

目前有兩種方式進行轉換,一種是使用 python 腳本,另一種是使用 ChatGPT 協助轉換。

使用 python 轉換格式

這邊可以使用 Google Colab 使用 python ,開始前先確定環境中已經有安裝 shapely 套件,如果沒有安裝可以使用以下指令安裝 shapely 套件。

install shapely
pip install shapely
unit 格式轉換.py
import json
from shapely.geometry import Polygon

# 定義原始的 GeoJSON 資料
input_geojson = # 這裡是從 osm 轉換完的 geojson 資料

# 定義自訂的 level_id
custom_level_id = "your_custom_level_id"  # 替換為你想要的 level_id

# 建立一個字典來儲存已計算過的中心點
centroid_cache = {}

# 構建新的 FeatureCollection
new_feature_collection = {
    "type": "FeatureCollection",
    "features": []
}

for feature in input_geojson.get('features', []):
    geometry = feature.get('geometry', {})
    if geometry.get('type') != 'LineString':
        continue  # 跳過非 LineString 的幾何
    
    coordinates = geometry.get('coordinates', [])
    
    # 確保 LineString 是閉合的
    if coordinates[0] != coordinates[-1]:
        coordinates.append(coordinates[0])
    
    # 將 LineString 轉換為 Polygon
    polygon_coords = [coordinates]
    polygon = Polygon(polygon_coords[0])
    
    # 檢查是否有效的多邊形
    if not polygon.is_valid:
        print(f"Invalid polygon for feature id {feature.get('id')}, skipping.")
        continue
    
    # 使用 tuple 作為字典的鍵
    coords_key = tuple(map(tuple, polygon_coords[0]))
    
    if coords_key in centroid_cache:
        centroid = centroid_cache[coords_key]
    else:
        centroid_point = polygon.centroid
        centroid = [centroid_point.x, centroid_point.y]
        centroid_cache[coords_key] = centroid
    
    # 建立新的 Feature,以下是 unit 的格式
    new_feature = {
        "type": "Feature",
        "id": "",
        "feature_type": "unit",
        "properties": {
            "category": "room", # 如果要轉換的是level 那就再調整這整個區域的格式
            "restriction": None,
            "accessibility": None,
            "name": None,
            "alt_name": None,
            "level_id": custom_level_id,
            "display_point": {
                "type": "Point",
                "coordinates": centroid
            }
        },
        "geometry": {
            "type": "Polygon",
            "coordinates": polygon_coords
        }
    }
    
    new_feature_collection["features"].append(new_feature)

# 將新的 FeatureCollection 輸出為 JSON 字串
output_json_str = json.dumps(new_feature_collection, ensure_ascii=False, indent=4)
print(output_json_str)
# 這裡是從 osm 轉換完的 geojson 資料
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "way/-18201",
      "properties": {
        "id": "way/-18201"
      },
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [121.51363570737, 25.12042655345],
          [121.51373230432, 25.12043076093],
          [121.51373902734, 25.12030422816],
          [121.51364243031, 25.12030002067],
          [121.51363570737, 25.12042655345]
        ]
      }
    },
    {
      "type": "Feature",
      "id": "way/-18238",
      "properties": {
        "id": "way/-18238"
      },
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [121.5136113667, 25.12042549325],
          [121.51361486493, 25.12035965334],
          [121.51346685566, 25.1203532065],
          [121.51346335743, 25.12041904642],
          [121.5136113667, 25.12042549325]
        ]
      }
    }
  ]
}
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "",
      "feature_type": "unit",
      "properties": {
        "category": "room",
        "restriction": null,
        "accessibility": null,
        "name": null,
        "alt_name": null,
        "level_id": "your_custom_level_id",
        "display_point": {
          "type": "Point",
          "coordinates": [
            121.51368736733507,
            25.12036539079371
          ]
        }
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              121.51363570737,
              25.12042655345
            ],
            [
              121.51373230432,
              25.12043076093
            ],
            [
              121.51373902734,
              25.12030422816
            ],
            [
              121.51364243031,
              25.12030002067
            ],
            [
              121.51363570737,
              25.12042655345
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "id": "",
      "feature_type": "unit",
      "properties": {
        "category": "room",
        "restriction": null,
        "accessibility": null,
        "name": null,
        "alt_name": null,
        "level_id": "your_custom_level_id",
        "display_point": {
          "type": "Point",
          "coordinates": [
            121.51353911117812,
            25.1203893498774
          ]
        }
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              121.5136113667,
              25.12042549325
            ],
            [
              121.51361486493,
              25.12035965334
            ],
            [
              121.51346685566,
              25.1203532065
            ],
            [
              121.51346335743,
              25.12041904642
            ],
            [
              121.5136113667,
              25.12042549325
            ]
          ]
        ]
      }
    }
  ]
}

ChatGPT 協助轉換

因為一份 GeoJSON 檔案包含了許多 polygon 每個 polygon 都需要改成 IMDF 格式,所以我們再次請到 ChatGPT 協助我們。

prompts.txt
將下面這份geojson依照,請你幫我依照以下的格式修改檔案,id欄位不用調整,
level_id改成"27771348-3f21-4563-9f8d-f4e6096a13c0",name欄位改成跟id一樣
,完整輸出一份geojson描述給我
格式:
{
      "type": "Feature",
      "id": "d67fdc22-e585-464f-b705-c8c205295200",
      "feature_type": "unit",
      "properties": {
        "category": "room",
        "restriction": null,
        "accessibility": null,
        "name": null,
        "alt_name": null,
        "level_id": "27771348-3f21-4563-9f8d-f4e6096a13c0",
        "display_point": null
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [121.5158817, 25.1228084],
            [121.5158814, 25.1228084],
            [121.5158559, 25.1228072],
            [121.5158572, 25.1227839],
            [121.5158572, 25.1227838],
            [121.515883, 25.122785],
            [121.5158829, 25.122787],
            [121.5158817, 25.1228084]
          ]
        ]
      }
    }

    // 你的 GeoJSON 檔案在這裡
    // ...

基本上完成後就可以將這份 GeoJSON 檔案放到 IMDF 資料夾中,這樣就完成了一份 IMDF 格式的 GeoJSON 檔案,壓縮後丟進 IMDF Sandbox 就可以看到你的建築了。

manifest.json
venue.geojson
address.geojson
building.geojson
footprint.geojson
level.geojson
unit.geojson
amenity.geojson
opening.geojson