source: subversion/applications/rendering/history/hqrun.pl @ 34399

Last change on this file since 34399 was 3500, checked in by frederik, 12 years ago

add loop

  • Property svn:executable set to *
File size: 11.9 KB
Line 
1#!/usr/bin/perl
2
3use LWP;
4use Geo::Proj4;
5use GD;
6use DBI;
7use Data::Dumper;
8use strict;
9
10my $ua = LWP::UserAgent->new();
11my $dsn="DBI:mysql:host=localhost:database=osmhistory";
12my $dbh = DBI->connect($dsn) or die;
13my $destpath = "/var/www/webspace/gryph.de/openstreetmap.gryph.de/history/images/";
14my $thumbpath = "/var/www/webspace/gryph.de/openstreetmap.gryph.de/history/thumbnails/";
15
16my $colormap = { 
17    "0" => [ 255, 0, 0 ], # red
18    "1" => [ 255, 255, 0 ], # yellow
19    "2" => [ 255, 255, 255 ], # white
20    "3" => [ 0, 0, 255 ], # blue
21};
22
23my $query = <<EOF;
24select *
25from     jobs
26where    status='waiting'
27order by date_entered asc
28limit    1
29EOF
30
31my $sth = $dbh->prepare($query) or die;
32my $sth_planet = $dbh->prepare("select filedate from planets") or die;
33
34my $sth_begin = $dbh->prepare(<<EOF) or die;
35update jobs
36set status='processing', 
37date_started=? 
38where id=?
39EOF
40
41my $sth_failure = $dbh->prepare(<<EOF) or die;
42update jobs
43set status='failed', 
44errmsg=?, 
45date_finished=? 
46where id=?
47EOF
48
49my $sth_success = $dbh->prepare(<<EOF) or die;
50update jobs
51set status='finished', 
52date_finished=?,
53width=?,
54height=?,
55max_nodes=?,
56filename=?,
57filesize=?,
58num_frames=?
59where id=?
60EOF
61
62while(1)
63{
64    if (-f "/tmp/hqrun.terminate")
65    {
66        print "/tmp/hqrun.terminate exists, aborting\n";
67        exit;
68    }
69    $sth->execute();
70    if (my $row = $sth->fetchrow_hashref)
71    {
72        my $input = {};
73        foreach my $key(keys(%$row))
74        {
75            $input->{$key} = $row->{$key};
76        }
77
78        my @filedates = get_filedates();
79        my @usedates;
80        my $used = {};
81
82        my $lastdate = defined($input->{"todate"}) ? $input->{"todate"} : $filedates[$#filedates];
83        my $firstdate = defined($input->{"fromdate"}) ? $input->{"fromdate"} : $filedates[0];
84        $lastdate = $lastdate + $input->{"frequency"};
85        while(1)
86        {
87            my $want = todays($lastdate) - $input->{"frequency"};
88            my $bestdiff = 9999999;
89            my $thisdate;
90            foreach my $date(@filedates)
91            {
92                next if ($used->{$date});
93                next if ($date < $firstdate);
94                next if ($date > $lastdate);
95                my $diff = abs($want-todays($date));
96                if ($diff<$bestdiff)
97                {
98                    $bestdiff = $diff;
99                    $thisdate = $date;
100                }
101            }
102            last if ($bestdiff == 9999999);
103            unshift(@usedates, $thisdate);
104            $used->{$thisdate} = 1;
105            $lastdate = $thisdate;
106        }
107
108        $input->{"filedates"} = \@usedates;
109        $sth_begin->execute(time(), $input->{"id"});
110        my $output = doit($input);
111        if (ref($output) ne "HASH")
112        {
113            # print "fail: $output\n";
114            $sth_failure->execute($output, time(), $input->{"id"});
115        }
116        else
117        {
118            my $filename = $destpath . $input->{"id"} . ".gif";
119            system "mv ".$output->{"filename"}." ".$filename;
120            my $filesize = -s $filename;
121            system "mv ".$output->{"thumbname"}." ".$thumbpath.$input->{"id"} . ".gif";
122            $sth_success->execute(time(), $output->{"width"}, $output->{"height"}, $output->{"max_nodes"}, $input->{"id"}.".gif", $filesize, scalar(@usedates)+1, $input->{"id"});
123        }
124    }
125    else
126    {
127        sleep 30;
128    }
129}
130
131sub doit
132{
133    my $input = shift;
134    my $output = {};
135    my @tmpfiles;
136    my $outfile = "/tmp/hqrun.out.$$.gif";
137    my $thumbfile = "/tmp/hqrun.thumb.$$.gif";
138
139    my $proj;
140    if ($input->{"projection"} == 1)
141    {
142        $proj = Geo::Proj4->new(proj => "latlong")
143            or return "parameter error: ".Geo::Proj4->error;
144    }
145    elsif ($input->{"projection"} == 2)
146    {
147        $proj = Geo::Proj4->new(proj => "merc", ellps => "WGS84")
148            or return "parameter error: ".Geo::Proj4->error;
149    }
150    else
151    {
152        return "invalid 'projection' parameter: ".$input->{"projection"};
153    }
154
155    return "minlat > maxlat" if ($input->{'minlat'} > $input->{'maxlat'});
156    return "minlon > maxlon" if ($input->{'minlon'} > $input->{'maxlon'});
157    return "lat range too large (max 90deg)" if ($input->{'maxlat'} - $input->{'minlat'} > 90);
158    return "lon range too large (max 120deg)" if ($input->{'maxlon'} - $input->{'minlon'} > 120);
159
160    return "bad minlat" if ($input->{'minlat'} > 90 or $input->{"minlat"} < -90);
161    return "bad maxlat" if ($input->{'maxlat'} > 90 or $input->{"maxlat"} < -90);
162    return "bad minlon" if ($input->{'minlon'} > 180 or $input->{"minlon"} < -180);
163    return "bad maxlon" if ($input->{'maxlon'} > 180 or $input->{"maxlon"} < -180);
164
165    return "width too large (max 1600)" if ($input->{'width'} > 1600);
166    return "height too large (max 1200)" if ($input->{'height'} > 1200);
167
168    my ($min_e, $min_n) = $proj->forward($input->{'minlat'}, $input->{'minlon'});
169    my ($max_e, $max_n) = $proj->forward($input->{'maxlat'}, $input->{'maxlon'});
170
171    my ($width_e, $height_n) = ($max_e - $min_e, $max_n - $min_n);
172
173    return "width is 0" if ($width_e == 0);
174    return "height is 0" if ($height_n == 0);
175
176    my $scale;
177    my $height;
178    my $width;
179
180    if ($input->{"width"} >0)
181    {
182        $width = $input->{"width"};
183        $scale = $width_e / $width; 
184        $height = int($height_n / $scale + .5);
185    }
186    else
187    {
188        $height = $input->{"height"};
189        $scale = $height_n / $height; 
190        $width = int($width_e / $scale + .5);
191    }
192
193    $output->{"width"} = $width;
194
195    my $statusheight = 35;
196    $output->{"height"} = $height + $statusheight;
197
198    # initialize images
199    my $images = {};
200    $images->{0}->{"img"} = new GD::Image($width, $height + $statusheight, 0);
201    for (my $i = 0; $i < scalar(@{$input->{"filedates"}}); $i++)
202    {
203        my $key = $input->{"filedates"}->[$i];
204        $images->{$key}->{"img"} = new GD::Image($width, $height + $statusheight, 0);
205        my ($r, $g, $b) = @{$colormap->{$input->{"color"}}};
206        $images->{$key}->{"col"} = $images->{$key}->{"img"}->colorAllocate($r, $g, $b);
207        $images->{$key}->{"txt"} = $images->{$key}->{"img"}->colorAllocate(255,255,255);
208        $images->{$key}->{"bgr"} = $images->{$key}->{"img"}->colorAllocate(100,100,100);
209    }
210
211    my @tmp = sort keys(%$images);
212    my $minfd = $tmp[1]; 
213    my $maxfd = $tmp[$#tmp];
214    my $request;
215
216    if ($input->{"bgimage"} == 1)
217    {
218        $request = "http://labs.metacarta.com/wms/vmap0?service=WMS&request=GetMap&srs=EPSG:4326&format=image/jpeg&version=1.1.1&layers=basic";
219    }
220    elsif ($input->{"bgimage"} == 2)
221    {
222        $request = "http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers=global_mosaic&styles=&srs=EPSG:4326&format=image/jpeg";
223    }
224    my $image;
225
226    if ($request ne "")
227    {
228        $request = $request . sprintf("&bbox=%f,%f,%f,%f&width=%d&height=%d", 
229                $input->{"minlon"}, $input->{"minlat"}, 
230                $input->{"maxlon"}, $input->{"maxlat"}, $width, $height);
231
232        # print "GET $request\n";
233        my $response = $ua->get($request);
234        # print "response: ".$response->status_line."\n";
235        if (!$response->is_success)
236        {
237            return "WMS server error: ".$response->status_line;
238        }
239        unless ($image = GD::Image->newFromJpegData($response->content, 0))
240        {
241            return "WMS server error: not returned a valid image";
242        }
243    }
244    else
245    {
246        $image = GD::Image->new($width, $height + $statusheight, 0);
247        my $bgr = $image->colorAllocate(100,100,100);
248        $image->filledRectangle(0, 0, $width, $height + $statusheight, $bgr);
249    }
250
251    foreach my $key(keys %$images)
252    {
253        $images->{$key}->{"img"}->copy($image, 0, 0, 0, 0, $width, $height);
254    }
255
256    my @buckets;
257
258    for (my $lat = int($input->{"minlat"}*2); $lat <= int($input->{"maxlat"}*2)+1; $lat++)
259    {
260        for (my $lon = int($input->{"minlon"}*2); $lon <= int($input->{"maxlon"}*2)+1; $lon++)
261        {
262            push(@buckets, ($lat+180)*720+$lon+360);
263        }
264    }
265
266    my $buckets = join(",", @buckets);
267    my $mila = int($input->{"minlat"} * 10000);
268    my $milo = int($input->{"minlon"} * 10000);
269    my $mala = int($input->{"maxlat"} * 10000);
270    my $malo = int($input->{"maxlon"} * 10000);
271
272    my $query =<<EOF;
273select lat, lon, fromdate, todate
274from   nodes
275where  bucket in ($buckets)
276and    fromdate <= $maxfd
277and    todate >= $minfd
278and    lat >= $mila
279and    lat <= $mala
280and    lon >= $milo
281and    lon <= $malo;
282EOF
283
284    #print "$query\n";
285    my $sth = $dbh->prepare($query) or return $dbh->errstr;
286    $sth->execute() or return $dbh->errstr;
287
288    my ($x, $y);
289    my $pixel = $input->{"pixel"};
290
291    while (my $row = $sth->fetchrow_arrayref)
292    {
293        my ($x, $y) = $proj->forward($row->[0] / 10000, $row->[1] / 10000);
294        $x = int(($x-$min_e)/$scale);
295        $y = $height - int(($y-$min_n)/$scale);
296        foreach my $key(keys(%$images))
297        {
298            if ($row->[2] <= $key && $row->[3] >= $key)
299            {
300                if ($pixel == 0)
301                {
302                    $images->{$key}->{"img"}->setPixel($x, $y, $images->{$key}->{"col"});
303                }
304                elsif ($pixel == 1)
305                {
306                    $images->{$key}->{"img"}->rectangle($x, $y, $x+1, $y+1, $images->{$key}->{"col"});
307                }
308                elsif ($pixel == 2)
309                {
310                    $images->{$key}->{"img"}->rectangle($x-1, $y-1, $x+1, $y+1, $images->{$key}->{"col"});
311                }
312                else
313                {
314                    $images->{$key}->{"img"}->filledEllipse($x, $y, 5, 5, $images->{$key}->{"col"});
315                }
316                $images->{$key}->{"cnt"}++;
317            }
318        }
319    }
320
321    my $maxnodes = 0;
322    foreach my $key(keys %$images)
323    {
324        $maxnodes = $images->{$key}->{"cnt"} if ($images->{$key}->{"cnt"} > $maxnodes);
325    }
326    $output->{"max_nodes"} = $maxnodes;
327    my $digitspace = 7 * length($maxnodes);
328    my $finalframe; 
329
330    foreach my $key(sort keys %$images)
331    {
332        my $i = $images->{$key}->{"img"};
333        $finalframe = $i;
334        my $d = sprintf "20%02d-%02d-%02d", $key/10000, ($key%10000)/100, $key%100;
335        my $c = $images->{$key}->{"cnt"};
336
337        my $scaleleft = todays($minfd);
338        my $scaleright = todays($maxfd);
339        my $barwidth = ($width - 120 - $digitspace);
340        my $barscale = $barwidth / ($scaleright - $scaleleft);
341        my $thisbar = (todays($key)-$scaleleft)*$barscale;
342#printf "scale left $scaleleft right $scaleright this date %d gives %d\n", todays($key),$thisbar;
343        $i->filledRectangle(0,$height+1,$width,$height+$statusheight,$images->{$key}->{"bgr"});
344        $i->filledRectangle(110+$digitspace,$height+11,$thisbar+110+$digitspace,$height+20, $images->{$key}->{"txt"});
345
346        $i->string(gdMediumBoldFont, 10, $height + 10, "$d ($c)", $images->{$key}->{"txt"});
347#add_frame_data($i);
348#    $gifdata .= $i->gifanimadd(undef, 0, 0, 100, 1, $prev);
349#    $prev = $i;
350        my $tmp = sprintf("/tmp/hqrun.tmp.$$.frame-%06d.gif", $key);
351        open(BLA, ">$tmp") or return $!;
352        print(BLA $i->gif());
353        close(BLA);
354        push(@tmpfiles, $tmp);
355    }
356
357    my $loop = ($input->{"loopflag"}) ? "--loopcount" : "";
358    system "gifsicle --colors 256 $loop --delay ".$input->{"delay"}." -O2 ".join(" ", @tmpfiles)." > $outfile";
359    foreach my $tmp (@tmpfiles) { unlink $tmp; }
360    $output->{"filename"} = $outfile;
361
362    my $tw = 160;
363    my $th = 160 / $width * ($height);
364    my $thumb = GD::Image->new($tw, $th, 0); 
365    $thumb->copyResampled($finalframe, 0, 0, 0, 0, $tw, $th, $width, $height);
366    open(BLA, ">$thumbfile") or return $!;
367    print(BLA $thumb->gif());
368    close(BLA);
369    $output->{"thumbname"} = $thumbfile;
370   
371    return $output;
372}
373
374sub todays
375{
376    my $d = shift;
377    return 365 * int($d/10000)+30*int(($d%10000)/100)+$d%100;
378}
379
380sub get_filedates
381{
382    my @ret;
383    $sth_planet->execute();
384    while(my $row = $sth_planet->fetchrow_arrayref())
385    {
386        push(@ret, $row->[0]);
387    }
388    return @ret;
389}
Note: See TracBrowser for help on using the repository browser.