Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Change log

### 0.3.4
- Fix OSM→OSW conversion when OSM Way contains consecutive duplicate nodes (bug 3286). Instead of generating an invalid 0 length geometry, the segment is ignored.

### 0.3.3
- Fix OSM→OSW export classification so canonical OSM tags are used for semantic recognition and `ext:*` tags are preserved as extensions instead of being treated as feature-defining tags.
- Fix closed ext-only ways such as `ext:demolished:building=yes` to emit polygon output without falling through to point geometry construction.
Expand Down
10 changes: 9 additions & 1 deletion src/osm_osw_reformatter/serializer/osm/osm_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def way(self, w) -> None:

d2 = {**d, **OSWWayNormalizer(tags).normalize()}

segment_n = 0
for i in range(len(w.nodes) - 1):
u = w.nodes[i]
v = w.nodes[i + 1]
Expand All @@ -49,12 +50,19 @@ def way(self, w) -> None:
v_lon = float(v.lon)
v_lat = float(v.lat)

# Skip consecutive duplicate nodes. They create zero-length segments.
if u_ref == v_ref:
del u
del v
continue

d3 = {**d2}
d3['segment'] = i
d3['segment'] = segment_n
d3['ndref'] = [u_ref, v_ref]
self.G.add_edges_from([(u_ref, v_ref, d3)])
self.G.add_node(u_ref, lon=u_lon, lat=u_lat)
self.G.add_node(v_ref, lon=v_lon, lat=v_lat)
segment_n += 1
del u
del v

Expand Down
2 changes: 1 addition & 1 deletion src/osm_osw_reformatter/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.3.3'
__version__ = '0.3.4'
10 changes: 10 additions & 0 deletions tests/unit_tests/test_files/bug_3286.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="TDEI exporter" upload="false">
<node visible="true" version="1" id="8223" lat="47.9217092" lon="-122.2499566"><tag k="ext:osm_version" v="2"/></node>
<node visible="true" version="1" id="8224" lat="47.9217137" lon="-122.2499283"><tag k="ext:osm_version" v="2"/></node>
<node visible="true" version="1" id="8232" lat="47.9217122" lon="-122.2499433"><tag k="ext:osm_version" v="2"/></node>
<node visible="true" version="1" id="8237" lat="47.9217066" lon="-122.2499667"><tag k="ext:osm_version" v="2"/></node>
<node visible="true" version="1" id="8241" lat="47.9217132" lon="-122.2499356"><tag k="ext:osm_version" v="2"/></node>
<node visible="true" version="1" id="16255" lat="47.9217166" lon="-122.2495229"><tag k="ext:osm_version" v="2"/></node>
<way visible="true" version="1" id="19002"><nd ref="8237"/><nd ref="8237"/><nd ref="8223"/><nd ref="8232"/><nd ref="8241"/><nd ref="8224"/><nd ref="16255"/><tag k="width" v="2.0"/><tag k="footway" v="sidewalk"/><tag k="highway" v="footway"/><tag k="incline" v="0.009"/><tag k="surface" v="concrete"/><tag k="ext:osm_version" v="3"/><tag k="ext:width_confidence" v="1.0"/><tag k="ext:sidewalk_corrected" v="yes"/></way>
</osm>
21 changes: 21 additions & 0 deletions tests/unit_tests/test_osm2osw/test_osm2osw.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
TEST_INVALID_NODE_TAGS_FILE = os.path.join(ROOT_DIR, 'test_files/node_with_invalid_tags.xml')
TEST_TREE_FILE = os.path.join(ROOT_DIR, 'test_files/tree-test.xml')
TEST_BUG_3477_FILE = os.path.join(ROOT_DIR, 'test_files/bug_3477.xml')
TEST_BUG_3286_FILE = os.path.join(ROOT_DIR, 'test_files/bug_3286.xml')


def is_valid_float(value):
Expand Down Expand Up @@ -350,6 +351,26 @@ async def run_test():

asyncio.run(run_test())

def test_bug_3286_consecutive_duplicate_nodes(self):
osm_file_path = TEST_BUG_3286_FILE

async def run_test():
osm2osw = OSM2OSW(osm_file=osm_file_path, workdir=OUTPUT_DIR, prefix='test')
result = await osm2osw.convert()
self.assertTrue(result.status)
self.assertEqual(len(result.generated_files), 2)

for file_path in result.generated_files:
if file_path.endswith('edges.geojson'):
with open(file_path) as f:
geojson = json.load(f)
self.assertEqual(len(geojson.get("features", [])), 1)

for file_path in result.generated_files:
os.remove(file_path)

asyncio.run(run_test())


if __name__ == '__main__':
unittest.main()
Loading