package Geo::Vector::Feature;
# @brief A root class for complex features.
use strict;
use warnings;
use Carp;
use Encode;
use Geo::GDAL;
use Geo::OGC::Geometry;
sub new {
my $package = shift;
my %params = @_;
my $self = { properties => {} };
bless $self => (ref($package) or $package);
$self->{class} = $params{class} if exists $params{class};
$self->{class} = 'Feature' unless $self->{class};
$self->GeoJSON($params{GeoJSON}) if ($params{GeoJSON});
return $self;
}
sub _Geometry {
my($self, $object) = @_;
# set type 25D depending on the actual dimension
my $geometry;
if ($object->{type} eq 'GeometryCollection') {
$geometry = Geo::OGR::Geometry->create( Type => $object->{type} );
for my $g (@{$object->{geometries}}) {
$geometry->AddGeometry($self->_Geometry($g));
}
} else { # assuming a non-collection geometry
$geometry = Geo::OGR::Geometry->create( Type => $object->{type}, Points => $object->{coordinates} );
}
return $geometry;
}
sub GeoJSON {
my($self, $object) = @_;
if ($object) {
if ($object->{type} eq 'Feature') {
$self->{OGRGeometry} = $self->_Geometry($object->{geometry});
my $to = $self->{properties};
my $from = $object->{properties};
for my $field (keys %$from) {
$to->{$field} = $from->{$field};
}
} else { # assuming a geometry
$self->{OGRGeometry} = $self->_Geometry($object);
}
} else {
$object->{type} = 'Feature';
my $from = $self->{properties};
my $to = $object->{properties} = {};
for my $field (keys %$from) {
$to->{$field} = $from->{$field};
}
my $type = $self->{OGRGeometry}->GeometryType;
$type =~ s/25D//;
if ($type =~ /Collection/) {
$object->{geometry}{type} = $type;
$object->{geometry}{geometries} = [];
for my $i (0..$self->{OGRGeometry}->GetGeometryCount-1) {
my $g = $self->{OGRGeometry}->GetGeometryRef($i);
my $type = $g->GeometryType;
$type =~ s/25D//;
my $geometry = { type => $type, coordinates => $g->Points };
push @{$object->{geometry}{geometries}}, $geometry;
}
} else {
$object->{geometry}{type} = $type;
$object->{geometry}{coordinates} = $self->{OGRGeometry}->Points;
}
}
return $object;
}
sub Schema {
my($self) = @_;
my $s = Gtk2::Ex::Geo::Schema->new;
my @fields;
for my $f (sort keys %{$self->{properties}}) {
next if $f eq 'class';
push @fields, { Name => $f, Type => 'Scalar' }; # this needs more work
}
my $type = $self->{OGRGeometry} ? $self->{OGRGeometry}->GeometryType : '';
$s->{GeometryType} = $type;
$s->{Fields} = \@fields;
return $s;
}
sub DeleteField {
my($self, $field) = @_;
delete $self->{properties}{$field};
}
sub Field {
my($self, $field, $value) = @_;
$self->{properties}{$field} = $value if defined $value;
$self->{properties}{$field};
}
*GetField = *Field;
*SetField = *Field;
sub GetFieldCount {
my($self) = @_;
return sort keys %{$self->{properties}};
}
sub Geometry {
my($self, $geometry) = @_;
$self->{OGRGeometry} = $geometry if $geometry;
return $self->{OGRGeometry};
}
*SetGeometry = *Geometry;
*GetGeometryRef = *Geometry;
# FID is unique within a layer, thus only the owning layer can legally
# set the fid.
sub FID {
my($self) = @_;
return $self->{FID};
}
*GetFID = *FID;
sub Row {
my($self, %row) = @_;
for my $key (keys %row) {
if ($key eq 'FID') {
} elsif ($key eq 'Geometry') {
$self->Geometry($row{Geometry});
} else {
$self->Field($row{$key});
}
}
%row = ( FID => $self->FID, Geometry => $self->Geometry );
for my $key (keys %{$self->{properties}}) {
$row{$key} = $self->{properties}{$key};
}
return \%row;
}
1;