dc-l1-tokyo-ring-orientation
Map (reference ← swipe → agent)
0:00
tokyo_buildings_legacy.geojson is a footprint export from an old in-house tool. When we load it into web-based GeoJSON viewers, building interiors are shaded incorrectly: holes appear filled and exteriors render as empty space. Our tile-server import script also rejects every feature with geometry warnings. Fix the geometries so that standard GeoJSON web viewers render them correctly. Attributes must be untouched. Output to tokyo_buildings_fixed.geojson.
Every feature must remain a Polygon with interior rings and holes preserved exactly as they are; do not flatten them. feature_id is the join key.
0:00
System info
{
"adapter": "openrouter",
"model": "deepseek/deepseek-v4-flash",
"base_url": "https://openrouter.ai/api/v1"
}
0:03
Let me start by examining the input file to understand its structure and identify the geometry issues.
0:03
Read
/work/tokyo_buildings_legacy.geojson
1 {
2 "type": "FeatureCollection",
3 "name": "tokyo_buildings_legacy",
4 "crs": {
5 "type": "name",
6 "properties": {
7 "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
8 }
9 },
10 "features": [
11 {
12 "type": "Feature",
13 "geometry": {
14 "type": "Polygon",
15 "coordinates": [
16 [
17 [
18 139.7029081,
19 35.6592372
20 ],
21 [
22 139.7027971,
23 35.659202
24 ],
25 [
26 139.7027755,
27 35.6592471
28 ],
29 [
30 139.7028864,
31 35.6592823
32 ],
33 [
34 139.7029081,
35 35.6592372
36 ]
37 ]
38 ]
39 },
40 "properties": {
41 "feature_id": 1,
42 "overture_id": "01302ced-3141-4b64-b630-98019352a9fd",
43 "name_primary": "渋谷協和ビル",
44 "building_class": "",
45 "height": null
46 }
47 },
48 {
49 "type": "Feature",
50 "geometry": {
51 "type": "Polygon",
52 "coordinates": [
53 [
54 [
55 139.7010896,
56 35.6601981
57 ],
58 [
59 139.7010851,
60 35.660084
61 ],
62 [
63 139.7010559,
64 35.660088
65 ],
66 [
67 139.7010511,
68 35.6600707
69 ],
70 [
71 139.7009769,
72 35.6600834
73 ],
74 [
75 139.7009923,
76 35.6601243
77 ],
78 [
79 139.7009007,
80 35.6601417
81 ],
82 [
83 139.7009195,
84 35.6602237
85 ],
86 [
87 139.7010896,
88 35.6601981
89 ]
90 ]
91 ]
92 },
93 "properties": {
94 "feature_id": 2,
95 "overture_id": "046ab130-a9a2-4a0e-9142-b7ea36374fdb",
96 "name_primary": "丸大ビル",
97 "building_class": "",
98 "height": null
99 }
100 },
<system-reminder>Showed lines 1-100 of 4430. Re-call Read with offset=101 to continue, or raise limit.</system-reminder>
0:04
Bash
head -c 2000 /work/tokyo_buildings_legacy.geojson
{
"type": "FeatureCollection",
"name": "tokyo_buildings_legacy",
"crs": {
"type": "name",
"properties": {
"name": "urn:ogc:def:crs:OGC:1.3:CRS84"
}
},
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
139.7029081,
35.6592372
],
[
139.7027971,
35.659202
],
[
139.7027755,
35.6592471
],
[
139.7028864,
35.6592823
],
[
139.7029081,
35.6592372
]
]
]
},
"properties": {
"feature_id": 1,
"overture_id": "01302ced-3141-4b64-b630-98019352a9fd",
"name_primary": "渋谷協和ビル",
"building_class": "",
"height": null
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
139.7010896,
35.6601981
],
[
139.7010851,
35.660084
],
[
139.7010559,
35.660088
],
[
139.7010511,
35.6600707
],
[
139.7009769,
35.6600834
],
[
139.7009923,
35.6601243
],
[
139.7009007,
35.6601417
],
[
139.7009195,
35.6602237
],
[
139.7010896,
35.6601981
]
]
]
},
"properties": {
"feature_id": 2,
"overture_id": "046ab130-a9a2-4a0e-9142-b7ea36374fdb",
"name_primary": "丸大ビル",
"bui
0:08
Let me look at more of the file to understand the structure, especially features with holes (interior rings).
0:08
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
with open('tokyo_buildings_legacy.geojson') as f:
data = json.load(f)
print(f'Total features: {len(data[\"features\"])}')
print(f'Has CRS: {\"crs\" in data}')
print(f'CRS: {data.get(\"crs\")}')
# Inspect geometry types
from collections import Counter
types = Counter()
hole_count = Counter()
for feat in data['features']:
g = feat['geometry']
types[g['type']] += 1
if g['type'] == 'Polygon':
n_rings = len(g['coordinates'])
hole_count[n_rings-1] += 1
elif g['type'] == 'MultiPolygon':
for poly in g['coordinates']:
n_rings = len(poly)
hole_count[n_rings-1] += 1
print(f'Geometry types: {dict(types)}')
print(f'Hole counts (Polygons): {dict(hole_count)}')
# Check for common issues: clockwise vs counterclockwise
import shapely.geometry as sg
import shapely.validation as sv
issues = 0
valid_issues = 0
for feat in data['features']:
g = feat['geometry']
try:
shape = sg.shape(g)
if not shape.is_valid:
valid_issues += 1
reason = sv.explain_validity(shape)
if issues < 10:
print(f' feature_id={feat[\"properties\"][\"feature_id\"]}: {reason}')
issues += 1
except Exception as e:
print(f' Error: {e}')
print(f'Total invalid features: {issues}')
print(f'Shapely invalid: {valid_issues}')
"
Total features: 100
Has CRS: True
CRS: {'type': 'name', 'properties': {'name': 'urn:ogc:def:crs:OGC:1.3:CRS84'}}
Geometry types: {'Polygon': 100}
Hole counts (Polygons): {0: 95, 1: 5}
Total invalid features: 0
Shapely invalid: 0
0:18
Interesting - all 100 features are Polygon type, 5 have holes (interior rings), and shapely reports them as valid. But the user says that web viewers render holes incorrectly (filled) and exteriors render as empty space, and the tile-server rejects them with geometry warnings. The issue is likely about **ring orientation**. In GeoJSON, the outer ring of a Polygon must be counterclockwise (or clockwise? let me check). According to the GeoJSON specification (RFC 7946): - The **exterior ring** must be **counterclockwise** (when viewed from above) - **Interior rings** (holes) must be **clockwise** The old GeoJSON might have the opposite orientation, which would cause: 1. Web viewers using the GeoJSON spec to misinterpret which area is "inside" vs "outside" 2. The exterior and interior being flipped, so holes appear filled and the exterior appears empty Let me check the orientation of the rings.
0:18
(no output)
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
from shapely.geometry import Polygon, shape
from shapely import wkt
with open('tokyo_buildings_legacy.geojson') as f:
data = json.load(f)
def ring_orientation(ring):
"""Return 'CW' if clockwise, 'CCW' if counterclockwise"""
# Shoelace formula - positive area = CCW in math coords, but in lat/lon,
# positive = CW (since y increases northward and x eastward, standard screen-like)
# Actually for lat/lon: positive area (signed) = clockwise
# Let's just compute signed area
area = 0.0
n = len(ring)
for i in range(n - 1):
x1, y1 = ring[i]
x2, y2 = ring[i+1]
area += (x2 - x1) * (y1 + y2)
return 'CW' if area > 0 else 'CCW'
for feat in data['features']:
fid = feat['properties']['feature_id']
coords = feat['geometry']['coordinates']
outer = coords[0]
outer_orient = ring_orientation(outer)
issues = []
if outer_orient != 'CCW':
issues.append(f'outer ring is {outer_orient} (should be CCW)')
for idx, inner in enumerate(coords[1:], 1):
inner_orient = ring_orientation(inner)
if inner_orient != 'CW':
issues.append(f'inner ring {idx} is {inner_orient} (should be CW)')
if issues:
print(f'feature_id={fid}: {\" | \".join(issues)}')
"
0:30
So shapely says all polygons are valid (is_valid = True), and the ring orientations seem correct (no output from that check). Let me look more closely at the data. Maybe the issue is with the CRS or something else. Let me check the actual coordinates more carefully - maybe there's a winding order issue with specific features that have holes. Let me check the features that have holes more carefully.
0:30
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
with open('tokyo_buildings_legacy.geojson') as f:
data = json.load(f)
# Find features with holes (inner rings)
for feat in data['features']:
coords = feat['geometry']['coordinates']
if len(coords) > 1:
fid = feat['properties']['feature_id']
print(f'feature_id={fid}: {len(coords)-1} holes, outer has {len(coords[0])} points')
for i, ring in enumerate(coords):
print(f' Ring {i}: {len(ring)} points, closed={ring[0]==ring[-1]}')
# Show first/last few coords
if len(ring) < 10:
print(f' {ring}')
else:
print(f' first: {ring[0]}, last: {ring[-1]}')
"
feature_id=6: 1 holes, outer has 9 points
Ring 0: 9 points, closed=True
[[139.7025726, 35.661211], [139.7025732, 35.6612697], [139.7027844, 35.6612685], [139.7027837, 35.6611824], [139.7025917, 35.6611836], [139.7025916, 35.6611717], [139.7024481, 35.6611726], [139.7024485, 35.6612117], [139.7025726, 35.661211]]
Ring 1: 5 points, closed=True
[[139.70261625, 35.6612158], [139.70263306500001, 35.6612158], [139.70263306500001, 35.6612207], [139.70261625, 35.6612207], [139.70261625, 35.6612158]]
feature_id=18: 1 holes, outer has 6 points
Ring 0: 6 points, closed=True
[[139.7028171, 35.6598877], [139.7028265, 35.6597316], [139.7027047, 35.6597141], [139.702617, 35.6597873], [139.702736, 35.6598859], [139.7028171, 35.6598877]]
Ring 1: 5 points, closed=True
[[139.70271756, 35.659795692], [139.702728035, 35.659795692], [139.702728035, 35.659804372], [139.70271756, 35.659804372], [139.70271756, 35.659795692]]
feature_id=32: 1 holes, outer has 5 points
Ring 0: 5 points, closed=True
[[139.7035951, 35.6602969], [139.7036068, 35.6602603], [139.7035542, 35.6602492], [139.7035425, 35.6602858], [139.7035951, 35.6602969]]
Ring 1: 5 points, closed=True
[[139.703573364, 35.660271142], [139.70357657899999, 35.660271142], [139.70357657899999, 35.660273527], [139.703573364, 35.660273527], [139.703573364, 35.660271142]]
feature_id=50: 1 holes, outer has 5 points
Ring 0: 5 points, closed=True
[[139.7036066, 35.6604974], [139.7036375, 35.6604001], [139.7035278, 35.6603771], [139.7034969, 35.6604744], [139.7036066, 35.6604974]]
Ring 1: 5 points, closed=True
[[139.70356017, 35.660436047], [139.7035672, 35.660436047], [139.7035672, 35.660442061999994], [139.70356017, 35.660442061999994], [139.70356017, 35.660436047]]
feature_id=74: 1 holes, outer has 5 points
Ring 0: 5 points, closed=True
[[139.7033678, 35.6584623], [139.7034246, 35.6583194], [139.7033638, 35.6583179], [139.7033071, 35.6584448], [139.7033678, 35.6584623]]
Ring 1: 5 points, closed=True
[[139.7033635, 35.658387212], [139.703369375, 35.658387212], [139.703369375, 35.658394432], [139.7033635, 35.658394432], [139.7033635, 35.658387212]]
0:51
Let me analyze the geometry issues: 1. The outer ring orientation: Let me check if the outer rings are CW or CCW. In GeoJSON, the standard is that outer rings should be counterclockwise (CCW) and inner rings (holes) should be clockwise (CW). However, the GeoJSON spec actually says it doesn't mandate orientation - RFC 7946 says exterior rings should be CCW and interior rings should be CW. Let me check the orientation of the first few features. Also, looking at the data more carefully, I notice feature_id=6 has an unusual outer ring - it has 9 points where the ring goes: - [139.7025726, 35.661211] → [139.7025732, 35.6612697] → [139.7027844, 35.6612685] → [139.7027837, 35.6611824] → [139.7025917, 35.6611836] → [139.7025916, 35.6611717] → [139.7024481, 35.6611726] → [139.7024485, 35.6612117] → [139.7025726, 35.661211] This is self-intersecting/weird - it goes right, then left, then down... Let me check if the outer ring might be self-intersecting. Let me check the ring orientations more carefully.
0:51
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
with open('tokyo_buildings_legacy.geojson') as f:
data = json.load(f)
def signed_area(ring):
area = 0.0
n = len(ring)
for i in range(n - 1):
x1, y1 = ring[i]
x2, y2 = ring[i+1]
area += (x1 * y2 - x2 * y1)
return area / 2.0
def orientation(ring):
sa = signed_area(ring)
return 'CW' if sa < 0 else 'CCW' if sa > 0 else 'ZERO'
# Check all features
for feat in data['features']:
fid = feat['properties']['feature_id']
coords = feat['geometry']['coordinates']
outer = coords[0]
outer_orient = orientation(outer)
inner_orients = [orientation(r) for r in coords[1:]]
all_cw = all(o == 'CW' for o in inner_orients)
all_ccw = all(o == 'CCW' for o in inner_orients)
if outer_orient != 'CCW' or not all_cw:
print(f'feature_id={fid}: outer={outer_orient}, inners={inner_orients}')
# Also check if feature_id=6 outer ring is self-intersecting
print()
print('Feature 6 outer ring:')
for i, pt in enumerate(data['features'][5]['geometry']['coordinates'][0]):
print(f' {i}: {pt}')
"
feature_id=1: outer=CW, inners=[] feature_id=2: outer=CW, inners=[] feature_id=3: outer=CW, inners=[] feature_id=4: outer=CW, inners=[] feature_id=5: outer=CW, inners=[] feature_id=6: outer=CW, inners=['CCW'] feature_id=7: outer=CW, inners=[] feature_id=8: outer=CW, inners=[] feature_id=9: outer=CW, inners=[] feature_id=10: outer=CW, inners=[] feature_id=11: outer=CW, inners=[] feature_id=12: outer=CW, inners=[] feature_id=13: outer=CW, inners=[] feature_id=14: outer=CW, inners=[] feature_id=15: outer=CW, inners=[] feature_id=16: outer=CW, inners=[] feature_id=17: outer=CW, inners=[] feature_id=18: outer=CW, inners=['CCW'] feature_id=19: outer=CW, inners=[] feature_id=20: outer=CW, inners=[] feature_id=21: outer=CW, inners=[] feature_id=22: outer=CW, inners=[] feature_id=23: outer=CW, inners=[] feature_id=24: outer=CW, inners=[] feature_id=25: outer=CW, inners=[] feature_id=26: outer=CW, inners=[] feature_id=27: outer=CW, inners=[] feature_id=28: outer=CW, inners=[] feature_id=29: outer=CW, inners=[] feature_id=30: outer=CW, inners=[] feature_id=31: outer=CW, inners=[] feature_id=32: outer=CW, inners=['CCW'] feature_id=33: outer=CW, inners=[] feature_id=34: outer=CW, inners=[] feature_id=35: outer=CW, inners=[] feature_id=36: outer=CW, inners=[] feature_id=37: outer=CW, inners=[] feature_id=38: outer=CW, inners=[] feature_id=39: outer=CW, inners=[] feature_id=40: outer=CW, inners=[] feature_id=41: outer=CW, inners=[] feature_id=42: outer=CW, inners=[] feature_id=43: outer=CW, inners=[] feature_id=44: outer=CW, inners=[] feature_id=45: outer=CW, inners=[] feature_id=46: outer=CW, inners=[] feature_id=47: outer=CW, inners=[] feature_id=48: outer=CW, inners=[] feature_id=49: outer=CW, inners=[] feature_id=50: outer=CW, inners=['CCW'] feature_id=51: outer=CW, inners=[] feature_id=52: outer=CW, inners=[] feature_id=53: outer=CW, inners=[] feature_id=54: outer=CW, inners=[] feature_id=55: outer=CW, inners=[] feature_id=56: outer=CW, inners=[] feature_id=57: outer=CW, inners=[] feature_id=58: outer=CW, inners=[] feature_id=59: outer=CW, inners=[] feature_id=60: outer=CW, inners=[] feature_id=61: outer=CW, inners=[] feature_id=62: outer=CW, inners=[] feature_id=63: outer=CW, inners=[] feature_id=64: outer=CW, inners=[] feature_id=65: outer=CW, inners=[] feature_id=66: outer=CW, inners=[] feature_id=67: outer=CW, inners=[] feature_id=68: outer=CW, inners=[] feature_id=69: outer=CW, inners=[] feature_id=70: outer=CW, inners=[] feature_id=71: outer=CW, inners=[] feature_id=72: outer=CW, inners=[] feature_id=73: outer=CW, inners=[] feature_id=74: outer=CW, inners=['CCW'] feature_id=75: outer=CW, inners=[] feature_id=76: outer=CW, inners=[] feature_id=77: outer=CW, inners=[] feature_id=78: outer=CW, inners=[] feature_id=79: outer=CW, inners=[] feature_id=80: outer=CW, inners=[] feature_id=81: outer=CW, inners=[] feature_id=82: outer=CW, inners=[] feature_id=83: outer=CW, inners=[] feature_id=84: outer=CW, inners=[] feature_id=85: outer=CW, inners=[] feature_id=86: outer=CW, inners=[] feature_id=87: outer=CW, inners=[] feature_id=88: outer=CW, inners=[] feature_id=89: outer=CW, inners=[] feature_id=90: outer=CW, inners=[] feature_id=91: outer=CW, inners=[] feature_id=92: outer=CW, inners=[] feature_id=93: outer=CW, inners=[] feature_id=94: outer=CW, inners=[] feature_id=95: outer=CW, inners=[] feature_id=96: outer=CW, inners=[] feature_id=97: outer=CW, inners=[] feature_id=98: outer=CW, inners=[] feature_id=99: outer=CW, inners=[] feature_id=100: outer=CW, inners=[] Feature 6 outer ring: 0: [139.7025726, 35.661211] 1: [139.7025732, 35.6612697] 2: [139.7027844, 35.6612685] 3: [139.7027837, 35.6611824] 4: [139.7025917, 35.6611836] 5: [139.7025916, 35.6611717] 6: [139.7024481, 35.6611726] 7: [139.7024485, 35.6612117] 8: [139.7025726, 35.661211]
0:58
Now I understand the issue. The GeoJSON spec (RFC 7946) requires that: 1. **Outer rings** must be counterclockwise (CCW) 2. **Inner rings (holes)** must be clockwise (CW) Currently, all outer rings are clockwise (CW) and all inner rings are counterclockwise (CCW) - the exact OPPOSITE of what's required. This explains why web viewers render them incorrectly - holes appear filled because the orientation is wrong. The fix is simple: reverse the coordinate order for each ring to flip the orientation. Let me write the script. Wait, I need to be careful. The instruction says "Every feature must remain a Polygon with interior rings and holes preserved exactly as they are; do not flatten them." So I just need to reverse the coordinate order of each ring (both outer and inner) to fix the orientation. Let me verify: currently all outer rings are CW (signed area negative). We need them CCW. And inner rings are CCW (signed area positive), we need them CW. So reversing each ring's coordinates should fix both. Let me write the script.
0:58
0:58
Write
/work/fix_rings.py
content · 39 lines · py
#!/usr/bin/env python3
"""
Fix ring orientation in tokyo_buildings_legacy.geojson.
GeoJSON RFC 7946 requires:
- Outer rings: counterclockwise (CCW)
- Inner rings (holes): clockwise (CW)
The legacy file has them all reversed (outer=CW, inner=CCW).
We reverse each ring's coordinate order to fix orientation while
preserving the exact geometry, attributes, and polygon structure.
"""
import json
INPUT = "/work/tokyo_buildings_legacy.geojson"
OUTPUT = "/work/tokyo_buildings_fixed.geojson"
with open(INPUT, "r", encoding="utf-8") as f:
data = json.load(f)
fixed_count = 0
for feat in data["features"]:
geom = feat["geometry"]
if geom["type"] != "Polygon":
continue # skip non-polygon (there are none in this file)
coords = geom["coordinates"]
# Reverse each ring (outer and all inner holes) to flip orientation
fixed_coords = [list(reversed(ring)) for ring in coords]
geom["coordinates"] = fixed_coords
fixed_count += 1
print(f"Fixed {fixed_count} features.")
with open(OUTPUT, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False)
print(f"Written to {OUTPUT}")
Wrote /work/fix_rings.py (1136 chars).
0:59
Let me run it and then verify the results.
0:59
Bash
cd /work && python3 fix_rings.py
Fixed 100 features. Written to /work/tokyo_buildings_fixed.geojson
1:06
Let me verify the fix worked correctly.
1:06
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
with open('tokyo_buildings_fixed.geojson') as f:
data = json.load(f)
def signed_area(ring):
area = 0.0
n = len(ring)
for i in range(n - 1):
x1, y1 = ring[i]
x2, y2 = ring[i+1]
area += (x1 * y2 - x2 * y1)
return area / 2.0
def orientation(ring):
sa = signed_area(ring)
return 'CW' if sa < 0 else 'CCW' if sa > 0 else 'ZERO'
errors = []
for feat in data['features']:
fid = feat['properties']['feature_id']
coords = feat['geometry']['coordinates']
outer = coords[0]
outer_orient = orientation(outer)
inner_orients = [orientation(r) for r in coords[1:]]
if outer_orient != 'CCW':
errors.append(f'feature_id={fid}: outer is {outer_orient} (should be CCW)')
for i, o in enumerate(inner_orients):
if o != 'CW':
errors.append(f'feature_id={fid}: inner ring {i+1} is {o} (should be CW)')
if errors:
for e in errors:
print(e)
else:
print('All rings correctly oriented: outer=CCW, inner=CW')
# Verify attributes are untouched
with open('tokyo_buildings_legacy.geojson') as f_orig:
orig = json.load(f_orig)
for o_f, f_f in zip(orig['features'], data['features']):
assert o_f['properties'] == f_f['properties'], f'Attribute mismatch for feature_id={f_f[\"properties\"][\"feature_id\"]}'
# Verify same number of rings
assert len(o_f['geometry']['coordinates']) == len(f_f['geometry']['coordinates']), f'Ring count mismatch'
# Verify same structure (just reversed orientation)
for o_ring, f_ring in zip(o_f['geometry']['coordinates'], f_f['geometry']['coordinates']):
# One should be the reverse of the other
assert list(reversed(o_ring)) == f_ring or o_ring == f_ring, \
f'Ring mismatch for feature_id={f_f[\"properties\"][\"feature_id\"]}'
print('All attributes and geometry structure preserved.')
print(f'Feature count: {len(data[\"features\"])}')
"
All rings correctly oriented: outer=CCW, inner=CW All attributes and geometry structure preserved. Feature count: 100
1:09
Let me also verify with Shapely that the geometries are valid now.
1:09
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
from shapely.geometry import shape
from shapely.validation import explain_validity
with open('tokyo_buildings_fixed.geojson') as f:
data = json.load(f)
invalid = 0
for feat in data['features']:
g = shape(feat['geometry'])
if not g.is_valid:
invalid += 1
print(f' feature_id={feat[\"properties\"][\"feature_id\"]}: {explain_validity(g)}')
print(f'Invalid features: {invalid}')
print('Done.')
"
Invalid features: 0 Done.
1:12
All checks pass. Let me also verify the output file is valid GeoJSON (no CRS, as per RFC 7946) but actually the task says to fix geometries so that standard GeoJSON web viewers render them correctly. The CRS field is non-standard for RFC 7946 GeoJSON but the instruction didn't ask to remove it, so I'll leave it as-is. The key fix was ring orientation. Let me also quickly check the output file to make sure it looks good.
1:12
1:12
Bash
cd /work && python3 -c "
cd /work && python3 -c "
import json
with open('tokyo_buildings_fixed.geojson') as f:
data = json.load(f)
# Show first feature to confirm format
feat = data['features'][0]
print(json.dumps(feat, indent=2, ensure_ascii=False))
# Check feature_id 6 (has hole) to verify hole is now CW
feat6 = data['features'][5]
print()
print('Feature 6 (has hole) inner ring:')
print(json.dumps(feat6['geometry']['coordinates'][1], indent=2))
"
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
139.7029081,
35.6592372
],
[
139.7028864,
35.6592823
],
[
139.7027755,
35.6592471
],
[
139.7027971,
35.659202
],
[
139.7029081,
35.6592372
]
]
]
},
"properties": {
"feature_id": 1,
"overture_id": "01302ced-3141-4b64-b630-98019352a9fd",
"name_primary": "渋谷協和ビル",
"building_class": "",
"height": null
}
}
Feature 6 (has hole) inner ring:
[
[
139.70261625,
35.6612158
],
[
139.70261625,
35.6612207
],
[
139.70263306500001,
35.6612207
],
[
139.70263306500001,
35.6612158
],
[
139.70261625,
35.6612158
]
]
1:16
The fix is complete. Let me verify the output file is at the right path.
1:16