Relations are utilized in OSM to group a number of different parts right into a single object. Right here we are going to focus solely on the (multi-) polygons. These particular parts have a sort
tag with one in all two values: boundary
, and multipolygon
.
This sort of object is essentially the most complicated to reconstruct the geometry for and right here is the listing of steps now we have to do:
- Choose relations with correct
sort
worth. - Unnest all refs associated to the relation and preserve solely approach refs — we solely want associated approach refs to reconstruct a polygon.
- Choose required methods with linestring geometries — right here we will make the most of steps from setting up methods.
- Assign an ‘outer’ position to the way in which ref if it’s
null
and test if any ref from the relation has the position ‘outer’ — if a relation has no ‘outer’ refs then deal with all of them as ‘outer’. - Group all linestrings per ‘outer’ and ‘internal’ position and merge them right into a single multilinestring — many relations are outlined with a number of single linestrings that solely collectively create a closed polygon.
- Break up multilinestrings into single closed-loop linestrings and save them as polygons.
- Break up geometries into ‘outer’ and ‘internal’ polygons. These may be extracted from the
ref_role
column of the relation object. - For every ‘outer’ polygon, choose all ‘internal’ polygons which might be absolutely inside it and make holes on this polygon.
- Make a union of all ‘outer’ polygons with holes.
Let’s begin with deciding on relations with matching tag values.
CREATE TEMP TABLE matching_relations AS
SELECT id, tags
FROM ST_READOSM('monaco-latest.osm.pbf')
WHERE variety = 'relation' AND len(refs) > 0
AND tags IS NOT NULL AND cardinality(tags) > 0
AND list_contains(map_keys(tags), 'sort')
AND list_has_any(map_extract(tags, 'sort'), ['boundary', 'multipolygon']);SELECT * FROM matching_relations;
┌──────────┬───────────────────────────────────────────────────────────────────┐
│ id │ tags │
│ int64 │ map(varchar, varchar) │
├──────────┼───────────────────────────────────────────────────────────────────┤
│ 7385 │ {ISO3166-2=FR-06, admin_level=6, alt_name:de=Meeralpen, border_… │
│ 8654 │ {ISO3166-2=FR-PAC, admin_level=4, border_type=area, boundary=… │
│ 36990 │ {ISO3166-1=MC, ISO3166-1:alpha2=MC, ISO3166-1:alpha3=MCO, admin… │
│ 174558 │ {admin_level=8, boundary=administrative, identify=Roquebrune-Cap-Ma… │
│ 174562 │ {admin_level=8, boundary=administrative, identify=Beausoleil, identify:… │
│ 174956 │ {admin_level=8, alt_name:it=Capo d`Aglio, boundary=administrati… │
│ 174958 │ {admin_level=8, boundary=administrative, identify=La Turbie, identify:i… │
│ 393226 │ {constructing=fort, castle_type=palace, cost=10€, e mail=visites… │
│ 393481 │ {constructing=faculty, identify=Pensionnat des Dames de Saint-Maur, sort… │
│ 1124039 │ {ISO3166-1=MC, ISO3166-1:alpha2=MC, ISO3166-1:alpha3=MCO, ISO31… │
│ · │ · │
│ · │ · │
│ · │ · │
│ 14399505 │ {space=sure, floating=sure, man_made=pier, sort=multipolygon} │
│ 16248281 │ {constructing=residences, identify=F, sort=multipolygon} │
│ 16248282 │ {constructing=residences, identify=E, sort=multipolygon} │
│ 16248283 │ {constructing=residences, identify=D, sort=multipolygon} │
│ 16248284 │ {constructing=residences, identify=C, sort=multipolygon} │
│ 16248285 │ {constructing=residences, identify=B, sort=multipolygon} │
│ 16248286 │ {constructing=residences, identify=A, sort=multipolygon} │
│ 16250182 │ {addr:nation=MC, alt_name=Parc de la Roseraie, leisure=park, n… │
│ 16261416 │ {pure=water, sort=multipolygon, water=pond} │
│ 16467322 │ {admin_level=2, boundary=land_area, land_area=administrative, n… │
├──────────┴───────────────────────────────────────────────────────────────────┤
│ 78 rows (20 proven) 2 columns │
└──────────────────────────────────────────────────────────────────────────────┘
Now we are going to unnest refs lists and cut up them into particular person rows. Like with methods, right here we will even make the most of DuckDB’s indexing capabilities to recollect the order of parts within the authentic listing. Moreover, we are going to solely preserve the approach
refs.
CREATE TEMP TABLE matching_relations_with_ways_refs AS
WITH unnested_relation_refs AS (
SELECT
r.id,
UNNEST(refs) as ref,
UNNEST(ref_types) as ref_type,
UNNEST(ref_roles) as ref_role,
UNNEST(vary(size(refs))) as ref_idx
FROM ST_READOSM('monaco-latest.osm.pbf') r
SEMI JOIN matching_relations USING (id)
WHERE variety = 'relation'
)
SELECT id, ref, ref_role, ref_idx
FROM unnested_relation_refs
WHERE ref_type = 'approach';SELECT * FROM matching_relations_with_ways_refs;
┌──────────┬───────────┬──────────┬─────────┐
│ id │ ref │ ref_role │ ref_idx │
│ int64 │ int64 │ varchar │ int64 │
├──────────┼───────────┼──────────┼─────────┤
│ 7385 │ 30836152 │ outer │ 2 │
│ 7385 │ 889278953 │ outer │ 3 │
│ 7385 │ 889278956 │ outer │ 4 │
│ 7385 │ 889278957 │ outer │ 5 │
│ 7385 │ 889278958 │ outer │ 6 │
│ 7385 │ 889278962 │ outer │ 7 │
│ 7385 │ 960087656 │ outer │ 8 │
│ 7385 │ 30836155 │ outer │ 9 │
│ 7385 │ 889278965 │ outer │ 10 │
│ 7385 │ 889278963 │ outer │ 11 │
│ · │ · │ · │ · │
│ · │ · │ · │ · │
│ · │ · │ · │ · │
│ 11278320 │ 35150936 │ outer │ 197 │
│ 11278320 │ 466647567 │ outer │ 198 │
│ 11278320 │ 214008684 │ outer │ 199 │
│ 11278320 │ 466647569 │ outer │ 200 │
│ 11278320 │ 466647568 │ outer │ 201 │
│ 11278320 │ 214008689 │ outer │ 202 │
│ 11278320 │ 263776194 │ outer │ 203 │
│ 11278320 │ 31124893 │ outer │ 204 │
│ 11278320 │ 31124895 │ outer │ 205 │
│ 11278320 │ 31124899 │ outer │ 206 │
├──────────┴───────────┴──────────┴─────────┤
│ ? rows (>9999 rows, 20 proven) 4 columns │
└───────────────────────────────────────────┘
Within the subsequent step, we are going to assemble linestrings for the methods required by the relations. The question beneath compresses virtually full logic of studying methods in a single go (getting required nodes, setting up factors and grouping them into linestrings):
CREATE TEMP TABLE required_ways_linestrings AS
WITH ways_required_by_relations_with_nodes_refs AS (
SELECT id, UNNEST(refs) as ref, UNNEST(vary(size(refs))) as ref_idx
FROM ST_READOSM('monaco-latest.osm.pbf') methods
SEMI JOIN matching_relations_with_ways_refs
ON methods.id = matching_relations_with_ways_refs.ref
WHERE variety = 'approach'
),
nodes_required_by_relations_with_geometries AS (
SELECT id, ST_POINT(lon, lat) geometry
FROM ST_READOSM('monaco-latest.osm.pbf') nodes
SEMI JOIN ways_required_by_relations_with_nodes_refs
ON nodes.id = ways_required_by_relations_with_nodes_refs.ref
WHERE variety = 'node'
)
SELECT
methods.id,
ST_MakeLine(listing(nodes.geometry ORDER BY ref_idx ASC)) linestring
FROM ways_required_by_relations_with_nodes_refs methods
JOIN nodes_required_by_relations_with_geometries nodes
ON methods.ref = nodes.id
GROUP BY 1;SELECT * FROM required_ways_linestrings;
┌────────────┬─────────────────────────────────────────────────────────────────┐
│ id │ linestring │
│ int64 │ geometry │
├────────────┼─────────────────────────────────────────────────────────────────┤
│ 37794470 │ LINESTRING (7.438411400000001 43.749422300000006, 7.4384056 4… │
│ 87878917 │ LINESTRING (7.418041100000001 43.7256933, 7.4181547 43.725613… │
│ 94252430 │ LINESTRING (7.4141873 43.729494100000004, 7.414203400000001 4… │
│ 94399618 │ LINESTRING (7.4239717 43.740543100000004, 7.4238252 43.740372… │
│ 94399736 │ LINESTRING (7.423881400000001 43.7402971, 7.4239411 43.740265… │
│ 104863462 │ LINESTRING (7.424840000000001 43.731281800000005, 7.424917000… │
│ 120114110 │ LINESTRING (7.420872 43.7370979, 7.4207787 43.7370534, 7.4206… │
│ 156242249 │ LINESTRING (7.4294728 43.739895600000004, 7.429579500000001 4… │
│ 165636038 │ LINESTRING (7.419717100000001 43.732398700000005, 7.419772900… │
│ 169297863 │ LINESTRING (7.422815300000001 43.7321967, 7.4234109 43.732263… │
│ · │ · │
│ · │ · │
│ · │ · │
│ 24874398 │ LINESTRING (7.418523400000001 43.7247599, 7.419012800000001 4… │
│ 92627424 │ LINESTRING (7.4166521 43.7322122, 7.4162303 43.73173910000000… │
│ 94452829 │ LINESTRING (7.4317066 43.7469647, 7.4317998 43.7470371, 7.431… │
│ 335740502 │ LINESTRING (7.4185151 43.7353633, 7.418442000000001 43.735298… │
│ 398377193 │ LINESTRING (7.420872 43.7370979, 7.420939000000001 43.7371298… │
│ 405529436 │ LINESTRING (7.417534900000001 43.7258914, 7.4175347 43.725833… │
│ 423632259 │ LINESTRING (7.4212208 43.7320944, 7.421461300000001 43.732057… │
│ 572935479 │ LINESTRING (7.427508100000001 43.7394168, 7.427496700000001 4… │
│ 586494707 │ LINESTRING (7.4270357 43.739109000000006, 7.4269512 43.739155… │
│ 1202570715 │ LINESTRING (7.426448400000001 43.739491400000006, 7.4264682 4… │
├────────────┴─────────────────────────────────────────────────────────────────┤
│ 141 rows (20 proven) 2 columns │
└──────────────────────────────────────────────────────────────────────────────┘
After creating the required linestrings, now we will be a part of them with relations information. We will even make it possible for the required ref_role
is correctly parsed — fill within the empty values or change them if the relation has incorrectly outlined ref_roles
within the OSM database.
CREATE TEMP TABLE matching_relations_with_ways_linestrings AS
WITH unnested_relations_with_way_linestrings AS (
SELECT
r.id,
COALESCE(r.ref_role, 'outer') as ref_role,
r.ref,
w.linestring::GEOMETRY as geometry
FROM matching_relations_with_ways_refs r
JOIN required_ways_linestrings w
ON w.id = r.ref
ORDER BY r.id, r.ref_idx
),
any_outer_refs AS (
-- test if any approach hooked up to the relation has the `outer` position
SELECT id, bool_or(ref_role == 'outer') has_any_outer_refs
FROM unnested_relations_with_way_linestrings
GROUP BY id
)
SELECT
unnested_relations_with_way_linestrings.* EXCLUDE (ref_role),
-- if not one of the approach refs has `outer` position - deal with every ref as `outer`
CASE WHEN any_outer_refs.has_any_outer_refs
THEN unnested_relations_with_way_linestrings.ref_role
ELSE 'outer'
END as ref_role
FROM unnested_relations_with_way_linestrings
JOIN any_outer_refs
ON any_outer_refs.id = unnested_relations_with_way_linestrings.id;SELECT * FROM matching_relations_with_ways_linestrings;
┌──────────┬───────────┬────────────────────────────────────────────┬──────────┐
│ id │ ref │ geometry │ ref_role │
│ int64 │ int64 │ geometry │ varchar │
├──────────┼───────────┼────────────────────────────────────────────┼──────────┤
│ 7385 │ 772081595 │ LINESTRING (7.415291600000001 43.7234393… │ outer │
│ 7385 │ 212810311 │ LINESTRING (7.4120416 43.7280955, 7.4123… │ outer │
│ 7385 │ 176533407 │ LINESTRING (7.412670800000001 43.7316348… │ outer │
│ 7385 │ 37811853 │ LINESTRING (7.4127007 43.7346954, 7.4126… │ outer │
│ 7385 │ 37794471 │ LINESTRING (7.428754700000001 43.7460174… │ outer │
│ 7385 │ 398372186 │ LINESTRING (7.436885 43.7519173, 7.43677… │ outer │
│ 7385 │ 37794470 │ LINESTRING (7.438411400000001 43.7494223… │ outer │
│ 7385 │ 770774507 │ LINESTRING (7.439171000000001 43.7490109… │ outer │
│ 8654 │ 772081595 │ LINESTRING (7.415291600000001 43.7234393… │ outer │
│ 8654 │ 212810311 │ LINESTRING (7.4120416 43.7280955, 7.4123… │ outer │
│ · │ · │ · │ · │
│ · │ · │ · │ · │
│ · │ · │ · │ · │
│ 11546878 │ 840890844 │ LINESTRING (7.420754 43.735872900000004,… │ outer │
│ 11546878 │ 840890848 │ LINESTRING (7.4207413 43.7356673, 7.4207… │ outer │
│ 16467322 │ 772081595 │ LINESTRING (7.415291600000001 43.7234393… │ outer │
│ 16467322 │ 212810311 │ LINESTRING (7.4120416 43.7280955, 7.4123… │ outer │
│ 16467322 │ 176533407 │ LINESTRING (7.412670800000001 43.7316348… │ outer │
│ 16467322 │ 37811853 │ LINESTRING (7.4127007 43.7346954, 7.4126… │ outer │
│ 16467322 │ 37794471 │ LINESTRING (7.428754700000001 43.7460174… │ outer │
│ 16467322 │ 398372186 │ LINESTRING (7.436885 43.7519173, 7.43677… │ outer │
│ 16467322 │ 37794470 │ LINESTRING (7.438411400000001 43.7494223… │ outer │
│ 16467322 │ 770774507 │ LINESTRING (7.439171000000001 43.7490109… │ outer │
├──────────┴───────────┴────────────────────────────────────────────┴──────────┤
│ 410 rows (20 proven) 4 columns │
└──────────────────────────────────────────────────────────────────────────────┘
As you’ll be able to see, there are a number of methods with linestrings assigned to every relation. Let’s have a look at an instance to see how they appear on the map:
To create full polygons, now we have to make the most of a ST_LineMerge
operate, that can mix an inventory of linestrings (you’ll be able to examine it to tying items of string collectively). You’ll be able to learn extra about this operation right here:
As an extra validation step, we are going to test if the produced linestrings have at the very least 4 factors and if the primary level equals the final level, earlier than changing them into polygons:
CREATE TEMP TABLE matching_relations_with_merged_polygons AS
WITH merged_linestrings AS (
SELECT
id,
ref_role,
UNNEST(
ST_Dump(ST_LineMerge(ST_Collect(listing(geometry)))),
recursive := true
),
FROM matching_relations_with_ways_linestrings
GROUP BY id, ref_role
),
relations_with_linestrings AS (
SELECT
id,
ref_role,
-- ST_Dump returns column named `geom`
geom AS geometry,
row_number() OVER (PARTITION BY id) as geometry_id
FROM
merged_linestrings
-- discard linestrings with lower than 4 factors
WHERE ST_NPoints(geom) >= 4
),
valid_relations AS (
SELECT id, is_valid
FROM (
SELECT
id,
bool_and(
-- Examine if begin level equals the top level
ST_Equals(ST_StartPoint(geometry), ST_EndPoint(geometry))
) is_valid
FROM relations_with_linestrings
GROUP BY id
)
WHERE is_valid = true
)
SELECT
id,
ref_role,
ST_MakePolygon(geometry) geometry,
geometry_id
FROM relations_with_linestrings
SEMI JOIN valid_relations
ON relations_with_linestrings.id = valid_relations.id;SELECT * FROM matching_relations_with_merged_polygons;
┌──────────┬──────────┬──────────────────────────────────────────┬─────────────┐
│ id │ ref_role │ geometry │ geometry_id │
│ int64 │ varchar │ geometry │ int64 │
├──────────┼──────────┼──────────────────────────────────────────┼─────────────┤
│ 1369631 │ internal │ POLYGON ((7.438232200000001 43.7511057… │ 1 │
│ 1369631 │ outer │ POLYGON ((7.438008600000001 43.7502850… │ 2 │
│ 1484217 │ outer │ POLYGON ((7.423010700000001 43.7307028… │ 1 │
│ 1484217 │ internal │ POLYGON ((7.423114600000001 43.7305994… │ 2 │
│ 5986436 │ outer │ POLYGON ((7.428754700000001 43.7460174… │ 1 │
│ 8269572 │ outer │ POLYGON ((7.4287048 43.737701400000006… │ 1 │
│ 8269572 │ internal │ POLYGON ((7.4284492 43.7375604, 7.4286… │ 2 │
│ 16248286 │ outer │ POLYGON ((7.426306200000001 43.7391565… │ 1 │
│ 16248286 │ internal │ POLYGON ((7.4263241 43.7390763, 7.4263… │ 2 │
│ 16261416 │ internal │ POLYGON ((7.417829200000001 43.731382,… │ 1 │
│ · │ · │ · │ · │
│ · │ · │ · │ · │
│ · │ · │ · │ · │
│ 8280869 │ internal │ POLYGON ((7.426753300000001 43.7388868… │ 2 │
│ 8280869 │ internal │ POLYGON ((7.4270357 43.739109000000006… │ 3 │
│ 8280869 │ internal │ POLYGON ((7.4271374 43.739011500000004… │ 4 │
│ 8280869 │ internal │ POLYGON ((7.4272666 43.7389165, 7.4273… │ 5 │
│ 11384697 │ outer │ POLYGON ((7.427075 43.7315167, 7.42749… │ 1 │
│ 11384697 │ internal │ POLYGON ((7.426917700000001 43.7313266… │ 2 │
│ 11384697 │ internal │ POLYGON ((7.427001400000001 43.7313937… │ 3 │
│ 11546878 │ outer │ POLYGON ((7.4207413 43.7356673, 7.4207… │ 1 │
│ 11538023 │ internal │ POLYGON ((7.426528200000001 43.7329359… │ 1 │
│ 11538023 │ outer │ POLYGON ((7.426554 43.7328276, 7.42654… │ 2 │
├──────────┴──────────┴──────────────────────────────────────────┴─────────────┤
│ 88 rows (20 proven) 4 columns │
└──────────────────────────────────────────────────────────────────────────────┘
Let’s see the earlier instance after this operation. We should always count on two separate polygons to be current:
I’ve talked about beforehand the outer
and internal
‘ref_types’ of ways in which create a relation. Right here you’ll be able to see what it seems like:
The roles imply that the internal
methods are the ‘holes’ inside outer
polygons and now we have to breed this step to make correct geometries.
Let’s focus now on splitting the polygons into teams with and with out holes, utilizing the ST_Within
predicate, which checks if a geometry is absolutely inside one other.
CREATE TEMP TABLE matching_relations_with_outer_polygons_with_holes AS
WITH outer_polygons AS (
SELECT id, geometry_id, geometry
FROM matching_relations_with_merged_polygons
WHERE ref_role = 'outer'
), inner_polygons AS (
SELECT id, geometry_id, geometry
FROM matching_relations_with_merged_polygons
WHERE ref_role = 'internal'
)
SELECT
op.id,
op.geometry_id,
ST_Difference(any_value(op.geometry), ST_Union_Agg(ip.geometry)) geometry
FROM outer_polygons op
JOIN inner_polygons ip
ON op.id = ip.id AND ST_WITHIN(ip.geometry, op.geometry)
GROUP BY op.id, op.geometry_id;CREATE TEMP TABLE matching_relations_with_outer_polygons_without_holes AS
WITH outer_polygons AS (
SELECT id, geometry_id, geometry
FROM matching_relations_with_merged_polygons
WHERE ref_role = 'outer'
)
SELECT
op.id,
op.geometry_id,
op.geometry
FROM outer_polygons op
ANTI JOIN matching_relations_with_outer_polygons_with_holes opwh
ON op.id = opwh.id AND op.geometry_id = opwh.geometry_id;
SELECT * FROM matching_relations_with_outer_polygons_with_holes
UNION ALL
SELECT * FROM matching_relations_with_outer_polygons_without_holes;
┌──────────┬─────────────┬─────────────────────────────────────────────────────┐
│ id │ geometry_id │ geometry │
│ int64 │ int64 │ geometry │
├──────────┼─────────────┼─────────────────────────────────────────────────────┤
│ 16248286 │ 1 │ POLYGON ((7.4263139 43.7391602, 7.426324900000001… │
│ 1369192 │ 1 │ POLYGON ((7.4226247 43.7402251, 7.4227848 43.7396… │
│ 8147763 │ 1 │ POLYGON ((7.438223000000001 43.7477296, 7.4382403… │
│ 393226 │ 1 │ POLYGON ((7.4204802 43.731016700000005, 7.4203979… │
│ 11484092 │ 4 │ POLYGON ((7.417896900000001 43.724827000000005, 7… │
│ 11384697 │ 1 │ POLYGON ((7.4274934 43.731250700000004, 7.4267196… │
│ 8269572 │ 1 │ POLYGON ((7.4287166 43.7376724, 7.4287948 43.7376… │
│ 16261416 │ 3 │ POLYGON ((7.4178309 43.731391, 7.417877000000001 … │
│ 16248284 │ 1 │ POLYGON ((7.426637500000001 43.7394678, 7.4266485… │
│ 16248285 │ 1 │ POLYGON ((7.426114600000001 43.739267600000005, 7… │
│ · │ · │ · │
│ · │ · │ · │
│ · │ · │ · │
│ 11546879 │ 1 │ POLYGON ((7.4209316 43.7356234, 7.421037 43.73562… │
│ 2220206 │ 1 │ POLYGON ((7.4120416 43.7280955, 7.412103900000001… │
│ 5986438 │ 1 │ POLYGON ((7.4191482 43.738887500000004, 7.4199833… │
│ 2221178 │ 1 │ POLYGON ((7.415860400000001 43.7313885, 7.416195 … │
│ 2221179 │ 1 │ POLYGON ((7.422280000000001 43.7367186, 7.4227584… │
│ 2220208 │ 1 │ POLYGON ((7.41849 43.730922400000004, 7.4185156 4… │
│ 2254506 │ 1 │ POLYGON ((7.432995900000001 43.7447102, 7.4329125… │
│ 5986437 │ 1 │ POLYGON ((7.4307593 43.745595, 7.4306621 43.74541… │
│ 5986437 │ 2 │ POLYGON ((7.4343358 43.7457085, 7.4341337 43.7455… │
│ 11546878 │ 1 │ POLYGON ((7.4207413 43.7356673, 7.4207413 43.7357… │
├──────────┴─────────────┴─────────────────────────────────────────────────────┤
│ 47 rows (20 proven) 3 columns │
└──────────────────────────────────────────────────────────────────────────────┘
On this question, there’s utilized one other particular be a part of — ANTI JOIN
. This one filters out all of the rows on the left-side desk which might be joined by the right-side desk.
The final step that’s wanted is to merge all of the polygons for a single relation utilizing the ST_Union_Agg
operation. It should mix all polygons into multipolygons (if there’s a couple of) and produce a single geometry.
WITH unioned_outer_geometries AS (
SELECT id, geometry
FROM matching_relations_with_outer_polygons_with_holes
UNION ALL
SELECT id, geometry
FROM matching_relations_with_outer_polygons_without_holes
),
final_geometries AS (
SELECT id, ST_Union_Agg(geometry) geometry
FROM unioned_outer_geometries
GROUP BY id
)
SELECT r_g.id, r.tags, r_g.geometry
FROM final_geometries r_g
JOIN matching_relations r
ON r.id = r_g.id;┌──────────┬──────────────────────┬────────────────────────────────────────────┐
│ id │ tags │ geometry │
│ int64 │ map(varchar, varch… │ geometry │
├──────────┼──────────────────────┼────────────────────────────────────────────┤
│ 393226 │ {constructing=fort, … │ POLYGON ((7.4204802 43.731016700000005, … │
│ 393481 │ {constructing=faculty, … │ POLYGON ((7.423992800000001 43.731841800… │
│ 1369191 │ {constructing=apartmen… │ POLYGON ((7.4231004 43.7412894, 7.423314… │
│ 1369192 │ {constructing=apartmen… │ POLYGON ((7.4226247 43.7402251, 7.422784… │
│ 1369193 │ {constructing=apartmen… │ POLYGON ((7.424 43.7405491, 7.4240401 43… │
│ 1369195 │ {constructing=apartmen… │ POLYGON ((7.418679900000001 43.738187100… │
│ 1369631 │ {addr:housenumber=… │ POLYGON ((7.4379729 43.7502505, 7.437937… │
│ 1369632 │ {addr:metropolis=Monaco,… │ POLYGON ((7.4317121 43.74709, 7.4318277 … │
│ 1484190 │ {addr:metropolis=Monaco,… │ POLYGON ((7.425469 43.731494000000005, 7… │
│ 1484217 │ {constructing=retail, … │ POLYGON ((7.423202300000001 43.7307117, … │
│ · │ · │ · │
│ · │ · │ · │
│ · │ · │ · │
│ 14399505 │ {space=sure, floatin… │ POLYGON ((7.4195986 43.7265293, 7.419595… │
│ 16248281 │ {constructing=apartmen… │ POLYGON ((7.4260438 43.739789800000004, … │
│ 16248282 │ {constructing=apartmen… │ POLYGON ((7.426243100000001 43.7396824, … │
│ 16248283 │ {constructing=apartmen… │ POLYGON ((7.426438200000001 43.739575200… │
│ 16248284 │ {constructing=apartmen… │ POLYGON ((7.426637500000001 43.7394678, … │
│ 16248285 │ {constructing=apartmen… │ POLYGON ((7.426114600000001 43.739267600… │
│ 16248286 │ {constructing=apartmen… │ POLYGON ((7.4263139 43.7391602, 7.426324… │
│ 16250182 │ {addr:nation=MC, … │ POLYGON ((7.418348300000001 43.7256979, … │
│ 16261416 │ {pure=water, ty… │ POLYGON ((7.4178309 43.731391, 7.4178770… │
│ 11546878 │ {addr:metropolis=Monaco,… │ POLYGON ((7.4207413 43.7356673, 7.420741… │
├──────────┴──────────────────────┴────────────────────────────────────────────┤
│ 46 rows (20 proven) 3 columns │
└──────────────────────────────────────────────────────────────────────────────┘
Right here is the earlier relation instance, now with holes: