DBIO-PostgreSQL-PostGIS
view release on metacpan or search on metacpan
lib/DBIO/PostgreSQL/PostGIS/Geometry.pm view on Meta::CPAN
package DBIO::PostgreSQL::PostGIS::Geometry;
# ABSTRACT: Lightweight PostGIS geometry/geography value object
use strict;
use warnings;
use DBIO::Exception ();
use DBIO::PostgreSQL::PostGIS::Codec::WKT::Parser ();
use DBIO::PostgreSQL::PostGIS::Codec::WKT::Builder ();
use DBIO::PostgreSQL::PostGIS::Codec::WKB::Decoder ();
sub new {
my ($class, %args) = @_;
my $self = {
srid => $args{srid},
wkt => $args{wkt},
ewkb_hex => $args{ewkb_hex},
geometry_type => $args{geometry_type},
coordinates => $args{coordinates},
};
return bless $self, $class;
}
sub from_wkt {
my ($class, $wkt, %args) = @_;
DBIO::Exception->throw("from_wkt requires a WKT string") unless defined $wkt;
my $parsed = DBIO::PostgreSQL::PostGIS::Codec::WKT::Parser->parse($wkt);
return $class->new(
wkt => $wkt,
srid => $args{srid},
geometry_type => $parsed ? $parsed->{type} : undef,
coordinates => $parsed ? $parsed->{coords} : undef,
);
}
sub from_ewkt {
my ($class, $ewkt) = @_;
DBIO::Exception->throw("from_ewkt requires an EWKT string") unless defined $ewkt;
if ($ewkt =~ /\ASRID=(\d+);(.+)\z/s) {
return $class->new(srid => $1, wkt => $2);
}
return $class->new(wkt => $ewkt);
}
sub from_ewkb_hex {
my ($class, $hex) = @_;
my $decoded = eval {
DBIO::PostgreSQL::PostGIS::Codec::WKB::Decoder->decode_hex($hex);
};
return undef unless $decoded && $decoded->{type} ne 'unknown';
return $class->new(
ewkb_hex => $hex,
srid => $decoded->{srid},
geometry_type => $decoded->{type},
coordinates => $decoded->{coords},
);
}
sub point {
my $class = shift;
my @coords;
push @coords, shift while @_ && !ref $_[0] && $_[0] =~ /\A-?[0-9.eE+\-]+\z/;
my %args = @_;
my $wkt = 'POINT(' . join(' ', @coords) . ')';
return $class->new(wkt => $wkt, srid => $args{srid}, geometry_type => 'POINT');
}
sub from_lat_lon {
my ($class, $lat, $lon) = @_;
return $class->point($lon, $lat, srid => 4326);
}
sub linestring {
my ($class, $coords, %args) = @_;
my $wkt = 'LINESTRING(' . join(',', map { join ' ', @$_ } @$coords) . ')';
return $class->new(wkt => $wkt, srid => $args{srid}, geometry_type => 'LINESTRING');
}
sub polygon {
my ($class, $rings, %args) = @_;
my $wkt = 'POLYGON('
. join(',', map {
'(' . join(',', map { join ' ', @$_ } @$_) . ')'
} @$rings)
. ')';
return $class->new(wkt => $wkt, srid => $args{srid}, geometry_type => 'POLYGON');
}
sub bbox_polygon {
my ($class, $xmin, $ymin, $xmax, $ymax, %args) = @_;
return $class->polygon(
[[ [$xmin,$ymin], [$xmax,$ymin], [$xmax,$ymax], [$xmin,$ymax], [$xmin,$ymin] ]],
%args,
);
}
sub from_geojson {
my ($class, $gj, %args) = @_;
my $srid = exists $args{srid} ? $args{srid} : 4326;
my $type = $gj->{type}
or DBIO::Exception->throw("from_geojson: missing 'type'");
my $coords = $gj->{coordinates};
my $wkt;
if ($type eq 'Point') {
$wkt = 'POINT(' . join(' ', @$coords) . ')';
}
elsif ($type eq 'LineString' or $type eq 'MultiPoint') {
$wkt = uc($type =~ s/(?<=[a-z])(?=[A-Z])/ /gr) =~ s/ //gr;
$wkt = ($type eq 'LineString' ? 'LINESTRING' : 'MULTIPOINT')
lib/DBIO/PostgreSQL/PostGIS/Geometry.pm view on Meta::CPAN
DBIO::PostgreSQL::PostGIS::Geometry - Lightweight PostGIS geometry/geography value object
=head1 VERSION
version 0.900001
=head1 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]
=head1 DESCRIPTION
A lightweight Perl-side representation of a PostGIS geometry or geography
value. Stores SRID + WKT (lazily parsed). Optional inflate path through
L<Geo::OGR> when installed for heavy spatial operations.
This object is what L<DBIO::PostgreSQL::PostGIS> inflates C<geometry>
and C<geography> column values to. On the way out (deflate) it serializes
back to EWKT for the database.
=head1 METHODS
=head2 from_wkt
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_wkt($wkt, srid => 4326);
Constructs from a Well-Known Text representation.
=head2 from_ewkt
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_ewkt('SRID=4326;POINT(0 0)');
Parses an Extended WKT string (PostGIS's C<SRID=N;WKT> form).
=head2 from_ewkb_hex
my $g = DBIO::PostgreSQL::PostGIS::Geometry->from_ewkb_hex($hex);
Constructs from PostGIS's default hex-encoded EWKB output. Stores the
hex unparsed; geometry_type/coordinates are decoded lazily on demand.
=head2 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 C<srid>).
=head2 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 C<POINT(lon lat)> â this method swaps for you.
=head2 linestring
my $l = DBIO::PostgreSQL::PostGIS::Geometry->linestring(
[[0,0],[1,1],[2,0]], srid => 4326,
);
=head2 polygon
my $p = DBIO::PostgreSQL::PostGIS::Geometry->polygon(
[ [[0,0],[10,0],[10,10],[0,10],[0,0]] ], # outer ring + optional holes
srid => 4326,
);
=head2 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.
=head2 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.
=head2 srid
=head2 wkt
=head2 ewkb_hex
=head2 geometry_type
The geometry type as an upper-case string: C<POINT>, C<LINESTRING>,
C<POLYGON>, C<MULTIPOINT>, C<MULTILINESTRING>, C<MULTIPOLYGON>,
C<GEOMETRYCOLLECTION>. Lazily derived from WKT or EWKB.
=head2 ewkt
( run in 1.100 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )