CreateTopoGeom — Creates a new topo geometry object from topo element array - tg_type: 1:[multi]point, 2:[multi]line, 3:[multi]poly, 4:collection
topogeometry CreateTopoGeom(varchar toponame, integer tg_type, integer layer_id, topoelementarray tg_objs, bigint tg_id);
topogeometry CreateTopoGeom(varchar toponame, integer tg_type, integer layer_id);
Creates a topogeometry object for layer denoted by layer_id and registers it in the relations table in the toponame schema.
tg_type is an integer: 1:[multi]point (punctal), 2:[multi]line (lineal), 3:[multi]poly (areal), 4:collection. layer_id is the layer id in the topology.layer table.
punctal layers are formed from set of nodes, lineal layers are formed from a set of edges, areal layers are formed from a set of faces, and collections can be formed from a mixture of nodes, edges, and faces.
Omitting the array of components generates an empty TopoGeometry object.
Availability: 1.1
Form from existing edges.
Create a topogeom in ri_topo schema for layer 2 (our ri_roads), of type (2) LINE, for the first edge (we loaded in ST_CreateTopoGeo).
INSERT INTO ri.ri_roads(road_name, topo)
VALUES (
'Unknown',
topology.CreateTopoGeom(
'ri_topo',
2,
2,
'{{1,2}}'::topology.topoelementarray
)
);
Convert an areal geometry to best guess topogeometry.
Lets say we have geometries that should be formed from a collection of faces. We have for example blockgroups table and want to know the topo geometry of each block group. If our data was perfectly aligned, we could do this:
Create the topogeometry column.
SELECT topology.AddTopoGeometryColumn( 'topo_boston', 'boston', 'blockgroups', 'topo', 'POLYGON');
1
Update the column assuming everything is perfectly aligned with the edges.
UPDATE boston.blockgroups AS bg
SET topo = topology.CreateTopoGeom(
'topo_boston',
3,
1,
foo.bfaces
)
FROM (
SELECT
b.gid,
topology.TopoElementArray_Agg(ARRAY[f.face_id, 3]) AS bfaces
FROM boston.blockgroups AS b
INNER JOIN topo_boston.face AS f
ON b.geom && f.mbr
WHERE ST_Covers(
b.geom,
topology.ST_GetFaceGeometry('topo_boston', f.face_id)
)
GROUP BY b.gid
) AS foo
WHERE foo.gid = bg.gid;
The world is rarely perfect, so this version allows some error. It counts a face if 50 percent of it falls within the expected block group boundary.
WITH candidate_faces AS (
SELECT
b.gid,
b.geom AS block_geom,
f.face_id,
topology.ST_GetFaceGeometry('topo_boston', f.face_id) AS face_geom
FROM boston.blockgroups AS b
INNER JOIN topo_boston.face AS f
ON b.geom && f.mbr
),
block_faces AS (
SELECT
gid,
topology.TopoElementArray_Agg(ARRAY[face_id, 3]) AS bfaces
FROM candidate_faces
WHERE ST_Covers(block_geom, face_geom)
OR (
ST_Intersects(block_geom, face_geom)
AND ST_Area(ST_Intersection(block_geom, face_geom))
> ST_Area(face_geom) * 0.5
)
GROUP BY gid
)
UPDATE boston.blockgroups AS bg
SET topo = topology.CreateTopoGeom(
'topo_boston',
3,
1,
block_faces.bfaces
)
FROM block_faces
WHERE block_faces.gid = bg.gid;
To convert the topogeometry back to a denormalized geometry aligned with faces and edges, cast the topogeometry to a geometry. The resulting geometries are aligned with the TIGER street centerlines.
UPDATE boston.blockgroups SET new_geom = topo::geometry;