Geo-GDAL-FFI-0.12/0000755000175500017550000000000014634406675012322 5ustar pausepauseGeo-GDAL-FFI-0.12/MANIFEST0000644000175500017550000000133014634406675013450 0ustar pausepauseMANIFEST LICENSE README.md Changes Makefile.PL build-tools/README build-tools/parse_h.pl lib/Geo/GDAL/FFI.pm lib/Geo/GDAL/FFI/Band.pm lib/Geo/GDAL/FFI/Dataset.pm lib/Geo/GDAL/FFI/Driver.pm lib/Geo/GDAL/FFI/FeatureDefn.pm lib/Geo/GDAL/FFI/Feature.pm lib/Geo/GDAL/FFI/FieldDefn.pm lib/Geo/GDAL/FFI/Geometry.pm lib/Geo/GDAL/FFI/GeomFieldDefn.pm lib/Geo/GDAL/FFI/Layer.pm lib/Geo/GDAL/FFI/Object.pm lib/Geo/GDAL/FFI/SpatialReference.pm lib/Geo/GDAL/FFI/VSI.pm lib/Geo/GDAL/FFI/VSI/File.pm t/00.t t/geometry.t t/pdl.t t/sr.t t/vsistdout.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Geo-GDAL-FFI-0.12/t/0000755000175500017550000000000014634406662012561 5ustar pausepauseGeo-GDAL-FFI-0.12/t/sr.t0000644000175500017550000000077614215214043013365 0ustar pausepauseuse v5.10; use strict; use warnings; use Carp; use Encode qw(decode encode); use Geo::GDAL::FFI; use Test::More; use Data::Dumper; use JSON; use FFI::Platypus::Buffer; my $gdal = Geo::GDAL::FFI->get_instance(); { SKIP: { skip "GDAL support files not found.", 1 if !$gdal->FindFile('gcs.csv'); my $sr = Geo::GDAL::FFI::SpatialReference->new(EPSG => 3067); ok($sr->Export('Wkt') =~ /^PROJCS/, 'SpatialReference constructor and WKT export'); } } done_testing(); Geo-GDAL-FFI-0.12/t/vsistdout.t0000644000175500017550000000473314540140111014775 0ustar pausepauseuse v5.10; use strict; use warnings; use Carp; use Encode qw(decode encode); use Geo::GDAL::FFI qw/GetDriver/; use Test::More; use Data::Dumper; use JSON; { package Output; use strict; use warnings; our @output; sub new { return bless {}, 'Output'; } sub write { my $line = shift; push @output, $line; return 1; } sub close { return 1; } sub output { my $output = join '', @output; $output =~ s/\n//g; return $output; } } # test vsistdout redirection if(1){ # create a small layer and copy it to vsistdout with redirection my $ds = GetDriver('Memory')->Create; my $layer = $ds->CreateLayer({GeometryType => 'None'}); $layer->CreateField(value => 'Integer'); $layer->CreateGeomField(geom => 'Point'); for my $i (1..2) { my $feature = Geo::GDAL::FFI::Feature->new($layer->GetDefn); $feature->SetField(value => 12); $feature->SetGeomField(geom => [WKT => "POINT(1 $i)"]); $layer->CreateFeature($feature); } $ds->FlushCache; my $output = Output->new; my $gdal = Geo::GDAL::FFI->get_instance; $gdal->SetWriter($output); GetDriver('GeoJSON')->Create('/vsistdout')->CopyLayer($layer); $gdal->CloseWriter; my $ret = $output->output; $ret = decode_json $ret; my $exp = decode_json (get_expected_json_data()); is_deeply ($ret, $exp, "Redirect vsistdout to write/close methods of a class."); } # test Translate if(1){ my $ds = GetDriver('GTiff')->Create('/vsimem/test.tiff', 10); my $translated = $ds->Translate('/vsimem/translated.tiff', [-of => 'GTiff']); ok($translated->GetDriver->GetName eq 'GTiff', "Translate"); } done_testing(); sub get_expected_json_data { my $json = <<'EOJSON' { "type": "FeatureCollection", "features": [{ "type": "Feature", "id": 0, "properties": { "value": 12 }, "geometry": { "type": "Point", "coordinates": [1.0, 1.0] } }, { "type": "Feature", "id": 1, "properties": { "value": 12 }, "geometry": { "type": "Point", "coordinates": [1.0, 2.0] } } ] } EOJSON ; return $json; } Geo-GDAL-FFI-0.12/t/00.t0000644000175500017550000004704514634406006013167 0ustar pausepauseuse v5.10; use strict; use warnings; use Config; use Carp; use Encode qw(decode encode); use Test::More; use Data::Dumper; use JSON; use Test::TempDir::Tiny; use Path::Tiny qw/path/; BEGIN { use_ok('Geo::GDAL::FFI', qw/:all/); } if(1){ Geo::GDAL::FFI::UnsetErrorHandling(); print STDERR "test a - GDAL error messages without Geo::GDAL::FFI error handling:\n"; my $err_cat = $Geo::GDAL::FFI::Debug; Geo::GDAL::FFI::CPLError( $err_cat, 1, "A GDAL Debug message."); $err_cat = $Geo::GDAL::FFI::Warning; Geo::GDAL::FFI::CPLError( $err_cat, 1, "A GDAL Warning message."); $err_cat = $Geo::GDAL::FFI::Failure; Geo::GDAL::FFI::CPLError( $err_cat, 1, "A GDAL Failure error message."); print STDERR "Fatal GDAL error ends the program even when run inside eval.\n"; # Fatal error dumps core #eval { # $err_cat = $Geo::GDAL::FFI::Fatal; # Geo::GDAL::FFI::CPLError( # $err_cat, 1, "This is GDAL Fatal error ($Geo::GDAL::FFI::Fatal) without Geo::GDAL::FFI error handling..."); #}; #print STDERR "run in Perl eval {};\n"; Geo::GDAL::FFI::SetErrorHandling(); print STDERR "test b - GDAL error messages with Geo::GDAL::FFI error handling:\n"; $err_cat = $Geo::GDAL::FFI::Debug; print STDERR "GDAL Debug message requires \$Geo::GDAL::FFI::DEBUG set to true.\n"; Geo::GDAL::FFI::CPLError( $err_cat, 1, "You don't see this."); $Geo::GDAL::FFI::DEBUG = 1; Geo::GDAL::FFI::CPLError( $err_cat, 1, "\$Geo::GDAL::FFI::DEBUG is now true.\n"); $Geo::GDAL::FFI::DEBUG = 0; $err_cat = $Geo::GDAL::FFI::Warning; $SIG{'__WARN__'} = sub { print STDERR "Perl warning: $_[0]"; }; Geo::GDAL::FFI::CPLError( $err_cat, 1, "A GDAL Warning is converted into a Perl warn call."); $err_cat = $Geo::GDAL::FFI::Failure; Geo::GDAL::FFI::CPLError( $err_cat, 1, "A GDAL Failure."); print STDERR "GDAL Failures are stored in \@Geo::GDAL::FFI::errors:\n@Geo::GDAL::FFI::errors\n"; } # test the singleton if(1){ my $gdal = Geo::GDAL::FFI->get_instance(); $gdal->{favourite_animal} = 'llama'; my $gdal2 = Geo::GDAL::FFI->get_instance(); ok($gdal->{favourite_animal} eq $gdal2->{favourite_animal}, "Instance is a singleton 1/2."); $gdal2 = Geo::GDAL::FFI->new(); ok($gdal->{favourite_animal} eq $gdal2->{favourite_animal}, "Instance is a singleton 2/2."); } # test unavailable function if(1){ my $gdal = Geo::GDAL::FFI->get_instance(); my $can = $gdal->can('is_not_available'); ok(!$can, "Can't call missing functions."); } # test error handler: if(1){ eval { my $ds = Open('itsnotthere.tiff'); }; ok(defined $@, "Got error: '$@'."); } # test CSL if(1){ ok(Geo::GDAL::FFI::CSLCount(0) == 0, "empty CSL"); my @list; my $csl = Geo::GDAL::FFI::CSLAddString(0, 'foo'); for my $i (0..Geo::GDAL::FFI::CSLCount($csl)-1) { push @list, Geo::GDAL::FFI::CSLGetField($csl, $i); } ok(@list == 1 && $list[0] eq 'foo', "list with one string: '@list'"); } # test file finder if(1){ my $gdal_data_dir = GetConfigOption(GDAL_DATA => ''); SKIP: { skip "GDAL (Alien::gdal) is not properly installed; GDAL support files are not available.", 3 unless $gdal_data_dir; my $target_file= 'stateplane.csv'; my $path = FindFile($target_file); ok(defined $path, "GDAL support files found."); my $version = Geo::GDAL::FFI::GetVersionInfo('SEMANTIC'); say STDERR "FYI: Your GDAL is version $version"; say STDERR "FYI: GDAL_DATA = $gdal_data_dir"; if (!$path) { # what's wrong with GDAL_DATA?? if (opendir(my $dh, $gdal_data_dir)) { my @contents = grep { -f "$gdal_data_dir/$_" } readdir($dh); closedir $dh; @contents = sort @contents; say STDERR "Contents of GDAL_DATA: @contents"; } else { say STDERR "Can't opendir $gdal_data_dir: $!"; } } PopFinderLocation(); #FinderClean; my $path2 = FindFile($target_file); ok(not(defined $path2), "GDAL support files not found after popping finder."); $path =~ s/[\w.]+$//; PushFinderLocation($path); $path = FindFile($target_file); ok(defined $path, "GDAL support files found when working path inserted."); } } # test VersionInfo if(1){ my $info = GetVersionInfo(); ok($info, "Got info: '$info'."); } # test driver count if(1){ my $n = GetDrivers(); ok($n > 0, "Have $n drivers."); } # test metadata if(1){ my $dr; eval {$dr = GetDriver('NITF');}; SKIP: { skip "metadata tests. NITF driver not found." unless defined $dr; my $ds = $dr->Create('/vsimem/test.nitf', 10); my @d = $ds->GetMetadataDomainList; ok(@d > 0, "GetMetadataDomainList"); # DERIVED_SUBDATASETS NITF_METADATA CGM my %d = $ds->GetMetadata; is_deeply([sort keys %d], [sort @d], "GetMetadata"); %d = $ds->GetMetadata('NITF_METADATA'); @d = keys %d; # NITFFileHeader NITFImageSubheader ok(@d == 2, "GetMetadata(\$domain)"); $ds->SetMetadata({x => {a => 'b'}}); %d = $ds->GetMetadata('x'); is_deeply(\%d, {a => 'b'}, "SetMetadata"); } } # test progress function if(1){ my $dr = GetDriver('GTiff'); my $ds = $dr->Create('/vsimem/test.tiff', 10); my $was_at_fct = 0; my $progress = sub { my ($fraction, $msg, $data) = @_; #say STDERR "$fraction $data"; ++$was_at_fct; }; my $data = 'whoa'; my $ds2 = $dr->Create('/vsimem/copy.tiff', {Source => $ds, Progress => $progress, ProgressData => \$data}); ok($was_at_fct > 0, "Progress callback called $was_at_fct times."); } # test Info if(1){ my $dr = GetDriver('GTiff'); my $ds = $dr->Create('/vsimem/test.tiff', 10); my $info = decode_json $ds->GetInfo(['-json']); ok($info->{files}[0] eq '/vsimem/test.tiff', "Info"); } # test dataset if(1){ my $ffi = Geo::GDAL::FFI->new; my $dr = GetDriver('GTiff'); my $ds = $dr->Create('/vsimem/test.tiff', 10); my $ogc_wkt = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS84",6378137,298.257223563,'. 'AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,'. 'AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,'. 'AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]'; if ($ffi->{gdal}->version ge '3') { $ogc_wkt = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS84",6378137,298.257223563,'. 'AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,'. 'AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,'. 'AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],'. 'AUTHORITY["EPSG","4326"]]'; } $ds->SetProjectionString($ogc_wkt); my $p = $ds->GetProjectionString; is($p, $ogc_wkt, "Set/get projection string"); my $transform = [10,2,0,20,0,3]; $ds->SetGeoTransform($transform); my $inv = [0,0,0,0,0,0]; ok(Geo::GDAL::FFI::GDALInvGeoTransform($transform, $inv) && "@$inv" eq "-5 0.5 0 -6.66666666666667 0 0.333333333333333", "Invert geotransform"); my ($x, $y); Geo::GDAL::FFI::GDALApplyGeoTransform($transform,5,5,\$x,\$y); ok($x == 20 && $y == 35, "Applied geotransform to pixel coords"); my $t = $ds->GetGeoTransform; is_deeply($t, $transform, "Set/get geotransform"); } # test band if(1){ my $dr = GetDriver('GTiff'); my $ds = $dr->Create('/vsimem/test.tiff', 256); my $b = $ds->GetBand; #say STDERR $b; my @size = $b->GetBlockSize; #say STDERR "block size = @size"; ok($size[0] == 256 && $size[1] == 32, "Band block size."); my @data = ( [1, 2, 3], [4, 5, 6] ); $b->Write(\@data); my $data = $b->Read(0, 0, 3, 2); is_deeply(\@data, $data, "Raster i/o"); $ds->FlushCache; my $block = $b->ReadBlock(); for my $ln (@$block) { #say STDERR "@$ln"; } ok(@{$block->[0]} == 256 && @$block == 32 && $block->[1][2] == 6, "Read block ($block->[1][2])"); $block->[1][2] = 7; $b->WriteBlock($block); $block = $b->ReadBlock(); ok($block->[1][2] == 7, "Write block ($block->[1][2])"); $b->SetCategoryNames('a', 'b'); my @names = $b->GetCategoryNames; is_deeply(\@names, ['a', 'b'], "Set and get raster category names (got '@names')."); my $v = $b->GetNoDataValue; ok(!defined($v), "Get nodata value."); $b->SetNoDataValue(13); $v = $b->GetNoDataValue; ok($v == 13, "Set nodata value."); $b->SetNoDataValue(); $v = $b->GetNoDataValue; ok(!defined($v), "Delete nodata value."); # the color table test with GTiff fails with # Cannot modify tag "PhotometricInterpretation" while writing at (a line afterwards this). # should investigate why #$b->SetColorTable([[1,2,3,4],[5,6,7,8]]); if(0){ # band metadata test $b->SetMetadata({'d' => {'a' => 'b'}}); my $md = $b->GetMetadata(); for my $d (keys %$md) { say 'domain ',$d; for (keys %{$md->{$d}}) { say $_, '=>', $md->{$d}{$_}; } } } } if(1){ my $dr = GetDriver('MEM'); my $ds = $dr->Create('', 10); my $b = $ds->GetBand; my $table = [[1,2,3,4],[5,6,7,8]]; $b->SetColorTable($table); my $t = $b->GetColorTable; is_deeply($t, $table, "Set/get color table"); $b->SetColorInterpretation('PaletteIndex'); $ds->FlushCache; } # test creating a shapefile if(1){ my $dir = tempdir(); my $testfile = path($dir, 'test.shp'); my $dr = GetDriver('ESRI Shapefile'); my $ds = $dr->Create($testfile); my @sr = (); if (FindFile('gcs.csv')) { # should be version checked? GDAL 3 does not use gcs.csv @sr = (SpatialReference => Geo::GDAL::FFI::SpatialReference->new(EPSG => 3067)); } my $l = $ds->CreateLayer({Name => 'test', GeometryType => 'Point', @sr}); my $d = $l->GetDefn(); my $f = Geo::GDAL::FFI::Feature->new($d); $l->CreateFeature($f); undef $l; # otherwise $ds is not flushed due to parent ref $ds = Open($testfile); $l = $ds->GetLayer; $d = $l->GetDefn(); ok($d->GetGeomType eq 'Point', "Create point shapefile and open it."); } # test field definitions if(1){ my $f = Geo::GDAL::FFI::FieldDefn->new({Name => 'test', Type => 'Integer'}); ok($f->GetName eq 'test', "Field definition: get name"); ok($f->GetType eq 'Integer', "Field definition: get type"); $f->SetName('test2'); ok($f->GetName eq 'test2', "Field definition: name"); $f->SetType('Real'); ok($f->GetType eq 'Real', "Field definition: type"); $f->SetSubtype('Float32'); ok($f->GetSubtype eq 'Float32', "Field definition: subtype"); $f->SetJustify('Left'); ok($f->GetJustify eq 'Left', "Field definition: Justify"); $f->SetWidth(10); ok($f->GetWidth == 10, "Field definition: Width"); $f->SetPrecision(10); ok($f->GetPrecision == 10, "Field definition: Precision"); $f->SetIgnored; ok($f->IsIgnored, "Field definition: Ignored "); $f->SetIgnored(0); ok(!$f->IsIgnored, "Field definition: not Ignored"); $f->SetNullable(1); ok($f->IsNullable, "Field definition: Nullable"); $f->SetNullable; ok(!$f->IsNullable, "Field definition: Nullable"); $f = Geo::GDAL::FFI::GeomFieldDefn->new({Name => 'test', GeometryType => 'Point'}); ok($f->GetName eq 'test', "Geometry field definition: get name"); ok($f->GetType eq 'Point', "Geometry field definition: get type"); $f->SetName('test2'); ok($f->GetName eq 'test2', "Geometry field definition: name"); $f->SetType('LineString'); ok($f->GetType eq 'LineString', "Geometry field definition: type"); $f->SetIgnored; ok($f->IsIgnored, "Geometry field definition: Ignored"); $f->SetIgnored(0); ok(!$f->IsIgnored, "Geometry field definition: not Ignored"); $f->SetNullable(1); ok($f->IsNullable, "Geometry field definition: Nullable"); $f->SetNullable; ok(!$f->IsNullable, "Geometry field definition: Nullable"); } # test feature definitions if(1){ my $d = Geo::GDAL::FFI::FeatureDefn->new; ok($d->GetFieldDefns == 0, "GetFieldCount"); ok($d->GetGeomFieldDefns == 1, "GetGeomFieldCount ".(scalar $d->GetGeomFieldDefns)); $d->SetGeometryIgnored(1); ok($d->IsGeometryIgnored, "IsGeometryIgnored"); $d->SetGeometryIgnored(0); ok(!$d->IsGeometryIgnored, "IsGeometryIgnored"); $d->SetStyleIgnored(1); ok($d->IsStyleIgnored, "IsStyleIgnored"); $d->SetStyleIgnored(0); ok(!$d->IsStyleIgnored, "IsStyleIgnored"); $d->SetGeomType('Polygon'); ok($d->GetGeomType eq 'Polygon', "GeomType"); $d->AddFieldDefn(Geo::GDAL::FFI::FieldDefn->new({Name => 'test', Type => 'Integer'})); ok($d->GetFieldDefns == 1, "GetFieldCount"); $d->DeleteFieldDefn(0); ok($d->GetFieldDefns == 0, "DeleteFieldDefn"); $d->AddGeomFieldDefn(Geo::GDAL::FFI::GeomFieldDefn->new({Name => 'test', GeometryType => 'Point'})); ok($d->GetGeomFieldDefns == 2, "GetGeomFieldCount"); $d->DeleteGeomFieldDefn(1); ok($d->GetGeomFieldDefns == 1, "DeleteGeomFieldDefn"); } # test creating a geometry object if(1){ my $g = Geo::GDAL::FFI::Geometry->new('Point'); my $wkt = $g->AsText; ok($wkt eq 'POINT EMPTY', "Got WKT: '$wkt'."); $g = Geo::GDAL::FFI::Geometry->new(WKT => 'POINT (1 2)'); ok($g->AsText eq 'POINT (1 2)', "Import from WKT"); ok($g->GetPointCount == 1, "Point count"); my @p = $g->GetPoint; ok(@p == 2 && $p[0] == 1 && $p[1] == 2, "Get point"); $g->SetPoint(2, 3, 4, 5); @p = $g->GetPoint; ok(@p == 2 && $p[0] == 2 && $p[1] == 3, "Set point: @p"); $g = Geo::GDAL::FFI::Geometry->new('PointZM'); ok($g->GetType eq 'PointZM', "Geom constructor respects M & Z"); $g = Geo::GDAL::FFI::Geometry->new('Point25D'); ok($g->GetType eq 'Point25D', "Geom constructor respects M & Z"); $g = Geo::GDAL::FFI::Geometry->new('PointM'); ok($g->GetType eq 'PointM', "Geom constructor respects M & Z"); $wkt = $g->AsText; ok($wkt eq 'POINT M EMPTY', "Got WKT: '$wkt'."); $g = Geo::GDAL::FFI::Geometry->new(WKT => 'POINTM (1 2 3)'); ok($g->AsText eq 'POINT M (1 2 3)', "Import PointM from WKT"); } # test features if(1){ my $d = Geo::GDAL::FFI::FeatureDefn->new(); # geometry type checking is not implemented in GDAL #$d->SetGeomType('PointM'); $d->AddGeomFieldDefn(Geo::GDAL::FFI::GeomFieldDefn->new({Name => 'test2', GeometryType => 'LineString'})); my $f = Geo::GDAL::FFI::Feature->new($d); ok($d->GetGeomFieldDefns == 2, "GetGeometryCount"); #GetGeomFieldDefnRef my $g = Geo::GDAL::FFI::Geometry->new('PointM'); $g->SetPoint(1,2,3,4); $f->SetGeomField($g); my $h = $f->GetGeomField(); ok($h->AsText eq 'POINT M (1 2 4)', "GetGeometry"); $g = Geo::GDAL::FFI::Geometry->new('LineString'); $g->SetPoint(0, 5,6,7,8); $g->SetPoint(1, [7,8]); $f->SetGeomField(1 => $g); $h = $f->GetGeomField(1); ok($h->AsText eq 'LINESTRING (5 6,7 8)', "2nd geom field"); } # test setting field if(1){ my $types = \%Geo::GDAL::FFI::field_types; my $d = Geo::GDAL::FFI::FeatureDefn->new(); for my $t (sort {$types->{$a} <=> $types->{$b}} keys %$types) { $d->AddFieldDefn(Geo::GDAL::FFI::FieldDefn->new({Name => $t, Type => $t})); } my $f = Geo::GDAL::FFI::Feature->new($d); my $n = 'Integer'; my $x = $f->IsFieldSet($n) ? 'set' : 'not set'; ok($x eq 'not set', "Not set"); $x = $f->IsFieldNull($n) ? 'null' : 'not null'; ok($x eq 'not null', "Not null"); $f->SetField($n, undef); $x = $f->IsFieldSet($n) ? 'set' : 'not set'; ok($x eq 'set', "Set"); $x = $f->IsFieldNull($n) ? 'null' : 'not null'; ok($x eq 'null', "Null"); $f->SetField($n); $x = $f->IsFieldSet($n) ? 'set' : 'not set'; ok($x eq 'not set', "Not set"); $x = $f->IsFieldNull($n) ? 'null' : 'not null'; ok($x eq 'not null', "Not null"); # scalar types $f->SetField($n, 13); $x = $f->GetField($n); ok($x == 13, "Set/get Integer field: $x"); SKIP: { skip "64 bit integers not supported in this Perl.",1 unless $Config{use64bitint} eq 'define'; $n = 'Integer64'; $f->SetField($n, 0x90000001); $x = $f->GetField($n); ok($x == 0x90000001, "Set/get Integer64 field: $x"); } $f->SetField(Real => 1.123); $x = $f->GetField('Real'); $x = sprintf("%.3f", $x); ok($x eq '1.123', "Set/get Real field: $x"); my $s = decode utf8 => 'åäö'; $f->SetField(String => $s); $x = $f->GetField(String => 'utf8'); ok($x eq $s, "Set/get String field: $x"); # WideString not tested #$f->SetFieldBinary(Binary}, 1); my @s = (13, 21, 7, 5); $f->SetField(IntegerList => @s); my @x = $f->GetField('IntegerList'); is_deeply(\@x, \@s, "Set/get IntegerList field: @x"); SKIP: { skip "64 bit integers not supported in this Perl.",1 unless $Config{use64bitint} eq 'define'; $n = 'Integer64List'; @s = (0x90000001, 21, 7, 5); $f->SetField($n, @s); @x = $f->GetField($n); is_deeply(\@x, \@s, "Set/get Integer64List field: @s => @x"); } @s = (3, 21.2, 7.4, 5.5); $f->SetField(RealList => @s); @x = $f->GetField('RealList'); for (@s) { $_ = sprintf("%.3f", $_); } for (@x) { $_ = sprintf("%.3f", $_); } is_deeply(\@x, \@s, "Set/get DoubleList field: @x"); @s = ('a', 'gdal', 'perl'); $f->SetField(StringList => @s); @x = $f->GetField('StringList'); is_deeply(\@x, \@s, "Set/get StringList field: @x"); @s = (1962, 4, 23); $f->SetField(Date => @s); @x = $f->GetField('Date'); is_deeply(\@x, \@s, "Set/get Date field: @x"); $n = 'Time'; @s = (15, 23, 23.34, 1); $f->SetField($n, @s); @x = $f->GetField($n); is_deeply(\@x, \@s, "Set/get Time field: @x"); $n = 'DateTime'; @s = (1962, 4, 23, 15, 23, 23.34, 1); $f->SetField($n, @s); @x = $f->GetField($n); is_deeply(\@x, \@s, "Set/get DateTime field: @x"); # Binary => 8, @s = (1962, 4, 23); $f->SetField(Date => @s); @x = $f->GetField('Date'); is_deeply(\@x, \@s, "Set/get Date field: @x"); } # test layer feature manipulation if(1){ my $dr = GetDriver('Memory'); my $ds = $dr->Create({Name => 'test'}); my @sr = (); if (FindFile('stateplane.csv')) { @sr = (SpatialReference => Geo::GDAL::FFI::SpatialReference->new(EPSG => 3067)); } my $l = $ds->CreateLayer({Name => 'test', GeometryType => 'Point', @sr}); $l->CreateField(Geo::GDAL::FFI::FieldDefn->new({Name => 'int', Type => 'Integer'})); my $f = Geo::GDAL::FFI::Feature->new($l->GetDefn); $f->SetField(int => 5); my $g = Geo::GDAL::FFI::Geometry->new('Point'); $g->SetPoint(3, 5); $f->SetGeomField($g); $l->CreateFeature($f); my $fid = $f->GetFID; ok($fid == 0, "FID of first feature"); $f = $l->GetFeature($fid); ok($f->GetField('int') == 5, "Field was set"); ok($f->GetGeomField->AsText eq 'POINT (3 5)', "Geom Field was set"); } done_testing(); Geo-GDAL-FFI-0.12/t/pdl.t0000644000175500017550000000214114215214043013504 0ustar pausepauseuse v5.10; use strict; use warnings; use Carp; use Encode qw(decode encode); use Geo::GDAL::FFI qw/GetDriver/; use Test::More; use Data::Dumper; use JSON; use FFI::Platypus::Buffer; my $band = GetDriver('MEM')->Create('', {Width => 7, Height => 15})->GetBand; my $t = $band->Read; $t->[5][3] = 1; $band->Write($t); $t->[5][3] = 0; my $pdl = $band->GetPiddle; my @s = $pdl->dims; ok($s[0] == 7 && $s[1] == 15, "Piddle size is right (1)."); ok($pdl->at(3,5) == 1, "Piddle data is ok (1)."); $pdl = $band->GetPiddle(1,2,4,4); @s = $pdl->dims; ok($s[0] == 4 && $s[1] == 4, "Piddle size is right (2)."); ok($pdl->at(2,3) == 1, "Piddle data is ok (2)."); $pdl += 1; $band->Write($t); # zero raster $band->SetPiddle($pdl); ok($band->Read->[3][2] == 2, "Data from piddle into band at(0,0)."); $band->Write($t); # zero raster $band->SetPiddle($pdl,1,2); ok($band->Read->[5][3] == 2, "Data from piddle into band at(1,2)."); $band->Write($t); # zero raster $band->SetPiddle($pdl,0,0,7,15); ok($band->Read->[12][4] == 2, "Data from piddle into band (stretched)."); done_testing(); Geo-GDAL-FFI-0.12/t/geometry.t0000644000175500017550000000534214341242577014603 0ustar pausepauseuse v5.10; use strict; use warnings; use Carp; use Encode qw(decode encode); use Geo::GDAL::FFI qw/GetVersionInfo HaveGEOS/; use Test::More; use Data::Dumper; use JSON; my $version = GetVersionInfo() / 100; my $have_geos = HaveGEOS; { my $geometry = Geo::GDAL::FFI::Geometry->new(WKT => 'POINT(1 1)'); ok($geometry->GetType eq 'Point', "Create Point from WKT (1)."); ok($geometry->AsText eq 'POINT (1 1)', "Create point from WKT (2)."); } { my $geometry = Geo::GDAL::FFI::Geometry->new(WKT => 'POINTM(1 2 3)'); my $type = $geometry->GetType; ok($type eq 'PointM', "Create PointM from WKT: $type"); my $wkt = $geometry->AsText; ok($wkt eq 'POINT M (1 2 3)', "Create point from WKT: $wkt"); } { my $g = Geo::GDAL::FFI::Geometry->new('Point'); $g->SetPoint(5, 8); my @p = $g->GetPoint; ok($p[0] == 5, "Set/GetPoint"); } SKIP: { skip "No GEOS support", 1 unless $have_geos; my $geometry = Geo::GDAL::FFI::Geometry->new(WKT => 'POINT(1 1)'); my $c = $geometry->Centroid; ok($geometry->AsText eq 'POINT (1 1)', "Centroid"); } { my $g = Geo::GDAL::FFI::Geometry->new(WKT => 'POLYHEDRALSURFACE Z ( '. '((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)), '. '((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)), '. '((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)), '. '((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)), '. '((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)), '. '((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))) '); my $p = $g->GetPoints; ok(@$p == 6, "GetPoints"); $p->[0][0][0][0] = 2; $g->SetPoints($p); $p = $g->GetPoints; ok($p->[0][0][0][0] == 2, "SetPoints"); } # GetEnvelope { my $geom = Geo::GDAL::FFI::Geometry->new( WKT => 'POLYGON ((0 -1 0, -1 0 0, 0 1 1, 1 0 1, 0 -1 1))', ); my $envelope = $geom->GetEnvelope; is_deeply ($envelope, [-1,1,-1,1], 'correct geometry envelope'); my $envelope3d = $geom->GetEnvelope3D; is_deeply ($envelope3d, [-1,1,-1,1,0,1], 'correct 3D geometry envelope'); } SKIP: { skip "No GEOS support in GDAL.", 5 unless $have_geos; skip "Needs version >= 3.0", 1 unless $version >= 30000; my $wkt = 'POLYGON ((0 -1,-1 0,0 1,1 0,0 -1))'; my $geom = Geo::GDAL::FFI::Geometry->new(WKT => $wkt); my $test = $geom->MakeValid(METHOD => 'LINEWORK'); ok($wkt eq $test->AsText); } SKIP: { skip "No GEOS support in GDAL.", 5 unless $have_geos; skip "Needs version >= 3.3", 1 unless $version >= 30300; my $wkt = 'POLYGON ((0 -1,-1 0,0 1,1 0,0 -1))'; my $geom = Geo::GDAL::FFI::Geometry->new(WKT => $wkt); my $test = $geom->Normalize(); ok($test->AsText eq 'POLYGON ((-1 0,0 1,1 0,0 -1,-1 0))'); } done_testing(); Geo-GDAL-FFI-0.12/META.yml0000644000175500017550000000156514634406665013601 0ustar pausepause--- abstract: 'A foreign function interface to GDAL' author: - 'Ari Jolma ' build_requires: Data::Dumper: '0' ExtUtils::MakeMaker: '0' JSON: '0' Path::Tiny: '0' Test::Exception: '0' Test::More: '0' Test::TempDir::Tiny: '0' configure_requires: Alien::gdal: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Geo-GDAL-FFI no_index: directory: - t - inc requires: Alien::gdal: '0' FFI::Platypus: '0' PDL: '0' PkgConfig: '0.23026' Sort::Versions: '0' resources: bugtracker: https://github.com/ajolma/Geo-GDAL-FFI/issues/ repository: git://github.com/ajolma/Geo-GDAL-FFI.git version: 0.12 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Geo-GDAL-FFI-0.12/LICENSE0000644000175500017550000001446414215214043013315 0ustar pausepause The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End Geo-GDAL-FFI-0.12/README.md0000644000175500017550000000257314504416071013573 0ustar pausepause![Linux bin workflow](https://github.com/ajolma/Geo-GDAL-FFI/actions/workflows/linux_bin_build.yml/badge.svg)
![Linux share workflow](https://github.com/ajolma/Geo-GDAL-FFI/actions/workflows/linux_share_build.yml/badge.svg)
![Linus sys workflow](https://github.com/ajolma/Geo-GDAL-FFI/actions/workflows/linux_sys_build.yml/badge.svg)
![MacOS share workflow](https://github.com/ajolma/Geo-GDAL-FFI/actions/workflows/macos_share_builds.yml/badge.svg)
![MacOS workflow](https://github.com/ajolma/Geo-GDAL-FFI/actions/workflows/macos.yml/badge.svg)
![Windows workflow](https://github.com/ajolma/Geo-GDAL-FFI/actions/workflows/windows.yml/badge.svg) Geo-GDAL-FFI ======================= Perl FFI to GDAL using FFI::Platypus INSTALLATION FROM CPAN DISTRIBUTION To build, test and install this module the basic steps are perl Makefile.PL make make test make install DEPENDENCIES FFI::Platypus PDL Alien::gdal Alien::gdal downloads and compiles GDAL. This package will try to use an existing GDAL in the system if Alien::gdal is not found or GDAL location prefix is specified as an argument to Makefile.PL, for example perl Makefile.PL GDAL=/usr/local DOCUMENTATION COPYRIGHT AND LICENCE Copyright (C) 2017- by Ari Jolma. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Geo-GDAL-FFI-0.12/META.json0000644000175500017550000000313414634406675013744 0ustar pausepause{ "abstract" : "A foreign function interface to GDAL", "author" : [ "Ari Jolma " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.70, CPAN::Meta::Converter version 2.150010", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Geo-GDAL-FFI", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "Alien::gdal" : "0" } }, "runtime" : { "requires" : { "Alien::gdal" : "0", "FFI::Platypus" : "0", "PDL" : "0", "PkgConfig" : "0.23026", "Sort::Versions" : "0" } }, "test" : { "requires" : { "Data::Dumper" : "0", "JSON" : "0", "Path::Tiny" : "0", "Test::Exception" : "0", "Test::More" : "0", "Test::TempDir::Tiny" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/ajolma/Geo-GDAL-FFI/issues/" }, "repository" : { "type" : "git", "url" : "git://github.com/ajolma/Geo-GDAL-FFI.git", "web" : "https://github.com/ajolma/Geo-GDAL-FFI" } }, "version" : 0.12, "x_serialization_backend" : "JSON::PP version 4.16" } Geo-GDAL-FFI-0.12/lib/0000755000175500017550000000000014634407013013053 5ustar pausepauseGeo-GDAL-FFI-0.12/lib/Geo/0000755000175500017550000000000014634406662013576 5ustar pausepauseGeo-GDAL-FFI-0.12/lib/Geo/GDAL/0000755000175500017550000000000014634406662014305 5ustar pausepauseGeo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/0000755000175500017550000000000014634407013014700 5ustar pausepauseGeo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Driver.pm0000644000175500017550000000670114631756006016503 0ustar pausepausepackage Geo::GDAL::FFI::Driver; use v5.10; use strict; use warnings; use Carp; use base 'Geo::GDAL::FFI::Object'; our $VERSION = 0.1200; sub GetName { my $self = shift; return $self->GetDescription; } sub Create { my ($self, $name, $args, $h) = @_; $name //= ''; $args //= {}; $args = {Width => $args, Height => $h} unless ref $args; my $o = 0; for my $key (keys %{$args->{Options}}) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$args->{Options}{$key}"); } my $ds; if ($args->{Source}) { my $src = ${$args->{Source}}; my $s = $args->{Strict} // 0; my $ffi = FFI::Platypus->new; my $p = $ffi->closure($args->{Progress}); $ds = Geo::GDAL::FFI::GDALCreateCopy($$self, $name, $src, $s, $o, $p, $args->{ProgressData}); } elsif (not $args->{Width}) { $ds = Geo::GDAL::FFI::GDALCreate($$self, $name, 0, 0, 0, 0, $o); } else { my $w = $args->{Width}; $h //= $args->{Height} // $w; my $b = $args->{Bands} // 1; my $dt = $args->{DataType} // 'Byte'; my $tmp = $Geo::GDAL::FFI::data_types{$dt}; unless (defined $tmp) { confess "Unknown constant: $dt."; Geo::GDAL::FFI::CSLDestroy($o); } $ds = Geo::GDAL::FFI::GDALCreate($$self, $name, $w, $h, $b, $tmp, $o); } Geo::GDAL::FFI::CSLDestroy($o); my $msg = Geo::GDAL::FFI::error_msg(); if (!$ds || $msg) { $msg //= "Driver " . $self->Name . " failed to create dataset '$name'."; confess $msg; } return bless \$ds, 'Geo::GDAL::FFI::Dataset'; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Driver - A GDAL data access driver =head1 SYNOPSIS =head1 DESCRIPTION A format driver. Use the Driver method of a Geo::GDAL::FFI object to obtain one. =head1 METHODS =head2 GetName my $name = $driver->GetName; Returns the name of the driver. =head2 Create my $name = $driver->Create($name, {Width => 100, ...}); Create a dataset. $name is the name for the dataset to create. Named arguments are the following. =over 4 =item C Optional, but required to create a raster dataset. =item C Optional, default is the same as width. =item C Optional, the number of raster bands in the dataset, default is one. =item C Optional, the data type (a string) for the raster cells, default is 'Byte'. =item C Optional, the dataset to copy. =item C Optional, used only in dataset copy, a reference to a subroutine. The subroutine is called with three arguments C<($fraction, $msg, $data)>, where C<$fraction> is a number, C<$msg> is a string, and C<$data> is a pointer that is given as the progress data argument. =item C Optional, used only in dataset copy, a reference. =item C Optional, used only in dataset copy, default is false (0). =item C Optional, driver specific creation options, default is reference to an empty hash. =back my $name = $driver->Create($name, $width); A simple syntax for calling Create to create a raster dataset. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Dataset.pm0000644000175500017550000004460514631756006016642 0ustar pausepausepackage Geo::GDAL::FFI::Dataset; use v5.10; use strict; use warnings; use Carp; use base 'Geo::GDAL::FFI::Object'; use Scalar::Util qw /blessed/; our $VERSION = 0.1200; sub DESTROY { my $self = shift; $self->FlushCache; #say STDERR "DESTROY $self"; Geo::GDAL::FFI::GDALClose($$self); } sub GetName { my $self = shift; return $self->GetDescription; } sub FlushCache { my $self = shift; Geo::GDAL::FFI::GDALFlushCache($$self); } sub GetDriver { my $self = shift; my $dr = Geo::GDAL::FFI::GDALGetDatasetDriver($$self); return bless \$dr, 'Geo::GDAL::FFI::Driver'; } sub GetWidth { my $self = shift; return Geo::GDAL::FFI::GDALGetRasterXSize($$self); } sub GetHeight { my $self = shift; return Geo::GDAL::FFI::GDALGetRasterYSize($$self); } sub GetSize { my $self = shift; return ( Geo::GDAL::FFI::GDALGetRasterXSize($$self), Geo::GDAL::FFI::GDALGetRasterYSize($$self) ); } sub GetProjectionString { my ($self) = @_; return Geo::GDAL::FFI::GDALGetProjectionRef($$self); } sub SetProjectionString { my ($self, $proj) = @_; my $e = Geo::GDAL::FFI::GDALSetProjection($$self, $proj); if ($e != 0) { confess Geo::GDAL::FFI::error_msg(); } } sub GetGeoTransform { my ($self) = @_; my $t = [0,0,0,0,0,0]; Geo::GDAL::FFI::GDALGetGeoTransform($$self, $t); return wantarray ? @$t : $t; } sub SetGeoTransform { my $self = shift; my $t = @_ > 1 ? [@_] : shift; Geo::GDAL::FFI::GDALSetGeoTransform($$self, $t); } sub GetBand { my ($self, $i) = @_; $i //= 1; my $b = Geo::GDAL::FFI::GDALGetRasterBand($$self, $i); Geo::GDAL::FFI::_register_parent_ref ($b, $self); return bless \$b, 'Geo::GDAL::FFI::Band'; } sub GetBands { my $self = shift; my @bands; for my $i (1..Geo::GDAL::FFI::GDALGetRasterCount($$self)) { push @bands, $self->GetBand($i); } return @bands; } sub GetLayerCount { my ($self) = @_; return Geo::GDAL::FFI::GDALDatasetGetLayerCount($$self); } sub GetLayer { my ($self, $i) = @_; $i //= 0; my $l = Geo::GDAL::FFI::isint($i) ? Geo::GDAL::FFI::GDALDatasetGetLayer($$self, $i) : Geo::GDAL::FFI::GDALDatasetGetLayerByName($$self, $i); unless ($l) { my $msg = Geo::GDAL::FFI::error_msg() // "Could not access layer $i in data set."; confess $msg if $msg; } Geo::GDAL::FFI::_register_parent_ref ($l, $self); return bless \$l, 'Geo::GDAL::FFI::Layer'; } sub CreateLayer { my ($self, $args) = @_; $args //= {}; my $name = $args->{Name} // ''; my ($gt, $sr); if ($args->{GeometryFields}) { $gt = $Geo::GDAL::FFI::geometry_types{None}; } else { $gt = $args->{GeometryType} // 'Unknown'; $gt = $Geo::GDAL::FFI::geometry_types{$gt}; confess "Unknown geometry type: '$args->{GeometryType}'." unless defined $gt; $sr = Geo::GDAL::FFI::OSRClone(${$args->{SpatialReference}}) if $args->{SpatialReference}; } my $o = 0; if ($args->{Options}) { for my $key (keys %{$args->{Options}}) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$args->{Options}->{$key}"); } } my $l = Geo::GDAL::FFI::GDALDatasetCreateLayer($$self, $name, $sr, $gt, $o); Geo::GDAL::FFI::CSLDestroy($o); Geo::GDAL::FFI::OSRRelease($sr) if $sr; my $msg = Geo::GDAL::FFI::error_msg(); confess $msg if $msg; Geo::GDAL::FFI::_register_parent_ref ($l, $self); my $layer = bless \$l, 'Geo::GDAL::FFI::Layer'; if ($args->{Fields}) { for my $f (@{$args->{Fields}}) { $layer->CreateField($f); } } if ($args->{GeometryFields}) { for my $f (@{$args->{GeometryFields}}) { $layer->CreateGeomField($f); } } return $layer; } sub CopyLayer { my ($self, $layer, $name, $options) = @_; $name //= ''; my $o = 0; for my $key (keys %$options) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$options->{$key}"); } my $l = Geo::GDAL::FFI::GDALDatasetCopyLayer($$self, $$layer, $name, $o); Geo::GDAL::FFI::CSLDestroy($o); unless ($l) { my $msg = Geo::GDAL::FFI::error_msg() // "GDALDatasetCopyLayer failed."; confess $msg if $msg; } Geo::GDAL::FFI::_register_parent_ref ($l, $self); return bless \$l, 'Geo::GDAL::FFI::Layer'; } sub ExecuteSQL { my ($self, $sql, $filter, $dialect) = @_; my $lyr = Geo::GDAL::FFI::GDALDatasetExecuteSQL( $$self, $sql, $$filter, $dialect ); if ($lyr) { if (defined wantarray) { Geo::GDAL::FFI::_register_parent_ref ($lyr, $self); return bless \$lyr, 'Geo::GDAL::FFI::Layer::ResultSet'; } else { Geo::GDAL::FFI::GDALDatasetReleaseResultSet ($lyr, $$self); } } # This is perhaps unnecessary, but ensures # internal details do not leak if spatial # index is built in non-void context. return undef; } ## utilities sub new_options { my ($constructor, $options) = @_; $options //= []; confess "The options must be a reference to an array." unless ref $options; my $csl = 0; for my $s (@$options) { $csl = Geo::GDAL::FFI::CSLAddString($csl, $s); } $options = $constructor->($csl, 0); Geo::GDAL::FFI::CSLDestroy($csl); return $options; } sub GetInfo { my ($self, $options) = @_; $options = new_options(\&Geo::GDAL::FFI::GDALInfoOptionsNew, $options); my $info = Geo::GDAL::FFI::GDALInfo($$self, $options); Geo::GDAL::FFI::GDALInfoOptionsFree($options); return $info; } *Info = *GetInfo; sub set_progress { my ($options, $args, $setter) = @_; return unless $args->{Progress}; my $ffi = FFI::Platypus->new; $setter->($options, $ffi->closure($args->{Progress}), $args->{ProgressData}); } sub Translate { my ($self, $path, $options, $progress, $data) = @_; $options = new_options(\&Geo::GDAL::FFI::GDALTranslateOptionsNew, $options); my $args = {Progress => $progress, ProgressData => $data}; set_progress($options, $args, \&Geo::GDAL::FFI::GDALTranslateOptionsSetProgress); my $e = 0; my $ds = Geo::GDAL::FFI::GDALTranslate($path, $$self, $options, \$e); Geo::GDAL::FFI::GDALTranslateOptionsFree($options); return bless \$ds, 'Geo::GDAL::FFI::Dataset' if $ds && ($e == 0); my $msg = Geo::GDAL::FFI::error_msg() // 'Translate failed.'; confess $msg; } sub destination { my ($dst) = @_; confess "Destination missing." unless $dst; my $path; if (ref $dst) { $dst = $$dst; } else { $path = $dst; undef $dst; } return ($path, $dst); } sub dataset_input { my ($self, $input) = @_; $input //= []; confess "The input must be a reference to an array of datasets." unless ref ($input) =~ /ARRAY/; my @datasets = ($$self); for my $ds (@$input) { push @datasets, $$ds; } return \@datasets; } sub Warp { my ($self, $args) = @_; my ($path, $dst) = destination($args->{Destination}); confess "Destination object should not be passed for non-void context" if defined wantarray && blessed $dst; my $input = $self->dataset_input($args->{Input}); my $options = new_options(\&Geo::GDAL::FFI::GDALWarpAppOptionsNew, $args->{Options}); set_progress($options, $args, \&Geo::GDAL::FFI::GDALWarpAppOptionsSetProgress); my $e = 0; my $result; if (blessed($dst)) { Geo::GDAL::FFI::GDALWarp($path, $dst, scalar @$input, $input, $options, \$e); } else { $result = Geo::GDAL::FFI::GDALWarp($path, undef, scalar @$input, $input, $options, \$e); } Geo::GDAL::FFI::GDALWarpAppOptionsFree($options); if (defined $result) { confess Geo::GDAL::FFI::error_msg() // 'Warp failed.' if !$result || $e != 0; return bless \$result, 'Geo::GDAL::FFI::Dataset'; } } sub VectorTranslate { my ($self, $args) = @_; my ($path, $dst) = destination($args->{Destination}); confess "Destination object should not be passed for non-void context" if defined wantarray && blessed $dst; my $input = $self->dataset_input($args->{Input}); my $options = new_options(\&Geo::GDAL::FFI::GDALVectorTranslateOptionsNew, $args->{Options}); set_progress($options, $args, \&Geo::GDAL::FFI::GDALVectorTranslateOptionsSetProgress); my $e = 0; my $result; if (blessed($dst)) { Geo::GDAL::FFI::GDALVectorTranslate(undef, $$dst, scalar @$input, $input, $options, \$e); } else { my $result = Geo::GDAL::FFI::GDALVectorTranslate($path, undef, scalar @$input, $input, $options, \$e); } Geo::GDAL::FFI::GDALVectorTranslateOptionsFree($options); confess Geo::GDAL::FFI::error_msg() // 'VectorTranslate failed.' if $e != 0; if (defined $result) { return bless \$result, 'Geo::GDAL::FFI::Dataset'; } } sub DEMProcessing { my ($self, $path, $args) = @_; my $processing = $args->{Processing} // 'hillshade'; my $colorfile = $args->{ColorFilename}; my $options = new_options(\&Geo::GDAL::FFI::GDALDEMProcessingOptionsNew, $args->{Options}); set_progress($options, $args, \&Geo::GDAL::FFI::GDALDEMProcessingOptionsSetProgress); my $e = 0; my $result = Geo::GDAL::FFI::GDALDEMProcessing($path, $$self, $processing, $colorfile, $options, \$e); Geo::GDAL::FFI::GDALDEMProcessingOptionsFree($options); confess Geo::GDAL::FFI::error_msg() // 'DEMProcessing failed.' if !$result || $e != 0; return bless \$result, 'Geo::GDAL::FFI::Dataset'; } sub NearBlack { my ($self, $args) = @_; my ($path, $dst) = destination($args->{Destination}); confess "Destination object should not be passed for non-void context" if defined wantarray && blessed $dst; my $input = $self->dataset_input($args->{Input}); my $options = new_options(\&Geo::GDAL::FFI::GDALNearblackOptionsNew, $args->{Options}); set_progress($options, $args, \&Geo::GDAL::FFI::GDALNearblackOptionsSetProgress); my $e = 0; my $result; if (blessed($dst)) { Geo::GDAL::FFI::GDALNearblack($path, $$dst, $$self, $options, \$e); } else { $result = Geo::GDAL::FFI::GDALNearblack($path, undef, $$self, $options, \$e); } Geo::GDAL::FFI::GDALNearblackOptionsFree($options); confess Geo::GDAL::FFI::error_msg() // 'NearBlack failed.' if $e != 0; if (defined $result) { return bless \$result, 'Geo::GDAL::FFI::Dataset'; } } sub Grid { my ($self, $path, $options, $progress, $data) = @_; $options = new_options(\&Geo::GDAL::FFI::GDALGridOptionsNew, $options); my $args = {Progress => $progress, ProgressData => $data}; set_progress($options, $args, \&Geo::GDAL::FFI::GDALGridOptionsSetProgress); my $e = 0; my $result = Geo::GDAL::FFI::GDALGrid($path, $$self, $options, \$e); Geo::GDAL::FFI::GDALGridOptionsFree($options); confess Geo::GDAL::FFI::error_msg() // 'Grid failed.' if !$result || $e != 0; return bless \$result, 'Geo::GDAL::FFI::Dataset'; } sub Rasterize { my ($self, $args) = @_; my $dst = $args->{Destination}; confess "Destination argument should not be passed for non-void context" if defined wantarray && blessed $dst; my $options = new_options(\&Geo::GDAL::FFI::GDALRasterizeOptionsNew, $args->{Options}); set_progress($options, $args, \&Geo::GDAL::FFI::GDALRasterizeOptionsSetProgress); my $e = 0; my $result; if (blessed($dst)) { Geo::GDAL::FFI::GDALRasterize(undef, $$dst, $$self, $options, \$e); } else { $result = Geo::GDAL::FFI::GDALRasterize($dst, undef, $$self, $options, \$e); } Geo::GDAL::FFI::GDALRasterizeOptionsFree($options); confess Geo::GDAL::FFI::error_msg() // 'Rasterize failed.' if $e != 0; if (defined $result) { return bless \$result, 'Geo::GDAL::FFI::Dataset'; } } sub BuildVRT { my ($self, $path, $args) = @_; my $input = $self->dataset_input($args->{Input}); my $options = new_options(\&Geo::GDAL::FFI::GDALBuildVRTOptionsNew, $args->{Options}); set_progress($options, $args, \&Geo::GDAL::FFI::GDALBuildVRTOptionsSetProgress); my $e = 0; my $result = Geo::GDAL::FFI::GDALBuildVRT($path, scalar @$input, $input, 0, $options, \$e); Geo::GDAL::FFI::GDALBuildVRTOptionsFree($options); confess Geo::GDAL::FFI::error_msg() // 'BuildVRT failed.' if !$result || $e != 0; return bless \$result, 'Geo::GDAL::FFI::Dataset'; } 1; { # dummy class for result sets from ExecuteSQL # allows specialised destroy method package Geo::GDAL::FFI::Layer::ResultSet; use base qw /Geo::GDAL::FFI::Layer/; sub DESTROY { my ($self) = @_; my $parent = Geo::GDAL::FFI::_get_parent_ref ($$self); Geo::GDAL::FFI::GDALDatasetReleaseResultSet ($$parent, $$self); Geo::GDAL::FFI::_deregister_parent_ref ($$self); } 1; } =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Dataset - A GDAL dataset =head1 SYNOPSIS =head1 DESCRIPTION A collection of raster bands or vector layers. Obtain a dataset object by opening it with the Open method of Geo::GDAL::FFI object or by creating it with the Create method of a Driver object. =head1 METHODS =head2 GetDriver my $driver = $dataset->GetDriver; =head2 GetWidth my $w = $dataset->GetWidth; =head2 GetHeight my $h = $dataset->GetHeight; =head2 GetSize my @size = $dataset->GetSize; Returns the size (width, height) of the bands of this raster dataset. =head2 GetBand my $band = $dataset->GetBand($i); Get the ith (by default the first) band of a raster dataset. =head2 GetBands my @bands = $dataset->GetBands; Returns a list of Band objects representing the bands of this raster dataset. =head2 CreateLayer my $layer = $dataset->CreateLayer({Name => 'layer', ...}); Create a new vector layer into this vector dataset. Named arguments are the following. =over 4 =item C Optional, string, default is ''. =item C Optional, default is 'Unknown', the type of the first geometry field; note: if type is 'None', the layer schema does not initially contain any geometry fields. =item C Optional, a SpatialReference object, the spatial reference for the first geometry field. =item C Optional, driver specific options in an anonymous hash. =item C Optional, a reference to an array of Field objects or schemas, the fields to create into the layer. =item C Optional, a reference to an array of GeometryField objects or schemas, the geometry fields to create into the layer; note that if this argument is defined then the arguments GeometryType and SpatialReference are ignored. =back =head2 GetLayerCount my $count = $dataset->GetLayerCount(); =head2 GetLayer my $layer = $dataset->GetLayer($name); If $name is strictly an integer, then returns the (name-1)th layer in the dataset, otherwise returns the layer whose name is $name. Without arguments returns the first layer. =head2 CopyLayer my $copy = $dataset->CopyLayer($layer, $name, {DST_SRSWKT => 'WKT of a SRS', ...}); Copies the given layer into this dataset using the name $name and returns the new layer. The options hash is mostly driver specific. =head2 ExecuteSQL $dataset->ExecuteSQL ($sql, $filter, $dialect); # build a spatial index $dataset->ExecuteSQL (qq{CREATE SPATIAL INDEX ON "$some_layer_name"}); # filter a data set using the SQLite dialect and a second geometry my $filtered = $dataset->ExecuteSQL ( qq{SELECT "$fld1", "$fld2" FROM "$some_layer_name"}, $some_geometry, 'SQLite', ); =head2 Info my $info = $dataset->Info($options); my $info = $dataset->Info(['-json', '-stats']); This is the same as gdalinfo utility. $options is a reference to an array. Valid options are as per the L utility. =head2 Translate my $target = $source->Translate($path, $options, $progress, $progress_data); Convert a raster dataset into another raster dataset. This is the same as the L utility. $name is the name of the target dataset. $options is a reference to an array of switches. =head2 Warp my $result = $dataset->Warp($args); $args is a hashref, keys may be Destination, Input, Options, Progress, ProgressData. Valid options are as per the L utility. =head2 VectorTranslate my $result = $dataset->VectorTranslate($args); $args is a hashref, keys may be Destination, Input, Options, Progress, ProgressData. Valid options are as per the L utility. =head2 DEMProcessing my $result = $dataset->DEMProcessing($path, $args); $args is a hashref, keys may be Processing, ColorFilename, Options, Progress, ProgressData. See also L. =head2 NearBlack my $result = $dataset->NearBlack($args); $args is a hashref, keys may be Destination, Options, Progress, ProgressData. Valid options are as per the L utility. =head2 Grid my $result = $dataset->Grid($path, $options, $progress, $progress_data); Valid options are as per the L utility. =head2 Rasterize my $result = $dataset->Rasterize($args); my $result = $dataset->Rasterize({Options => [-b => 1, -at]}); $args is a hashref, keys may be Destination, Options, Progress, ProgressData. Valid options are as per the L utility. =head2 BuildVRT my $result = $dataset->BuildVRT($path, $args); $args is a hashref, keys may be Input, Options, Progress, ProgressData. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Layer.pm0000644000175500017550000001562214631756006016326 0ustar pausepausepackage Geo::GDAL::FFI::Layer; use v5.10; use strict; use warnings; use Carp; use base 'Geo::GDAL::FFI::Object'; our $VERSION = 0.1200; sub DESTROY { my $self = shift; Geo::GDAL::FFI::OGR_L_SyncToDisk($$self); #say STDERR "delete parent $parent{$$self}"; Geo::GDAL::FFI::_deregister_parent_ref ($$self); #say STDERR "destroy $self"; } sub GetParentDataset { my ($self) = @_; return Geo::GDAL::FFI::_get_parent_ref ($$self); } sub GetDefn { my $self = shift; my $d = Geo::GDAL::FFI::OGR_L_GetLayerDefn($$self); return bless \$d, 'Geo::GDAL::FFI::FeatureDefn'; } sub CreateField { my $self = shift; my $def = shift; unless (ref $def) { # name => type calling syntax my $name = $def; my $type = shift; $def = Geo::GDAL::FFI::FieldDefn->new({Name => $name, Type => $type}) } elsif (ref $def eq 'HASH') { $def = Geo::GDAL::FFI::FieldDefn->new($def) } my $approx_ok = shift // 1; my $e = Geo::GDAL::FFI::OGR_L_CreateField($$self, $$def, $approx_ok); return unless $e; confess Geo::GDAL::FFI::error_msg({OGRError => $e}); } sub CreateGeomField { my $self = shift; my $def = shift; unless (ref $def) { # name => type calling syntax my $name = $def; my $type = shift; $def = Geo::GDAL::FFI::GeomFieldDefn->new({Name => $name, Type => $type}); } elsif (ref $def eq 'HASH') { $def = Geo::GDAL::FFI::GeomFieldDefn->new($def) } my $approx_ok = shift // 1; my $e = Geo::GDAL::FFI::OGR_L_CreateGeomField($$self, $$def, $approx_ok); return unless $e; confess Geo::GDAL::FFI::error_msg({OGRError => $e}); } sub GetSpatialRef { my ($self) = @_; my $sr = Geo::GDAL::FFI::OGR_L_GetSpatialRef($$self); return unless $sr; return bless \$sr, 'Geo::GDAL::FFI::SpatialReference'; } sub ResetReading { my $self = shift; Geo::GDAL::FFI::OGR_L_ResetReading($$self); } sub GetNextFeature { my $self = shift; my $f = Geo::GDAL::FFI::OGR_L_GetNextFeature($$self); return unless $f; return bless \$f, 'Geo::GDAL::FFI::Feature'; } sub GetFeature { my ($self, $fid) = @_; my $f = Geo::GDAL::FFI::OGR_L_GetFeature($$self, $fid); confess unless $f; return bless \$f, 'Geo::GDAL::FFI::Feature'; } sub GetFeatureCount { my ($self, $force) = @_; Geo::GDAL::FFI::OGR_L_GetFeatureCount($$self, !!$force); } sub SetFeature { my ($self, $f) = @_; Geo::GDAL::FFI::OGR_L_SetFeature($$self, $$f); } sub CreateFeature { my ($self, $f) = @_; my $e = Geo::GDAL::FFI::OGR_L_CreateFeature($$self, $$f); return $f unless $e; } sub DeleteFeature { my ($self, $fid) = @_; my $e = Geo::GDAL::FFI::OGR_L_DeleteFeature($$self, $fid); return unless $e; confess Geo::GDAL::FFI::error_msg({OGRError => $e}); } __PACKAGE__->_make_overlay_methods(); sub _make_overlay_methods { my ($pkg) = @_; my @methods = (qw / Intersection Union SymDifference Identity Update Clip Erase /); no strict 'refs'; foreach my $method_name (@methods) { *{$pkg . '::' . $method_name} = sub { my ($self, $method, $args) = @_; confess "Method layer missing." unless $method; $args //= {}; my $result = $args->{Result}; unless ($result) { my $schema = { GeometryType => 'Unknown' }; $result = Geo::GDAL::FFI::GetDriver('Memory')->Create->CreateLayer($schema); } my $o = 0; for my $key (keys %{$args->{Options}}) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$args->{Options}{$key}"); } my $p = 0; $p = FFI::Platypus->new->closure($args->{Progress}) if $args->{Progress}; my $e = &{'Geo::GDAL::FFI::OGR_L_'.$method_name} ($$self, $$method, $$result, $o, $p, $args->{ProgressData}); Geo::GDAL::FFI::CSLDestroy($o); return $result unless $e; confess Geo::GDAL::FFI::error_msg({OGRError => $e}); }; } return; } sub GetExtent { my ($self, $force) = @_; my $extent = [0,0,0,0]; $force = $force ? \1 : \0; # ensure $force is a ref my $e = Geo::GDAL::FFI::OGR_L_GetExtent ($$self, $extent, $force); return $extent unless $e; confess Geo::GDAL::FFI::error_msg({OGRError => $e}); } sub GetName { my ($self) = @_; return $self->GetDefn->GetName; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Layer - A collection of vector features in GDAL =head1 SYNOPSIS =head1 DESCRIPTION A set of (vector) features having a same schema (the same Defn object). Obtain a layer object by the CreateLayer or GetLayer method of a vector dataset object. Note that the system stores a reference to the parent dataset for each layer object to ensure layer objects remain viable. If you are relying on a dataset object's destruction to flush its dataset cache and then close it then you need to ensure all associated child layers are also destroyed. Failure to do so could lead to corrupt data when reading in newly written files. =head1 METHODS =head2 GetDefn my $defn = $layer->GetDefn; Returns the FeatureDefn object for this layer. =head2 ResetReading $layer->ResetReading; =head2 GetNextFeature my $feature = $layer->GetNextFeature; =head2 GetFeature my $feature = $layer->GetFeature($fid); =head2 SetFeature $layer->SetFeature($feature); =head2 CreateFeature $layer->CreateFeature($feature); =head2 DeleteFeature $layer->DeleteFeature($fid); =head2 GetFeatureCount my $count = $layer->GetFeatureCount(); =head2 GetExtent $layer->GetExtent(); $layer->GetExtent(1); Returns an array ref with [minx, miny, maxx, maxy]. Argument is a boolean to force calculation even if it is expensive. =head2 Intersection, Union, SymDifference, Identity, Update, Clip, Erase $result = $layer->($method, $args); Runs the algorithm between layer and method layer. Named arguments are the following. =over 4 =item C Optional, allows the user to define the result layer. =item C Optional, allows the user to define the options (see GDAL docs). =item C Optional, the progress indicator callback. =item C Optional, data for the progress callback. =back =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/FieldDefn.pm0000644000175500017550000001424214631756006017067 0ustar pausepausepackage Geo::GDAL::FFI::FieldDefn; use v5.10; use strict; use warnings; use Carp; our $VERSION = 0.1200; sub new { my ($class, $args) = @_; my $name = $args->{Name} // 'Unnamed'; my $type = $args->{Type} // 'String'; my $tmp = $Geo::GDAL::FFI::field_types{$type}; confess "Unknown field type: '$type'." unless defined $tmp; my $self = bless \Geo::GDAL::FFI::OGR_Fld_Create($name, $tmp), $class; $self->SetDefault($args->{Default}) if defined $args->{Default}; $self->SetSubtype($args->{Subtype}) if defined $args->{Subtype}; $self->SetJustify($args->{Justify}) if defined $args->{Justify}; $self->SetWidth($args->{Width}) if defined $args->{Width}; $self->SetPrecision($args->{Precision}) if defined $args->{Precision}; $self->SetNullable(0) if $args->{NotNullable}; return $self; } sub DESTROY { my $self = shift; #say STDERR "destroy $self => $$self"; if ($Geo::GDAL::FFI::immutable{$$self}) { #say STDERR "remove it from immutable"; $Geo::GDAL::FFI::immutable{$$self}--; delete $Geo::GDAL::FFI::immutable{$$self} if $Geo::GDAL::FFI::immutable{$$self} == 0; } else { #say STDERR "destroy it"; Geo::GDAL::FFI::OGR_Fld_Destroy($$self); } } sub GetSchema { my $self = shift; my $schema = { Name => $self->GetName, Type => $self->GetType, Subtype => $self->GetSubtype, Justify => $self->GetJustify, Width => $self->GetWidth, Precision => $self->GetPrecision, }; my $default = $self->GetDefault; $schema->{Default} = $default if defined $default; $schema->{NotNullable} = 1 unless $self->IsNullable; return $schema; } sub SetName { my ($self, $name) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $name //= ''; Geo::GDAL::FFI::OGR_Fld_SetName($$self, $name); } sub GetName { my ($self) = @_; return Geo::GDAL::FFI::OGR_Fld_GetNameRef($$self); } sub SetType { my ($self, $type) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $type //= 'String'; my $tmp = $Geo::GDAL::FFI::field_types{$type}; confess "Unknown field type: $type." unless defined $tmp; $type = $tmp; Geo::GDAL::FFI::OGR_Fld_SetType($$self, $type); } sub GetType { my ($self) = @_; return $Geo::GDAL::FFI::field_types_reverse{Geo::GDAL::FFI::OGR_Fld_GetType($$self)}; } sub GetDefault { my $self = shift; return Geo::GDAL::FFI::OGR_Fld_GetDefault($$self) } sub SetDefault { my ($self, $default) = @_; Geo::GDAL::FFI::OGR_Fld_SetDefault($$self, $default); } sub IsDefaultDriverSpecific { my $self = shift; return Geo::GDAL::FFI::OGR_Fld_IsDefaultDriverSpecific($$self); } sub SetSubtype { my ($self, $subtype) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $subtype //= 'None'; my $tmp = $Geo::GDAL::FFI::field_subtypes{$subtype}; confess "Unknown field subtype: $subtype." unless defined $tmp; $subtype = $tmp; Geo::GDAL::FFI::OGR_Fld_SetSubType($$self, $subtype); } sub GetSubtype { my ($self) = @_; return $Geo::GDAL::FFI::field_subtypes_reverse{Geo::GDAL::FFI::OGR_Fld_GetSubType($$self)}; } sub SetJustify { my ($self, $justify) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $justify //= 'Undefined'; my $tmp = $Geo::GDAL::FFI::justification{$justify}; confess "Unknown justify: $justify." unless defined $tmp; $justify = $tmp; Geo::GDAL::FFI::OGR_Fld_SetJustify($$self, $justify); } sub GetJustify { my ($self) = @_; return $Geo::GDAL::FFI::justification_reverse{Geo::GDAL::FFI::OGR_Fld_GetJustify($$self)}; } sub SetWidth { my ($self, $width) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $width //= ''; Geo::GDAL::FFI::OGR_Fld_SetWidth($$self, $width); } sub GetWidth { my ($self) = @_; return Geo::GDAL::FFI::OGR_Fld_GetWidth($$self); } sub SetPrecision { my ($self, $precision) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $precision //= ''; Geo::GDAL::FFI::OGR_Fld_SetPrecision($$self, $precision); } sub GetPrecision { my ($self) = @_; return Geo::GDAL::FFI::OGR_Fld_GetPrecision($$self); } sub SetIgnored { my ($self, $ignored) = @_; #confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $ignored //= 1; Geo::GDAL::FFI::OGR_Fld_SetIgnored($$self, $ignored); } sub IsIgnored { my ($self) = @_; return Geo::GDAL::FFI::OGR_Fld_IsIgnored($$self); } sub SetNullable { my ($self, $nullable) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $nullable //= 0; Geo::GDAL::FFI::OGR_Fld_SetNullable($$self, $nullable); } sub IsNullable { my ($self) = @_; return Geo::GDAL::FFI::OGR_Fld_IsNullable($$self); } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::FieldDefn - A field in a GDAL feature schema =head1 SYNOPSIS =head1 DESCRIPTION There should not usually be any reason to directly access this method except for the ignore methods. This object is created/read from/to the Perl data structure in the CreateLayer method of a dataset, or in the constructor or schema method of FeatureDefn. The schema of a FieldDefn is (Name, Type, Default, Subtype, Justify, Width, Precision, NotNullable). =head1 METHODS =head2 SetIgnored $defn->SetIgnored($arg); Ignore this field when reading features from a layer. To not ignore this field call this method with defined but false (0) argument. =head2 IsIgnored Is this field ignored when reading features from a layer. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/FeatureDefn.pm0000644000175500017550000001525414631756006017443 0ustar pausepausepackage Geo::GDAL::FFI::FeatureDefn; use v5.10; use strict; use warnings; use Carp; our $VERSION = 0.1200; sub new { my ($class, $args) = @_; $args //= {}; my $name = $args->{Name} // ''; my $self = bless \Geo::GDAL::FFI::OGR_FD_Create($name), $class; if ($args->{Fields}) { for my $field (@{$args->{Fields}}) { $self->AddField(Geo::GDAL::FFI::FieldDefn->new($field)); } } if ($args->{GeometryFields}) { my $first = 1; for my $field (@{$args->{GeometryFields}}) { if ($first) { my $d = bless \Geo::GDAL::FFI::OGR_FD_GetGeomFieldDefn($$self, 0), 'Geo::GDAL::FFI::GeomFieldDefn'; $d->SetName($field->{Name}) if defined $field->{Name}; $self->SetGeomType($field->{Type}); $d->SetSpatialRef($field->{SpatialReference}) if $field->{SpatialReference}; $d->SetNullable(0) if $field->{NotNullable}; $first = 0; } else { $self->AddGeomField(Geo::GDAL::FFI::GeomFieldDefn->new($field)); } } } else { $self->SetGeomType($args->{GeometryType}); } $self->SetStyleIgnored if $args->{StyleIgnored}; return $self; } sub DESTROY { my $self = shift; #Geo::GDAL::FFI::OGR_FD_Release($$self); } sub GetSchema { my $self = shift; my $schema = {Name => $self->GetName}; for (my $i = 0; $i < Geo::GDAL::FFI::OGR_FD_GetFieldCount($$self); $i++) { push @{$schema->{Fields}}, $self->GetFieldDefn($i)->GetSchema; } for (my $i = 0; $i < Geo::GDAL::FFI::OGR_FD_GetGeomFieldCount($$self); $i++) { push @{$schema->{GeometryFields}}, $self->GetGeomFieldDefn($i)->GetSchema; } $schema->{StyleIgnored} = 1 if $self->IsStyleIgnored; return $schema; } sub GetName { my ($self) = @_; return Geo::GDAL::FFI::OGR_FD_GetName($$self); } sub GetFieldDefn { my ($self, $fname) = @_; my $i = $fname // 0; $i = Geo::GDAL::FFI::OGR_FD_GetFieldIndex($$self, $i) unless Geo::GDAL::FFI::isint($i); my $d = Geo::GDAL::FFI::OGR_FD_GetFieldDefn($$self, $i); confess "No such field: $fname." unless $d; ++$Geo::GDAL::FFI::immutable{$d}; return bless \$d, 'Geo::GDAL::FFI::FieldDefn'; } sub GetFieldDefns { my $self = shift; my @retval; for my $i (0..Geo::GDAL::FFI::OGR_FD_GetFieldCount($$self)-1) { push @retval, $self->GetFieldDefn($i); } return @retval; } sub GetGeomFieldDefn { my ($self, $fname) = @_; my $i = $fname // 0; $i = Geo::GDAL::FFI::OGR_FD_GetGeomFieldIndex($$self, $i) unless Geo::GDAL::FFI::isint($i); my $d = Geo::GDAL::FFI::OGR_FD_GetGeomFieldDefn($$self, $i); confess "No such field: $fname." unless $d; ++$Geo::GDAL::FFI::immutable{$d}; return bless \$d, 'Geo::GDAL::FFI::GeomFieldDefn'; } sub GetGeomFieldDefns { my $self = shift; my @retval; for my $i (0..Geo::GDAL::FFI::OGR_FD_GetGeomFieldCount($$self)-1) { push @retval, $self->GetGeomFieldDefn($i); } return @retval; } sub AddFieldDefn { my ($self, $d) = @_; Geo::GDAL::FFI::OGR_FD_AddFieldDefn($$self, $$d); } sub AddGeomFieldDefn { my ($self, $d) = @_; Geo::GDAL::FFI::OGR_FD_AddGeomFieldDefn($$self, $$d); } sub DeleteFieldDefn { my ($self, $i) = @_; $i //= 0; $i = $self->GetFieldIndex($i) unless Geo::GDAL::FFI::isint($i); Geo::GDAL::FFI::OGR_FD_DeleteFieldDefn($$self, $i); } sub DeleteGeomFieldDefn { my ($self, $i) = @_; $i //= 0; $i = $self->GetGeomFieldIndex($i) unless Geo::GDAL::FFI::isint($i); Geo::GDAL::FFI::OGR_FD_DeleteGeomFieldDefn($$self, $i); } sub GetGeomType { my ($self) = @_; return $Geo::GDAL::FFI::geometry_types_reverse{Geo::GDAL::FFI::OGR_FD_GetGeomType($$self)}; } sub SetGeomType { my ($self, $type) = @_; $type //= 'Unknown'; my $tmp = $Geo::GDAL::FFI::geometry_types{$type}; confess "Unknown geometry type: $type." unless defined $tmp; Geo::GDAL::FFI::OGR_FD_SetGeomType($$self, $tmp); } sub IsGeometryIgnored { my ($self) = @_; Geo::GDAL::FFI::OGR_FD_IsGeometryIgnored($$self); } sub SetGeometryIgnored { my ($self, $i) = @_; $i //= 1; Geo::GDAL::FFI::OGR_FD_SetGeometryIgnored($$self, $i); } sub IsStyleIgnored { my ($self) = @_; Geo::GDAL::FFI::OGR_FD_IsStyleIgnored($$self); } sub SetStyleIgnored { my ($self, $i) = @_; $i //= 1; Geo::GDAL::FFI::OGR_FD_SetStyleIgnored($$self, $i); } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::FeatureDefn - A GDAL feature schema =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 new $defn = Geo::GDAL::FFI::FeatureDefn->new({Fields => [...], GeometryType => 'Point'}); Create a new FeatureDefn object. The named arguments (optional) are the following. =over 4 =item C Optional; the name for this feature class; default is the empty string. =item C Optional, a reference to an array of FieldDefn objects or schemas. =item C Optional, a reference to an array of GeomFieldDefn objects or schemas. =item C Optional, the type for the first geometry field; default is Unknown. Note that this argument is ignored if GeometryFields is given. =item C =back =head2 GetSchema Returns the definition as a perl data structure. =head2 GetFieldDefn my $field_defn = $defn->GetFieldDefn($name); Get the specified non spatial field object. If the argument is explicitly an integer and not a string, it is taken as the field index. =head2 GetFieldDefns my @field_defns = $defn->GetFieldDefns; =head2 GetGeomFieldDefn my $geom_field_defn = $defn->GetGeomFieldDefn($name); Get the specified spatial field object. If the argument is explicitly an integer and not a string, it is taken as the field index. =head2 GetGeomFieldDefns my @geom_field_defns = $defn->GetGeomFieldDefns; =head2 SetGeometryIgnored $defn->SetGeometryIgnored($arg); Ignore the first geometry field when reading features from a layer. To not ignore the first geometry field call this method with defined but false (0) argument. =head2 IsGeometryIgnored my $is = $defn->IsGeometryIgnored; Is the first geometry field ignored when reading features from a layer. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/GeomFieldDefn.pm0000644000175500017550000001017414631756006017677 0ustar pausepausepackage Geo::GDAL::FFI::GeomFieldDefn; use v5.10; use strict; use warnings; use Carp; our $VERSION = 0.1200; sub new { my ($class, $args) = @_; $args //= {}; my $name = $args->{Name} // 'Unnamed'; my $type = $args->{Type} // 'Point'; my $tmp = $Geo::GDAL::FFI::geometry_types{$type}; confess "Unknown geometry type: $type." unless defined $tmp; my $self = bless \Geo::GDAL::FFI::OGR_GFld_Create($name, $tmp), $class; $self->SetSpatialRef($args->{SpatialReference}) if $args->{SpatialReference}; $self->SetNullable(0) if $args->{NotNullable}; return $self; } sub DESTROY { my $self = shift; if ($Geo::GDAL::FFI::immutable{$$self}) { $Geo::GDAL::FFI::immutable{$$self}--; delete $Geo::GDAL::FFI::immutable{$$self} if $Geo::GDAL::FFI::immutable{$$self} == 0; } else { Geo::GDAL::FFI::OGR_GFld_Destroy($$self); } } sub GetSchema { my $self = shift; my $schema = { Name => $self->GetName, Type => $self->GetType }; if (my $sr = $self->GetSpatialRef) { $schema->{SpatialReference} = $sr->Export('Wkt'); } $schema->{NotNullable} = 1 unless $self->IsNullable; return $schema; } sub SetName { my ($self, $name) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $name //= ''; Geo::GDAL::FFI::OGR_GFld_SetName($$self, $name); } sub GetName { my ($self) = @_; return Geo::GDAL::FFI::OGR_GFld_GetNameRef($$self); } sub SetType { my ($self, $type) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $type //= 'Point'; my $tmp = $Geo::GDAL::FFI::geometry_types{$type}; confess "Unknown geometry type: $type." unless defined $tmp; $type = $tmp; Geo::GDAL::FFI::OGR_GFld_SetType($$self, $type); } sub GetType { my ($self) = @_; return $Geo::GDAL::FFI::geometry_types_reverse{Geo::GDAL::FFI::OGR_GFld_GetType($$self)}; } sub SetSpatialRef { my ($self, $sr) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $sr = Geo::GDAL::FFI::SpatialReference->new($sr) unless ref $sr; Geo::GDAL::FFI::OGR_GFld_SetSpatialRef($$self, $$sr); } sub GetSpatialRef { my ($self) = @_; my $sr = Geo::GDAL::FFI::OGR_GFld_GetSpatialRef($$self); return bless \$sr, 'Geo::GDAL::FFI::SpatialReference' if $sr; } sub SetIgnored { my ($self, $ignored) = @_; #confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $ignored //= 1; Geo::GDAL::FFI::OGR_GFld_SetIgnored($$self, $ignored); } sub IsIgnored { my ($self) = @_; return Geo::GDAL::FFI::OGR_GFld_IsIgnored($$self); } sub SetNullable { my ($self, $nullable) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; $nullable //= 0; Geo::GDAL::FFI::OGR_GFld_SetNullable($$self, $nullable); } sub IsNullable { my ($self) = @_; return Geo::GDAL::FFI::OGR_GFld_IsNullable($$self); } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::GeomFieldDefn - A spatial field in a GDAL feature schema =head1 SYNOPSIS =head1 DESCRIPTION There should not usually be any reason to directly access this method except for the ignore methods. This object is created/read from/to the Perl data structure in the CreateLayer method of a dataset, or in the constructor or schema method of FeatureDefn. The schema of a GeomFieldDefn is (Name, Type, SpatialReference, NotNullable). =head1 METHODS =head2 SetIgnored $defn->SetIgnored($arg); Ignore this field when reading features from a layer. To not ignore this field call this method with defined but false (0) argument. =head2 IsIgnored Is this field ignored when reading features from a layer. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/SpatialReference.pm0000644000175500017550000000716714631756006020473 0ustar pausepausepackage Geo::GDAL::FFI::SpatialReference; use v5.10; use strict; use warnings; use Carp; our $VERSION = 0.1200; sub new { my ($class, $arg, @arg) = @_; my $sr; if (not defined $arg) { $sr = Geo::GDAL::FFI::OSRNewSpatialReference(); } elsif (not @arg) { $sr = Geo::GDAL::FFI::OSRNewSpatialReference($arg); } else { $sr = Geo::GDAL::FFI::OSRNewSpatialReference(); my $gdal = Geo::GDAL::FFI->get_instance; $arg = $gdal->get_importer($arg); if ($arg->($sr, @arg) != 0) { Geo::GDAL::FFI::OSRDestroySpatialReference($sr); $sr = 0; } } return bless \$sr, $class if $sr; confess Geo::GDAL::FFI::error_msg(); } sub DESTROY { my $self = shift; # OSRGetReferenceCount method not yet implemented my $refcount = (Geo::GDAL::FFI::OSRReference ($$self)-1); Geo::GDAL::FFI::OSRDereference ($$self); # immediately decrement if ($refcount == 0) { #warn "Calling DESTROY method for $$self\n"; Geo::GDAL::FFI::OSRDestroySpatialReference($$self); } } sub Export { my $self = shift; my $format = shift; my $gdal = Geo::GDAL::FFI->get_instance; my $exporter = $gdal->get_exporter($format); my $x; if ($exporter->($$self, \$x, @_) != 0) { confess Geo::GDAL::FFI::error_msg(); } return $x; } sub Set { my $self = shift; my $set = shift; my $gdal = Geo::GDAL::FFI->get_instance; my $setter = $gdal->get_setter($set); if ($setter->($$self, @_) != 0) { confess Geo::GDAL::FFI::error_msg(); } } sub Clone { my $self = shift; my $s = Geo::GDAL::FFI::OSRClone($$self); return bless \$s, 'Geo::GDAL::FFI::SpatialReference'; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::SpatialReference - A spatial reference system in GDAL =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 new Create a new SpatialReference object. my $sr = Geo::GDAL::FFI::SpatialReference->new('WKT here...'); If only one argument is given, it is taken as the well known text (WKT) associated with the spatial reference system (SRS). my $sr = Geo::GDAL::FFI::SpatialReference->new(EPSG => 3067); If there are more than one argument, the first argument is taken as a format and the rest of the arguments are taken as arguments to the format. The list of formats known to GDAL (at the time of this writing) is EPSG, EPSGA, Wkt, Proj4, ESRI, PCI, USGS, XML, Dict, Panorama, Ozi, MICoordSys, ERM, Url. =head2 Export $sr->Export($format, @args); Export a SpatialReference object to a format. The list of formats known to GDAL (at the time of this writing) is Wkt, PrettyWkt, Proj4, PCI, USGS, XML, Panorama, MICoordSys, ERM. =head2 Set $sr->Set($proj, @args); Set projection parameters in a SpatialReference object. The list of projection parameters known to GDAL (at the time of this writing) is Axes, ACEA, AE, Bonne, CEA, CS, EC, Eckert, EckertIV, EckertVI, Equirectangular, Equirectangular2, GS, GH, IGH, GEOS, GaussSchreiberTMercator, Gnomonic, HOM, HOMAC, HOM2PNO, IWMPolyconic, Krovak, LAEA, LCC, LCC1SP, LCCB, MC, Mercator, Mercator2SP, Mollweide, NZMG, OS, Orthographic, Polyconic, PS, Robinson, Sinusoidal, Stereographic, SOC, TM, TMVariant, TMG, TMSO, TPED, VDG, Wagner, QSC, SCH. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Geometry.pm0000644000175500017550000004300614631756006017042 0ustar pausepausepackage Geo::GDAL::FFI::Geometry; use v5.10; use strict; use warnings; use Carp; our $VERSION = 0.1200; my %ref; sub new { my $class = shift; my $g = 0; confess "Must give either geometry type or format => data." unless @_; if (@_ == 1) { my $type = shift // ''; my $tmp = $Geo::GDAL::FFI::geometry_types{$type}; confess "Empty or unknown geometry type: '$type'." unless defined $tmp; my $m = $type =~ /M$/; my $z = $type =~ /ZM$/ || $type =~ /25D$/; $g = Geo::GDAL::FFI::OGR_G_CreateGeometry($tmp); confess "OGR_G_CreateGeometry failed." unless $g; # should not happen Geo::GDAL::FFI::OGR_G_SetMeasured($g, 1) if $m; Geo::GDAL::FFI::OGR_G_Set3D($g, 1) if $z; return bless \$g, $class; } else { my ($format, $string, $sr) = @_; my $tmp = $Geo::GDAL::FFI::geometry_formats{$format}; confess "Empty or unknown geometry format: '$format'." unless defined $tmp; $sr = $$sr if $sr; if ($format eq 'WKT') { my $e = Geo::GDAL::FFI::OGR_G_CreateFromWkt(\$string, $sr, \$g); confess(Geo::GDAL::FFI::error_msg({OGRError => $e})) if $e; } } return bless \$g, $class; } sub DESTROY { my ($self) = @_; Geo::GDAL::FFI::_deregister_parent_ref ($$self); if ($ref{$$self}) { delete $ref{$$self}; return; } if ($Geo::GDAL::FFI::immutable{$$self}) { #say STDERR "forget $$self $immutable{$$self}"; $Geo::GDAL::FFI::immutable{$$self}--; delete $Geo::GDAL::FFI::immutable{$$self} if $Geo::GDAL::FFI::immutable{$$self} == 0; } else { #say STDERR "destroy $$self"; Geo::GDAL::FFI::OGR_G_DestroyGeometry($$self); } } sub Clone { my ($self) = @_; my $g = Geo::GDAL::FFI::OGR_G_Clone($$self); return bless \$g, 'Geo::GDAL::FFI::Geometry'; } sub GetType { my ($self, $mode) = @_; $mode //= ''; my $t = Geo::GDAL::FFI::OGR_G_GetGeometryType($$self); Geo::GDAL::FFI::OGR_GT_Flatten($t) if $mode =~ /flatten/i; #say STDERR "type is $t"; return $Geo::GDAL::FFI::geometry_types_reverse{$t}; } sub GetPointCount { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_GetPointCount($$self); } sub SetPoint { my $self = shift; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; my $i; if (Geo::GDAL::FFI::OGR_G_GetDimension($$self) == 0) { $i = 0; } else { $i = shift; } my ($x, $y, $z, $m, $is3d, $ism); confess "SetPoint missing coordinate parameters." unless @_; if (ref $_[0]) { ($x, $y, $z, $m) = @{$_[0]}; $is3d = $_[1] // Geo::GDAL::FFI::OGR_G_Is3D($$self); $ism = $_[2] // Geo::GDAL::FFI::OGR_G_IsMeasured($$self); } else { confess "SetPoint missing coordinate parameters." unless @_ > 1; ($x, $y, $z, $m) = @_; $is3d = Geo::GDAL::FFI::OGR_G_Is3D($$self); $ism = Geo::GDAL::FFI::OGR_G_IsMeasured($$self); } if ($is3d && $ism) { $z //= 0; $m //= 0; Geo::GDAL::FFI::OGR_G_SetPointZM($$self, $i, $x, $y, $z, $m); } elsif ($ism) { $m //= 0; Geo::GDAL::FFI::OGR_G_SetPointM($$self, $i, $x, $y, $m); } elsif ($is3d) { $z //= 0; Geo::GDAL::FFI::OGR_G_SetPoint($$self, $i, $x, $y, $z); } else { Geo::GDAL::FFI::OGR_G_SetPoint_2D($$self, $i, $x, $y); } } sub GetPoint { my ($self, $i, $is3d, $ism) = @_; $i //= 0; $is3d //= Geo::GDAL::FFI::OGR_G_Is3D($$self); $ism //= Geo::GDAL::FFI::OGR_G_IsMeasured($$self); my ($x, $y, $z, $m) = (0, 0, 0, 0); Geo::GDAL::FFI::OGR_G_GetPointZM($$self, $i, \$x, \$y, \$z, \$m); my @point = ($x, $y); push @point, $z if $is3d; push @point, $m if $ism; return wantarray ? @point : \@point; } sub GetPoints { my ($self, $is3d, $ism) = @_; $is3d //= Geo::GDAL::FFI::OGR_G_Is3D($$self); $ism //= Geo::GDAL::FFI::OGR_G_IsMeasured($$self); my $points = []; my $n = $self->GetGeometryCount; if ($n == 0) { $n = $self->GetPointCount; return scalar $self->GetPoint(0, $is3d, $ism) if $n == 0; for my $i (0..$n-1) { my $p = $self->GetPoint($i, $is3d, $ism); push @$points, $p; } return $points; } for my $i (0..$n-1) { push @$points, $self->GetGeometry($i)->GetPoints($is3d, $ism); } return $points; } sub SetPoints { my ($self, $points, $is3d, $ism) = @_; confess "SetPoints must be called with an arrayref." unless ref $points; $is3d //= Geo::GDAL::FFI::OGR_G_Is3D($$self); $ism //= Geo::GDAL::FFI::OGR_G_IsMeasured($$self); my $n = $self->GetGeometryCount; if ($n == 0) { unless (ref $points->[0]) { $self->SetPoint($points, $is3d, $ism); return; } $n = @$points; for my $i (0..$n-1) { $self->SetPoint($i, $points->[$i], $is3d, $ism); } return; } for my $i (0..$n-1) { $self->GetGeometry($i)->SetPoints($points->[$i], $is3d, $ism); } } sub GetGeometryCount { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_GetGeometryCount($$self); } sub GetGeometry { my ($self, $i) = @_; my $g = Geo::GDAL::FFI::OGR_G_GetGeometryRef($$self, $i); Geo::GDAL::FFI::_register_parent_ref ($g, $self); $ref{$g} = 1; return bless \$g, 'Geo::GDAL::FFI::Geometry'; } sub AddGeometry { my ($self, $g) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; my $e = Geo::GDAL::FFI::OGR_G_AddGeometry($$self, $$g); return unless $e; confess(Geo::GDAL::FFI::error_msg()); } sub RemoveGeometry { my ($self, $i) = @_; confess "Can't modify an immutable object." if $Geo::GDAL::FFI::immutable{$$self}; my $e = Geo::GDAL::FFI::OGR_G_RemoveGeometry($$self, $i, 1); return unless $e; confess(Geo::GDAL::FFI::error_msg()); } sub ExportToWKT { my ($self, $variant) = @_; $variant //= 'ISO'; my $wkt = ''; if ($variant =~ /(?i)iso/) { Geo::GDAL::FFI::OGR_G_ExportToIsoWkt($$self, \$wkt); } else { Geo::GDAL::FFI::OGR_G_ExportToWkt($$self, \$wkt); } return $wkt; } *AsText = *ExportToWKT; sub ExportToGML { my ($self, %options) = @_; my $o = 0; for my $key (keys %options) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$options{$key}"); } my $p; if ($o) { $p = Geo::GDAL::FFI::OGR_G_ExportToGMLEx($$self, $o); Geo::GDAL::FFI::CSLDestroy($o); } else { $p = Geo::GDAL::FFI::OGR_G_ExportToGML($$self); } my $ffi = FFI::Platypus->new; my $gml = $ffi->cast(opaque => 'string', $p); Geo::GDAL::FFI::VSIFree($p); confess Geo::GDAL::FFI::error_msg() unless $gml; return $gml; } sub ExportToKML { my ($self) = @_; my $p = Geo::GDAL::FFI::OGR_G_ExportToKML($$self); my $ffi = FFI::Platypus->new; my $kml = $ffi->cast(opaque => 'string', $p); Geo::GDAL::FFI::VSIFree($p); confess Geo::GDAL::FFI::error_msg() unless $kml; return $kml; } sub ExportToJSON { my ($self, %options) = @_; my $o = 0; for my $key (keys %options) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$options{$key}"); } my $p; if ($o) { $p = Geo::GDAL::FFI::OGR_G_ExportToJsonEx($$self, $o); Geo::GDAL::FFI::CSLDestroy($o); } else { $p = Geo::GDAL::FFI::OGR_G_ExportToJson($$self); } my $ffi = FFI::Platypus->new; my $json = $ffi->cast(opaque => 'string', $p); Geo::GDAL::FFI::VSIFree($p); confess Geo::GDAL::FFI::error_msg() unless $json; return $json; } sub Intersects { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Intersects($$self, $$geom); } sub Equals { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Equals($$self, $$geom); } sub Disjoint { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Disjoint($$self, $$geom); } sub Touches { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Touches($$self, $$geom); } sub Crosses { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Crosses($$self, $$geom); } sub Within { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Within($$self, $$geom); } sub Contains { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Contains($$self, $$geom); } sub Overlaps { my ($self, $geom) = @_; return Geo::GDAL::FFI::OGR_G_Overlaps($$self, $$geom); } sub Boundary { my ($self) = @_; return bless \Geo::GDAL::FFI::OGR_G_Boundary($$self), 'Geo::GDAL::FFI::Geometry'; } sub ConvexHull { my ($self) = @_; return bless \Geo::GDAL::FFI::OGR_G_ConvexHull($$self), 'Geo::GDAL::FFI::Geometry'; } sub Buffer { my ($self, $dist, $quad_segs) = @_; return bless \Geo::GDAL::FFI::OGR_G_Buffer($$self, $dist, $quad_segs), 'Geo::GDAL::FFI::Geometry'; } sub Intersection { my ($self, $geom) = @_; confess "Undefined geometry." unless $geom; $self = Geo::GDAL::FFI::OGR_G_Intersection($$self, $$geom); confess Geo::GDAL::FFI::error_msg() unless $self; return bless \$self, 'Geo::GDAL::FFI::Geometry'; } sub Union { my ($self, $geom) = @_; confess "Undefined geometry." unless $geom; $self = Geo::GDAL::FFI::OGR_G_Union($$self, $$geom); confess Geo::GDAL::FFI::error_msg() unless $self; return bless \$self, 'Geo::GDAL::FFI::Geometry'; } sub Difference { my ($self, $geom) = @_; confess "Undefined geometry." unless $geom; $self = Geo::GDAL::FFI::OGR_G_Difference($$self, $$geom); confess Geo::GDAL::FFI::error_msg() unless $self; return bless \$self, 'Geo::GDAL::FFI::Geometry'; } sub SymDifference { my ($self, $geom) = @_; confess "Undefined geometry." unless $geom; $self = Geo::GDAL::FFI::OGR_G_SymDifference($$self, $$geom); confess Geo::GDAL::FFI::error_msg() unless $self; return bless \$self, 'Geo::GDAL::FFI::Geometry'; } sub Distance { my ($self, $geom) = @_; confess "Undefined geometry." unless $geom; return Geo::GDAL::FFI::OGR_G_Distance($$self, $$geom); } sub Distance3D { my ($self, $geom) = @_; confess "Undefined geometry." unless $geom; return Geo::GDAL::FFI::OGR_G_Distance3D($$self, $$geom); } sub Length { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_Length($$self); } sub Area { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_Area($$self); } sub Centroid { my ($self) = @_; my $centroid = Geo::GDAL::FFI::Geometry->new('Point'); Geo::GDAL::FFI::OGR_G_Centroid($$self, $$centroid); my $msg = Geo::GDAL::FFI::error_msg(); confess($msg) if $msg; return $centroid; } sub Empty { my ($self) = @_; Geo::GDAL::FFI::OGR_G_Empty($$self); } sub IsEmpty { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_IsEmpty($$self); } sub IsValid { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_IsValid($$self); } sub IsSimple { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_IsSimple($$self); } sub IsRing { my ($self) = @_; return Geo::GDAL::FFI::OGR_G_IsRing($$self); } sub GetEnvelope { my ($self) = @_; my $envelope = [0,0,0,0]; Geo::GDAL::FFI::OGR_G_GetEnvelope ($$self, $envelope); return $envelope; } sub GetEnvelope3D { my ($self) = @_; my $envelope = [0,0,0,0,0,0]; Geo::GDAL::FFI::OGR_G_GetEnvelope3D ($$self, $envelope); return $envelope; } sub MakeValid { my ($self, %options) = @_; my $o = 0; for my $key (keys %options) { $o = Geo::GDAL::FFI::CSLAddString($o, "$key=$options{$key}"); } my $p; if ($o) { $p = Geo::GDAL::FFI::OGR_G_MakeValidEx($$self, $o); Geo::GDAL::FFI::CSLDestroy($o); } else { $p = Geo::GDAL::FFI::OGR_G_MakeValid($$self); } confess Geo::GDAL::FFI::error_msg() unless $p; return bless \$p, 'Geo::GDAL::FFI::Geometry'; } sub Normalize { my ($self) = @_; my $g = Geo::GDAL::FFI::OGR_G_Normalize($$self); confess Geo::GDAL::FFI::error_msg() unless $g; return bless \$g, 'Geo::GDAL::FFI::Geometry'; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Geometry - A GDAL geometry =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 new my $geom = Geo::GDAL::FFI::Geometry->new($geometry_type); $type must be one of Geo::GDAL::FFI::GeometryTypes(). my $geom = Geo::GDAL::FFI::Geometry->new($format, $arg, $sr); $format must be one of Geo::GDAL::FFI::GeometryFormats(), e.g., 'WKT'. $sr should be a SpatialRef object if given. =head2 Clone my $geom2 = $geom1->Clone; Clones this geometry and returns the clone. =head2 GetType my $type = $geom->GetType($mode); Returns the type of this geometry. If $mode (optional) is 'flatten', returns the type without Z, M, or ZM postfix. =head2 GetPointCount Returns the point count of this geometry. =head2 SetPoint $point->SetPoint($x, $y, $z, $m); Set the coordinates of a point geometry. The usage of $z and $m in the method depend on the actual 3D or measured status of the point. $point->SetPoint([$x, $y, $z, $m]); Set the coordinates of a point geometry. The usage of $z and $m in the method depend on the actual 3D or measured status of the geometry. $geom->SetPoint($i, $x, $y, $z, $m); Set the coordinates of the ith (zero based index) point in a curve geometry. The usage of $z and $m in the method depend on the actual 3D or measured status of the geometry. Note that setting the nth point of a curve creates all points 0..n-2 unless they exist. $geom->SetPoint($i, $coords); Set the coordinates of the ith (zero based index) point in this curve. $coords must be a reference to an array of the coordinates. The usage of $z and $m in the method depend on the 3D or measured status of the geometry. Note that setting the nth point of a curve may create all points 0..n-2. =head2 GetPoint my $coords = $geom->GetPoint($i); Get the coordinates of the ith (zero based index) point in this curve. This method can also be used to set the coordinates of a point geometry and then the $i must be zero if it is given. Returns the coordinates either as a list or a reference to an anonymous array depending on the context. The coordinates contain $z and $m depending on the 3D or measured status of the geometry. =head2 GetPoints my $points = $geom->GetPoints; Returns the coordinates of the vertices of this geometry in an obvious array based data structure. Note that different geometry types have similar data structures. =head2 SetPoints $geom->SetPoints($points); Sets the coordinates of the vertices of this geometry from an obvious array based data structure. Note that different geometry types may have similar data structures. If the geometry contains subgeometries (like polygon contains rings for example), the data structure is assumed to adhere to this structure. Uses SetPoint and may thus add points to curves. =head2 GetGeometryCount my $num_geometries = $geom->GetGeometryCount; =head2 GetGeometry my $outer_ring = $polygon->GetGeometry(0); Returns the ith subgeometry (zero based index) in this geometry. The returned geometry object is only a wrapper to the underlying C++ reference and thus changing that geometry will change the parent. =head2 AddGeometry $polygon->AddGeometry($ring); =head2 RemoveGeometry $geom->RemoveGeometry($i); =head2 ExportToWKT($variant) my $wkt = $geom->ExportToWKT($variant); Returns the geometry as WKT. $variant is optional (default is 'ISO'). =head2 AsText Alias to ExportToWKT. =head2 ExportToGML(%options) my $gml = $geom->ExportToGML(%options); Returns the geometry as GML string. %options may contain options as described in GDAL documentation. =head2 ExportToJSON(%options) my $json = $geom->ExportToJSON(%options); Returns the geometry as JSON string. %options may contain options as described in GDAL documentation. =head2 Intersects =head2 Equals =head2 Disjoint =head2 Touches =head2 Crosses =head2 Within =head2 Contains =head2 Overlaps =head2 Boundary =head2 ConvexHull =head2 Buffer =head2 Intersection =head2 Union =head2 Difference =head2 SymDifference =head2 Distance =head2 Distance3D =head2 Length =head2 Area =head2 Centroid =head2 Empty =head2 IsEmpty =head2 IsValid =head2 IsSimple =head2 IsRing =head2 GetEnvelope Returns a four element array reference containing [Xmin, Xmax, Ymin, Ymax]. =head2 GetEnvelope3D Returns a six element array reference containing [Xmin, Xmax, Ymin, Ymax, Zmin, Zmax]. =head2 MakeValid(%options) my $valid_geom = $geom->MakeValid(%options); Attempts to make an invalid geometry valid and returns that. %options may contain options as described in GDAL documentation. Requires GDAL version >= 3.0 =head2 Normalize() my $normalized_geom = $geom->Normalize(); Attempts to bring geometry into normalized/canonical form. Requires GDAL version >= 3.3 =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/VSI.pm0000644000175500017550000000446414631756006015715 0ustar pausepausepackage Geo::GDAL::FFI::VSI; use v5.10; use strict; use warnings; use Encode qw(decode encode); use Carp; use FFI::Platypus::Buffer; require Exporter; our $VERSION = 0.1200; our @ISA = qw(Exporter); our @EXPORT_OK = qw(Mkdir Rmdir ReadDir FOpen Unlink Rename); sub FOpen { return Geo::GDAL::FFI::VSI::File->Open(@_); } sub Unlink { my ($path) = @_; my $e = Geo::GDAL::FFI::VSIUnlink(encode(utf8 => $path)); confess Geo::GDAL::FFI::error_msg() // "Failed to unlink '$path'." if $e == -1; } sub Rename { my ($path, $new_path) = @_; my $e = Geo::GDAL::FFI::VSIRename(encode(utf8 => $path), encode(utf8 => $new_path)); confess Geo::GDAL::FFI::error_msg() // "Failed to rename '$path' to '$new_path'." if $e == -1; } sub Mkdir { my ($path, $mode) = @_; $mode //= hex '0x0666'; my $e = Geo::GDAL::FFI::VSIMkdir(encode(utf8 => $path), $mode); confess Geo::GDAL::FFI::error_msg() // "Failed to mkdir '$path'." if $e == -1; } sub Rmdir { my ($path) = @_; my $e = Geo::GDAL::FFI::VSIRmdir(encode(utf8 => $path)); confess Geo::GDAL::FFI::error_msg() // "Failed to rmdir '$path'." if $e == -1; } sub ReadDir { my ($path, $max_files) = @_; $max_files //= 0; my $csl = Geo::GDAL::FFI::VSIReadDirEx(encode(utf8 => $path), $max_files); my @dir; for my $i (0 .. Geo::GDAL::FFI::CSLCount($csl)-1) { push @dir, decode utf8 => Geo::GDAL::FFI::CSLGetField($csl, $i); } Geo::GDAL::FFI::CSLDestroy($csl); return @dir; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::VSI - A GDAL virtual file system =head1 SYNOPSIS use Geo::GDAL::FFI::VSI qw/FOpen Mkdir ReadDir/; =head1 DESCRIPTION =head1 METHODS =head2 FOpen($path, $access) my $file = FOpen('/vsimem/file', 'w'); Short for Geo::GDAL::FFI::VSI::File::Open =head2 Mkdir($path, $mode) $mode is optional and by default 0x0666. =head2 ReadDir($path, $max_files) $max_files is optional and by default 0, i.e., read all names of files in the dir. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Band.pm0000644000175500017550000002606314631756006016117 0ustar pausepausepackage Geo::GDAL::FFI::Band; use v5.10; use strict; use warnings; use Carp; use FFI::Platypus::Buffer; use base 'Geo::GDAL::FFI::Object'; our $VERSION = 0.1200; sub DESTROY { my $self = shift; Geo::GDAL::FFI::_deregister_parent_ref ($$self); } sub GetDataType { my $self = shift; return $Geo::GDAL::FFI::data_types_reverse{Geo::GDAL::FFI::GDALGetRasterDataType($$self)}; } sub GetWidth { my $self = shift; Geo::GDAL::FFI::GDALGetRasterBandXSize($$self); } sub GetHeight { my $self = shift; Geo::GDAL::FFI::GDALGetRasterBandYSize($$self); } sub GetSize { my $self = shift; return ( Geo::GDAL::FFI::GDALGetRasterBandXSize($$self), Geo::GDAL::FFI::GDALGetRasterBandYSize($$self) ); } sub GetCategoryNames { my $self = shift; my $csl = Geo::GDAL::FFI::GDALGetRasterCategoryNames($$self); my @names; for my $i (0..Geo::GDAL::FFI::CSLCount($csl)-1) { push @names, Geo::GDAL::FFI::CSLGetField($csl, $i); } return @names; } sub SetCategoryNames { my ($self, @names) = @_; my $csl = 0; for my $n (@names) { $csl = Geo::GDAL::FFI::CSLAddString($csl, $n); } Geo::GDAL::FFI::GDALSetRasterCategoryNames($$self, $csl); Geo::GDAL::FFI::CSLDestroy($csl); } sub GetNoDataValue { my $self = shift; my $b = 0; my $v = Geo::GDAL::FFI::GDALGetRasterNoDataValue($$self, \$b); return unless $b; return $v; } sub SetNoDataValue { my $self = shift; unless (@_) { Geo::GDAL::FFI::GDALDeleteRasterNoDataValue($$self); return; } my $v = shift; my $e = Geo::GDAL::FFI::GDALSetRasterNoDataValue($$self, $v); return unless $e; confess Geo::GDAL::FFI::error_msg() // "SetNoDataValue not supported by the driver."; } sub GetBlockSize { my $self = shift; my ($w, $h); Geo::GDAL::FFI::GDALGetBlockSize($$self, \$w, \$h); return ($w, $h); } sub pack_char { my $t = shift; my $is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; # from Programming Perl return ('C', 1) if $t == 1; return ($is_big_endian ? ('n', 2) : ('v', 2)) if $t == 2; return ('s', 2) if $t == 3; return ($is_big_endian ? ('N', 4) : ('V', 4)) if $t == 4; return ('l', 4) if $t == 5; return ('f', 4) if $t == 6; return ('d', 8) if $t == 7; # CInt16 => 8, # CInt32 => 9, # CFloat32 => 10, # CFloat64 => 11 } sub Read { my ($self, $xoff, $yoff, $xsize, $ysize, $bufxsize, $bufysize) = @_; $xoff //= 0; $yoff //= 0; my $t = Geo::GDAL::FFI::GDALGetRasterDataType($$self); my ($pc, $bytes_per_cell) = pack_char($t); my $w; $xsize //= Geo::GDAL::FFI::GDALGetRasterBandXSize($$self); $ysize //= Geo::GDAL::FFI::GDALGetRasterBandYSize($$self); $bufxsize //= $xsize; $bufysize //= $ysize; $w = $bufxsize * $bytes_per_cell; my $buf = ' ' x ($bufysize * $w); my ($pointer, $size) = scalar_to_buffer $buf; Geo::GDAL::FFI::GDALRasterIO($$self, $Geo::GDAL::FFI::Read, $xoff, $yoff, $xsize, $ysize, $pointer, $bufxsize, $bufysize, $t, 0, 0); my $offset = 0; my @data; for my $y (0..$bufysize-1) { my @d = unpack($pc."[$bufxsize]", substr($buf, $offset, $w)); push @data, \@d; $offset += $w; } return \@data; } sub ReadBlock { my ($self, $xoff, $yoff, $xsize, $ysize, $t) = @_; $xoff //= 0; $yoff //= 0; Geo::GDAL::FFI::GDALGetBlockSize($$self, \$xsize, \$ysize) unless defined $xsize; $t = Geo::GDAL::FFI::GDALGetRasterDataType($$self) unless defined $t; my $buf; my ($pc, $bytes_per_cell) = pack_char($t); my $w = $xsize * $bytes_per_cell; $buf = ' ' x ($ysize * $w); my ($pointer, $size) = scalar_to_buffer $buf; Geo::GDAL::FFI::GDALReadBlock($$self, $xoff, $yoff, $pointer); my $offset = 0; my @data; for my $y (0..$ysize-1) { my @d = unpack($pc."[$xsize]", substr($buf, $offset, $w)); push @data, \@d; $offset += $w; } return \@data; } sub Write { my ($self, $data, $xoff, $yoff, $xsize, $ysize) = @_; $xoff //= 0; $yoff //= 0; my $bufxsize = @{$data->[0]}; my $bufysize = @$data; $xsize //= $bufxsize; $ysize //= $bufysize; my $t = Geo::GDAL::FFI::GDALGetRasterDataType($$self); my ($pc, $bytes_per_cell) = pack_char($t); my $buf = ''; for my $i (0..$bufysize-1) { $buf .= pack($pc."[$bufxsize]", @{$data->[$i]}); } my ($pointer, $size) = scalar_to_buffer $buf; Geo::GDAL::FFI::GDALRasterIO($$self, $Geo::GDAL::FFI::Write, $xoff, $yoff, $xsize, $ysize, $pointer, $bufxsize, $bufysize, $t, 0, 0); } sub WriteBlock { my ($self, $data, $xoff, $yoff) = @_; my ($xsize, $ysize); Geo::GDAL::FFI::GDALGetBlockSize($$self, \$xsize, \$ysize); my $t = Geo::GDAL::FFI::GDALGetRasterDataType($$self); my ($pc, $bytes_per_cell) = pack_char($t); my $buf = ''; for my $i (0..$ysize-1) { $buf .= pack($pc."[$xsize]", @{$data->[$i]}); } my ($pointer, $size) = scalar_to_buffer $buf; Geo::GDAL::FFI::GDALWriteBlock($$self, $xoff, $yoff, $pointer); } sub GetColorInterpretation { my $self = shift; return $Geo::GDAL::FFI::color_interpretations_reverse{ Geo::GDAL::FFI::GDALGetRasterColorInterpretation($$self) }; } sub SetColorInterpretation { my ($self, $i) = @_; my $tmp = $Geo::GDAL::FFI::color_interpretations{$i}; confess "Unknown color interpretation: $i." unless defined $tmp; $i = $tmp; Geo::GDAL::FFI::GDALSetRasterColorInterpretation($$self, $i); } sub GetColorTable { my $self = shift; my $ct = Geo::GDAL::FFI::GDALGetRasterColorTable($$self); return unless $ct; # color table is a table of [c1...c4] # the interpretation of colors is from next method my @table; for my $i (0..Geo::GDAL::FFI::GDALGetColorEntryCount($ct)-1) { my $c = Geo::GDAL::FFI::GDALGetColorEntry($ct, $i); push @table, $c; } return wantarray ? @table : \@table; } sub SetColorTable { my ($self, $table) = @_; my $ct = Geo::GDAL::FFI::GDALCreateColorTable(); for my $i (0..$#$table) { Geo::GDAL::FFI::GDALSetColorEntry($ct, $i, $table->[$i]); } Geo::GDAL::FFI::GDALSetRasterColorTable($$self, $ct); Geo::GDAL::FFI::GDALDestroyColorTable($ct); } sub GetPiddle { require PDL::Lite; # minimal load my ($self, $xoff, $yoff, $xsize, $ysize, $xdim, $ydim, $alg) = @_; $xoff //= 0; $yoff //= 0; my ($w, $h) = $self->GetSize; $xsize //= $w - $xoff; $ysize //= $h - $yoff; my $t = Geo::GDAL::FFI::GDALGetRasterDataType($$self); my $pdl_t = $Geo::GDAL::FFI::data_type2pdl_data_type{$Geo::GDAL::FFI::data_types_reverse{$t}}; confess "The Piddle data_type is unsuitable." unless defined $pdl_t; $xdim //= $xsize; $ydim //= $ysize; $alg //= 'NearestNeighbour'; my $tmp = $Geo::GDAL::FFI::resampling{$alg}; confess "Unknown resampling scheme: $alg." unless defined $tmp; $alg = $tmp; my $bufxsize = $xsize; my $bufysize = $ysize; my ($pc, $bytes_per_cell) = pack_char($t); my $buf = ' ' x ($bufysize * $bufxsize * $bytes_per_cell); my ($pointer, $size) = scalar_to_buffer $buf; Geo::GDAL::FFI::GDALRasterIO($$self, $Geo::GDAL::FFI::Read, $xoff, $yoff, $xsize, $ysize, $pointer, $bufxsize, $bufysize, $t, 0, 0); my $pdl = PDL->new; $pdl->set_datatype($pdl_t); $pdl->setdims([$xdim, $ydim]); my $data = $pdl->get_dataref(); # FIXME: see http://pdl.perl.org/PDLdocs/API.html how to wrap $buf into a piddle $$data = $buf; $pdl->upd_data; # FIXME: we want approximate equality since no data value can be very large floating point value my $bad = GetNoDataValue($self); return $pdl->setbadif($pdl == $bad) if defined $bad; return $pdl; } sub SetPiddle { my ($self, $pdl, $xoff, $yoff, $xsize, $ysize) = @_; $xoff //= 0; $yoff //= 0; my ($w, $h) = $self->GetSize; my $t = $Geo::GDAL::FFI::pdl_data_type2data_type{$pdl->get_datatype}; confess "The Piddle data_type '".$pdl->get_datatype."' is unsuitable." unless defined $t; $t = $Geo::GDAL::FFI::data_types{$t}; my ($xdim, $ydim) = $pdl->dims(); $xsize //= $xdim; $ysize //= $ydim; if ($xdim > $w - $xoff) { warn "Piddle too wide ($xdim) for this raster band (width = $w, offset = $xoff)."; $xdim = $w - $xoff; } if ($ydim > $h - $yoff) { $ydim = $h - $yoff; warn "Piddle too tall ($ydim) for this raster band (height = $h, offset = $yoff)."; } my $data = $pdl->get_dataref(); my ($pointer, $size) = scalar_to_buffer $$data; Geo::GDAL::FFI::GDALRasterIO($$self, $Geo::GDAL::FFI::Write, $xoff, $yoff, $xsize, $ysize, $pointer, $xdim, $ydim, $t, 0, 0); } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Band - A GDAL raster band =head1 SYNOPSIS =head1 DESCRIPTION A band (channel) in a raster dataset. Use the Band method of a dataset object to obtain a band object. =head1 METHODS =head2 GetDataType my $datatype = $band->GetDataType; =head2 GetSize my @size = $band->GetSize; =head2 GetBlockSize my @size = $band->GetBlockSize; =head2 GetNoDataValue my $nodata = $band->GetNoDataValue; =head2 SetNoDataValue $band->SetNoDataValue($value); Calling the method without arguments deletes the nodata value. $band->SetNoDataValue; =head2 Read my $data = $band->Read($xoff, $yoff, $xsize, $ysize, $bufxsize, $bufysize); All arguments are optional. If no arguments are given, reads the whole raster band into a 2D Perl array. The returned array is an array of references to arrays of row values. =head2 ReadBlock my $data = $band->ReadBlock($xoff, $yoff, @blocksize, $datatype); Reads a block of data from the band and returns it as a Perl 2D array. C<@blocksize> and C<$datatype> (an integer) are optional and obtained from the GDAL raster object if not given. =head2 Write $band->Write($data, $xoff, $yoff, $xsize, $ysize); =head2 WriteBlock $band->WriteBlock($data, $xoff, $yoff); =head2 SetPiddle $band->SetPiddle($pdl, $xoff, $yoff, $xsize, $ysize); Read data from a piddle into this Band. =head2 GetPiddle $band->GetPiddle($xoff, $yoff, $xsize, $ysize, $xdim, $ydim); Read data from this Band into a piddle. =head2 GetColorInterpretation my $ci = $band->GetColorInterpretation; =head2 SetColorInterpretation $band->SetColorInterpretation($ci); =head2 GetColorTable my $color_table = $band->GetColorTable; Returns the color table as an array of arrays. The inner tables are colors [c1...c4]. =head2 SetColorTable $band->SetColorTable($color_table); =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Feature.pm0000644000175500017550000002270314631756006016643 0ustar pausepausepackage Geo::GDAL::FFI::Feature; use v5.10; use strict; use warnings; use Config; use Carp; use Encode qw(decode encode); use FFI::Platypus::Buffer; our $VERSION = 0.1200; sub new { my ($class, $defn) = @_; my $f = Geo::GDAL::FFI::OGR_F_Create($$defn); return bless \$f, $class; } sub DESTROY { my $self = shift; Geo::GDAL::FFI::OGR_F_Destroy($$self); } sub GetFID { my ($self) = @_; return Geo::GDAL::FFI::OGR_F_GetFID($$self); } sub SetFID { my ($self, $fid) = @_; $fid //= 0; Geo::GDAL::FFI::OGR_F_GetFID($$self, $fid); } sub GetDefn { my ($self) = @_; my $d = Geo::GDAL::FFI::OGR_F_GetDefnRef($$self); ++$Geo::GDAL::FFI::immutable{$d}; #say STDERR "$d immutable"; return bless \$d, 'Geo::GDAL::FFI::FeatureDefn'; } sub Clone { my ($self) = @_; my $f = Geo::GDAL::FFI::OGR_F_Clone($$self); return bless \$f, 'Geo::GDAL::FFI::Feature'; } sub Equals { my ($self, $f) = @_; return Geo::GDAL::FFI::OGR_F_Equal($$self, $$f); } sub field_index { my ($self, $field_name, $is_geom) = @_; my $index = $is_geom ? Geo::GDAL::FFI::OGR_F_GetGeomFieldIndex($$self, $field_name) : Geo::GDAL::FFI::OGR_F_GetFieldIndex($$self, $field_name); confess "Field '$field_name' does not exist." if $index < 0; return $index; } sub SetField { my $self = shift; my $i = shift; $i //= 0; $i = $self->field_index($i) unless Geo::GDAL::FFI::isint($i); unless (@_) { Geo::GDAL::FFI::OGR_F_UnsetField($$self, $i) ; return; } my ($value) = @_; unless (defined $value) { Geo::GDAL::FFI::OGR_F_SetFieldNull($$self, $i); return; } my $d = Geo::GDAL::FFI::OGR_F_GetFieldDefnRef($$self, $i); my $t = $Geo::GDAL::FFI::field_types_reverse{Geo::GDAL::FFI::OGR_Fld_GetType($d)}; if ($t =~ /^Integer64/ && $Config{use64bitint} ne 'define') { confess "Your Perl does not support 64 bit integers."; } Geo::GDAL::FFI::OGR_F_SetFieldInteger($$self, $i, $value) if $t eq 'Integer'; Geo::GDAL::FFI::OGR_F_SetFieldInteger64($$self, $i, $value) if $t eq 'Integer64'; Geo::GDAL::FFI::OGR_F_SetFieldDouble($$self, $i, $value) if $t eq 'Real'; Geo::GDAL::FFI::OGR_F_SetFieldString($$self, $i, $value) if $t eq 'String'; confess "Can't yet set binary fields." if $t eq 'Binary'; my @s = @_; Geo::GDAL::FFI::OGR_F_SetFieldIntegerList($$self, $i, scalar @s, \@s) if $t eq 'IntegerList'; Geo::GDAL::FFI::OGR_F_SetFieldInteger64List($$self, $i, scalar @s, \@s) if $t eq 'Integer64List'; Geo::GDAL::FFI::OGR_F_SetFieldDoubleList($$self, $i, scalar @s, \@s) if $t eq 'RealList'; if ($t eq 'StringList') { my $csl = 0; for my $s (@s) { $csl = Geo::GDAL::FFI::CSLAddString($csl, $s); } Geo::GDAL::FFI::OGR_F_SetFieldStringList($$self, $i, $csl); Geo::GDAL::FFI::CSLDestroy($csl); } elsif ($t eq 'Date') { my @dt = @_; $dt[0] //= 2000; # year $dt[1] //= 1; # month 1-12 $dt[2] //= 1; # day 1-31 $dt[3] //= 0; # hour 0-23 $dt[4] //= 0; # minute 0-59 $dt[5] //= 0.0; # second with millisecond accuracy $dt[6] //= 100; # TZ Geo::GDAL::FFI::OGR_F_SetFieldDateTimeEx($$self, $i, @dt); } elsif ($t eq 'Time') { my @dt = (0, 0, 0, @_); $dt[3] //= 0; # hour 0-23 $dt[4] //= 0; # minute 0-59 $dt[5] //= 0.0; # second with millisecond accuracy $dt[6] //= 100; # TZ Geo::GDAL::FFI::OGR_F_SetFieldDateTimeEx($$self, $i, @dt); } elsif ($t eq 'DateTime') { my @dt = @_; $dt[0] //= 2000; # year $dt[1] //= 1; # month 1-12 $dt[2] //= 1; # day 1-31 $dt[3] //= 0; # hour 0-23 $dt[4] //= 0; # minute 0-59 $dt[5] //= 0.0; # second with millisecond accuracy $dt[6] //= 100; # TZ Geo::GDAL::FFI::OGR_F_SetFieldDateTimeEx($$self, $i, @dt); } } sub GetField { my ($self, $i, $encoding) = @_; $i //= 0; $i = $self->field_index($i) unless Geo::GDAL::FFI::isint($i); return unless $self->IsFieldSetAndNotNull($i); my $d = Geo::GDAL::FFI::OGR_F_GetFieldDefnRef($$self, $i); my $t = $Geo::GDAL::FFI::field_types_reverse{Geo::GDAL::FFI::OGR_Fld_GetType($d)}; if ($t =~ /^Integer64/ && $Config{use64bitint} ne 'define') { confess "Your Perl does not support 64 bit integers."; } return Geo::GDAL::FFI::OGR_F_GetFieldAsInteger($$self, $i) if $t eq 'Integer'; return Geo::GDAL::FFI::OGR_F_GetFieldAsInteger64($$self, $i) if $t eq 'Integer64'; return Geo::GDAL::FFI::OGR_F_GetFieldAsDouble($$self, $i) if $t eq 'Real'; if ($t eq 'String') { my $retval = Geo::GDAL::FFI::OGR_F_GetFieldAsString($$self, $i); $retval = decode $encoding => $retval if defined $encoding; return $retval; } return Geo::GDAL::FFI::OGR_F_GetFieldAsBinary($$self, $i) if $t eq 'Binary'; my @list; if ($t eq 'IntegerList') { my $len; my $p = Geo::GDAL::FFI::OGR_F_GetFieldAsIntegerList($$self, $i, \$len); @list = unpack("l[$len]", buffer_to_scalar($p, $len*4)); } elsif ($t eq 'Integer64List') { my $len; my $p = Geo::GDAL::FFI::OGR_F_GetFieldAsInteger64List($$self, $i, \$len); @list = unpack("q[$len]", buffer_to_scalar($p, $len*8)); } elsif ($t eq 'RealList') { my $len; my $p = Geo::GDAL::FFI::OGR_F_GetFieldAsDoubleList($$self, $i, \$len); @list = unpack("d[$len]", buffer_to_scalar($p, $len*8)); } elsif ($t eq 'StringList') { my $p = Geo::GDAL::FFI::OGR_F_GetFieldAsStringList($$self, $i); for my $i (0..Geo::GDAL::FFI::CSLCount($p)-1) { push @list, Geo::GDAL::FFI::CSLGetField($p, $i); } } elsif ($t eq 'Date') { my ($y, $m, $d, $h, $min, $s, $tz) = (0, 0, 0, 0, 0, 0.0, 0); Geo::GDAL::FFI::OGR_F_GetFieldAsDateTimeEx($$self, $i, \$y, \$m, \$d, \$h, \$min, \$s, \$tz); @list = ($y, $m, $d); } elsif ($t eq 'Time') { my ($y, $m, $d, $h, $min, $s, $tz) = (0, 0, 0, 0, 0, 0.0, 0); Geo::GDAL::FFI::OGR_F_GetFieldAsDateTimeEx($$self, $i, \$y, \$m, \$d, \$h, \$min, \$s, \$tz); $s = sprintf("%.3f", $s) + 0; @list = ($h, $min, $s, $tz); } elsif ($t eq 'DateTime') { my ($y, $m, $d, $h, $min, $s, $tz) = (0, 0, 0, 0, 0, 0.0, 0); Geo::GDAL::FFI::OGR_F_GetFieldAsDateTimeEx($$self, $i, \$y, \$m, \$d, \$h, \$min, \$s, \$tz); $s = sprintf("%.3f", $s) + 0; @list = ($y, $m, $d, $h, $min, $s, $tz); } return @list; } sub IsFieldSet { my ($self, $i) = @_; $i //= 0; $i = $self->field_index($i) unless Geo::GDAL::FFI::isint($i); return Geo::GDAL::FFI::OGR_F_IsFieldSet($$self, $i); } sub IsFieldNull { my ($self, $i) = @_; $i //= 0; $i = $self->field_index($i) unless Geo::GDAL::FFI::isint($i); return Geo::GDAL::FFI::OGR_F_IsFieldNull($$self, $i); } sub IsFieldSetAndNotNull { my ($self, $i) = @_; $i //= 0; $i = $self->field_index($i) unless Geo::GDAL::FFI::isint($i); return Geo::GDAL::FFI::OGR_F_IsFieldSetAndNotNull($$self, $i); } sub GetGeomField { my ($self, $i) = @_; $i //= 0; $i = $self->field_index($i, 1) unless Geo::GDAL::FFI::isint($i); my $g = Geo::GDAL::FFI::OGR_F_GetGeomFieldRef($$self, $i); confess "No such field: $i" unless $g; ++$Geo::GDAL::FFI::immutable{$g}; #say STDERR "$g immutable"; return bless \$g, 'Geo::GDAL::FFI::Geometry'; } sub SetGeomField { my $self = shift; my $g = pop; my $i = shift; $i //= 0; $i = $self->field_index($i, 1) unless Geo::GDAL::FFI::isint($i); if (ref $g eq 'ARRAY') { $g = Geo::GDAL::FFI::Geometry->new(@$g); } ++$Geo::GDAL::FFI::immutable{$$g}; #say STDERR "$$g immutable"; Geo::GDAL::FFI::OGR_F_SetGeomFieldDirectly($$self, $i, $$g); } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Feature - A GDAL vector feature =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 new my $feature = Geo::GDAL::FFI::Feature->new($defn); Create a new Feature object. The argument is a FeatureDefn object, which you can get from a Layer object (Defn method), another Feature object (Defn method), or by explicitly creating a new FeatureDefn object. =head2 GetDefn Returns the FeatureDefn object for this Feature. =head2 GetFID =head2 SetFID =head2 Clone =head2 Equals my $equals = $feature1->Equals($feature2); =head2 SetField $feature->SetField($fname, ...); Set the value of field $fname. If no arguments after the name is given, the field is unset. If the arguments after the name is undefined, sets the field to NULL. Otherwise sets the field according to the field type. =head2 GetField my $value = $feature->GetField($fname); =head2 SetGeomField $feature->SetField($fname, $geom); $fname is optional and by default the first geometry field. =head2 GetGeomField my $geom = $feature->GetGeomField($fname); $fname is optional and by default the first geometry field. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/Object.pm0000644000175500017550000001031614631756006016453 0ustar pausepausepackage Geo::GDAL::FFI::Object; use v5.10; use strict; use warnings; use Carp; our $VERSION = 0.1200; sub GetDescription { my $self = shift; return Geo::GDAL::FFI::GDALGetDescription($$self); } sub HasCapability { my ($self, $cap) = @_; my $tmp = $Geo::GDAL::FFI::capabilities{$cap}; confess "Unknown capability: $cap." unless defined $tmp; my $md = $self->GetMetadata(''); return $md->{'DCAP_'.$cap}; } sub GetMetadataDomainList { my ($self) = @_; my $csl = Geo::GDAL::FFI::GDALGetMetadataDomainList($$self); my @list; for my $i (0..Geo::GDAL::FFI::CSLCount($csl)-1) { push @list, Geo::GDAL::FFI::CSLGetField($csl, $i); } Geo::GDAL::FFI::CSLDestroy($csl); return wantarray ? @list : \@list; } sub GetMetadata { my ($self, $domain) = @_; my %md; unless (defined $domain) { for $domain ($self->GetMetadataDomainList) { $md{$domain} = $self->GetMetadata($domain); } return wantarray ? %md : \%md; } my $csl = Geo::GDAL::FFI::GDALGetMetadata($$self, $domain); for my $i (0..Geo::GDAL::FFI::CSLCount($csl)-1) { my ($name, $value) = split /=/, Geo::GDAL::FFI::CSLGetField($csl, $i); $md{$name} = $value; } return wantarray ? %md : \%md; } sub SetMetadata { my ($self, $metadata, $domain) = @_; unless (defined $domain) { for $domain (keys %$metadata) { $self->SetMetadata($metadata->{$domain}, $domain); } } else { my $csl = 0; for my $name (keys %$metadata) { $csl = Geo::GDAL::FFI::CSLAddString($csl, "$name=$metadata->{$name}"); } my $err = Geo::GDAL::FFI::GDALSetMetadata($$self, $csl, $domain); Geo::GDAL::FFI::CSLDestroy($csl); confess Geo::GDAL::FFI::error_msg() if $err == $Geo::GDAL::FFI::Failure; warn Geo::GDAL::FFI::error_msg() if $err == $Geo::GDAL::FFI::Warning; } } sub GetMetadataItem { my ($self, $name, $domain) = @_; $domain //= ""; return Geo::GDAL::FFI::GDALGetMetadataItem($$self, $name, $domain); } sub SetMetadataItem { my ($self, $name, $value, $domain) = @_; $domain //= ""; my $err = Geo::GDAL::FFI::GDALSetMetadataItem($$self, $name, $value, $domain); confess Geo::GDAL::FFI::error_msg() if $err == $Geo::GDAL::FFI::Failure; warn Geo::GDAL::FFI::error_msg() if $err == $Geo::GDAL::FFI::Warning; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::Object - A GDAL major object =head1 SYNOPSIS =head1 DESCRIPTION The base class for classes Driver, Dataset, Band, and Layer. =head1 METHODS =head2 GetDescription my $desc = $object->GetDescription; =head2 HasCapability my $has_cap = $object->HasCapability($capability); =head2 GetMetadataDomainList my @domains = $object->GetMetadataDomainList; =head2 GetMetadata my %metadata = $object->GetMetadata($domain); Returns the object metadata of a given domain. my $metadata = $object->GetMetadata($domain); Returns the object metadata of a given domain in an anonymous hash. my %metadata = $object->GetMetadata; Returns the object metadata. my $metadata = $object->GetMetadata; Returns the object metadata in an anonymous hash. =head2 SetMetadata $object->SetMetadata($metadata, $domain); Sets the object metadata in a given domain. The metadata is in an anonymous hash. $object->SetMetadata($metadata); Sets the object metadata in the domains that are the keys of the hash $metadata references. The values of the hash are the metadata in anonymous hashes. =head2 GetMetadataItem my $value = $object->GetMetadataItem($item, $domain) Gets the value of the metadata item in a domain (by default an empty string). =head2 SetMetadataItem $object->GetMetadataItem($item, $value, $domain) Sets the value of the metadata item in a domain (by default an empty string). =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/VSI/0000755000175500017550000000000014634407013015341 5ustar pausepauseGeo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI/VSI/File.pm0000644000175500017550000000472014631756006016567 0ustar pausepausepackage Geo::GDAL::FFI::VSI::File; use v5.10; use strict; use warnings; use Encode qw(decode encode); use Carp; use FFI::Platypus::Buffer; our $VERSION = 0.1200; sub Open { my ($class, $path, $access) = @_; $access //= 'r'; my $self = {}; $self->{handle} = Geo::GDAL::FFI::VSIFOpenExL(encode(utf8 => $path), $access, 1); unless ($self->{handle}) { confess Geo::GDAL::FFI::error_msg() // "Failed to open '$path' with access '$access'."; } return bless $self, $class; } sub DESTROY { my ($self) = @_; $self->Close; } sub Close { my ($self) = @_; return unless $self->{handle}; my $e = Geo::GDAL::FFI::VSIFCloseL($self->{handle}); confess Geo::GDAL::FFI::error_msg() // "Failed to close a VSIFILE." if $e == -1; delete $self->{handle}; } sub Read { my ($self, $len) = @_; $len //= 1; my $buf = ' ' x $len; my ($pointer, $size) = scalar_to_buffer $buf; my $n = Geo::GDAL::FFI::VSIFReadL($pointer, 1, $len, $self->{handle}); return substr $buf, 0, $n; } sub Write { my ($self, $buf) = @_; my $len = do {use bytes; length($buf)}; my $ffi = FFI::Platypus->new(); my $address = $ffi->cast('string' => 'opaque', $buf); return Geo::GDAL::FFI::VSIFWriteL($address, 1, $len, $self->{handle}); } sub Ingest { my ($self) = @_; my $s; my $e = Geo::GDAL::FFI::VSIIngestFile($self->{handle}, '', \$s, 0, -1); return $s; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI::VSI::File - A GDAL virtual file =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 Open my $vsifile = Geo::GDAL::FFI::VSI::File->Open($name, $access); Open a virtual file. $name is the name of the file to open. $access is 'r', 'r+', 'a', or 'w'. 'r' is the default. Returns a Geo::GDAL::FFI::VSI::File object. =head2 Close Closes the file handle. Is done automatically when the object is destroyed. =head2 Read($len) Read $len bytes from the file. Returns the bytes in a Perl string. $len is optional and by default 1. =head2 Write($buf) Write the Perl string $buf into the file. Returns the number of successfully written bytes. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/lib/Geo/GDAL/FFI.pm0000644000175500017550000033231314634406006015244 0ustar pausepausepackage Geo::GDAL::FFI; use v5.10; use strict; use warnings; use Carp; use PDL::Types (); use Config (); # needed to silence some FFI::Platypus warnings use FFI::Platypus; use FFI::Platypus::Buffer; require Exporter; require B; use Sort::Versions; use Geo::GDAL::FFI::VSI; use Geo::GDAL::FFI::VSI::File; use Geo::GDAL::FFI::SpatialReference; use Geo::GDAL::FFI::Object; use Geo::GDAL::FFI::Driver; use Geo::GDAL::FFI::Dataset; use Geo::GDAL::FFI::Band; use Geo::GDAL::FFI::Layer; use Geo::GDAL::FFI::FeatureDefn; use Geo::GDAL::FFI::FieldDefn; use Geo::GDAL::FFI::GeomFieldDefn; use Geo::GDAL::FFI::Feature; use Geo::GDAL::FFI::Geometry; our $VERSION = 0.1200; our $DEBUG = 0; our @ISA = qw(Exporter); our @EXPORT_OK = qw(@errors GetVersionInfo SetErrorHandling UnsetErrorHandling Capabilities OpenFlags DataTypes ResamplingMethods FieldTypes FieldSubtypes Justifications ColorInterpretations GeometryTypes GeometryFormats GridAlgorithms GetDriver GetDrivers IdentifyDriver Open HaveGEOS SetConfigOption GetConfigOption FindFile PushFinderLocation PopFinderLocation FinderClean); our %EXPORT_TAGS = (all => \@EXPORT_OK); our $None = 0; our $Debug = 1; our $Warning = 2; our $Failure = 3; our $Fatal = 4; our %ogr_errors = ( 1 => 'NOT_ENOUGH_DATA', 2 => 'NOT_ENOUGH_MEMORY', 3 => 'UNSUPPORTED_GEOMETRY_TYPE', 4 => 'UNSUPPORTED_OPERATION', 5 => 'CORRUPT_DATA', 6 => 'FAILURE', 7 => 'UNSUPPORTED_SRS', 8 => 'INVALID_HANDLE', 9 => 'NON_EXISTING_FEATURE', ); our $Read = 0; our $Write = 1; our @errors; our %immutable; my %parent_ref_hash; #say STDERR "XXX " . $ENV{LD_LIBRARY_PATH}; #my $instance = __PACKAGE__->new; my $instance; sub SetErrorHandling { return unless $instance; return if exists $instance->{CPLErrorHandler}; $instance->{CPLErrorHandler} = $instance->{ffi}->closure( sub { my ($err_cat, $err_num, $msg) = @_; if ($err_cat == $None) { } elsif ($err_cat == $Debug) { if ($DEBUG) { print STDERR $msg; } } elsif ($err_cat == $Warning) { warn $msg; } else { push @errors, $msg; } }); $instance->{CPLErrorHandler}->sticky; CPLPushErrorHandler($instance->{CPLErrorHandler}); } sub UnsetErrorHandling { return unless $instance; return unless exists $instance->{CPLErrorHandler}; $instance->{CPLErrorHandler}->unstick; CPLPopErrorHandler($instance->{CPLErrorHandler}); delete $instance->{CPLErrorHandler}; } sub error_msg { my $args = shift; return unless @errors || $args; unless (@errors) { return $ogr_errors{$args->{OGRError}} if $args->{OGRError}; return "Unknown error."; } my $msg = join("\n", @errors); @errors = (); return $msg; } # internal methods sub _register_parent_ref { my ($gdal_handle, $parent) = @_; # ensure $gdal_handle is not blessed? confess "gdal handle is undefined" if !defined $gdal_handle; confess "Parent ref is undefined" if !$parent; $parent_ref_hash{$gdal_handle} = $parent; } sub _deregister_parent_ref { my ($gdal_handle) = @_; # we get undef vals in global cleanup return if !$gdal_handle; delete $parent_ref_hash{$gdal_handle}; } sub _get_parent_ref { my ($gdal_handle) = @_; warn "Attempting to access non-existent parent" if !$parent_ref_hash{$gdal_handle}; return $parent_ref_hash{$gdal_handle} } our %capabilities = ( OPEN => 1, CREATE => 2, CREATECOPY => 3, VIRTUALIO => 4, RASTER => 5, VECTOR => 6, GNM => 7, NOTNULL_FIELDS => 8, DEFAULT_FIELDS => 9, NOTNULL_GEOMFIELDS => 10, NONSPATIAL => 11, FEATURE_STYLES => 12, ); sub Capabilities { return sort {$capabilities{$a} <=> $capabilities{$b}} keys %capabilities; } our %open_flags = ( READONLY => 0x00, UPDATE => 0x01, ALL => 0x00, RASTER => 0x02, VECTOR => 0x04, GNM => 0x08, SHARED => 0x20, VERBOSE_ERROR => 0x40, INTERNAL => 0x80, ARRAY_BLOCK_ACCESS => 0x100, HASHSET_BLOCK_ACCESS => 0x200, ); sub OpenFlags { return sort {$open_flags{$a} <=> $open_flags{$b}} keys %open_flags; } our %data_types = ( Unknown => 0, Byte => 1, UInt16 => 2, Int16 => 3, UInt32 => 4, Int32 => 5, Float32 => 6, Float64 => 7, CInt16 => 8, CInt32 => 9, CFloat32 => 10, CFloat64 => 11 ); our %data_types_reverse = reverse %data_types; sub DataTypes { return sort {$data_types{$a} <=> $data_types{$b}} keys %data_types; } our %rat_field_type = ( Integer => 0, Real => 1, String => 2 ); our %rat_field_usage = ( Generic => 0, PixelCount => 1, Name => 2, Min => 3, Max => 4, MinMax => 5, Red => 6, Green => 7, Blue => 8, Alpha => 9, RedMin => 10, GreenMin => 11, BlueMin => 12, AlphaMin => 13, RedMax => 14, GreenMax => 15, BlueMax => 16, AlphaMax => 17, ); our %rat_table_type = ( THEMATIC => 0, ATHEMATIC => 1 ); our %resampling = ( NearestNeighbour => 0, Bilinear => 1, Cubic => 2, CubicSpline => 3, ORA_Lanczos => 4, Average => 5, Mode => 6, Gauss => 7 ); sub ResamplingMethods { return sort {$resampling{$a} <=> $resampling{$b}} keys %resampling; } our %data_type2pdl_data_type = ( Byte => $PDL::Types::PDL_B, Int16 => $PDL::Types::PDL_S, UInt16 => $PDL::Types::PDL_US, Int32 => $PDL::Types::PDL_L, Float32 => $PDL::Types::PDL_F, Float64 => $PDL::Types::PDL_D, ); our %pdl_data_type2data_type = reverse %data_type2pdl_data_type; our %field_types = ( Integer => 0, IntegerList => 1, Real => 2, RealList => 3, String => 4, StringList => 5, #WideString => 6, # do not use #WideStringList => 7, # do not use Binary => 8, Date => 9, Time => 10, DateTime => 11, Integer64 => 12, Integer64List => 13, ); our %field_types_reverse = reverse %field_types; sub FieldTypes { return sort {$field_types{$a} <=> $field_types{$b}} keys %field_types; } our %field_subtypes = ( None => 0, Boolean => 1, Int16 => 2, Float32 => 3 ); our %field_subtypes_reverse = reverse %field_subtypes; sub FieldSubtypes { return sort {$field_subtypes{$a} <=> $field_subtypes{$b}} keys %field_subtypes; } our %justification = ( Undefined => 0, Left => 1, Right => 2 ); our %justification_reverse = reverse %justification; sub Justifications { return sort {$justification{$a} <=> $justification{$b}} keys %justification; } our %color_interpretations = ( Undefined => 0, GrayIndex => 1, PaletteIndex => 2, RedBand => 3, GreenBand => 4, BlueBand => 5, AlphaBand => 6, HueBand => 7, SaturationBand => 8, LightnessBand => 9, CyanBand => 10, MagentaBand => 11, YellowBand => 12, BlackBand => 13, YCbCr_YBand => 14, YCbCr_CbBand => 15, YCbCr_CrBand => 16, ); our %color_interpretations_reverse = reverse %color_interpretations; sub ColorInterpretations { return sort {$color_interpretations{$a} <=> $color_interpretations{$b}} keys %color_interpretations; } our %geometry_types = ( Unknown => 0, Point => 1, LineString => 2, Polygon => 3, MultiPoint => 4, MultiLineString => 5, MultiPolygon => 6, GeometryCollection => 7, CircularString => 8, CompoundCurve => 9, CurvePolygon => 10, MultiCurve => 11, MultiSurface => 12, Curve => 13, Surface => 14, PolyhedralSurface => 15, TIN => 16, Triangle => 17, None => 100, LinearRing => 101, CircularStringZ => 1008, CompoundCurveZ => 1009, CurvePolygonZ => 1010, MultiCurveZ => 1011, MultiSurfaceZ => 1012, CurveZ => 1013, SurfaceZ => 1014, PolyhedralSurfaceZ => 1015, TINZ => 1016, TriangleZ => 1017, PointM => 2001, LineStringM => 2002, PolygonM => 2003, MultiPointM => 2004, MultiLineStringM => 2005, MultiPolygonM => 2006, GeometryCollectionM => 2007, CircularStringM => 2008, CompoundCurveM => 2009, CurvePolygonM => 2010, MultiCurveM => 2011, MultiSurfaceM => 2012, CurveM => 2013, SurfaceM => 2014, PolyhedralSurfaceM => 2015, TINM => 2016, TriangleM => 2017, PointZM => 3001, LineStringZM => 3002, PolygonZM => 3003, MultiPointZM => 3004, MultiLineStringZM => 3005, MultiPolygonZM => 3006, GeometryCollectionZM => 3007, CircularStringZM => 3008, CompoundCurveZM => 3009, CurvePolygonZM => 3010, MultiCurveZM => 3011, MultiSurfaceZM => 3012, CurveZM => 3013, SurfaceZM => 3014, PolyhedralSurfaceZM => 3015, TINZM => 3016, TriangleZM => 3017, Point25D => 0x80000001, LineString25D => 0x80000002, Polygon25D => 0x80000003, MultiPoint25D => 0x80000004, MultiLineString25D => 0x80000005, MultiPolygon25D => 0x80000006, GeometryCollection25D => 0x80000007 ); our %geometry_types_reverse = reverse %geometry_types; sub GeometryTypes { return sort {$geometry_types{$a} <=> $geometry_types{$b}} keys %geometry_types; } our %geometry_formats = ( WKT => 1, ); sub GeometryFormats { return sort {$geometry_formats{$a} <=> $geometry_formats{$b}} keys %geometry_formats; } our %grid_algorithms = ( InverseDistanceToAPower => 1, MovingAverage => 2, NearestNeighbor => 3, MetricMinimum => 4, MetricMaximum => 5, MetricRange => 6, MetricCount => 7, MetricAverageDistance => 8, MetricAverageDistancePts => 9, Linear => 10, InverseDistanceToAPowerNearestNeighbor => 11 ); sub GridAlgorithms { return sort {$grid_algorithms{$a} <=> $grid_algorithms{$b}} keys %grid_algorithms; } sub isint { my $value = shift; my $b_obj = B::svref_2object(\$value); my $flags = $b_obj->FLAGS; return 1 if $flags & B::SVp_IOK() && !($flags & B::SVp_NOK()) && !($flags & B::SVp_POK()); } sub new { my $class = shift; my $gdal = shift; return $instance if $instance; my $ffi = FFI::Platypus->new; my @libs = $gdal->dynamic_libs; $ffi->lib(@libs); $ffi->type('(pointer,size_t,size_t,opaque)->size_t' => 'VSIWriteFunction'); $ffi->type('(int,int,string)->void' => 'CPLErrorHandler'); $ffi->type('(double,string,pointer)->int' => 'GDALProgressFunc'); $ffi->type('(pointer,int, pointer,int,int,unsigned int,unsigned int,int,int)->int' => 'GDALDerivedPixelFunc'); $ffi->type('(pointer,int,int,pointer,pointer,pointer,pointer)->int' => 'GDALTransformerFunc'); $ffi->type('(double,int,pointer,pointer,pointer)->int' => 'GDALContourWriter'); $ffi->type('(string,string,sint64,sint64,pointer)->void' => 'GDALQueryLoggerFunc'); $ffi->type('(string,pointer,pointer,int,int,pointer,pointer,pointer,pointer,pointer,pointer)->int' => 'GDALVRTProcessedDatasetFuncInit'); $ffi->type('(string,pointer,pointer)->void' => 'GDALVRTProcessedDatasetFuncFree'); $ffi->type('(string,pointer,pointer,int,int,int,pointer,size_t,int,int,pointer,pointer,size_t,int,int,pointer,double,double,double,double,pointer,string,int)->int' => 'GDALVRTProcessedDatasetFuncProcess'); $ffi->ignore_not_found(1); # from port/*.h $ffi->attach(VSIMalloc => [qw/uint/] => 'opaque'); croak "Can't attach to GDAL methods. Problem with GDAL dynamic libs: '@libs'?" unless $class->can('VSIMalloc'); $ffi->attach(VSIFree => ['opaque'] => 'void'); $ffi->attach(CPLError => [qw/int int string/] => 'void'); $ffi->attach(VSIFOpenL => [qw/string string/] => 'opaque'); $ffi->attach(VSIFOpenExL => [qw/string string int/] => 'opaque'); $ffi->attach(VSIFCloseL => ['opaque'] => 'int'); $ffi->attach(VSIFWriteL => [qw/opaque uint uint opaque/] => 'uint'); $ffi->attach(VSIFReadL => [qw/opaque uint uint opaque/] => 'uint'); $ffi->attach(VSIIngestFile => [qw/opaque string string* uint64* sint64/] => 'int'); $ffi->attach(VSIMkdir => [qw/string sint64/] => 'int'); $ffi->attach(VSIRmdir => [qw/string/] => 'int'); $ffi->attach(VSIReadDirEx => [qw/string int/] => 'opaque'); $ffi->attach(VSIUnlink => [qw/string/] => 'int'); $ffi->attach(VSIRename => [qw/string string/] => 'int'); $ffi->attach(VSIStdoutSetRedirection => ['VSIWriteFunction', 'opaque'] => 'void'); $ffi->attach(CPLSetErrorHandler => ['CPLErrorHandler'] => 'opaque'); $ffi->attach(CPLPushErrorHandler => ['CPLErrorHandler'] => 'void'); $ffi->attach(CPLPopErrorHandler => ['CPLErrorHandler'] => 'void'); $ffi->attach(CSLDestroy => ['opaque'] => 'void'); $ffi->attach(CSLAddString => ['opaque', 'string'] => 'opaque'); $ffi->attach(CSLCount => ['opaque'] => 'int'); $ffi->attach(CSLGetField => ['opaque', 'int'] => 'string'); $ffi->attach(CPLGetConfigOption => ['string', 'string'] => 'string'); $ffi->attach(CPLSetConfigOption => ['string', 'string'] => 'void'); $ffi->attach(CPLFindFile => ['string', 'string'] => 'string'); $ffi->attach(CPLPushFinderLocation => ['string'] => 'void'); $ffi->attach(CPLPopFinderLocation => [] => 'void'); $ffi->attach(CPLFinderClean => [] => 'void'); # from ogr_core.h $ffi->attach( 'OGR_GT_Flatten' => ['unsigned int'] => 'unsigned int'); # generated with parse_h.pl # from gcore/gdal.h $ffi->attach('GDALGetDataTypeSize' => ['unsigned int'] => 'int'); $ffi->attach('GDALGetDataTypeSizeBits' => ['unsigned int'] => 'int'); $ffi->attach('GDALGetDataTypeSizeBytes' => ['unsigned int'] => 'int'); $ffi->attach('GDALDataTypeIsComplex' => ['unsigned int'] => 'int'); $ffi->attach('GDALDataTypeIsInteger' => ['unsigned int'] => 'int'); $ffi->attach('GDALDataTypeIsFloating' => ['unsigned int'] => 'int'); $ffi->attach('GDALDataTypeIsSigned' => ['unsigned int'] => 'int'); $ffi->attach('GDALGetDataTypeName' => ['unsigned int'] => 'string'); $ffi->attach('GDALGetDataTypeByName' => [qw/string/] => 'unsigned int'); $ffi->attach('GDALDataTypeUnion' => ['unsigned int','unsigned int'] => 'unsigned int'); $ffi->attach('GDALDataTypeUnionWithValue' => ['unsigned int','double','int'] => 'unsigned int'); $ffi->attach('GDALFindDataType' => [qw/int int int int/] => 'unsigned int'); $ffi->attach('GDALFindDataTypeForValue' => [qw/double int/] => 'unsigned int'); $ffi->attach('GDALAdjustValueToDataType' => ['unsigned int','double','int*','int*'] => 'double'); $ffi->attach('GDALGetNonComplexDataType' => ['unsigned int'] => 'unsigned int'); $ffi->attach('GDALDataTypeIsConversionLossy' => ['unsigned int','unsigned int'] => 'int'); $ffi->attach('GDALGetAsyncStatusTypeName' => ['unsigned int'] => 'string'); $ffi->attach('GDALGetAsyncStatusTypeByName' => [qw/string/] => 'unsigned int'); $ffi->attach('GDALGetColorInterpretationName' => ['unsigned int'] => 'string'); $ffi->attach('GDALGetColorInterpretationByName' => [qw/string/] => 'unsigned int'); $ffi->attach('GDALGetPaletteInterpretationName' => ['unsigned int'] => 'string'); $ffi->attach('GDALAllRegister' => [] => 'void'); $ffi->attach('GDALCreate' => ['opaque','string','int','int','int','unsigned int','opaque'] => 'opaque'); $ffi->attach('GDALCreateCopy' => [qw/opaque string opaque int opaque GDALProgressFunc opaque/] => 'opaque'); $ffi->attach('GDALIdentifyDriver' => [qw/string opaque/] => 'opaque'); $ffi->attach('GDALIdentifyDriverEx' => ['string','unsigned int','opaque','opaque'] => 'opaque'); $ffi->attach('GDALOpen' => ['string','unsigned int'] => 'opaque'); $ffi->attach('GDALOpenShared' => ['string','unsigned int'] => 'opaque'); $ffi->attach('GDALOpenEx' => ['string','unsigned int','opaque','opaque','opaque'] => 'opaque'); $ffi->attach('GDALDumpOpenDatasets' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetDriverByName' => [qw/string/] => 'opaque'); $ffi->attach('GDALGetDriverCount' => [] => 'int'); $ffi->attach('GDALGetDriver' => [qw/int/] => 'opaque'); $ffi->attach('GDALCreateDriver' => [] => 'opaque'); $ffi->attach('GDALDestroyDriver' => [qw/opaque/] => 'void'); $ffi->attach('GDALRegisterDriver' => [qw/opaque/] => 'int'); $ffi->attach('GDALDeregisterDriver' => [qw/opaque/] => 'void'); $ffi->attach('GDALDestroyDriverManager' => [] => 'void'); $ffi->attach('GDALDestroy' => [] => 'void'); $ffi->attach('GDALDeleteDataset' => [qw/opaque string/] => 'int'); $ffi->attach('GDALRenameDataset' => [qw/opaque string string/] => 'int'); $ffi->attach('GDALCopyDatasetFiles' => [qw/opaque string string/] => 'int'); $ffi->attach('GDALValidateCreationOptions' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALGetDriverShortName' => [qw/opaque/] => 'string'); $ffi->attach('GDALGetDriverLongName' => [qw/opaque/] => 'string'); $ffi->attach('GDALGetDriverHelpTopic' => [qw/opaque/] => 'string'); $ffi->attach('GDALGetDriverCreationOptionList' => [qw/opaque/] => 'string'); $ffi->attach('GDALInitGCPs' => [qw/int opaque/] => 'void'); $ffi->attach('GDALDeinitGCPs' => [qw/int opaque/] => 'void'); $ffi->attach('GDALDuplicateGCPs' => [qw/int opaque/] => 'opaque'); $ffi->attach('GDALGCPsToGeoTransform' => [qw/int opaque double* int/] => 'int'); $ffi->attach('GDALInvGeoTransform' => [qw/double[] double[]/] => 'int'); $ffi->attach('GDALApplyGeoTransform' => [qw/double[6] double double double* double*/] => 'void'); $ffi->attach('GDALComposeGeoTransforms' => [qw/double[6] double[6] double[6]/] => 'void'); $ffi->attach('GDALGetMetadataDomainList' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetMetadata' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALSetMetadata' => [qw/opaque opaque string/] => 'int'); $ffi->attach('GDALGetMetadataItem' => [qw/opaque string string/] => 'string'); $ffi->attach('GDALSetMetadataItem' => [qw/opaque string string string/] => 'int'); $ffi->attach('GDALGetDescription' => [qw/opaque/] => 'string'); $ffi->attach('GDALSetDescription' => [qw/opaque string/] => 'void'); $ffi->attach('GDALGetDatasetDriver' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetFileList' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALClose' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterXSize' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterYSize' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterBand' => [qw/opaque int/] => 'opaque'); $ffi->attach('GDALAddBand' => ['opaque','unsigned int','opaque'] => 'int'); $ffi->attach('GDALBeginAsyncReader' => ['opaque','int','int','int','int','opaque','int','int','unsigned int','int','int*','int','int','int','opaque'] => 'opaque'); $ffi->attach('GDALEndAsyncReader' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALDatasetRasterIO' => ['opaque','unsigned int','int','int','int','int','opaque','int','int','unsigned int','int','int*','int','int','int'] => 'int'); $ffi->attach('GDALDatasetRasterIOEx' => ['opaque','unsigned int','int','int','int','int','opaque','int','int','unsigned int','int','int*','sint64','sint64','sint64','opaque'] => 'int'); $ffi->attach('GDALDatasetAdviseRead' => ['opaque','int','int','int','int','int','int','unsigned int','int','int*','opaque'] => 'int'); $ffi->attach('GDALDatasetGetCompressionFormats' => [qw/opaque int int int int int int*/] => 'opaque'); $ffi->attach('GDALDatasetReadCompressedData' => [qw/opaque string int int int int int int* opaque size_t string*/] => 'int'); $ffi->attach('GDALGetProjectionRef' => [qw/opaque/] => 'string'); $ffi->attach('GDALGetSpatialRef' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALSetProjection' => [qw/opaque string/] => 'int'); $ffi->attach('GDALSetSpatialRef' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALGetGeoTransform' => [qw/opaque double[6]/] => 'int'); $ffi->attach('GDALSetGeoTransform' => [qw/opaque double[6]/] => 'int'); $ffi->attach('GDALGetGCPCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetGCPProjection' => [qw/opaque/] => 'string'); $ffi->attach('GDALGetGCPSpatialRef' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetGCPs' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALSetGCPs' => [qw/opaque int opaque string/] => 'int'); $ffi->attach('GDALSetGCPs2' => [qw/opaque int opaque opaque/] => 'int'); $ffi->attach('GDALGetInternalHandle' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALReferenceDataset' => [qw/opaque/] => 'int'); $ffi->attach('GDALDereferenceDataset' => [qw/opaque/] => 'int'); $ffi->attach('GDALReleaseDataset' => [qw/opaque/] => 'int'); $ffi->attach('GDALBuildOverviews' => [qw/opaque string int int* int int* GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALBuildOverviewsEx' => [qw/opaque string int int* int int* GDALProgressFunc opaque opaque/] => 'int'); $ffi->attach('GDALGetOpenDatasets' => [qw/uint64* int*/] => 'void'); $ffi->attach('GDALGetAccess' => [qw/opaque/] => 'int'); $ffi->attach('GDALFlushCache' => [qw/opaque/] => 'int'); $ffi->attach('GDALCreateDatasetMaskBand' => [qw/opaque int/] => 'int'); $ffi->attach('GDALDatasetCopyWholeRaster' => [qw/opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALRasterBandCopyWholeRaster' => [qw/opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALRegenerateOverviews' => [qw/opaque int uint64* string GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALRegenerateOverviewsEx' => [qw/opaque int uint64* string GDALProgressFunc opaque opaque/] => 'int'); $ffi->attach('GDALDatasetGetLayerCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALDatasetGetLayer' => [qw/opaque int/] => 'opaque'); $ffi->attach('GDALDatasetGetLayerByName' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALDatasetIsLayerPrivate' => [qw/opaque int/] => 'int'); $ffi->attach('GDALDatasetDeleteLayer' => [qw/opaque int/] => 'int'); $ffi->attach('GDALDatasetCreateLayer' => ['opaque','string','opaque','unsigned int','opaque'] => 'opaque'); $ffi->attach('GDALDatasetCopyLayer' => [qw/opaque opaque string opaque/] => 'opaque'); $ffi->attach('GDALDatasetResetReading' => [qw/opaque/] => 'void'); $ffi->attach('GDALDatasetGetNextFeature' => [qw/opaque uint64* double* GDALProgressFunc opaque/] => 'opaque'); $ffi->attach('GDALDatasetTestCapability' => [qw/opaque string/] => 'int'); $ffi->attach('GDALDatasetExecuteSQL' => [qw/opaque string opaque string/] => 'opaque'); $ffi->attach('GDALDatasetAbortSQL' => [qw/opaque/] => 'int'); $ffi->attach('GDALDatasetReleaseResultSet' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALDatasetGetStyleTable' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALDatasetSetStyleTableDirectly' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALDatasetSetStyleTable' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALDatasetStartTransaction' => [qw/opaque int/] => 'int'); $ffi->attach('GDALDatasetCommitTransaction' => [qw/opaque/] => 'int'); $ffi->attach('GDALDatasetRollbackTransaction' => [qw/opaque/] => 'int'); $ffi->attach('GDALDatasetClearStatistics' => [qw/opaque/] => 'void'); $ffi->attach('GDALDatasetGetFieldDomainNames' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALDatasetGetFieldDomain' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALDatasetAddFieldDomain' => [qw/opaque opaque string*/] => 'bool'); $ffi->attach('GDALDatasetDeleteFieldDomain' => [qw/opaque string string*/] => 'bool'); $ffi->attach('GDALDatasetUpdateFieldDomain' => [qw/opaque opaque string*/] => 'bool'); $ffi->attach('GDALDatasetGetRelationshipNames' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALDatasetGetRelationship' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALDatasetAddRelationship' => [qw/opaque opaque string*/] => 'bool'); $ffi->attach('GDALDatasetDeleteRelationship' => [qw/opaque string string*/] => 'bool'); $ffi->attach('GDALDatasetUpdateRelationship' => [qw/opaque opaque string*/] => 'bool'); $ffi->attach('GDALDatasetSetQueryLoggerFunc' => [qw/opaque GDALQueryLoggerFunc opaque/] => 'bool'); $ffi->attach('GDALGetRasterDataType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALGetBlockSize' => [qw/opaque int* int*/] => 'void'); $ffi->attach('GDALGetActualBlockSize' => [qw/opaque int int int* int*/] => 'int'); $ffi->attach('GDALRasterAdviseRead' => ['opaque','int','int','int','int','int','int','unsigned int','opaque'] => 'int'); $ffi->attach('GDALRasterIO' => ['opaque','unsigned int','int','int','int','int','opaque','int','int','unsigned int','int','int'] => 'int'); $ffi->attach('GDALRasterIOEx' => ['opaque','unsigned int','int','int','int','int','opaque','int','int','unsigned int','sint64','sint64','opaque'] => 'int'); $ffi->attach('GDALReadBlock' => [qw/opaque int int opaque/] => 'int'); $ffi->attach('GDALWriteBlock' => [qw/opaque int int opaque/] => 'int'); $ffi->attach('GDALGetRasterBandXSize' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterBandYSize' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterAccess' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALGetBandNumber' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetBandDataset' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetRasterColorInterpretation' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALSetRasterColorInterpretation' => ['opaque','unsigned int'] => 'int'); $ffi->attach('GDALGetRasterColorTable' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALSetRasterColorTable' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALHasArbitraryOverviews' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetOverviewCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetOverview' => [qw/opaque int/] => 'opaque'); $ffi->attach('GDALGetRasterNoDataValue' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALGetRasterNoDataValueAsInt64' => [qw/opaque int*/] => 'int'); $ffi->attach('GDALGetRasterNoDataValueAsUInt64' => [qw/opaque int*/] => 'uint64'); $ffi->attach('GDALSetRasterNoDataValue' => [qw/opaque double/] => 'int'); $ffi->attach('GDALSetRasterNoDataValueAsInt64' => [qw/opaque int/] => 'int'); $ffi->attach('GDALSetRasterNoDataValueAsUInt64' => [qw/opaque uint64/] => 'int'); $ffi->attach('GDALDeleteRasterNoDataValue' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterCategoryNames' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALSetRasterCategoryNames' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALGetRasterMinimum' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALGetRasterMaximum' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALGetRasterStatistics' => [qw/opaque int int double* double* double* double*/] => 'int'); $ffi->attach('GDALComputeRasterStatistics' => [qw/opaque int double* double* double* double* GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALSetRasterStatistics' => [qw/opaque double double double double/] => 'int'); $ffi->attach('GDALRasterBandAsMDArray' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetRasterUnitType' => [qw/opaque/] => 'string'); $ffi->attach('GDALSetRasterUnitType' => [qw/opaque string/] => 'int'); $ffi->attach('GDALGetRasterOffset' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALSetRasterOffset' => [qw/opaque double/] => 'int'); $ffi->attach('GDALGetRasterScale' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALSetRasterScale' => [qw/opaque double/] => 'int'); $ffi->attach('GDALComputeRasterMinMax' => [qw/opaque int double/] => 'int'); $ffi->attach('GDALFlushRasterCache' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetRasterHistogram' => [qw/opaque double double int int* int int GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALGetRasterHistogramEx' => [qw/opaque double double int uint64* int int GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALGetDefaultHistogram' => [qw/opaque double* double* int* int* int GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALGetDefaultHistogramEx' => [qw/opaque double* double* int* uint64* int GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALSetDefaultHistogram' => [qw/opaque double double int int*/] => 'int'); $ffi->attach('GDALSetDefaultHistogramEx' => [qw/opaque double double int uint64*/] => 'int'); $ffi->attach('GDALGetRandomRasterSample' => [qw/opaque int float*/] => 'int'); $ffi->attach('GDALGetRasterSampleOverview' => [qw/opaque int/] => 'opaque'); $ffi->attach('GDALGetRasterSampleOverviewEx' => [qw/opaque uint64/] => 'opaque'); $ffi->attach('GDALFillRaster' => [qw/opaque double double/] => 'int'); $ffi->attach('GDALComputeBandStats' => [qw/opaque int double* double* GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALOverviewMagnitudeCorrection' => [qw/opaque int uint64* GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALGetDefaultRAT' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALSetDefaultRAT' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALAddDerivedBandPixelFunc' => [qw/string GDALDerivedPixelFunc/] => 'int'); $ffi->attach('GDALAddDerivedBandPixelFuncWithArgs' => [qw/string GDALDerivedPixelFunc string/] => 'int'); $ffi->attach('GDALGetMaskBand' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetMaskFlags' => [qw/opaque/] => 'int'); $ffi->attach('GDALCreateMaskBand' => [qw/opaque int/] => 'int'); $ffi->attach('GDALIsMaskBand' => [qw/opaque/] => 'bool'); $ffi->attach('GDALGetDataCoverageStatus' => [qw/opaque int int int int int double*/] => 'int'); $ffi->attach('GDALARGetNextUpdatedRegion' => [qw/opaque double int* int* int* int*/] => 'unsigned int'); $ffi->attach('GDALARLockBuffer' => [qw/opaque double/] => 'int'); $ffi->attach('GDALARUnlockBuffer' => [qw/opaque/] => 'void'); $ffi->attach('GDALGeneralCmdLineProcessor' => [qw/int string* int/] => 'int'); $ffi->attach('GDALSwapWords' => [qw/opaque int int int/] => 'void'); $ffi->attach('GDALSwapWordsEx' => [qw/opaque int size_t int/] => 'void'); $ffi->attach('GDALCopyWords' => ['opaque','unsigned int','int','opaque','unsigned int','int','int'] => 'void'); $ffi->attach('GDALCopyWords64' => ['opaque','unsigned int','int','opaque','unsigned int','int','int'] => 'void'); $ffi->attach('GDALCopyBits' => [qw/pointer int int pointer int int int int/] => 'void'); $ffi->attach('GDALDeinterleave' => ['opaque','unsigned int','int','opaque','unsigned int','size_t'] => 'void'); $ffi->attach('GDALLoadWorldFile' => [qw/string double*/] => 'int'); $ffi->attach('GDALReadWorldFile' => [qw/string string double*/] => 'int'); $ffi->attach('GDALWriteWorldFile' => [qw/string string double*/] => 'int'); $ffi->attach('GDALLoadTabFile' => [qw/string double* string* int* opaque/] => 'int'); $ffi->attach('GDALReadTabFile' => [qw/string double* string* int* opaque/] => 'int'); $ffi->attach('GDALLoadOziMapFile' => [qw/string double* string* int* opaque/] => 'int'); $ffi->attach('GDALReadOziMapFile' => [qw/string double* string* int* opaque/] => 'int'); $ffi->attach('GDALDecToDMS' => [qw/double string int/] => 'string'); $ffi->attach('GDALPackedDMSToDec' => [qw/double/] => 'double'); $ffi->attach('GDALDecToPackedDMS' => [qw/double/] => 'double'); $ffi->attach('GDALVersionInfo' => [qw/string/] => 'string'); $ffi->attach('GDALCheckVersion' => [qw/int int string/] => 'int'); $ffi->attach('GDALExtractRPCInfoV1' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALExtractRPCInfoV2' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALCreateColorTable' => ['unsigned int'] => 'opaque'); $ffi->attach('GDALDestroyColorTable' => [qw/opaque/] => 'void'); $ffi->attach('GDALCloneColorTable' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGetPaletteInterpretation' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALGetColorEntryCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALGetColorEntry' => [qw/opaque int/] => 'short[4]'); $ffi->attach('GDALGetColorEntryAsRGB' => [qw/opaque int short[4]/] => 'int'); $ffi->attach('GDALSetColorEntry' => [qw/opaque int short[4]/] => 'void'); $ffi->attach('GDALCreateColorRamp' => [qw/opaque int short[4] int short[4]/] => 'void'); $ffi->attach('GDALCreateRasterAttributeTable' => [] => 'opaque'); $ffi->attach('GDALDestroyRasterAttributeTable' => [qw/opaque/] => 'void'); $ffi->attach('GDALRATGetColumnCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALRATGetNameOfCol' => [qw/opaque int/] => 'string'); $ffi->attach('GDALRATGetUsageOfCol' => [qw/opaque int/] => 'unsigned int'); $ffi->attach('GDALRATGetTypeOfCol' => [qw/opaque int/] => 'unsigned int'); $ffi->attach('GDALRATGetColOfUsage' => ['opaque','unsigned int'] => 'int'); $ffi->attach('GDALRATGetRowCount' => [qw/opaque/] => 'int'); $ffi->attach('GDALRATGetValueAsString' => [qw/opaque int int/] => 'string'); $ffi->attach('GDALRATGetValueAsInt' => [qw/opaque int int/] => 'int'); $ffi->attach('GDALRATGetValueAsDouble' => [qw/opaque int int/] => 'double'); $ffi->attach('GDALRATSetValueAsString' => [qw/opaque int int string/] => 'void'); $ffi->attach('GDALRATSetValueAsInt' => [qw/opaque int int int/] => 'void'); $ffi->attach('GDALRATSetValueAsDouble' => [qw/opaque int int double/] => 'void'); $ffi->attach('GDALRATChangesAreWrittenToFile' => [qw/opaque/] => 'int'); $ffi->attach('GDALRATValuesIOAsDouble' => ['opaque','unsigned int','int','int','int','double*'] => 'int'); $ffi->attach('GDALRATValuesIOAsInteger' => ['opaque','unsigned int','int','int','int','int*'] => 'int'); $ffi->attach('GDALRATValuesIOAsString' => ['opaque','unsigned int','int','int','int','opaque'] => 'int'); $ffi->attach('GDALRATSetRowCount' => [qw/opaque int/] => 'void'); $ffi->attach('GDALRATCreateColumn' => ['opaque','string','unsigned int','unsigned int'] => 'int'); $ffi->attach('GDALRATSetLinearBinning' => [qw/opaque double double/] => 'int'); $ffi->attach('GDALRATGetLinearBinning' => [qw/opaque double* double*/] => 'int'); $ffi->attach('GDALRATSetTableType' => ['opaque','unsigned int'] => 'int'); $ffi->attach('GDALRATGetTableType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALRATInitializeFromColorTable' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALRATTranslateToColorTable' => [qw/opaque int/] => 'opaque'); $ffi->attach('GDALRATDumpReadable' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALRATClone' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALRATSerializeJSON' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALRATGetRowOfValue' => [qw/opaque double/] => 'int'); $ffi->attach('GDALRATRemoveStatistics' => [qw/opaque/] => 'void'); $ffi->attach('GDALRelationshipCreate' => ['string','string','string','unsigned int'] => 'opaque'); $ffi->attach('GDALDestroyRelationship' => [qw/opaque/] => 'void'); $ffi->attach('GDALRelationshipGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipGetCardinality' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALRelationshipGetLeftTableName' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipGetRightTableName' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipGetMappingTableName' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipSetMappingTableName' => [qw/opaque string/] => 'void'); $ffi->attach('GDALRelationshipGetLeftTableFields' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALRelationshipGetRightTableFields' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALRelationshipSetLeftTableFields' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALRelationshipSetRightTableFields' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALRelationshipGetLeftMappingTableFields' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALRelationshipGetRightMappingTableFields' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALRelationshipSetLeftMappingTableFields' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALRelationshipSetRightMappingTableFields' => [qw/opaque opaque/] => 'void'); $ffi->attach('GDALRelationshipGetType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALRelationshipSetType' => ['opaque','unsigned int'] => 'void'); $ffi->attach('GDALRelationshipGetForwardPathLabel' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipSetForwardPathLabel' => [qw/opaque string/] => 'void'); $ffi->attach('GDALRelationshipGetBackwardPathLabel' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipSetBackwardPathLabel' => [qw/opaque string/] => 'void'); $ffi->attach('GDALRelationshipGetRelatedTableType' => [qw/opaque/] => 'string'); $ffi->attach('GDALRelationshipSetRelatedTableType' => [qw/opaque string/] => 'void'); $ffi->attach('GDALSetCacheMax' => [qw/int/] => 'void'); $ffi->attach('GDALGetCacheMax' => [] => 'int'); $ffi->attach('GDALGetCacheUsed' => [] => 'int'); $ffi->attach('GDALSetCacheMax64' => [qw/sint64/] => 'void'); $ffi->attach('GDALGetCacheMax64' => [] => 'sint64'); $ffi->attach('GDALGetCacheUsed64' => [] => 'sint64'); $ffi->attach('GDALFlushCacheBlock' => [] => 'int'); $ffi->attach('GDALDatasetGetVirtualMem' => ['opaque','unsigned int','int','int','int','int','int','int','unsigned int','int','int*','int','sint64','sint64','size_t','size_t','int','opaque'] => 'opaque'); $ffi->attach('GDALRasterBandGetVirtualMem' => ['opaque','unsigned int','int','int','int','int','int','int','unsigned int','int','sint64','size_t','size_t','int','opaque'] => 'opaque'); $ffi->attach('GDALGetVirtualMemAuto' => ['opaque','unsigned int','int*','sint64*','opaque'] => 'opaque'); $ffi->attach('GDALDatasetGetTiledVirtualMem' => ['opaque','unsigned int','int','int','int','int','int','int','unsigned int','int','int*','unsigned int','size_t','int','opaque'] => 'opaque'); $ffi->attach('GDALRasterBandGetTiledVirtualMem' => ['opaque','unsigned int','int','int','int','int','int','int','unsigned int','size_t','int','opaque'] => 'opaque'); $ffi->attach('GDALCreatePansharpenedVRT' => [qw/string opaque int uint64*/] => 'opaque'); $ffi->attach('GDALGetJPEG2000Structure' => [qw/string opaque/] => 'opaque'); $ffi->attach('GDALCreateMultiDimensional' => [qw/opaque string opaque opaque/] => 'opaque'); $ffi->attach('GDALExtendedDataTypeCreate' => ['unsigned int'] => 'opaque'); $ffi->attach('GDALExtendedDataTypeCreateString' => [qw/size_t/] => 'opaque'); $ffi->attach('GDALExtendedDataTypeCreateStringEx' => [qw/size_t int/] => 'opaque'); $ffi->attach('GDALExtendedDataTypeCreateCompound' => [qw/string size_t size_t opaque/] => 'opaque'); $ffi->attach('GDALExtendedDataTypeRelease' => [qw/opaque/] => 'void'); $ffi->attach('GDALExtendedDataTypeGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALExtendedDataTypeGetClass' => [qw/opaque/] => 'int'); $ffi->attach('GDALExtendedDataTypeGetNumericDataType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('GDALExtendedDataTypeGetSize' => [qw/opaque/] => 'size_t'); $ffi->attach('GDALExtendedDataTypeGetMaxStringLength' => [qw/opaque/] => 'size_t'); $ffi->attach('GDALExtendedDataTypeGetComponents' => [qw/opaque size_t/] => 'uint64*'); $ffi->attach('GDALExtendedDataTypeFreeComponents' => [qw/uint64* size_t/] => 'void'); $ffi->attach('GDALExtendedDataTypeCanConvertTo' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALExtendedDataTypeEquals' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALExtendedDataTypeGetSubType' => [qw/opaque/] => 'int'); $ffi->attach('GDALEDTComponentCreate' => [qw/string size_t opaque/] => 'opaque'); $ffi->attach('GDALEDTComponentRelease' => [qw/opaque/] => 'void'); $ffi->attach('GDALEDTComponentGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALEDTComponentGetOffset' => [qw/opaque/] => 'size_t'); $ffi->attach('GDALEDTComponentGetType' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALDatasetGetRootGroup' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGroupRelease' => [qw/opaque/] => 'void'); $ffi->attach('GDALGroupGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALGroupGetFullName' => [qw/opaque/] => 'string'); $ffi->attach('GDALGroupGetMDArrayNames' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALGroupOpenMDArray' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('GDALGroupOpenMDArrayFromFullname' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('GDALGroupResolveMDArray' => [qw/opaque string string opaque/] => 'opaque'); $ffi->attach('GDALGroupGetGroupNames' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALGroupOpenGroup' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('GDALGroupOpenGroupFromFullname' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('GDALGroupGetVectorLayerNames' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALGroupOpenVectorLayer' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('GDALGroupGetDimensions' => [qw/opaque size_t opaque/] => 'uint64*'); $ffi->attach('GDALGroupGetAttribute' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALGroupGetAttributes' => [qw/opaque size_t opaque/] => 'uint64*'); $ffi->attach('GDALGroupGetStructuralInfo' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALGroupCreateGroup' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('GDALGroupCreateDimension' => [qw/opaque string string string uint64 opaque/] => 'opaque'); $ffi->attach('GDALGroupCreateMDArray' => [qw/opaque string size_t uint64* opaque opaque/] => 'opaque'); $ffi->attach('GDALGroupCreateAttribute' => [qw/opaque string size_t uint64* opaque opaque/] => 'opaque'); $ffi->attach('GDALMDArrayRelease' => [qw/opaque/] => 'void'); $ffi->attach('GDALMDArrayGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALMDArrayGetFullName' => [qw/opaque/] => 'string'); $ffi->attach('GDALMDArrayGetTotalElementsCount' => [qw/opaque/] => 'uint64'); $ffi->attach('GDALMDArrayGetDimensionCount' => [qw/opaque/] => 'size_t'); $ffi->attach('GDALMDArrayGetDimensions' => [qw/opaque size_t/] => 'uint64*'); $ffi->attach('GDALMDArrayGetDataType' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALMDArrayRead' => [qw/opaque uint64* size_t sint64 int* opaque opaque opaque size_t/] => 'int'); $ffi->attach('GDALMDArrayWrite' => [qw/opaque uint64* size_t sint64 int* opaque opaque opaque size_t/] => 'int'); $ffi->attach('GDALMDArrayAdviseRead' => [qw/opaque uint64* size_t/] => 'int'); $ffi->attach('GDALMDArrayAdviseReadEx' => [qw/opaque uint64* size_t opaque/] => 'int'); $ffi->attach('GDALMDArrayGetAttribute' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALMDArrayGetAttributes' => [qw/opaque size_t opaque/] => 'uint64*'); $ffi->attach('GDALMDArrayCreateAttribute' => [qw/opaque string size_t uint64* opaque opaque/] => 'opaque'); $ffi->attach('GDALMDArrayResize' => [qw/opaque uint64* opaque/] => 'bool'); $ffi->attach('GDALMDArrayGetRawNoDataValue' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALMDArrayGetNoDataValueAsDouble' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALMDArrayGetNoDataValueAsInt64' => [qw/opaque int*/] => 'int'); $ffi->attach('GDALMDArrayGetNoDataValueAsUInt64' => [qw/opaque int*/] => 'uint64'); $ffi->attach('GDALMDArraySetRawNoDataValue' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALMDArraySetNoDataValueAsDouble' => [qw/opaque double/] => 'int'); $ffi->attach('GDALMDArraySetNoDataValueAsInt64' => [qw/opaque int/] => 'int'); $ffi->attach('GDALMDArraySetNoDataValueAsUInt64' => [qw/opaque uint64/] => 'int'); $ffi->attach('GDALMDArraySetScale' => [qw/opaque double/] => 'int'); $ffi->attach('GDALMDArraySetScaleEx' => ['opaque','double','unsigned int'] => 'int'); $ffi->attach('GDALMDArrayGetScale' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALMDArrayGetScaleEx' => ['opaque','int*','unsigned int'] => 'double'); $ffi->attach('GDALMDArraySetOffset' => [qw/opaque double/] => 'int'); $ffi->attach('GDALMDArraySetOffsetEx' => ['opaque','double','unsigned int'] => 'int'); $ffi->attach('GDALMDArrayGetOffset' => [qw/opaque int*/] => 'double'); $ffi->attach('GDALMDArrayGetOffsetEx' => ['opaque','int*','unsigned int'] => 'double'); $ffi->attach('GDALMDArrayGetBlockSize' => [qw/opaque size_t/] => 'uint64'); $ffi->attach('GDALMDArraySetUnit' => [qw/opaque string/] => 'int'); $ffi->attach('GDALMDArrayGetUnit' => [qw/opaque/] => 'string'); $ffi->attach('GDALMDArraySetSpatialRef' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALMDArrayGetSpatialRef' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALMDArrayGetProcessingChunkSize' => [qw/opaque size_t size_t/] => 'size_t'); $ffi->attach('GDALMDArrayGetStructuralInfo' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALMDArrayGetView' => [qw/opaque string/] => 'opaque'); $ffi->attach('GDALMDArrayTranspose' => [qw/opaque size_t int*/] => 'opaque'); $ffi->attach('GDALMDArrayGetUnscaled' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALMDArrayGetMask' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALMDArrayAsClassicDataset' => [qw/opaque size_t size_t/] => 'opaque'); $ffi->attach('GDALMDArrayGetStatistics' => [qw/opaque opaque int int double* double* double* double* uint64 GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALMDArrayComputeStatistics' => [qw/opaque opaque int double* double* double* double* uint64 GDALProgressFunc opaque/] => 'int'); $ffi->attach('GDALMDArrayGetResampled' => [qw/opaque size_t opaque int opaque opaque/] => 'opaque'); $ffi->attach('GDALMDArrayGetGridded' => [qw/opaque string opaque opaque opaque/] => 'opaque'); $ffi->attach('GDALMDArrayGetCoordinateVariables' => [qw/opaque size_t/] => 'uint64*'); $ffi->attach('GDALReleaseArrays' => [qw/uint64* size_t/] => 'void'); $ffi->attach('GDALMDArrayCache' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALAttributeRelease' => [qw/opaque/] => 'void'); $ffi->attach('GDALReleaseAttributes' => [qw/uint64* size_t/] => 'void'); $ffi->attach('GDALAttributeGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALAttributeGetFullName' => [qw/opaque/] => 'string'); $ffi->attach('GDALAttributeGetTotalElementsCount' => [qw/opaque/] => 'uint64'); $ffi->attach('GDALAttributeGetDimensionCount' => [qw/opaque/] => 'size_t'); $ffi->attach('GDALAttributeGetDimensionsSize' => [qw/opaque size_t/] => 'uint64'); $ffi->attach('GDALAttributeGetDataType' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALAttributeReadAsRaw' => [qw/opaque size_t/] => 'pointer'); $ffi->attach('GDALAttributeFreeRawResult' => [qw/opaque pointer size_t/] => 'void'); $ffi->attach('GDALAttributeReadAsString' => [qw/opaque/] => 'string'); $ffi->attach('GDALAttributeReadAsInt' => [qw/opaque/] => 'int'); $ffi->attach('GDALAttributeReadAsDouble' => [qw/opaque/] => 'double'); $ffi->attach('GDALAttributeReadAsStringArray' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALAttributeReadAsIntArray' => [qw/opaque size_t/] => 'int*'); $ffi->attach('GDALAttributeReadAsDoubleArray' => [qw/opaque size_t/] => 'double*'); $ffi->attach('GDALAttributeWriteRaw' => [qw/opaque opaque size_t/] => 'int'); $ffi->attach('GDALAttributeWriteString' => [qw/opaque string/] => 'int'); $ffi->attach('GDALAttributeWriteStringArray' => [qw/opaque opaque/] => 'int'); $ffi->attach('GDALAttributeWriteInt' => [qw/opaque int/] => 'int'); $ffi->attach('GDALAttributeWriteDouble' => [qw/opaque double/] => 'int'); $ffi->attach('GDALAttributeWriteDoubleArray' => [qw/opaque double* size_t/] => 'int'); $ffi->attach('GDALDimensionRelease' => [qw/opaque/] => 'void'); $ffi->attach('GDALReleaseDimensions' => [qw/uint64* size_t/] => 'void'); $ffi->attach('GDALDimensionGetName' => [qw/opaque/] => 'string'); $ffi->attach('GDALDimensionGetFullName' => [qw/opaque/] => 'string'); $ffi->attach('GDALDimensionGetType' => [qw/opaque/] => 'string'); $ffi->attach('GDALDimensionGetDirection' => [qw/opaque/] => 'string'); $ffi->attach('GDALDimensionGetSize' => [qw/opaque/] => 'uint64'); $ffi->attach('GDALDimensionGetIndexingVariable' => [qw/opaque/] => 'opaque'); $ffi->attach('GDALDimensionSetIndexingVariable' => [qw/opaque opaque/] => 'int'); # from ogr/ogr_api.h $ffi->attach('OGRGetGEOSVersion' => [qw/int* int* int*/] => 'bool'); $ffi->attach('OGR_G_CreateFromWkb' => [qw/string opaque uint64* int/] => 'int'); $ffi->attach('OGR_G_CreateFromWkbEx' => [qw/opaque opaque uint64* size_t/] => 'int'); $ffi->attach('OGR_G_CreateFromWkt' => [qw/string* opaque uint64*/] => 'int'); $ffi->attach('OGR_G_CreateFromFgf' => [qw/string opaque uint64* int int*/] => 'int'); $ffi->attach('OGR_G_DestroyGeometry' => [qw/opaque/] => 'void'); $ffi->attach('OGR_G_CreateGeometry' => ['unsigned int'] => 'opaque'); $ffi->attach('OGR_G_ApproximateArcAngles' => [qw/double double double double double double double double double/] => 'opaque'); $ffi->attach('OGR_G_ForceToPolygon' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ForceToLineString' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ForceToMultiPolygon' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ForceToMultiPoint' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ForceToMultiLineString' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ForceTo' => ['opaque','unsigned int','opaque'] => 'opaque'); $ffi->attach('OGR_G_RemoveLowerDimensionSubGeoms' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_GetDimension' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_GetCoordinateDimension' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_CoordinateDimension' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_SetCoordinateDimension' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_G_Is3D' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_IsMeasured' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_Set3D' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_G_SetMeasured' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_G_Clone' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_GetEnvelope' => [qw/opaque double[4]/] => 'void'); $ffi->attach('OGR_G_GetEnvelope3D' => [qw/opaque double[6]/] => 'void'); $ffi->attach('OGR_G_ImportFromWkb' => [qw/opaque string int/] => 'int'); $ffi->attach('OGR_G_ExportToWkb' => ['opaque','unsigned int','string'] => 'int'); $ffi->attach('OGR_G_ExportToIsoWkb' => ['opaque','unsigned int','string'] => 'int'); $ffi->attach('OGR_G_WkbSize' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_WkbSizeEx' => [qw/opaque/] => 'size_t'); $ffi->attach('OGR_G_ImportFromWkt' => [qw/opaque string*/] => 'int'); $ffi->attach('OGR_G_ExportToWkt' => [qw/opaque string*/] => 'int'); $ffi->attach('OGR_G_ExportToIsoWkt' => [qw/opaque string*/] => 'int'); $ffi->attach('OGR_G_GetGeometryType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_G_GetGeometryName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_G_DumpReadable' => [qw/opaque opaque string/] => 'void'); $ffi->attach('OGR_G_FlattenTo2D' => [qw/opaque/] => 'void'); $ffi->attach('OGR_G_CloseRings' => [qw/opaque/] => 'void'); $ffi->attach('OGR_G_CreateFromGML' => [qw/string/] => 'opaque'); $ffi->attach('OGR_G_ExportToGML' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ExportToGMLEx' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_CreateFromGMLTree' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ExportToGMLTree' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ExportEnvelopeToGMLTree' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ExportToKML' => [qw/opaque string/] => 'opaque'); $ffi->attach('OGR_G_ExportToJson' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ExportToJsonEx' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_CreateGeometryFromJson' => [qw/string/] => 'opaque'); $ffi->attach('OGR_G_CreateGeometryFromEsriJson' => [qw/string/] => 'opaque'); $ffi->attach('OGR_G_AssignSpatialReference' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_G_GetSpatialReference' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_Transform' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_TransformTo' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_GeomTransformer_Create' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_GeomTransformer_Transform' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_GeomTransformer_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_G_Simplify' => [qw/opaque double/] => 'opaque'); $ffi->attach('OGR_G_SimplifyPreserveTopology' => [qw/opaque double/] => 'opaque'); $ffi->attach('OGR_G_DelaunayTriangulation' => [qw/opaque double int/] => 'opaque'); $ffi->attach('OGR_G_Segmentize' => [qw/opaque double/] => 'void'); $ffi->attach('OGR_G_Intersects' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Equals' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Disjoint' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Touches' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Crosses' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Within' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Contains' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Overlaps' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Boundary' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ConvexHull' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_ConcaveHull' => [qw/opaque double bool/] => 'opaque'); $ffi->attach('OGR_G_Buffer' => [qw/opaque double int/] => 'opaque'); $ffi->attach('OGR_G_Intersection' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_Union' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_UnionCascaded' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_UnaryUnion' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_PointOnSurface' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_Difference' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_SymDifference' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_Distance' => [qw/opaque opaque/] => 'double'); $ffi->attach('OGR_G_Distance3D' => [qw/opaque opaque/] => 'double'); $ffi->attach('OGR_G_Length' => [qw/opaque/] => 'double'); $ffi->attach('OGR_G_Area' => [qw/opaque/] => 'double'); $ffi->attach('OGR_G_Centroid' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Value' => [qw/opaque double/] => 'opaque'); $ffi->attach('OGR_G_Empty' => [qw/opaque/] => 'void'); $ffi->attach('OGR_G_IsEmpty' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_IsValid' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_MakeValid' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_MakeValidEx' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_Normalize' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_IsSimple' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_IsRing' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_Polygonize' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_Intersect' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_Equal' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_SymmetricDifference' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGR_G_GetArea' => [qw/opaque/] => 'double'); $ffi->attach('OGR_G_GetBoundary' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_G_GetPointCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_GetPoints' => [qw/opaque opaque int opaque int opaque int/] => 'int'); $ffi->attach('OGR_G_GetPointsZM' => [qw/opaque opaque int opaque int opaque int opaque int/] => 'int'); $ffi->attach('OGR_G_GetX' => [qw/opaque int/] => 'double'); $ffi->attach('OGR_G_GetY' => [qw/opaque int/] => 'double'); $ffi->attach('OGR_G_GetZ' => [qw/opaque int/] => 'double'); $ffi->attach('OGR_G_GetM' => [qw/opaque int/] => 'double'); $ffi->attach('OGR_G_GetPoint' => [qw/opaque int double* double* double*/] => 'void'); $ffi->attach('OGR_G_GetPointZM' => [qw/opaque int double* double* double* double*/] => 'void'); $ffi->attach('OGR_G_SetPointCount' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_G_SetPoint' => [qw/opaque int double double double/] => 'void'); $ffi->attach('OGR_G_SetPoint_2D' => [qw/opaque int double double/] => 'void'); $ffi->attach('OGR_G_SetPointM' => [qw/opaque int double double double/] => 'void'); $ffi->attach('OGR_G_SetPointZM' => [qw/opaque int double double double double/] => 'void'); $ffi->attach('OGR_G_AddPoint' => [qw/opaque double double double/] => 'void'); $ffi->attach('OGR_G_AddPoint_2D' => [qw/opaque double double/] => 'void'); $ffi->attach('OGR_G_AddPointM' => [qw/opaque double double double/] => 'void'); $ffi->attach('OGR_G_AddPointZM' => [qw/opaque double double double double/] => 'void'); $ffi->attach('OGR_G_SetPoints' => [qw/opaque int opaque int opaque int opaque int/] => 'void'); $ffi->attach('OGR_G_SetPointsZM' => [qw/opaque int opaque int opaque int opaque int opaque int/] => 'void'); $ffi->attach('OGR_G_SwapXY' => [qw/opaque/] => 'void'); $ffi->attach('OGR_G_GetGeometryCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_G_GetGeometryRef' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_G_AddGeometry' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_AddGeometryDirectly' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_G_RemoveGeometry' => [qw/opaque int int/] => 'int'); $ffi->attach('OGR_G_HasCurveGeometry' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_G_GetLinearGeometry' => [qw/opaque double opaque/] => 'opaque'); $ffi->attach('OGR_G_GetCurveGeometry' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OGRBuildPolygonFromEdges' => [qw/opaque int int double int*/] => 'opaque'); $ffi->attach('OGRSetGenerate_DB2_V72_BYTE_ORDER' => [qw/int/] => 'int'); $ffi->attach('OGRGetGenerate_DB2_V72_BYTE_ORDER' => [] => 'int'); $ffi->attach('OGRSetNonLinearGeometriesEnabledFlag' => [qw/int/] => 'void'); $ffi->attach('OGRGetNonLinearGeometriesEnabledFlag' => [] => 'int'); $ffi->attach('OGRHasPreparedGeometrySupport' => [] => 'int'); $ffi->attach('OGRCreatePreparedGeometry' => [qw/opaque/] => 'opaque'); $ffi->attach('OGRDestroyPreparedGeometry' => [qw/opaque/] => 'void'); $ffi->attach('OGRPreparedGeometryIntersects' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGRPreparedGeometryContains' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_Fld_Create' => ['string','unsigned int'] => 'opaque'); $ffi->attach('OGR_Fld_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_Fld_SetName' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_Fld_GetNameRef' => [qw/opaque/] => 'string'); $ffi->attach('OGR_Fld_SetAlternativeName' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_Fld_GetAlternativeNameRef' => [qw/opaque/] => 'string'); $ffi->attach('OGR_Fld_GetType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_Fld_SetType' => ['opaque','unsigned int'] => 'void'); $ffi->attach('OGR_Fld_GetSubType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_Fld_SetSubType' => ['opaque','unsigned int'] => 'void'); $ffi->attach('OGR_Fld_GetJustify' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_Fld_SetJustify' => ['opaque','unsigned int'] => 'void'); $ffi->attach('OGR_Fld_GetWidth' => [qw/opaque/] => 'int'); $ffi->attach('OGR_Fld_SetWidth' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_Fld_GetPrecision' => [qw/opaque/] => 'int'); $ffi->attach('OGR_Fld_SetPrecision' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_Fld_Set' => ['opaque','string','unsigned int','int','int','unsigned int'] => 'void'); $ffi->attach('OGR_Fld_IsIgnored' => [qw/opaque/] => 'int'); $ffi->attach('OGR_Fld_SetIgnored' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_Fld_IsNullable' => [qw/opaque/] => 'int'); $ffi->attach('OGR_Fld_SetNullable' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_Fld_IsUnique' => [qw/opaque/] => 'int'); $ffi->attach('OGR_Fld_SetUnique' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_Fld_GetDefault' => [qw/opaque/] => 'string'); $ffi->attach('OGR_Fld_SetDefault' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_Fld_IsDefaultDriverSpecific' => [qw/opaque/] => 'int'); $ffi->attach('OGR_Fld_GetDomainName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_Fld_SetDomainName' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_Fld_GetComment' => [qw/opaque/] => 'string'); $ffi->attach('OGR_Fld_SetComment' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_GetFieldTypeName' => ['unsigned int'] => 'string'); $ffi->attach('OGR_GetFieldSubTypeName' => ['unsigned int'] => 'string'); $ffi->attach('OGR_AreTypeSubTypeCompatible' => ['unsigned int','unsigned int'] => 'int'); $ffi->attach('OGR_GFld_Create' => ['string','unsigned int'] => 'opaque'); $ffi->attach('OGR_GFld_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_GFld_SetName' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_GFld_GetNameRef' => [qw/opaque/] => 'string'); $ffi->attach('OGR_GFld_GetType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_GFld_SetType' => ['opaque','unsigned int'] => 'void'); $ffi->attach('OGR_GFld_GetSpatialRef' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_GFld_SetSpatialRef' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_GFld_IsNullable' => [qw/opaque/] => 'int'); $ffi->attach('OGR_GFld_SetNullable' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_GFld_IsIgnored' => [qw/opaque/] => 'int'); $ffi->attach('OGR_GFld_SetIgnored' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_FD_Create' => [qw/string/] => 'opaque'); $ffi->attach('OGR_FD_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_FD_Release' => [qw/opaque/] => 'void'); $ffi->attach('OGR_FD_GetName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_FD_GetFieldCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_GetFieldDefn' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_FD_GetFieldIndex' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_FD_AddFieldDefn' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_FD_DeleteFieldDefn' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_FD_ReorderFieldDefns' => [qw/opaque int*/] => 'int'); $ffi->attach('OGR_FD_GetGeomType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_FD_SetGeomType' => ['opaque','unsigned int'] => 'void'); $ffi->attach('OGR_FD_IsGeometryIgnored' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_SetGeometryIgnored' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_FD_IsStyleIgnored' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_SetStyleIgnored' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_FD_Reference' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_Dereference' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_GetReferenceCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_GetGeomFieldCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FD_GetGeomFieldDefn' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_FD_GetGeomFieldIndex' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_FD_AddGeomFieldDefn' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_FD_DeleteGeomFieldDefn' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_FD_IsSame' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_F_Create' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_F_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_F_GetDefnRef' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_F_SetGeometryDirectly' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_F_SetGeometry' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_F_GetGeometryRef' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_F_StealGeometry' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_F_StealGeometryEx' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_F_Clone' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_F_Equal' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_F_GetFieldCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_F_GetFieldDefnRef' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_F_GetFieldIndex' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_F_IsFieldSet' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_F_UnsetField' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_F_IsFieldNull' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_F_IsFieldSetAndNotNull' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_F_SetFieldNull' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_F_GetRawFieldRef' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_RawField_IsUnset' => [qw/opaque/] => 'int'); $ffi->attach('OGR_RawField_IsNull' => [qw/opaque/] => 'int'); $ffi->attach('OGR_RawField_SetUnset' => [qw/opaque/] => 'void'); $ffi->attach('OGR_RawField_SetNull' => [qw/opaque/] => 'void'); $ffi->attach('OGR_F_GetFieldAsInteger' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_F_GetFieldAsInteger64' => [qw/opaque int/] => 'sint64'); $ffi->attach('OGR_F_GetFieldAsDouble' => [qw/opaque int/] => 'double'); $ffi->attach('OGR_F_GetFieldAsString' => [qw/opaque int/] => 'string'); $ffi->attach('OGR_F_GetFieldAsISO8601DateTime' => [qw/opaque int opaque/] => 'string'); $ffi->attach('OGR_F_GetFieldAsIntegerList' => [qw/opaque int int*/] => 'pointer'); $ffi->attach('OGR_F_GetFieldAsInteger64List' => [qw/opaque int int*/] => 'pointer'); $ffi->attach('OGR_F_GetFieldAsDoubleList' => [qw/opaque int int*/] => 'pointer'); $ffi->attach('OGR_F_GetFieldAsStringList' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_F_GetFieldAsBinary' => [qw/opaque int int*/] => 'pointer'); $ffi->attach('OGR_F_GetFieldAsDateTime' => [qw/opaque int int* int* int* int* int* int* int*/] => 'int'); $ffi->attach('OGR_F_GetFieldAsDateTimeEx' => [qw/opaque int int* int* int* int* int* float* int*/] => 'int'); $ffi->attach('OGR_F_SetFieldInteger' => [qw/opaque int int/] => 'void'); $ffi->attach('OGR_F_SetFieldInteger64' => [qw/opaque int sint64/] => 'void'); $ffi->attach('OGR_F_SetFieldDouble' => [qw/opaque int double/] => 'void'); $ffi->attach('OGR_F_SetFieldString' => [qw/opaque int string/] => 'void'); $ffi->attach('OGR_F_SetFieldIntegerList' => [qw/opaque int int int[]/] => 'void'); $ffi->attach('OGR_F_SetFieldInteger64List' => [qw/opaque int int sint64[]/] => 'void'); $ffi->attach('OGR_F_SetFieldDoubleList' => [qw/opaque int int double[]/] => 'void'); $ffi->attach('OGR_F_SetFieldStringList' => [qw/opaque int opaque/] => 'void'); $ffi->attach('OGR_F_SetFieldRaw' => [qw/opaque int opaque/] => 'void'); $ffi->attach('OGR_F_SetFieldBinary' => [qw/opaque int int opaque/] => 'void'); $ffi->attach('OGR_F_SetFieldDateTime' => [qw/opaque int int int int int int int int/] => 'void'); $ffi->attach('OGR_F_SetFieldDateTimeEx' => [qw/opaque int int int int int int float int/] => 'void'); $ffi->attach('OGR_F_GetGeomFieldCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_F_GetGeomFieldDefnRef' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_F_GetGeomFieldIndex' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_F_GetGeomFieldRef' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_F_SetGeomFieldDirectly' => [qw/opaque int opaque/] => 'int'); $ffi->attach('OGR_F_SetGeomField' => [qw/opaque int opaque/] => 'int'); $ffi->attach('OGR_F_GetFID' => [qw/opaque/] => 'sint64'); $ffi->attach('OGR_F_SetFID' => [qw/opaque sint64/] => 'int'); $ffi->attach('OGR_F_DumpReadable' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_F_SetFrom' => [qw/opaque opaque int/] => 'int'); $ffi->attach('OGR_F_SetFromWithMap' => [qw/opaque opaque int int*/] => 'int'); $ffi->attach('OGR_F_GetStyleString' => [qw/opaque/] => 'string'); $ffi->attach('OGR_F_SetStyleString' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_F_SetStyleStringDirectly' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_F_GetStyleTable' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_F_SetStyleTableDirectly' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_F_SetStyleTable' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_F_GetNativeData' => [qw/opaque/] => 'string'); $ffi->attach('OGR_F_SetNativeData' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_F_GetNativeMediaType' => [qw/opaque/] => 'string'); $ffi->attach('OGR_F_SetNativeMediaType' => [qw/opaque string/] => 'void'); $ffi->attach('OGR_F_FillUnsetWithDefault' => [qw/opaque int opaque/] => 'void'); $ffi->attach('OGR_F_Validate' => [qw/opaque int int/] => 'int'); $ffi->attach('OGR_FldDomain_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_FldDomain_GetName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_FldDomain_GetDescription' => [qw/opaque/] => 'string'); $ffi->attach('OGR_FldDomain_GetDomainType' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FldDomain_GetFieldType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_FldDomain_GetFieldSubType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_FldDomain_GetSplitPolicy' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FldDomain_SetSplitPolicy' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_FldDomain_GetMergePolicy' => [qw/opaque/] => 'int'); $ffi->attach('OGR_FldDomain_SetMergePolicy' => [qw/opaque int/] => 'void'); $ffi->attach('OGR_CodedFldDomain_Create' => ['string','string','unsigned int','unsigned int','int'] => 'opaque'); $ffi->attach('OGR_CodedFldDomain_GetEnumeration' => [qw/opaque/] => 'int'); $ffi->attach('OGR_RangeFldDomain_Create' => ['string','string','unsigned int','unsigned int','opaque','bool','opaque','bool'] => 'opaque'); $ffi->attach('OGR_RangeFldDomain_GetMin' => [qw/opaque bool/] => 'opaque'); $ffi->attach('OGR_RangeFldDomain_GetMax' => [qw/opaque bool/] => 'opaque'); $ffi->attach('OGR_GlobFldDomain_Create' => ['string','string','unsigned int','unsigned int','string'] => 'opaque'); $ffi->attach('OGR_GlobFldDomain_GetGlob' => [qw/opaque/] => 'string'); $ffi->attach('OGR_L_GetName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_L_GetGeomType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_L_GetGeometryTypes' => [qw/opaque int int int* GDALProgressFunc opaque/] => 'opaque'); $ffi->attach('OGR_L_GetSpatialFilter' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_L_SetSpatialFilter' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_L_SetSpatialFilterRect' => [qw/opaque double double double double/] => 'void'); $ffi->attach('OGR_L_SetSpatialFilterEx' => [qw/opaque int opaque/] => 'void'); $ffi->attach('OGR_L_SetSpatialFilterRectEx' => [qw/opaque int double double double double/] => 'void'); $ffi->attach('OGR_L_SetAttributeFilter' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_L_ResetReading' => [qw/opaque/] => 'void'); $ffi->attach('OGR_L_GetNextFeature' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_L_GetArrowStream' => [qw/opaque opaque opaque/] => 'bool'); $ffi->attach('OGR_L_SetNextByIndex' => [qw/opaque sint64/] => 'int'); $ffi->attach('OGR_L_GetFeature' => [qw/opaque sint64/] => 'opaque'); $ffi->attach('OGR_L_SetFeature' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_L_CreateFeature' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_L_DeleteFeature' => [qw/opaque sint64/] => 'int'); $ffi->attach('OGR_L_UpsertFeature' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_L_UpdateFeature' => [qw/opaque opaque int int* int int* bool/] => 'int'); $ffi->attach('OGR_L_GetLayerDefn' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_L_GetSpatialRef' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_L_GetSupportedSRSList' => [qw/opaque int int*/] => 'uint64*'); $ffi->attach('OGR_L_SetActiveSRS' => [qw/opaque int opaque/] => 'int'); $ffi->attach('OGR_L_FindFieldIndex' => [qw/opaque string int/] => 'int'); $ffi->attach('OGR_L_GetFeatureCount' => [qw/opaque int/] => 'sint64'); $ffi->attach('OGR_L_GetExtent' => [qw/opaque double[4] int/] => 'int'); $ffi->attach('OGR_L_GetExtentEx' => [qw/opaque int double[4] int/] => 'int'); $ffi->attach('OGR_L_TestCapability' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_L_CreateField' => [qw/opaque opaque int/] => 'int'); $ffi->attach('OGR_L_CreateGeomField' => [qw/opaque opaque int/] => 'int'); $ffi->attach('OGR_L_DeleteField' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_L_ReorderFields' => [qw/opaque int*/] => 'int'); $ffi->attach('OGR_L_ReorderField' => [qw/opaque int int/] => 'int'); $ffi->attach('OGR_L_AlterFieldDefn' => [qw/opaque int opaque int/] => 'int'); $ffi->attach('OGR_L_AlterGeomFieldDefn' => [qw/opaque int opaque int/] => 'int'); $ffi->attach('OGR_L_StartTransaction' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_CommitTransaction' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_RollbackTransaction' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_Rename' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_L_Reference' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_Dereference' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_GetRefCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_SyncToDisk' => [qw/opaque/] => 'int'); $ffi->attach('OGR_L_GetFeaturesRead' => [qw/opaque/] => 'sint64'); $ffi->attach('OGR_L_GetFIDColumn' => [qw/opaque/] => 'string'); $ffi->attach('OGR_L_GetGeometryColumn' => [qw/opaque/] => 'string'); $ffi->attach('OGR_L_GetStyleTable' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_L_SetStyleTableDirectly' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_L_SetStyleTable' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_L_SetIgnoredFields' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_L_Intersection' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_L_Union' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_L_SymDifference' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_L_Identity' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_L_Update' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_L_Clip' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_L_Erase' => [qw/opaque opaque opaque opaque GDALProgressFunc opaque/] => 'int'); $ffi->attach('OGR_DS_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_DS_GetName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_DS_GetLayerCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_DS_GetLayer' => [qw/opaque int/] => 'opaque'); $ffi->attach('OGR_DS_GetLayerByName' => [qw/opaque string/] => 'opaque'); $ffi->attach('OGR_DS_DeleteLayer' => [qw/opaque int/] => 'int'); $ffi->attach('OGR_DS_GetDriver' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_DS_CreateLayer' => ['opaque','string','opaque','unsigned int','opaque'] => 'opaque'); $ffi->attach('OGR_DS_CopyLayer' => [qw/opaque opaque string opaque/] => 'opaque'); $ffi->attach('OGR_DS_TestCapability' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_DS_ExecuteSQL' => [qw/opaque string opaque string/] => 'opaque'); $ffi->attach('OGR_DS_ReleaseResultSet' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_DS_Reference' => [qw/opaque/] => 'int'); $ffi->attach('OGR_DS_Dereference' => [qw/opaque/] => 'int'); $ffi->attach('OGR_DS_GetRefCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_DS_GetSummaryRefCount' => [qw/opaque/] => 'int'); $ffi->attach('OGR_DS_SyncToDisk' => [qw/opaque/] => 'int'); $ffi->attach('OGR_DS_GetStyleTable' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_DS_SetStyleTableDirectly' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_DS_SetStyleTable' => [qw/opaque opaque/] => 'void'); $ffi->attach('OGR_Dr_GetName' => [qw/opaque/] => 'string'); $ffi->attach('OGR_Dr_Open' => [qw/opaque string int/] => 'opaque'); $ffi->attach('OGR_Dr_TestCapability' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_Dr_CreateDataSource' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('OGR_Dr_CopyDataSource' => [qw/opaque opaque string opaque/] => 'opaque'); $ffi->attach('OGR_Dr_DeleteDataSource' => [qw/opaque string/] => 'int'); $ffi->attach('OGROpen' => [qw/string int uint64*/] => 'opaque'); $ffi->attach('OGROpenShared' => [qw/string int uint64*/] => 'opaque'); $ffi->attach('OGRReleaseDataSource' => [qw/opaque/] => 'int'); $ffi->attach('OGRRegisterDriver' => [qw/opaque/] => 'void'); $ffi->attach('OGRDeregisterDriver' => [qw/opaque/] => 'void'); $ffi->attach('OGRGetDriverCount' => [] => 'int'); $ffi->attach('OGRGetDriver' => [qw/int/] => 'opaque'); $ffi->attach('OGRGetDriverByName' => [qw/string/] => 'opaque'); $ffi->attach('OGRGetOpenDSCount' => [] => 'int'); $ffi->attach('OGRGetOpenDS' => [qw/int/] => 'opaque'); $ffi->attach('OGRRegisterAll' => [] => 'void'); $ffi->attach('OGRCleanupAll' => [] => 'void'); $ffi->attach('OGR_SM_Create' => [qw/opaque/] => 'opaque'); $ffi->attach('OGR_SM_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_SM_InitFromFeature' => [qw/opaque opaque/] => 'string'); $ffi->attach('OGR_SM_InitStyleString' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_SM_GetPartCount' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_SM_GetPart' => [qw/opaque int string/] => 'opaque'); $ffi->attach('OGR_SM_AddPart' => [qw/opaque opaque/] => 'int'); $ffi->attach('OGR_SM_AddStyle' => [qw/opaque string string/] => 'int'); $ffi->attach('OGR_ST_Create' => ['unsigned int'] => 'opaque'); $ffi->attach('OGR_ST_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_ST_GetType' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_ST_GetUnit' => [qw/opaque/] => 'unsigned int'); $ffi->attach('OGR_ST_SetUnit' => ['opaque','unsigned int','double'] => 'void'); $ffi->attach('OGR_ST_GetParamStr' => [qw/opaque int int*/] => 'string'); $ffi->attach('OGR_ST_GetParamNum' => [qw/opaque int int*/] => 'int'); $ffi->attach('OGR_ST_GetParamDbl' => [qw/opaque int int*/] => 'double'); $ffi->attach('OGR_ST_SetParamStr' => [qw/opaque int string/] => 'void'); $ffi->attach('OGR_ST_SetParamNum' => [qw/opaque int int/] => 'void'); $ffi->attach('OGR_ST_SetParamDbl' => [qw/opaque int double/] => 'void'); $ffi->attach('OGR_ST_GetStyleString' => [qw/opaque/] => 'string'); $ffi->attach('OGR_ST_GetRGBFromString' => [qw/opaque string int* int* int* int*/] => 'int'); $ffi->attach('OGR_STBL_Create' => [] => 'opaque'); $ffi->attach('OGR_STBL_Destroy' => [qw/opaque/] => 'void'); $ffi->attach('OGR_STBL_AddStyle' => [qw/opaque string string/] => 'int'); $ffi->attach('OGR_STBL_SaveStyleTable' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_STBL_LoadStyleTable' => [qw/opaque string/] => 'int'); $ffi->attach('OGR_STBL_Find' => [qw/opaque string/] => 'string'); $ffi->attach('OGR_STBL_ResetStyleStringReading' => [qw/opaque/] => 'void'); $ffi->attach('OGR_STBL_GetNextStyle' => [qw/opaque/] => 'string'); $ffi->attach('OGR_STBL_GetLastStyleName' => [qw/opaque/] => 'string'); # from ogr/ogr_srs_api.h $ffi->attach('OSRAxisEnumToName' => ['unsigned int'] => 'string'); $ffi->attach('OSRSetPROJSearchPaths' => [qw/opaque/] => 'void'); $ffi->attach('OSRGetPROJSearchPaths' => [] => 'opaque'); $ffi->attach('OSRSetPROJAuxDbPaths' => [qw/opaque/] => 'void'); $ffi->attach('OSRGetPROJAuxDbPaths' => [] => 'opaque'); $ffi->attach('OSRSetPROJEnableNetwork' => [qw/int/] => 'void'); $ffi->attach('OSRGetPROJEnableNetwork' => [] => 'int'); $ffi->attach('OSRGetPROJVersion' => [qw/int* int* int*/] => 'void'); $ffi->attach('OSRNewSpatialReference' => [qw/string/] => 'opaque'); $ffi->attach('OSRCloneGeogCS' => [qw/opaque/] => 'opaque'); $ffi->attach('OSRClone' => [qw/opaque/] => 'opaque'); $ffi->attach('OSRDestroySpatialReference' => [qw/opaque/] => 'void'); $ffi->attach('OSRReference' => [qw/opaque/] => 'int'); $ffi->attach('OSRDereference' => [qw/opaque/] => 'int'); $ffi->attach('OSRRelease' => [qw/opaque/] => 'void'); $ffi->attach('OSRValidate' => [qw/opaque/] => 'int'); $ffi->attach('OSRImportFromEPSG' => [qw/opaque int/] => 'int'); $ffi->attach('OSRImportFromEPSGA' => [qw/opaque int/] => 'int'); $ffi->attach('OSRImportFromWkt' => [qw/opaque string*/] => 'int'); $ffi->attach('OSRImportFromProj4' => [qw/opaque string/] => 'int'); $ffi->attach('OSRImportFromESRI' => [qw/opaque opaque/] => 'int'); $ffi->attach('OSRImportFromPCI' => [qw/opaque string string double*/] => 'int'); $ffi->attach('OSRImportFromUSGS' => [qw/opaque long long double* long/] => 'int'); $ffi->attach('OSRImportFromXML' => [qw/opaque string/] => 'int'); $ffi->attach('OSRImportFromDict' => [qw/opaque string string/] => 'int'); $ffi->attach('OSRImportFromPanorama' => [qw/opaque long long long double*/] => 'int'); $ffi->attach('OSRImportFromOzi' => [qw/opaque opaque/] => 'int'); $ffi->attach('OSRImportFromMICoordSys' => [qw/opaque string/] => 'int'); $ffi->attach('OSRImportFromERM' => [qw/opaque string string string/] => 'int'); $ffi->attach('OSRImportFromUrl' => [qw/opaque string/] => 'int'); $ffi->attach('OSRExportToWkt' => [qw/opaque string*/] => 'int'); $ffi->attach('OSRExportToWktEx' => [qw/opaque string* opaque/] => 'int'); $ffi->attach('OSRExportToPrettyWkt' => [qw/opaque string* int/] => 'int'); $ffi->attach('OSRExportToPROJJSON' => [qw/opaque string* opaque/] => 'int'); $ffi->attach('OSRExportToProj4' => [qw/opaque string*/] => 'int'); $ffi->attach('OSRExportToPCI' => [qw/opaque string* string* double*/] => 'int'); $ffi->attach('OSRExportToUSGS' => [qw/opaque long* long* double* long*/] => 'int'); $ffi->attach('OSRExportToXML' => [qw/opaque string* string/] => 'int'); $ffi->attach('OSRExportToPanorama' => [qw/opaque long* long* long* long* double*/] => 'int'); $ffi->attach('OSRExportToMICoordSys' => [qw/opaque string*/] => 'int'); $ffi->attach('OSRExportToERM' => [qw/opaque string string string/] => 'int'); $ffi->attach('OSRMorphToESRI' => [qw/opaque/] => 'int'); $ffi->attach('OSRMorphFromESRI' => [qw/opaque/] => 'int'); $ffi->attach('OSRStripVertical' => [qw/opaque/] => 'int'); $ffi->attach('OSRConvertToOtherProjection' => [qw/opaque string opaque/] => 'opaque'); $ffi->attach('OSRGetName' => [qw/opaque/] => 'string'); $ffi->attach('OSRSetAttrValue' => [qw/opaque string string/] => 'int'); $ffi->attach('OSRGetAttrValue' => [qw/opaque string int/] => 'string'); $ffi->attach('OSRSetAngularUnits' => [qw/opaque string double/] => 'int'); $ffi->attach('OSRGetAngularUnits' => [qw/opaque string*/] => 'double'); $ffi->attach('OSRSetLinearUnits' => [qw/opaque string double/] => 'int'); $ffi->attach('OSRSetTargetLinearUnits' => [qw/opaque string string double/] => 'int'); $ffi->attach('OSRSetLinearUnitsAndUpdateParameters' => [qw/opaque string double/] => 'int'); $ffi->attach('OSRGetLinearUnits' => [qw/opaque string*/] => 'double'); $ffi->attach('OSRGetTargetLinearUnits' => [qw/opaque string string*/] => 'double'); $ffi->attach('OSRGetPrimeMeridian' => [qw/opaque string*/] => 'double'); $ffi->attach('OSRIsGeographic' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsDerivedGeographic' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsLocal' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsProjected' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsCompound' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsGeocentric' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsVertical' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsDynamic' => [qw/opaque/] => 'int'); $ffi->attach('OSRIsSameGeogCS' => [qw/opaque opaque/] => 'int'); $ffi->attach('OSRIsSameVertCS' => [qw/opaque opaque/] => 'int'); $ffi->attach('OSRIsSame' => [qw/opaque opaque/] => 'int'); $ffi->attach('OSRIsSameEx' => [qw/opaque opaque opaque/] => 'int'); $ffi->attach('OSRSetCoordinateEpoch' => [qw/opaque double/] => 'void'); $ffi->attach('OSRGetCoordinateEpoch' => [qw/opaque/] => 'double'); $ffi->attach('OSRSetLocalCS' => [qw/opaque string/] => 'int'); $ffi->attach('OSRSetProjCS' => [qw/opaque string/] => 'int'); $ffi->attach('OSRSetGeocCS' => [qw/opaque string/] => 'int'); $ffi->attach('OSRSetWellKnownGeogCS' => [qw/opaque string/] => 'int'); $ffi->attach('OSRSetFromUserInput' => [qw/opaque string/] => 'int'); $ffi->attach('OSRCopyGeogCSFrom' => [qw/opaque opaque/] => 'int'); $ffi->attach('OSRSetTOWGS84' => [qw/opaque double double double double double double double/] => 'int'); $ffi->attach('OSRGetTOWGS84' => [qw/opaque double* int/] => 'int'); $ffi->attach('OSRAddGuessedTOWGS84' => [qw/opaque/] => 'int'); $ffi->attach('OSRSetCompoundCS' => [qw/opaque string opaque opaque/] => 'int'); $ffi->attach('OSRPromoteTo3D' => [qw/opaque string/] => 'int'); $ffi->attach('OSRDemoteTo2D' => [qw/opaque string/] => 'int'); $ffi->attach('OSRSetGeogCS' => [qw/opaque string string string double double string double string double/] => 'int'); $ffi->attach('OSRSetVertCS' => [qw/opaque string string int/] => 'int'); $ffi->attach('OSRGetSemiMajor' => [qw/opaque int*/] => 'double'); $ffi->attach('OSRGetSemiMinor' => [qw/opaque int*/] => 'double'); $ffi->attach('OSRGetInvFlattening' => [qw/opaque int*/] => 'double'); $ffi->attach('OSRSetAuthority' => [qw/opaque string string int/] => 'int'); $ffi->attach('OSRGetAuthorityCode' => [qw/opaque string/] => 'string'); $ffi->attach('OSRGetAuthorityName' => [qw/opaque string/] => 'string'); $ffi->attach('OSRGetAreaOfUse' => [qw/opaque double* double* double* double* string/] => 'int'); $ffi->attach('OSRSetProjection' => [qw/opaque string/] => 'int'); $ffi->attach('OSRSetProjParm' => [qw/opaque string double/] => 'int'); $ffi->attach('OSRGetProjParm' => [qw/opaque string double int*/] => 'double'); $ffi->attach('OSRSetNormProjParm' => [qw/opaque string double/] => 'int'); $ffi->attach('OSRGetNormProjParm' => [qw/opaque string double int*/] => 'double'); $ffi->attach('OSRSetUTM' => [qw/opaque int int/] => 'int'); $ffi->attach('OSRGetUTMZone' => [qw/opaque int*/] => 'int'); $ffi->attach('OSRSetStatePlane' => [qw/opaque int int/] => 'int'); $ffi->attach('OSRSetStatePlaneWithUnits' => [qw/opaque int int string double/] => 'int'); $ffi->attach('OSRAutoIdentifyEPSG' => [qw/opaque/] => 'int'); $ffi->attach('OSRFindMatches' => [qw/opaque opaque int* int*/] => 'uint64*'); $ffi->attach('OSRFreeSRSArray' => [qw/uint64*/] => 'void'); $ffi->attach('OSREPSGTreatsAsLatLong' => [qw/opaque/] => 'int'); $ffi->attach('OSREPSGTreatsAsNorthingEasting' => [qw/opaque/] => 'int'); $ffi->attach('OSRGetAxis' => ['opaque','string','int','unsigned int'] => 'string'); $ffi->attach('OSRGetAxesCount' => [qw/opaque/] => 'int'); $ffi->attach('OSRSetAxes' => ['opaque','string','string','unsigned int','string','unsigned int'] => 'int'); $ffi->attach('OSRGetAxisMappingStrategy' => [qw/opaque/] => 'int'); $ffi->attach('OSRSetAxisMappingStrategy' => [qw/opaque int/] => 'void'); $ffi->attach('OSRGetDataAxisToSRSAxisMapping' => [qw/opaque int*/] => 'int*'); $ffi->attach('OSRSetDataAxisToSRSAxisMapping' => [qw/opaque int int*/] => 'int'); $ffi->attach('OSRSetACEA' => [qw/opaque double double double double double double/] => 'int'); $ffi->attach('OSRSetAE' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetBonne' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetCEA' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetCS' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetEC' => [qw/opaque double double double double double double/] => 'int'); $ffi->attach('OSRSetEckert' => [qw/opaque int double double double/] => 'int'); $ffi->attach('OSRSetEckertIV' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetEckertVI' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetEquirectangular' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetEquirectangular2' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetGS' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetGH' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetIGH' => [qw/opaque/] => 'int'); $ffi->attach('OSRSetGEOS' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetGaussSchreiberTMercator' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetGnomonic' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetHOM' => [qw/opaque double double double double double double double/] => 'int'); $ffi->attach('OSRSetHOMAC' => [qw/opaque double double double double double double double/] => 'int'); $ffi->attach('OSRSetHOM2PNO' => [qw/opaque double double double double double double double double/] => 'int'); $ffi->attach('OSRSetIWMPolyconic' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetKrovak' => [qw/opaque double double double double double double double/] => 'int'); $ffi->attach('OSRSetLAEA' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetLCC' => [qw/opaque double double double double double double/] => 'int'); $ffi->attach('OSRSetLCC1SP' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetLCCB' => [qw/opaque double double double double double double/] => 'int'); $ffi->attach('OSRSetMC' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetMercator' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetMercator2SP' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetMollweide' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetNZMG' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetOS' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetOrthographic' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetPolyconic' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetPS' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetRobinson' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetSinusoidal' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetStereographic' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetSOC' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetTM' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetTMVariant' => [qw/opaque string double double double double double/] => 'int'); $ffi->attach('OSRSetTMG' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetTMSO' => [qw/opaque double double double double double/] => 'int'); $ffi->attach('OSRSetTPED' => [qw/opaque double double double double double double/] => 'int'); $ffi->attach('OSRSetVDG' => [qw/opaque double double double/] => 'int'); $ffi->attach('OSRSetWagner' => [qw/opaque int double double double/] => 'int'); $ffi->attach('OSRSetQSC' => [qw/opaque double double/] => 'int'); $ffi->attach('OSRSetSCH' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OSRSetVerticalPerspective' => [qw/opaque double double double double double double/] => 'int'); $ffi->attach('OSRCalcInvFlattening' => [qw/double double/] => 'double'); $ffi->attach('OSRCalcSemiMinorFromInvFlattening' => [qw/double double/] => 'double'); $ffi->attach('OSRCleanup' => [] => 'void'); $ffi->attach('OSRGetCRSInfoListFromDatabase' => [qw/string opaque int*/] => 'opaque'); $ffi->attach('OSRDestroyCRSInfoList' => [qw/opaque/] => 'void'); $ffi->attach('OCTNewCoordinateTransformation' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('OCTNewCoordinateTransformationOptions' => [] => 'opaque'); $ffi->attach('OCTCoordinateTransformationOptionsSetOperation' => [qw/opaque string int/] => 'int'); $ffi->attach('OCTCoordinateTransformationOptionsSetAreaOfInterest' => [qw/opaque double double double double/] => 'int'); $ffi->attach('OCTCoordinateTransformationOptionsSetDesiredAccuracy' => [qw/opaque double/] => 'int'); $ffi->attach('OCTCoordinateTransformationOptionsSetBallparkAllowed' => [qw/opaque int/] => 'int'); $ffi->attach('OCTDestroyCoordinateTransformationOptions' => [qw/opaque/] => 'void'); $ffi->attach('OCTNewCoordinateTransformationEx' => [qw/opaque opaque opaque/] => 'opaque'); $ffi->attach('OCTClone' => [qw/opaque/] => 'opaque'); $ffi->attach('OCTGetSourceCS' => [qw/opaque/] => 'opaque'); $ffi->attach('OCTGetTargetCS' => [qw/opaque/] => 'opaque'); $ffi->attach('OCTGetInverse' => [qw/opaque/] => 'opaque'); $ffi->attach('OCTDestroyCoordinateTransformation' => [qw/opaque/] => 'void'); $ffi->attach('OCTTransform' => [qw/opaque int double[] double[] double[]/] => 'int'); $ffi->attach('OCTTransformEx' => [qw/opaque int double[] double[] double[] int[]/] => 'int'); $ffi->attach('OCTTransform4D' => [qw/opaque int double[] double[] double[] double[] int[]/] => 'int'); $ffi->attach('OCTTransform4DWithErrorCodes' => [qw/opaque int double[] double[] double[] double[] int[]/] => 'int'); $ffi->attach('OCTTransformBounds' => [qw/opaque double double double double double[] double[] double[] double[] int/] => 'int'); # from apps/gdal_utils.h $ffi->attach('GDALInfoOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALInfoOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALInfo' => [qw/opaque opaque/] => 'string'); $ffi->attach('GDALTranslateOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALTranslateOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALTranslateOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALTranslate' => [qw/string opaque opaque int*/] => 'opaque'); $ffi->attach('GDALWarpAppOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALWarpAppOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALWarpAppOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALWarpAppOptionsSetQuiet' => [qw/opaque int/] => 'void'); $ffi->attach('GDALWarpAppOptionsSetWarpOption' => [qw/opaque string string/] => 'void'); $ffi->attach('GDALWarp' => [qw/string opaque int opaque[] opaque int*/] => 'opaque'); $ffi->attach('GDALVectorTranslateOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALVectorTranslateOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALVectorTranslateOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALVectorTranslate' => [qw/string opaque int opaque[] opaque int*/] => 'opaque'); $ffi->attach('GDALDEMProcessingOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALDEMProcessingOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALDEMProcessingOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALDEMProcessing' => [qw/string opaque string string opaque int*/] => 'opaque'); $ffi->attach('GDALNearblackOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALNearblackOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALNearblackOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALNearblack' => [qw/string opaque opaque opaque int*/] => 'opaque'); $ffi->attach('GDALGridOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALGridOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALGridOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALGrid' => [qw/string opaque opaque int*/] => 'opaque'); $ffi->attach('GDALRasterizeOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALRasterizeOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALRasterizeOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALRasterize' => [qw/string opaque opaque opaque int*/] => 'opaque'); $ffi->attach('GDALBuildVRTOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALBuildVRTOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALBuildVRTOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALBuildVRT' => [qw/string int opaque[] opaque opaque int*/] => 'opaque'); $ffi->attach('GDALMultiDimInfoOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALMultiDimInfoOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALMultiDimInfo' => [qw/opaque opaque/] => 'string'); $ffi->attach('GDALMultiDimTranslateOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALMultiDimTranslateOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALMultiDimTranslateOptionsSetProgress' => [qw/opaque GDALProgressFunc opaque/] => 'void'); $ffi->attach('GDALMultiDimTranslate' => [qw/string opaque int uint64* opaque int*/] => 'opaque'); $ffi->attach('GDALVectorInfoOptionsNew' => [qw/opaque opaque/] => 'opaque'); $ffi->attach('GDALVectorInfoOptionsFree' => [qw/opaque/] => 'void'); $ffi->attach('GDALVectorInfo' => [qw/opaque opaque/] => 'string'); # end of generated code if ($gdal eq 'Alien::gdal' and versioncmp($gdal->version, '2.3.1') <= 0) { # we do not use Alien::gdal->data_dir since it issues warnings due to GDAL bug my $pc = PkgConfig->find('gdal'); if ($pc->errmsg) { my $dir = Alien::gdal->dist_dir; my %options = (search_path_override => ["$dir/lib/pkgconfig", "$dir/lib64/pkgconfig"]); $pc = PkgConfig->find('gdal', %options); } if ($pc->errmsg) { warn $pc->errmsg; } else { my $dir = $pc->get_var('datadir'); # this gdal.pc bug was fixed in GDAL 2.3.1 # we just hope the one configuring GDAL did not change it to something that ends '/data' $dir =~ s/\/data$//; if (opendir(my $dh, $dir)) { CPLSetConfigOption(GDAL_DATA => $dir); } else { my $dist_data_dir = Alien::gdal->dist_dir . '/share/gdal'; if (-d $dist_data_dir) { CPLSetConfigOption(GDAL_DATA => $dist_data_dir); } else { warn "GDAL data directory ($dir) doesn't exist. Maybe Alien::gdal is not installed?"; } } } } else { CPLSetConfigOption(GDAL_DATA => $gdal->data_dir); } $instance = {}; $instance->{ffi} = $ffi; $instance->{gdal} = $gdal; SetErrorHandling(); GDALAllRegister(); return bless $instance, $class; } sub get_instance { my $class = shift; $instance = $class->new() unless $instance; return $instance; } sub DESTROY { UnsetErrorHandling(); } sub GetVersionInfo { my $request = shift // 'VERSION_NUM'; if ($request eq 'SEMANTIC') { my $version = GDALVersionInfo('VERSION_NUM') / 100; my $ret = ''; while ($version > 0) { my $v = $version % 100; $ret = ".$ret" if $ret ne ''; $ret = "$v$ret"; $version = int($version/100); } return $ret; } return GDALVersionInfo($request); } sub GetDriver { my ($i) = @_; my $d = isint($i) ? GDALGetDriver($i) : GDALGetDriverByName($i); confess error_msg() // "Driver '$i' not found." unless $d; return bless \$d, 'Geo::GDAL::FFI::Driver'; } sub GetDrivers { my @drivers; for my $i (0..GDALGetDriverCount()-1) { push @drivers, GetDriver($i); } return @drivers; } sub IdentifyDriver { my ($filename, $args) = @_; my $flags = 0; my $a = $args->{Flags} // []; for my $f (@$a) { print "$f\n"; $flags |= $open_flags{$f}; } print "$flags\n"; my $drivers = 0; for my $o (@{$args->{AllowedDrivers}}) { $drivers = Geo::GDAL::FFI::CSLAddString($drivers, $o); } my $list = 0; for my $o (@{$args->{FileList}}) { $list = Geo::GDAL::FFI::CSLAddString($list, $o); } my $d; if ($flags or $drivers) { $d = GDALIdentifyDriverEx($filename, $flags, $drivers, $list); } else { $d = GDALIdentifyDriver($filename, $list); } Geo::GDAL::FFI::CSLDestroy($drivers); Geo::GDAL::FFI::CSLDestroy($list); return bless \$d, 'Geo::GDAL::FFI::Driver'; } sub Open { my ($name, $args) = @_; $name //= ''; $args //= {}; my $flags = 0; my $a = $args->{Flags} // []; for my $f (@$a) { $flags |= $open_flags{$f}; } my $drivers = 0; for my $o (@{$args->{AllowedDrivers}}) { $drivers = Geo::GDAL::FFI::CSLAddString($drivers, $o); } my $options = 0; for my $o (@{$args->{Options}}) { $options = Geo::GDAL::FFI::CSLAddString($options, $o); } my $files = 0; for my $o (@{$args->{SiblingFiles}}) { $files = Geo::GDAL::FFI::CSLAddString($files, $o); } my $ds = GDALOpenEx($name, $flags, $drivers, $options, $files); Geo::GDAL::FFI::CSLDestroy($drivers); Geo::GDAL::FFI::CSLDestroy($options); Geo::GDAL::FFI::CSLDestroy($files); if (@errors) { my $msg = join("\n", @errors); @errors = (); confess $msg; } unless ($ds) { # no VERBOSE_ERROR in options and fail confess "Open failed for '$name'. Hint: add VERBOSE_ERROR to open_flags."; } return bless \$ds, 'Geo::GDAL::FFI::Dataset'; } sub write { print STDOUT $_[0]; } sub close { } sub SetWriter { my ($self, $writer) = @_; $writer = $self unless $writer; my $w = $writer->can('write'); my $c = $writer->can('close'); confess "$writer must be able to write and close." unless $w && $c; #$self->{write} = $w; $self->{close} = $c; $self->{writer} = $self->{ffi}->closure(sub { my ($buf, $size, $count, $stream) = @_; my $retval = $w->(buffer_to_scalar($buf, $size*$count)) // 1; return $retval; }); VSIStdoutSetRedirection($self->{writer}, 0); } sub CloseWriter { my $self = shift; $self->{close}->() if $self->{close}; $self->SetWriter; } sub get_importer { my ($self, $format) = @_; my $importer = $self->can('OSRImportFrom' . $format); confess "Spatial reference importer for format '$format' not found!" unless $importer; return $importer; } sub get_exporter { my ($self, $format) = @_; my $exporter = $self->can('OSRExportTo' . $format); confess "Spatial reference exporter for format '$format' not found!" unless $exporter; return $exporter; } sub get_setter { my ($self, $proj) = @_; my $setter = $self->can('OSRSet' . $proj); confess "Parameter setter for projection '$proj' not found!" unless $setter; return $setter; } sub HaveGEOS { my $t = $geometry_types{Point}; my $g = OGR_G_CreateGeometry($t); OGR_G_SetPoint($g, 0, 0, 0, 0); my $c = OGR_G_CreateGeometry($t); my $n = @errors; OGR_G_Centroid($g, $c); if (@errors > $n) { pop @errors; return undef; } else { return 1; } } sub SetConfigOption { my ($key, $default) = @_; CPLSetConfigOption($key, $default); } sub GetConfigOption { my ($key, $default) = @_; return CPLGetConfigOption($key, $default); } sub FindFile { my ($class, $basename) = @_ == 2 ? @_ : ('', @_); $class //= ''; $basename //= ''; return CPLFindFile($class, $basename); } sub PushFinderLocation { my ($location) = @_; $location //= ''; CPLPushFinderLocation($location); } sub PopFinderLocation { CPLPopFinderLocation(); } sub FinderClean { CPLFinderClean(); } BEGIN { require PkgConfig; PkgConfig->import; my $gdal; eval { require Geo::GDAL::gdal; $gdal = Geo::GDAL::gdal->new(); }; if ($@) { require Alien::gdal; no strict 'subs'; $gdal = Alien::gdal; } $instance = Geo::GDAL::FFI->new($gdal); } { # avoid some used only once warnings local $FFI::Platypus::keep; local $FFI::Platypus::TypeParser::ffi_type; } # # The next two subs are required for thread-safety, because GDAL error handling must be set per thread. # So, it is disabled just before starting a new thread and renabled after in the thread. # See perlmod and issue #53 for more information. # sub CLONE { SetErrorHandling(); } sub CLONE_SKIP { UnsetErrorHandling(); return 0; } 1; =pod =encoding UTF-8 =head1 NAME Geo::GDAL::FFI - A foreign function interface to GDAL =head1 VERSION Version 0.11 =head1 SYNOPSIS This is an example of creating a vector dataset. use Geo::GDAL::FFI qw/GetDriver/; my $sr = Geo::GDAL::FFI::SpatialReference->new(EPSG => 3067); my $layer = GetDriver('ESRI Shapefile') ->Create('test.shp') ->CreateLayer({ Name => 'test', SpatialReference => $sr, GeometryType => 'Point', Fields => [ { Name => 'name', Type => 'String' } ] }); my $f = Geo::GDAL::FFI::Feature->new($layer->GetDefn); $f->SetField(name => 'a'); my $g = Geo::GDAL::FFI::Geometry->new('Point'); $g->SetPoint(1, 2); $f->SetGeomField($g); $layer->CreateFeature($f); This is an example of reading a vector dataset. use Geo::GDAL::FFI qw/Open/; my $layer = Open('test.shp')->GetLayer; $layer->ResetReading; while (my $feature = $layer->GetNextFeature) { my $value = $feature->GetField('name'); my $geom = $feature->GetGeomField; say $value, ' ', $geom->AsText; } This is an example of creating a raster dataset. use Geo::GDAL::FFI qw/GetDriver/; my $tiff = GetDriver('GTiff')->Create('test.tiff', 3, 2); my $ogc_wkt = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS84",6378137,298.257223563,'. 'AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,'. 'AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,'. 'AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]'; $tiff->SetProjectionString($ogc_wkt); my $transform = [10,2,0,20,0,3]; $tiff->SetGeoTransform($transform); my $data = [[0,1,2],[3,4,5]]; $tiff->GetBand->Write($data); This is an example of reading a raster dataset. Note that using L and L can greatly reduce the time needed to process large raster datasets. use Geo::GDAL::FFI qw/Open/; my $band = Open($ARGV[0])->GetBand; my ($w_band, $h_band) = $band->GetSize; my ($w_block, $h_block) = $band->GetBlockSize; my $nodata = $band->GetNoDataValue; my ($xoff, $yoff) = (0,0); my ($min, $max); while (1) { if ($xoff >= $w_band) { $xoff = 0; $yoff += $h_block; last if $yoff >= $h_band; } my $w_real = $w_band - $xoff; $w_real = $w_block if $w_real > $w_block; my $h_real = $h_band - $yoff; $h_real = $h_block if $h_real > $h_block; my $data = $band->Read($xoff, $yoff, $w_real, $h_real); for my $y (0..$#$data) { my $row = $data->[$y]; for my $x (0..$#$row) { my $value = $row->[$x]; next if defined $nodata && $value == $nodata; $min = $value if !defined $min || $value < $min; $max = $value if !defined $max || $value > $max; } } $xoff += $w_block; } say "min = $min, max = $max"; =head1 DESCRIPTION This is a foreign function interface to the GDAL geospatial data access library. =head1 IMPORTABLE FUNCTIONS The most important importable functions are GetDriver and Open, which return a driver and a dataset objects respectively. GetDrivers returns all available drivers as objects. Other importable functions include error handling configuration (SetErrorHandling and UnsetErrorHandling), functions that return lists of strings that are used in methods (Capabilities, OpenFlags, DataTypes, ResamplingMethods, FieldTypes, FieldSubtypes, Justifications, ColorInterpretations, GeometryTypes, GeometryFormats, GridAlgorithms), also functions GetVersionInfo, HaveGEOS, SetConfigOption, GetConfigOption, FindFile, PushFinderLocation, PopFinderLocation, and FinderClean can be imported. :all imports all above functions. =head2 GetVersionInfo my $info = GetVersionInfo($request); Returns the version information from the underlying GDAL library. $request is optional and by default 'VERSION_NUM'. =head2 GetDriver my $driver = GetDriver($name); Returns the specific driver object. =head2 GetDrivers Returns a list of all available driver objects. =head2 Open my $dataset = Open($name, {Flags => [qw/READONLY/], ...}); Open a dataset. $name is the name of the dataset. Named arguments are the following. =over 4 =item C Optional, default is a reference to an empty array. Note that some drivers can open both raster and vector datasets. =item C Optional, default is all drivers. Use a reference to an array of driver names to limit which drivers to test. =item C Optional, default is to probe the file system. You may use a reference to an array of auxiliary file names. =item C Optional, a reference to an array of driver specific open options. Consult the main GDAL documentation for open options. =back =head2 Capabilities Returns the list of capabilities (strings) a GDAL major object (Driver, Dataset, Band, or Layer in Geo::GDAL::FFI) can have. =head2 OpenFlags Returns the list of opening flags to be used in the Open method. =head2 DataTypes Returns the list of raster cell data types to be used in e.g. the CreateDataset method of the Driver class. =head2 FieldTypes Returns the list of field types. =head2 FieldSubtypes Returns the list of field subtypes. =head2 Justifications Returns the list of field justifications. =head2 ColorInterpretations Returns the list of color interpretations. =head2 GeometryTypes Returns the list of geometry types. =head2 SetErrorHandling Set a Perl function to catch errors reported within GDAL with CPLError. The errors are collected into @Geo::GDAL::FFI::errors and confessed if a method fails. This is the default. =head2 UnsetErrorHandling Unset the Perl function to catch GDAL errors. If no other error handler is set, GDAL prints the errors into stderr. =head1 NOTES ABOUT THREAD-SAFETY This module is thread-safe provided the error handling is taken care of. To ensure thread-safety GDAL error handling is automatically disabled before creating a new thread and re-enabled after that in the just created thread. The main thread needs to renable it via C, after all thread creations and before eventually using any GDAL function. This must be done explicitly in the main thread because there is no way to do that automatically as for other threads. =head1 METHODS =head2 get_instance my $gdal = Geo::GDAL::FFI->get_instance; Obtain the Geo::GDAL::FFI singleton object. The object is usually not needed. =head1 LICENSE This software is released under the Artistic License. See L. =head1 AUTHOR Ari Jolma - Ari.Jolma at gmail.com =head1 SEE ALSO L L L L L L L L L L L L L L, L, L =cut __END__; Geo-GDAL-FFI-0.12/build-tools/0000755000175500017550000000000014634407013014542 5ustar pausepauseGeo-GDAL-FFI-0.12/build-tools/README0000644000175500017550000000115714215214043015420 0ustar pausepauseFFI::Platypus object is attached to foreign functions using 'attach' method call. These calls are in lib/Geo/GDAL/FFI.pm. parse_h.pl is a program to create these calls (wrapped in eval{};) from C/C++ header files. Currently it is used for the following header files: gcore/gdal.h ogr/ogr_api.h ogr/ogr_srs_api.h apps/gdal_utils.h To update lib/Geo/GDAL/FFI.pm run parse_h.pl with those files as arguments and paste the output to lib/Geo/GDAL/FFI.pm. Some foreign functions that are defined in header files port/*.h ogr/ogr_core.h are attached using manually written calls in lib/Geo/GDAL/FFI.pm. Geo-GDAL-FFI-0.12/build-tools/parse_h.pl0000644000175500017550000004641014634406006016526 0ustar pausepauseuse v5.10; use strict; use warnings; my $gdal_src_root = shift @ARGV; my @h_files = ( 'gcore/gdal.h', 'ogr/ogr_api.h', 'ogr/ogr_srs_api.h', 'apps/gdal_utils.h', #'alg/gdal_alg.h' ); my %pre = ( CPL_C_START => '', CPL_DLL => '', CPL_STDCALL => '', CPL_WARN_UNUSED_RESULT => '', CPL_RESTRICT => '' ); my %constants = ( GDALDataType => 1, GDALAsyncStatusType => 1, GDALColorInterp => 1, GDALPaletteInterp => 1, GDALAccess => 1, GDALRWFlag => 1, OGRwkbGeometryType => 1, GDALRATFieldUsage => 1, GDALRATFieldType => 1, GDALRATTableType => 1, GDALTileOrganization => 1, OGRwkbByteOrder => 1, OGRFieldType => 1, OGRFieldSubType => 1, OGRJustification => 1, OGRSTClassId => 1, OGRSTUnitId => 1, OGRAxisOrientation => 1, GDALGridAlgorithm => 1, GDALRelationshipCardinality => 1, GDALRelationshipType => 1, GDALViewshedMode => 1, GDALViewshedOutputType => 1, OGRwkbVariant => 1, ); my %callbacks = ( CPLErrorHandler => 1, GDALProgressFunc => 1, GDALDerivedPixelFunc => 1, GDALTransformerFunc => 1, GDALContourWriter => 1, GDALQueryLoggerFunc => 1, GDALVRTProcessedDatasetFuncInit => 1, GDALVRTProcessedDatasetFuncFree => 1, GDALVRTProcessedDatasetFuncProcess => 1, ); my %char_p_p_ok = ( OGR_G_CreateFromWkt => 1, OGR_G_ImportFromWkt => 1, OGR_G_ExportToWkt => 1, OGR_G_ExportToIsoWkt => 1, OSRExportToWkt => 1, OSRExportToPrettyWkt => 1, OSRExportToProj4 => 1, OSRExportToPCI => 1, OSRExportToXML => 1, OSRExportToMICoordSys => 1, GDALDatasetReadCompressedData => 1, GDALDatasetAddFieldDomain => 1, GDALDatasetDeleteFieldDomain => 1, GDALDatasetUpdateFieldDomain => 1, GDALDatasetAddRelationship => 1, GDALDatasetDeleteRelationship => 1, GDALDatasetUpdateRelationship => 1, GDALLoadTabFile => 1, GDALReadTabFile => 1, GDALLoadOziMapFile => 1, GDALReadOziMapFile => 1, OSRImportFromWkt => 1, 'OSRExportToWktEx.ppszResult' => 1, 'OSRExportToPROJJSON.ppszReturn' => 1, OSRGetAngularUnits => 1, OSRGetLinearUnits => 1, OSRGetTargetLinearUnits => 1, OSRGetPrimeMeridian => 1, ); my %use_CSL = ( GDALCreate => 1, GDALOpenEx => 1, GDALCreateCopy => 1, GDALGetMetadataDomainList => 1, GDALIdentifyDriver => 1, GDALIdentifyDriverEx => 1, GDALValidateCreationOptions => 1, GDALGetMetadata => 1, GDALSetMetadata => 1, GDALGetFileList => 1, GDALAddBand => 1, GDALDatasetCreateLayer => 1, GDALDatasetCopyLayer => 1, OGR_DS_CreateLayer => 1, OGR_DS_CopyLayer => 1, OGR_Dr_CreateDataSource => 1, OGR_Dr_CopyDataSource => 1, GDALGetRasterCategoryNames => 1, OGR_F_GetFieldAsStringList => 1, OGR_F_SetFieldStringList => 1, OGR_F_FillUnsetWithDefault => 1, OGR_G_ExportToGMLEx => 1, OGR_G_ExportToJsonEx => 1, OGR_G_ForceTo => 1, OGR_G_GetLinearGeometry => 1, OGR_G_GetCurveGeometry => 1, GDALInfoOptionsNew => 1, GDALTranslateOptionsNew => 1, GDALWarpAppOptionsNew => 1, GDALVectorTranslateOptionsNew => 1, GDALDEMProcessingOptionsNew => 1, GDALNearblackOptionsNew => 1, GDALGridOptionsNew => 1, GDALRasterizeOptionsNew => 1, GDALBuildVRTOptionsNew => 1, GDALBuildVRT => 1, OGR_L_Intersection => 1, OGR_L_Union => 1, OGR_L_SymDifference => 1, OGR_L_Identity => 1, OGR_L_Update => 1, OGR_L_Clip => 1, OGR_L_Erase => 1, OGR_L_GetArrowStream => 1, GDALDatasetGetCompressionFormats => 1, GDALRasterBandCopyWholeRaster => 1, GDALDatasetGetFieldDomainNames => 1, GDALDatasetGetRelationshipNames => 1, GDALRelationshipGetLeftTableFields => 1, GDALRelationshipGetRightTableFields => 1, GDALRelationshipGetLeftMappingTableFields => 1, GDALRelationshipGetRightMappingTableFields => 1, GDALGroupGetMDArrayNames => 1, GDALGroupGetGroupNames => 1, GDALGroupGetVectorLayerNames => 1, GDALAttributeReadAsStringArray => 1, OSRSetPROJSearchPaths => 1, OSRGetPROJSearchPaths => 1, OSRSetPROJAuxDbPaths => 1, OSRGetPROJAuxDbPaths => 1, OSRImportFromESRI => 1, OSRImportFromOzi => 1, 'OSRExportToWktEx.papszOptions' => 1, 'OSRExportToPROJJSON.papszOptions' => 1, OSRConvertToOtherProjection => 1, OSRIsSameEx => 1, OSRFindMatches => 1, GDALMultiDimInfoOptionsNew => 1, GDALMultiDimTranslateOptionsNew => 1, GDALVectorInfoOptionsNew => 1, ); # these return strings which must be freed my %use_ret_opaque = ( OGR_G_ExportToGML => 1, OGR_G_ExportToGMLEx => 1, OGR_G_ExportToKML => 1, OGR_G_ExportToJson => 1, OGR_G_ExportToJsonEx => 1, ); my %ret_string_ok = ( GDALGetDataTypeName => 1, GDALGetAsyncStatusTypeName => 1, GDALGetColorInterpretationName => 1, GDALGetPaletteInterpretationName => 1, GDALGetDriverShortName => 1, GDALGetDriverLongName => 1, GDALGetDriverHelpTopic => 1, GDALGetDriverCreationOptionList => 1, GDALGetMetadataItem => 1, GDALGetDescription => 1, GDALGetProjectionRef => 1, GDALGetGCPProjection => 1, GDALGetRasterUnitType => 1, GDALDecToDMS => 1, OGR_G_GetGeometryName => 1, ); my %use_array = ( OGR_F_SetFieldIntegerList => 1, OGR_F_SetFieldInteger64List => 1, OGR_F_SetFieldDoubleList => 1, GDALInvGeoTransform => 1, OCTTransform => 1, OCTTransformEx => 1, OCTTransform4D => 1, OCTTransform4DWithErrorCodes => 1, OCTTransformBounds => 1, GDALUseTransformer => 1, GDALGenImgProjTransform => 1, GDALReprojectionTransform => 1, GDALGCPTransform => 1, GDALTPSTransform => 1, GDALRPCTransform => 1, GDALGeoLocTransform => 1, GDALApproxTransform => 1, OGRContourWriter => 1, GDALContourGenerate => 1, GDALRasterizeGeometries => 1, GDALRasterizeGeometriesInt64 => 1, GDALRasterizeLayers => 1, GDALRasterizeLayersBuf => 1, GDALGridCreate => 1, GDALGridContextCreate => 1, GDALTriangulationCreateDelaunay => 1, GDALTriangulationComputeBarycentricCoefficients => 1, ); my %use_array6 = ( GDALGetGeoTransform => 1, GDALSetGeoTransform => 1, GDALComposeGeoTransforms => 1, GDALInvGeoTransform => 1, GDALSetTransformerDstGeoTransform => 1, GDALGetTransformerDstGeoTransform => 1, GDALCreateGenImgProjTransformer3 => 1, GDALCreateGenImgProjTransformer4 => 1, GDALSetGenImgProjTransformerDstGeoTransform => 1, ); my %use_opaque_array = ( GDALWarp => 1, GDALVectorTranslate => 1, GDALBuildVRT => 1, GDALRasterizeLayersBuf => 1, ); my %use_ret_pointer = ( OGR_F_GetFieldAsIntegerList => 1, OGR_F_GetFieldAsInteger64List => 1, OGR_F_GetFieldAsDoubleList => 1, ); my %use_string = ( OGR_G_CreateFromWkb => 1, OGR_G_CreateFromFgf => 1, OGR_G_ImportFromWkb => 1, ); my %opaque_pointers = ( GDAL_GCP => 1, GDALRPCInfo => 1, CPLXMLNode => 1, GDALRasterIOExtraArg => 1, GDALGridContext => 1, CPLVirtualMem => 1, OGRField => 1, GDALInfoOptions => 1, GDALInfoOptionsForBinary => 1, GDALTranslateOptions => 1, GDALTranslateOptionsForBinary => 1, GDALWarpAppOptions => 1, GDALWarpAppOptionsForBinary => 1, GDALVectorTranslateOptions => 1, GDALVectorTranslateOptionsForBinary => 1, GDALDEMProcessingOptions => 1, GDALDEMProcessingOptionsForBinary => 1, GDALNearblackOptions => 1, GDALNearblackOptionsForBinary => 1, GDALGridOptions => 1, GDALGridOptionsForBinary => 1, GDALRasterizeOptions => 1, GDALRasterizeOptionsForBinary => 1, GDALBuildVRTOptions => 1, GDALBuildVRTOptionsForBinary => 1, OGRGeometryTypeCounter => 1, ArrowArrayStream => 1, GDALVectorInfoOptions => 1, GDALVectorInfoOptionsForBinary => 1, ArrowSchema => 1, ArrowArray => 1, GDALFootprintOptions => 1, GDALFootprintOptionsForBinary => 1, GDALRPCInfoV2 => 1, GDALViewshedMode => 1, OGRwkbExportOptions =>1, GDALTileIndexOptions => 1, GDALTileIndexOptionsForBinary => 1, ); my %defines; my %enums; my %structs; say "# generated with parse_h.pl"; for my $f (@h_files) { say STDERR "parsing $f"; say "# from $f"; parse_h($gdal_src_root . '/' . $f); } say "# end of generated code"; sub parse_h { my $f = shift; open(my $fh, '<', $f) or die "can't open $f: $!"; my $s = ''; while (1) { my $n = pre_process($fh); #say STDERR "top: ",$n; last unless defined $n; $s .= ' '.$n; next unless $s =~ /;/; $s =~ s/^\s+//; $s =~ s/\s+$//; $s =~ tr/ //s; if ($s =~ /^typedef enum/) { $enums{$s} = 1; $s = ''; next; } if ($s =~ /^typedef struct .*?\{/) { my $struct = $s; while (1) { my $n = pre_process($fh); die "eof while parsing typedef struct" unless defined $n; # look for "} name;" $struct .= ' '.$n; if ($struct =~ /\} \w+;/) { last; } } $structs{$struct} = 1; $s = ''; next; } if ($s =~ /^typedef/) { $s = ''; next; } if ($s =~ /^struct/) { $s = ''; next; } # now $s should be a function #say 'line: ',$s; if ($s =~ /(\w+)\s*\((.*?)\)/) { my $name = $1; my $args = $2; my $ret = $s; $ret =~ s/$name.*//; $ret = parse_type($name, $ret, 'ret', 0); #print "parse type returns: $ret\n"; my @args = split /\s*,\s*/, $args; my $qw = 1; my $idx = 0; for my $arg (@args) { $arg = parse_type($name, $arg, 'arg', $idx++); #print "parse type returns: $arg\n"; $qw = 0 if $arg =~ /\s/; } #say "ret: $ret"; #say "name: $name"; #say "args: @args"; if (@args == 1 && $args[0] eq 'void') { $args = ''; } elsif ($qw) { $args = "qw/@args/"; } else { $args = "'".join("','", @args)."'"; } say "\$ffi->attach('$name' => [$args] => '$ret');"; } else { die "can't parse $s as function"; } $s = ''; } close $fh; } sub parse_type { my ($name, $arg, $mode, $argno) = @_; $arg =~ s/^\s+//; $arg =~ s/\s+$//; my $var = ''; $var = $1 if $arg =~ /(\w+)$/; #print "parse type: argno=$argno name=$name arg=$arg var=$var mode$mode\n"; for my $c (keys %constants) { if ($arg =~ /^$c/ or $arg =~ /^const $c/) { $arg = 'unsigned int'; } } for my $c (keys %callbacks) { if ($arg =~ /^$c/) { return $c; } } for my $c (keys %opaque_pointers) { if ($arg =~ /$c\s*\*/) { return 'opaque'; } } if ($arg =~ /^\w+?H\s*\*/) { if ($use_opaque_array{$name}) { $arg = 'opaque[]'; } else { $arg = 'uint64*'; } } elsif ($arg =~ /^\w+?H/) { $arg = 'opaque'; } elsif ($arg =~ /^const \w+?H/) { $arg = 'opaque'; } elsif ($arg =~ /GDALColorEntry\s*\*/) { $arg = 'short[4]'; } elsif ($arg =~ /OGREnvelope\s*\*/) { $arg = 'double[4]'; } elsif ($arg =~ /OGREnvelope3D\s*\*/) { $arg = 'double[6]'; } elsif ($arg =~ /GDALTriangulation/) { $arg = 'opaque'; # todo: actually a record } elsif ($arg =~ /^FILE\s*\*/) { $arg = 'opaque'; } elsif ($arg =~ /void\s*\*/) { for my $c (keys %use_string) { if ($c eq $name) { say STDERR "$name returns a string" if $mode eq 'ret' && !$ret_string_ok{$name}; return 'string'; } } $arg = 'opaque'; } elsif ($arg =~ /^char\s*\*\*/ or $arg =~ /^const char\s*\*\s*const\s*\*/) { if ($use_CSL{$name} or $use_CSL{$name.'.'.$var}) { $arg = 'opaque'; } else { my $ok = $char_p_p_ok{$name} || $char_p_p_ok{$name.'.'.$var}; say STDERR "$name returns a string*" unless $ok; $arg = 'string*'; } } elsif ($arg =~ /char\s*\*/) { if ($mode eq 'ret' && $use_ret_opaque{$name}) { $arg = 'opaque'; } else { say STDERR "$name returns a string" if $mode eq 'ret' && !$ret_string_ok{$name}; $arg = 'string'; } } elsif ($arg =~ /^unsigned char\s*\*/) { $arg = 'pointer'; } elsif ($arg =~ /int\s*\*/) { if ($use_array{$name}) { $arg = 'int[]'; } elsif ($mode eq 'ret' && $use_ret_pointer{$name}) { $arg = 'pointer'; } else { $arg = 'int*'; } } elsif ($arg =~ /^(const )?int/) { $arg = 'int'; } elsif ($arg =~ /^unsigned int\s*\*/) { $arg = 'unsigned int*'; } elsif ($arg =~ /^unsigned int/) { $arg = 'unsigned int'; } elsif ($arg =~ /^long\s*\*/) { $arg = 'long*'; } elsif ($arg =~ /^long/) { $arg = 'long'; } elsif ($arg =~ /double\s*\*/) { if ($use_array6{$name}) { $arg = 'double[6]'; } elsif ($name eq 'GDALApplyGeoTransform' and $argno == 0) { $arg = 'double[6]'; } elsif ($name eq 'GDALSuggestedWarpOutput' and $argno == 3) { $arg = 'double[6]'; } elsif ($name eq 'GDALSuggestedWarpOutput2' and $argno == 3) { $arg = 'double[6]'; } elsif ($name eq 'GDALSuggestedWarpOutput2' and $argno == 6) { $arg = 'double[4]'; } elsif ($use_array{$name}) { $arg = 'double[]'; } elsif ($mode eq 'ret' && $use_ret_pointer{$name}) { $arg = 'pointer'; } else { $arg = 'double*'; } } elsif ($arg =~ /^(const )?double/) { $arg = 'double'; } elsif ($arg =~ /float\s*\*/) { $arg = 'float*'; } elsif ($arg =~ /float/) { $arg = 'float'; } elsif ($arg =~ /^CPLErr/) { $arg = 'int'; } elsif ($arg =~ /^OGRErr\s*\*/) { $arg = 'int*'; } elsif ($arg =~ /^OGRErr/) { $arg = 'int'; } elsif ($arg =~ /^size_t/) { $arg = 'size_t'; } elsif ($arg =~ /^const size_t/) { $arg = 'size_t'; } elsif ($arg =~ /GByte\s*\*/) { $arg = 'pointer'; } elsif ($arg =~ /^GUInt32\s*\*/) { $arg = 'uint32*'; } elsif ($arg =~ /^GUInt32/) { $arg = 'uint32'; } elsif ($arg =~ /^const GInt64\s*\*/) { $arg = 'sint64'; } elsif ($arg =~ /^GUInt64/ || $arg =~ /^uint64_t/) { $arg = 'uint64'; } elsif ($arg =~ /^const GUInt64\s*\*/) { $arg = 'uint64*'; } elsif ($arg =~ /^GUIntBig\s*\*/) { $arg = 'uint64*'; } elsif ($arg =~ /^GUIntBig/) { $arg = 'uint64'; } elsif ($arg =~ /GIntBig\s*\*/) { if ($use_array{$name}) { $arg = 'sint64[]'; } elsif ($mode eq 'ret' && $use_ret_pointer{$name}) { $arg = 'pointer'; } else { $arg = 'sint64*'; } } elsif ($arg =~ /^GIntBig/ or $arg =~ /^GSpacing/) { $arg = 'sint64'; } elsif ($arg =~ /^void/) { $arg = 'void'; } elsif ($arg =~ /^CSLConstList/) { $arg = 'opaque'; } elsif ($arg =~ /^GPtrDiff_t/) { $arg = 'int'; } elsif ($arg =~ /^const GPtrDiff_t\s*\*/) { $arg = 'int*'; } elsif ($arg =~ /^GDALExtendedDataTypeClass/) { $arg = 'int'; } elsif ($arg =~ /^OSRAxisMappingStrategy/) { $arg = 'int'; } elsif ($arg =~ /^OSRCRSInfo/) { $arg = 'opaque'; } elsif ($arg =~ /^(const )?OSRCRSListParameters/) { $arg = 'opaque'; } elsif ($arg =~ /^(const )?GDALMultiDimInfoOptions/) { $arg = 'opaque'; } elsif ($arg =~ /^(const )?GDALMultiDimTranslateOptions/) { $arg = 'opaque'; } elsif ($arg =~ /^bool/) { $arg = 'bool'; } elsif ($arg =~ /^GDALRPCInfoV1/) { $arg = 'opaque'; } elsif ($arg =~ /^GDALRPCInfoV2/) { $arg = 'opaque'; } elsif ($arg =~ /^GDALExtendedDataTypeSubType/) { $arg = 'int'; } elsif ($arg =~ /^GDALRIOResampleAlg/) { $arg = 'int'; } elsif ($arg =~ /^OGRFieldDomainType/) { $arg = 'int'; } elsif ($arg =~ /^OGRFieldDomainSplitPolicy/) { $arg = 'int'; } elsif ($arg =~ /^OGRFieldDomainMergePolicy/) { $arg = 'int'; } elsif ($arg =~ /^(const )?OGRCodedValue/) { $arg = 'int'; } else { die "can't parse arg '$arg'"; } #print "return $arg\n"; return $arg; } sub pre_process { state $skip = 0; my $fh = shift; while (1) { my $s = ''; while (1) { my $n = get_line($fh); #say STDERR "got: ",$n; return if !defined($n) && $s eq ''; return $s unless defined $n; $s .= ' '.$n; last unless $s =~ /\\$/; } $s =~ s/^\s+//; $s =~ s/\s+$//; $s =~ tr/ //s; $s =~ s/^#\s+/#/; if ($s =~ /^#ifndef (\w+)/) { next; } if ($s =~ /^#ifdef (\w+)/ or $s =~ /^#if defined\((\w+)\)/) { if ( $1 eq 'DEBUG' or $1 eq 'undef' or $1 eq 'GDAL_COMPILATION' or $1 eq 'USE_DEPRECATED_SRS_WKT_WGS84' ) { $skip = 1; next; } } if ($s =~ /^#else/) { $skip = 0 if $skip; next; } if ($s =~ /^#define (\w+) (.*)/) { $defines{$1} = $2; next; } # skip all other defines if ($s =~ /^#define/) { next; } if ($s =~ /^#include/) { next; } if ($s =~ /^#endif/) { $skip = 0 if $skip; next; } next if $skip; return $s; } } sub get_line { state $state = ''; my $fh = shift; my $s = <$fh>; return unless $s; chomp $s; #say STDERR 'line: ',$s; if ($state eq 'comment') { if ($s =~ /\*\//) { $s =~ s/.*?\*\///; $state = ''; } else { return ''; } } # replace pre-defined constants for my $def (keys %pre) { $s =~ s/$def/$pre{$def}/; } # remove on-line comments if ($s =~ /\/\*/ and $s =~ /\*\//) { $s =~ s/\/\*.*?\*\///; } $s =~ s/\/\/.*//; # remove starting comment and set state if ($s =~ /\/\*/) { $s =~ s/\/\*.*//; $state = 'comment'; } return $s; } Geo-GDAL-FFI-0.12/Makefile.PL0000644000175500017550000000235314632174576014277 0ustar pausepauseuse strict; use warnings; use ExtUtils::MakeMaker 6.52; use Config; my %args = ( AUTHOR => ['Ari Jolma '], NAME => 'Geo::GDAL::FFI', ABSTRACT_FROM => "lib/Geo/GDAL/FFI.pm", VERSION_FROM => "lib/Geo/GDAL/FFI.pm", LICENSE => "artistic_2", CONFIGURE_REQUIRES => { 'Alien::gdal' => 0, }, PREREQ_PM => { 'PkgConfig' => 0.23026, 'FFI::Platypus' => 0, 'PDL' => 0, 'Sort::Versions' => 0, 'Alien::gdal' => 0, }, TEST_REQUIRES => { 'Test::More' => 0, 'Test::Exception' => 0, 'JSON' => 0, 'Data::Dumper' => 0, 'Path::Tiny' => 0, 'Test::TempDir::Tiny' => 0, }, META_MERGE => { "meta-spec" => { version => 2 }, resources => { repository => { type => 'git', url => 'git://github.com/ajolma/Geo-GDAL-FFI.git', web => 'https://github.com/ajolma/Geo-GDAL-FFI', }, bugtracker => { web => 'https://github.com/ajolma/Geo-GDAL-FFI/issues/', }, }, }, ); WriteMakefile(%args); Geo-GDAL-FFI-0.12/Changes0000644000175500017550000000377514634406646013627 0ustar pausepauseRevision history for Perl extension Geo::GDAL::FFI 0.12 June 19, 2024 - improved header parsing, updated to GDAL 3.9 (GH#79, @fpl++) - Package is now thread-safe (GH#69, @fpl++) - Makefile.PL: get all the info from Alien::gdal (GH#77) 0.11 December 19, 2023 - Removed use of to FFI::Platypus::Declare, now discouraged. - Add Layer::GetFeatureCount method - Bugfixes 0.10 July 10, 2023 - Add dependency to FFI::Platypus::Declare - Update from GDAL 3.4 and add MakeValid method to Geometry - Add Normalize method to Geometry - Update to gdal 3.7 - Make Band inherit from Object 0.09 Mar 16, 2021 - ? 0.08 May 15, 2020 - Update GDAL API to 3.1.0 - add a Dataset::GetLayerCount method - Add POD for GetLayerCount - Add Dataset::GetLayerCount method - Raise exceptions when invalid layers are accessed via Dataset::GetLayer - Better handling of GDAL warnings and debug messages. 0.07 Dec 9, 2018 - Layer GetExtent, GetName, GetParentDataset - Dataset ExecuteSQL - Geometry GetEnvelope, GetEnvelope3D 0.06 Nov 8, 2018 - BREAKING CHANGE: GetDriver and Open are not methods any more. - Refuse to handle 64 bit int data in non-64 bit Perl - Handle CSL arguments in GDAL API - Layer Intersection etc methods - Geometry exporter methods - Initialization in BEGIN 0.05_03 May 16, 2018 (yet another test release) - Set GDAL_DATA only if gdal.pc is found and datadir exists. 0.05_02 May 16, 2018 (yet another test release) - If Perl does not support 64 bit integers, frown upon them as field values 0.05 May 16, 2018 - Explitly set GDAL_DATA 0.04 May 2, 2018 - HaveGEOS method for tests. 0.03 Apr 27, 2018 - Replace failed 0.02. 0.02 Apr 27, 2018 - Fix get/set for GDAL metadata. - Separate classes into their own files. 0.01 Apr 6, 2018 - Included all basic functionality but lots of docs and methods to do.