NAME
DBIO::PostgreSQL::PostGIS::Geometry - Lightweight PostGIS geometry/geography value object
VERSION
version 0.900004
SYNOPSIS
use DBIO::PostgreSQL::PostGIS::Geometry;
# From WKT
my $point = DBIO::PostgreSQL::PostGIS::Geometry->from_wkt(
'POINT(13.4 52.5)', srid => 4326,
);
# From WKB hex (what PostGIS returns by default)
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_ewkb_hex($hex);
$point->srid; # 4326
$point->geometry_type; # 'POINT'
$point->wkt; # 'POINT(13.4 52.5)'
$point->ewkt; # 'SRID=4326;POINT(13.4 52.5)'
$point->coordinates; # [13.4, 52.5]
$point->x; $point->y;
$point->is_empty;
# Helpers
$point->to_geojson; # { type => 'Point', coordinates => [...] }
$point->bbox; # [xmin, ymin, xmax, ymax]
DESCRIPTION
A lightweight Perl-side representation of a PostGIS geometry or geography value. Stores SRID + WKT or EWKB-hex. Optional inflate path through Geo::OGR when installed for heavy spatial operations.
This object is what DBIO::PostgreSQL::PostGIS inflates geometry and geography column values to. On the way out (deflate) an object that carries EWKB hex -- every value read from the database does -- goes back as that hex, unchanged, so a geometry that is read and written again keeps its type, its dimension and its exact doubles. An object built in Perl has no hex and is serialized to EWKT.
METHODS
new
my $g = DBIO::PostgreSQL::PostGIS::Geometry->new(
geometry_type => 'POINT',
coordinates => [1, 2, 9],
has_m => 1,
srid => 4326,
);
The plain constructor behind all the others. Takes srid, wkt, ewkb_hex, geometry_type, coordinates, has_z, has_m and is_empty and stores them as given -- geometry_type upper-cased, see "geometry_type"; nothing is parsed, and nothing is checked against anything else. has_z and has_m say what the third and fourth ordinate of every point are. They matter only where the WKT has to be built from coordinates, see "to_wkt". is_empty, if given, is what "is_empty" answers and what the built WKT is told; left out, "is_empty" is judged from the WKT.
WKT and coordinates are derived from one another, so an object given neither has neither: "wkt", "ewkt", "coordinates" and "bbox" return undef. That holds for new(ewkb_hex => $hex) too -- the hex is kept for "ewkb_hex" and not decoded; "from_ewkb_hex" decodes.
from_wkt
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_wkt($wkt, srid => 4326);
Constructs from a Well-Known Text representation. Nesting of collections is limited to 32 levels; deeper input throws.
from_ewkt
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_ewkt('SRID=4326;POINT(0 0)');
Parses an Extended WKT string (PostGIS's SRID=N;WKT form). The prefix is read the way PostGIS accepts it: SRID in any case, blanks before it, before the semicolon and after it. SRID = 4326;... is refused by PostGIS and is not read as a prefix. The object's srid is the number and its wkt the text behind the semicolon; a string without a prefix is the WKT as given, without an srid.
from_ewkb_hex
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_ewkb_hex($hex);
Constructs from PostGIS's default hex-encoded EWKB output. The hex is decoded eagerly: srid, geometry_type and coordinates are populated at construction, and the hex is kept for "ewkb_hex".
The Z and M flags of the EWKB are kept with the object, so the WKT it builds ("wkt", "ewkt", "to_wkt") carries the dimension the geometry has: POINT M(1 2 9) stays M, a two-dimensional line stays two-dimensional however many points it has. The hex itself is what a column deflates to when the object is written back.
A value that is not decoded is still an object. PostGIS has geometry types the decoder names and does not decode -- CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE, MULTISURFACE, POLYHEDRALSURFACE, TIN, TRIANGLE, and a GEOMETRYCOLLECTION that holds one of them (see DBIO::PostgreSQL::PostGIS::Codec::WKB::Decoder). For such a value the object carries the hex as given, the srid, the Z and M flags and the geometry_type of the EWKB header (circularstring, ...), and no coordinates. "coordinates", "wkt", "ewkt", "to_wkt", "bbox", "x", "y", "z" and "to_geojson" return undef, and "is_empty" is false, whatever the geometry holds.
An empty geometry is decoded like any other: "is_empty" is true, "coordinates" is [], "wkt" is TYPE EMPTY (POINT EMPTY, POINT Z EMPTY), "bbox" is undef, and "to_geojson" gives the type with empty coordinates. The members of a GEOMETRYCOLLECTION come with their types, see "coordinates". "ewkb_hex" is the value, and a column deflates to it, so the geometry is read and written back unchanged although Perl does not know its coordinates.
An object, and neither undef nor an exception: undef is what a column gives for NULL, so a row holding a curve would read like a row holding nothing, and the "value" written to another row would store NULL; an exception would make such a row unreadable. The object keeps it readable and writable. "from_wkt" does the same for a WKT its parser cannot read.
The same goes for any other defined, non-empty string, including one that is no EWKB at all: the object carries the string as its "ewkb_hex", the srid, flags and geometry_type of its header if the whole header can be read (as with a body that is cut off), and none of them otherwise. PostGIS does not send such a value; written back, it goes to the server as it is, and the server refuses what it cannot read.
There is no object for an empty string: it is no hex, and from_ewkb_hex returns undef for it. undef is an error, as it is for "from_wkt" and "from_ewkt": from_ewkb_hex throws a DBIO::Exception. (It returned undef and warned "uninitialized" from the decoder. Code that hands over a column value which may be NULL checks for undef first.)
point
my $p = DBIO::PostgreSQL::PostGIS::Geometry->point($x, $y, srid => 4326);
my $p = DBIO::PostgreSQL::PostGIS::Geometry->point($x, $y, $z, srid => 4326);
Constructs a POINT geometry. Accepts 2 or 3 numeric coords followed by named options (currently just srid).
from_lat_lon
my $p = DBIO::PostgreSQL::PostGIS::Geometry->from_lat_lon($lat, $lon);
Convenience for building a 4326 POINT from latitude/longitude. Note the order: lat first (the human convention), but the WKT/PostGIS axis order is POINT(lon lat) — this method swaps for you.
linestring
my $l = DBIO::PostgreSQL::PostGIS::Geometry->linestring(
[[0,0],[1,1],[2,0]], srid => 4326,
);
polygon
my $p = DBIO::PostgreSQL::PostGIS::Geometry->polygon(
[ [[0,0],[10,0],[10,10],[0,10],[0,0]] ], # outer ring + optional holes
srid => 4326,
);
bbox_polygon
my $b = DBIO::PostgreSQL::PostGIS::Geometry->bbox_polygon(
$xmin, $ymin, $xmax, $ymax, srid => 4326,
);
Convenience for an axis-aligned rectangle as a closed POLYGON ring.
from_geojson
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_geojson(\%geojson);
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_geojson(\%geojson, srid => 4326);
Builds from a GeoJSON-shaped hashref. SRID defaults to 4326 (per the GeoJSON spec) unless overridden.
srid
wkt
The WKT, stored or built; the same as "to_wkt".
ewkb_hex
geometry_type
The geometry type, always upper-case, whatever built the object: POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON, GEOMETRYCOLLECTION. An object from "from_ewkb_hex" may also be one of the types that are named and not decoded: CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE, MULTISURFACE, POLYHEDRALSURFACE, TIN, TRIANGLE; and it has no type (undef) when the hex names none. This holds for every constructor and for inflated column values, the codecs' lower-case type being upper-cased on the way in (the column metadata annotated by DBIO::PostgreSQL::PostGIS::Extension keeps its own, lower-case spelling). Derived from the WKT when the constructor did not set it, without the dimension marker ST_AsEWKT glues to it: POINTM(1 2 9) is a POINT.
ewkt
Returns SRID=N;WKT if SRID is set, otherwise the bare WKT; undef when there is no WKT (see "to_wkt").
to_wkt
Returns the WKT string. Uses stored wkt if available; otherwise builds from coordinates using DBIO::PostgreSQL::PostGIS::Codec::WKT::Builder -- the case for every object from "from_ewkb_hex", and so for every value read from the database. Returns undef when the object has neither a stored WKT nor stored coordinates, and when it has coordinates but no "geometry_type" to build them under (new(coordinates => [1,2])): the type is what the WKT is called, so there is nothing to write, and "wkt" and "ewkt" are undef with it. Written to a column or bound by a spatial helper, such an object is an error, see "register_column" in DBIO::PostgreSQL::PostGIS.
An empty geometry builds TYPE EMPTY (LINESTRING EMPTY, with the marker before EMPTY: POINT Z EMPTY, GEOMETRYCOLLECTION M EMPTY). A GEOMETRYCOLLECTION builds from its members, each with its type, as ST_AsText prints it and PostGIS reads it: GEOMETRYCOLLECTION Z(POINT Z(1 2 3),LINESTRING Z(0 0 1,1 1 2)); the dimension marker is on the collection and on each member.
The dimension marker of a built WKT (Z, M, ZM) comes from the has_z / has_m flags the object was constructed with; "from_ewkb_hex" takes them from the EWKB. An object constructed without either flag is judged by the number of ordinates of one of its points: three are Z, four are ZM. To have three ordinates written as M, pass has_m => 1 to "new".
A built WKT holds each ordinate as Perl prints the double, which is 15 significant digits and not always the same number (0.1 + 0.2 prints as 0.3). The exact value is in "ewkb_hex".
coordinates
Returns the parsed coordinate structure for simple geometry types (POINT → [x,y], LINESTRING → [[x,y],...], POLYGON → [[[x,y],...],...]). Returns undef when the geometry is too complex to parse from WKT alone (use "to_geojson" via Geo::OGR for those), and when the object has neither stored coordinates nor a WKT to parse them from.
An empty geometry has an empty list, []: POINT EMPTY is [], not [NaN, NaN] as PostGIS writes it. An empty part of a MULTI* keeps its place as an empty list (MULTIPOINT(EMPTY,(1 2)) is [[], [1,2]]).
For a GEOMETRYCOLLECTION read from EWKB the structure is a list of its members, each a hashref { type, coords, is_empty } with the lower-case type of the member and the coordinates it would have on its own (for a collection in a collection, again such a list). Not the bare coordinates: those could not be told from each other. A collection made from WKT has the same list, read by the WKT parser; it has none (undef) if one member is of a type the parser does not read.
x
y
z
The ordinates of a POINT: x and y, and z if the point has a Z ordinate. For every other geometry type, for an empty point, and for z of a point without Z (a POINT M has a measure, not a Z) they return undef. The type is judged case-independent.
Behaviour change: they used to return, for a geometry that is not a point, the first, second and third part of its coordinates -- an arrayref.
is_empty
True if this represents an empty geometry (e.g. POINT EMPTY), as ST_IsEmpty says: a geometry without parts, or a MULTI* or GEOMETRYCOLLECTION with nothing but empty ones (MULTIPOINT(EMPTY)). For an object from "from_ewkb_hex" this is what the decoder found in the EWKB: a LINESTRING or POLYGON without points or rings, a MULTI* or GEOMETRYCOLLECTION without members, a POINT of NaN ordinates (this is how PostGIS writes POINT EMPTY). For any other object it is judged from the WKT: EMPTY in it and no number.
False for an object that has no WKT at all, and for a value the decoder does not decode (see "from_ewkb_hex"): nothing is known about what such a value holds.
bbox
Returns the bounding box as [xmin, ymin, xmax, ymax]. Requires coordinate parsing or a Geo::OGR fallback; undef when "coordinates" has none. For a GEOMETRYCOLLECTION it is the box of all its members, at any depth. It is undef for an empty geometry, and for one whose members are all empty, as ST_Extent is NULL for it. An empty member does not count.
to_geojson
Returns a GeoJSON-shaped hashref, whatever constructor built the object — the case "geometry_type" reports plays no part. Returns undef when no coordinates can be derived, and for a type that has no GeoJSON form (the curve types and the like).
An empty geometry gives its type with empty coordinates: { type => 'Point', coordinates => [] } for POINT EMPTY, the same for an object read from EWKB and one made from WKT; this is what ST_AsGeoJSON answers, and RFC 7946 allows it. An empty point is [], not ["NaN","NaN"].
A GEOMETRYCOLLECTION gives { type => 'GeometryCollection', geometries => [ ... ] }, a GeoJSON hashref for each member, nested for a collection in a collection (RFC 7946 allows it; PostGIS refuses to print one). GEOMETRYCOLLECTION EMPTY has geometries => []. An empty member is kept, as { type => 'Polygon', coordinates => [] }; ST_AsGeoJSON drops some of them (all but an empty two-dimensional point). Z and M are not told apart: a member's coordinates hold every ordinate the geometry has, an M one included, where ST_AsGeoJSON leaves M out.
to_ogr
Returns a Geo::OGR::Geometry object if Geo::OGR is installed; dies otherwise.
AUTHOR
DBIO Authors
COPYRIGHT AND LICENSE
Copyright (C) 2026 DBIO Authors
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.