Geoinformatica  0.90
Copy.pm
Go to the documentation of this file.
1 #** @file Copy.pm
2 #*
3 
4 package Geo::Raster::Layer::Dialogs::Copy;
5 
6 use strict;
7 use warnings;
8 use Carp;
9 use Glib qw/TRUE FALSE/;
10 use Gtk2::Ex::Geo::Dialogs qw/:all/;
12 
13 sub open {
14  my($self, $gui) = @_;
15 
16  # bootstrap:
17  my($dialog, $boot) = $self->bootstrap_dialog
18  ($gui, 'copy_raster_dialog', "Copy ".$self->name,
19  {
20  copy_raster_dialog => [delete_event => \&cancel_copy, [$self, $gui]],
21  copy_cancel_button => [clicked => \&cancel_copy, [$self, $gui]],
22  copy_ok_button => [clicked => \&do_copy, [$self, $gui, 1]],
23  from_EPSG_entry => [changed => \&Geo::Raster::Layer::epsg_help],
24  to_EPSG_entry => [changed => \&Geo::Raster::Layer::epsg_help],
25  copy_folder_button => [clicked => \&copy_select_folder, $self],
26  },
27  );
28 
29  if ($boot) {
30  my $from = $dialog->get_widget('from_EPSG_entry');
31  my $auto = Gtk2::EntryCompletion->new;
32  $auto->set_match_func(sub {1});
33  my $list = Gtk2::ListStore->new('Glib::String');
34  $auto->set_model($list);
35  $auto->set_text_column(0);
36  $from->set_completion($auto);
37 
38  my $to = $dialog->get_widget('to_EPSG_entry');
39  $auto = Gtk2::EntryCompletion->new;
40  $auto->set_match_func(sub {1});
41  $list = Gtk2::ListStore->new('Glib::String');
42  $auto->set_model($list);
43  $auto->set_text_column(0);
44  $to->set_completion($auto);
45 
46  my $combo = $dialog->get_widget('copy_driver_combobox');
47  my $renderer = Gtk2::CellRendererText->new;
48  $combo->pack_start ($renderer, TRUE);
49  $combo->add_attribute ($renderer, text => 0);
50  $combo->signal_connect(changed=>\&copy_driver_selected, [$self, $gui]);
51 
52  $combo = $dialog->get_widget('copy_datatype_combobox');
53  $renderer = Gtk2::CellRendererText->new;
54  $combo->pack_start ($renderer, TRUE);
55  $combo->add_attribute ($renderer, text => 0);
56 
57  $combo = $dialog->get_widget('copy_region_combobox');
58  $renderer = Gtk2::CellRendererText->new;
59  $combo->pack_start ($renderer, TRUE);
60  $combo->add_attribute ($renderer, text => 0);
61  $combo->signal_connect(changed=>\&copy_region_selected, [$self, $gui]);
62 
63  for ('minx','miny','maxx','maxy','cellsize') {
64  $dialog->get_widget('copy_'.$_.'_entry')->signal_connect(
65  changed =>
66  sub {
67  my(undef, $self) = @_;
68  return if $self->{_ignore_copy_entry_change};
69  $self->{copy_raster_dialog}->get_widget('copy_region_combobox')->set_active(0);
70  copy_info($self);
71  }, $self);
72  }
73  }
74 
75  $dialog->get_widget('copy_progressbar')->set_fraction(0);
76 
77  my $model = Gtk2::ListStore->new('Glib::String');
78  $model->set($model->append, 0, 'libral');
79  my @drivers;
80  for my $driver (Geo::GDAL::Drivers()) {
81  next unless $driver->TestCapability('Create');
82  my $name = $driver->{ShortName};
83  push @drivers, $name;
84  }
85  for my $driver (sort @drivers) {
86  $model->set($model->append, 0, $driver);
87  }
88  my $combo = $dialog->get_widget('copy_driver_combobox');
89  $combo->set_model($model);
90  $combo->set_active(0);
91 
92  $model = Gtk2::ListStore->new('Glib::String');
93  $model->set($model->append, 0, 'Default');
94  $model->set($model->append, 0, 'Byte');
95  $combo = $dialog->get_widget('copy_datatype_combobox');
96  $combo->set_model($model);
97  $combo->set_active(0);
98 
99  $model = Gtk2::ListStore->new('Glib::String');
100  $model->set($model->append, 0, '');
101  $model->set($model->append, 0, '<Current view>');
102  $model->set($model->append, 0, '<self>');
103  my %names;
104  for my $layer (@{$gui->{overlay}->{layers}}) {
105  my $n = $layer->name();
106  $names{$n} = 1;
107  next unless $layer->isa('Geo::Raster');
108  next if $n eq $self->name();
109  $model->set($model->append, 0, $n);
110  }
111  $combo = $dialog->get_widget('copy_region_combobox');
112  $combo->set_model($model);
113  $combo->set_active(2);
114 
115  copy_region_selected($combo, [$self, $gui]);
116 
117  my $i = ord('a');
118  while ($names{chr($i)}) {$i++}
119  my $name = chr($i);
120 
121  $dialog->get_widget('copy_name_entry')->set_text($name);
122 
123  return $dialog->get_widget('copy_raster_dialog');
124 }
125 
126 sub do_copy {
127  my($self, $gui, $close) = @{$_[1]};
128 
129  my $dialog = $self->{copy_raster_dialog};
130 
131  my $minx = get_number_from_entry($dialog->get_widget('copy_minx_entry'));
132  my $miny = get_number_from_entry($dialog->get_widget('copy_miny_entry'));
133  my $maxx = get_number_from_entry($dialog->get_widget('copy_maxx_entry'));
134  my $maxy = get_number_from_entry($dialog->get_widget('copy_maxy_entry'));
135  my $cellsize = get_number_from_entry($dialog->get_widget('copy_cellsize_entry'));
136  if ($minx eq '' or $miny eq '' or $maxx eq '' or $maxy eq '' or $cellsize eq '') {
137  return;
138  }
139 
140  my($src, $dst);
141  my $project = $dialog->get_widget('copy_projection_checkbutton')->get_active;
142  my @bounds;
143  if ($project) {
144  my $from = $dialog->get_widget('from_EPSG_entry')->get_text;
145  my $to = $dialog->get_widget('to_EPSG_entry')->get_text;
146  return unless $Geo::Raster::Layer::EPSG{$from} and $Geo::Raster::Layer::EPSG{$to};
147 
148  $src = Geo::OSR::SpatialReference->create( EPSG => $Geo::Raster::Layer::EPSG{$from} );
149  $dst = Geo::OSR::SpatialReference->create( EPSG => $Geo::Raster::Layer::EPSG{$to} );
150  return unless $src and $dst;
151 
152  # compute corner points in new srs
153  my $ct;
154  eval {
155  $ct = Geo::OSR::CoordinateTransformation->new($src, $dst);
156  };
157  if ($@ or !$ct) {
158  $@ = '' unless $@;
159  $@ = ": $@" if $@;
160  $gui->message("Can't create coordinate transformation$@.");
161  return;
162  }
163  my $points = [[$minx,$miny],[$minx,$maxy],[$maxx,$miny],[$maxx,$maxy]];
164  $ct->TransformPoints($points);
165  for (@$points) {
166  $bounds[0] = $_->[0] if (!defined($bounds[0]) or ($_->[0] < $bounds[0]));
167  $bounds[1] = $_->[1] if (!defined($bounds[1]) or ($_->[1] < $bounds[1]));
168  $bounds[2] = $_->[0] if (!defined($bounds[2]) or ($_->[0] > $bounds[2]));
169  $bounds[3] = $_->[1] if (!defined($bounds[3]) or ($_->[1] > $bounds[3]));
170  }
171 
172  $src = $src->ExportToPrettyWkt;
173  $dst = $dst->ExportToPrettyWkt;
174  }
175 
176  my $name = $dialog->get_widget('copy_name_entry')->get_text();
177  my $folder = $dialog->get_widget('copy_folder_entry')->get_text();
178  $folder .= '/' if $folder;
179 
180  my $combo = $dialog->get_widget('copy_driver_combobox');
181  my $iter = $combo->get_active_iter;
182  my $driver = $combo->get_model->get($iter);
183 
184  $combo = $dialog->get_widget('copy_datatype_combobox');
185  $iter = $combo->get_active_iter;
186  my $datatype = $combo->get_model->get($iter);
187 
188  $combo = $dialog->get_widget('copy_region_combobox');
189  $iter = $combo->get_active_iter;
190  my $region = $combo->get_model->get($iter);
191 
192  my($new_raster, $src_dataset, $dst_dataset);
193 
194  if ($driver eq 'libral' and !$project) {
195  if ($self->{GDAL}) {
196  $new_raster = $self->cache($minx, $miny, $maxx, $maxy, $cellsize);
197  } else {
198  $new_raster = $self * 1;
199  }
200  } else {
201  $src_dataset = $self->dataset;
202 
203  if ($project) {
204  #my($w, $h) = $src_dataset->Size;
205  #my @transform = $src_dataset->GeoTransform;
206  #my $w = int(($maxx-$minx)/$transform[1]);
207  #my $h = int(($miny-$maxy)/$transform[5]);
208  my $w = int(($bounds[2]-$bounds[0])/$cellsize+1);
209  my $h = int(($bounds[3]-$bounds[1])/$cellsize+1);
210  my $bands = $src_dataset->Bands;
211  my $type = $src_dataset->Band(1)->DataType;
212  my $d = $driver eq 'libral' ? 'MEM' : $driver;
213  $dst_dataset = Geo::GDAL::Driver($d)->Create($folder.$name, $w, $h, $bands, $type);
214  my @transform = ($bounds[0], $cellsize, 0,
215  $bounds[1], 0, $cellsize);
216  $dst_dataset->GeoTransform(@transform);
217  my $alg = 'NearestNeighbour';
218  my $bar = $dialog->get_widget('copy_progressbar');
219 
220  eval {
221  Geo::GDAL::ReprojectImage($src_dataset, $dst_dataset, $src, $dst, $alg, 0, 0.0,
222  \&progress, $bar);
223  };
224  if ($@) {
225  $gui->message("Error in reprojection: $@.");
226  return;
227  }
228  } else {
229  if ($datatype ne 'Default') {
230  my($ysize, $xsize) = $self->size();
231  $dst_dataset = Geo::GDAL::Driver($driver)->Create($folder.$name, $xsize, $ysize, 1, $datatype);
232  $dst_dataset->GeoTransform($src_dataset->GeoTransform);
233  $dst_dataset->Band(1)->NoDataValue($src_dataset->Band(1)->NoDataValue);
234  $dst_dataset->Band(1)->WriteTile($src_dataset->Band(1)->ReadTile);
235  $dst_dataset->FlushCache;
236  } else {
237  $dst_dataset = Geo::GDAL::Driver($driver)->Copy($folder.$name, $src_dataset);
238  }
239  }
240 
241  $new_raster = {};
242  $new_raster->{GDAL}->{dataset} = $dst_dataset;
243  $new_raster->{GDAL}->{band} = 1;
244  if ($driver eq 'libral') {
245  Geo::Raster::cache($new_raster);
246  delete $new_raster->{GDAL};
247  }
248  bless $new_raster => 'Geo::Raster';
249  }
250 
251  my $layer = $gui->add_layer($new_raster, $name, 1);
252  # copy the color palette
253  $layer->palette_type($self->palette_type);
254  $layer->color_table($self->color_table);
255 
256  #$gui->set_layer($new_layer);
257  #$gui->select_layer($name);
258  #$gui->{overlay}->zoom_to($new_layer);
259 
260  $self->hide_dialog('copy_raster_dialog') if $close;
261  $gui->{overlay}->render;
262 }
263 
264 sub cancel_copy {
265  my($self, $gui);
266  for (@_) {
267  next unless ref CORE::eq 'ARRAY';
268  ($self, $gui) = @{$_};
269  }
270  $self->hide_dialog('copy_raster_dialog');
271  $gui->set_layer($self);
272  $gui->{overlay}->render;
273  1;
274 }
275 
276 sub copy_select_folder {
277  my(undef, $self) = @_;
278  my $entry = $self->{copy_raster_dialog}->get_widget('copy_folder_entry');
279  file_chooser('Select a folder', 'select_folder', $entry);
280 }
281 
282 sub copy_driver_selected {
283  my $combo = $_[0];
284  my($self, $gui) = @{$_[1]};
285  my $dialog = $self->{copy_raster_dialog};
286  my $model = $combo->get_model;
287  my $iter = $combo->get_active_iter;
288  my $driver = $model->get($iter);
289  my $a = ($driver eq 'libral' or $driver eq 'MEM');
290  for ('copy_folder_button','copy_folder_entry') {
291  $dialog->get_widget($_)->set_sensitive(not $a);
292  }
293 }
294 
295 sub copy_region_selected {
296  my $combo = $_[0];
297  my($self, $gui) = @{$_[1]};
298  my $dialog = $self->{copy_raster_dialog};
299  my $model = $combo->get_model;
300  my $iter = $combo->get_active_iter;
301  my $region = $model->get($iter);
302  my @region;
303  if ($region eq '') {
304  } elsif ($region eq '<Current view>') {
305  @region = $gui->{overlay}->get_viewport();
306  push @region, $self->cell_size();
307  } else {
308  $region = $self->name if $region eq '<self>';
309  my $layer = $gui->{overlay}->get_layer_by_name($region);
310  @region = $layer->world();
311  push @region, $layer->cell_size();
312  }
313  copy_define_region($self, @region);
314 }
315 
316 sub copy_define_region {
317  my $self = shift;
318 
319  my $dialog = $self->{copy_raster_dialog};
320  $dialog->get_widget('copy_size_label')->set_text('?');
321  $dialog->get_widget('copy_memory_size_label')->set_text('?');
322 
323  my($minx, $miny, $maxx, $maxy, $cellsize);
324 
325  if (@_) {
326 
327  ($minx, $miny, $maxx, $maxy, $cellsize) = @_;
328 
329  } else {
330 
331  $minx = get_number_from_entry($dialog->get_widget('copy_minx_entry'));
332  $miny = get_number_from_entry($dialog->get_widget('copy_miny_entry'));
333  $maxx = get_number_from_entry($dialog->get_widget('copy_maxx_entry'));
334  $maxy = get_number_from_entry($dialog->get_widget('copy_maxy_entry'));
335  $cellsize = get_number_from_entry($dialog->get_widget('copy_cellsize_entry'));
336 
337  $cellsize = $self->cell_size() if $cellsize eq '';
338  my @world = $self->world(); # $min_x, $min_y, $max_x, $max_y
339 
340  $minx = $world[0] if $minx eq '';
341  $miny = $world[1] if $miny eq '';
342  $maxx = $world[2] if $maxx eq '';
343  $maxy = $world[3] if $maxy eq '';
344 
345  }
346 
347  $self->{_ignore_copy_entry_change} = 1;
348  $dialog->get_widget('copy_minx_entry')->set_text($minx);
349  $dialog->get_widget('copy_miny_entry')->set_text($miny);
350  $dialog->get_widget('copy_maxx_entry')->set_text($maxx);
351  $dialog->get_widget('copy_maxy_entry')->set_text($maxy);
352  $dialog->get_widget('copy_cellsize_entry')->set_text($cellsize);
353  $self->{_ignore_copy_entry_change} = 0;
354 
355  copy_info($self);
356 
357  return ($minx, $miny, $maxx, $maxy, $cellsize);
358 
359 }
360 
361 sub copy_info {
362  my($self) = @_;
363  my $dialog = $self->{copy_raster_dialog};
364  my $minx = get_number_from_entry($dialog->get_widget('copy_minx_entry'));
365  my $miny = get_number_from_entry($dialog->get_widget('copy_miny_entry'));
366  my $maxx = get_number_from_entry($dialog->get_widget('copy_maxx_entry'));
367  my $maxy = get_number_from_entry($dialog->get_widget('copy_maxy_entry'));
368  my $cellsize = get_number_from_entry($dialog->get_widget('copy_cellsize_entry'));
369  if ($minx eq '' or $miny eq '' or $maxx eq '' or $maxy eq '' or $cellsize eq '') {
370  $dialog->get_widget('copy_size_label')->set_text('?');
371  $dialog->get_widget('copy_memory_size_label')->set_text('?');
372  } else {
373  my $M = int(($maxy - $miny)/$cellsize)+1;
374  my $N = int(($maxx - $minx)/$cellsize)+1;
375  my $datatype = $self->datatype || '';
376  my $bytes = $datatype eq 'Integer' ? 2 : 4; # should look this up from libral/GDAL
377  my $size = $M*$N*$bytes;
378  if ($size > 1024) {
379  $size = int($size/1024);
380  if ($size > 1024) {
381  $size = int($size/1024);
382  if ($size > 1024) {
383  $size = int($size/1024);
384  $size = "$size GiB";
385  } else {
386  $size = "$size MiB";
387  }
388  } else {
389  $size = "$size KiB";
390  }
391  } else {
392  $size = "$size B";
393  }
394  $dialog->get_widget('copy_size_label')->set_text("~${M} x ~${N}");
395  $dialog->get_widget('copy_memory_size_label')->set_text($size);
396  }
397 }
398 
399 1;
A subclass of Gtk2::Ex::Geo::Layer and Geo::Raster.
Definition: Layer.pm:27
public Geo::Raster cache()
Creates a new grid from the GDAL source.
public method bootstrap_dialog()
public method epsg_help()