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

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

new

  • Property svn:executable set to *
File size: 12.1 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
131my $t=<<'EOF';
132my $inp = {
133    "projection" => 2,
134    "minlat" => 48.925,
135    "minlon" => 8.32,
136    "maxlat" => 49.05,
137    "maxlon" => 8.47,
138    "width" => 600,
139    "color" => 0,
140    "bgimage" => 2,
141    "height" => undef,
142    "delay" => 100,
143    "filedates" => [ 60818, 70307, 70620 ]
144};
145EOF
146
147sub doit
148{
149    my $input = shift;
150    my $output = {};
151    my @tmpfiles;
152    my $outfile = "/tmp/hqrun.out.$$.gif";
153    my $thumbfile = "/tmp/hqrun.thumb.$$.gif";
154
155    my $proj;
156    if ($input->{"projection"} == 1)
157    {
158        $proj = Geo::Proj4->new(proj => "latlong")
159            or return "parameter error: ".Geo::Proj4->error;
160    }
161    elsif ($input->{"projection"} == 2)
162    {
163        $proj = Geo::Proj4->new(proj => "merc", ellps => "WGS84")
164            or return "parameter error: ".Geo::Proj4->error;
165    }
166    else
167    {
168        return "invalid 'projection' parameter: ".$input->{"projection"};
169    }
170
171    return "minlat > maxlat" if ($input->{'minlat'} > $input->{'maxlat'});
172    return "minlon > maxlon" if ($input->{'minlon'} > $input->{'maxlon'});
173    return "lat range too large (max 90deg)" if ($input->{'maxlat'} - $input->{'minlat'} > 90);
174    return "lon range too large (max 120deg)" if ($input->{'maxlon'} - $input->{'minlon'} > 120);
175
176    return "bad minlat" if ($input->{'minlat'} > 90 or $input->{"minlat"} < -90);
177    return "bad maxlat" if ($input->{'maxlat'} > 90 or $input->{"maxlat"} < -90);
178    return "bad minlon" if ($input->{'minlon'} > 180 or $input->{"minlon"} < -180);
179    return "bad maxlon" if ($input->{'maxlon'} > 180 or $input->{"maxlon"} < -180);
180
181    return "width too large (max 1600)" if ($input->{'width'} > 1600);
182    return "height too large (max 1200)" if ($input->{'height'} > 1200);
183
184    my ($min_e, $min_n) = $proj->forward($input->{'minlat'}, $input->{'minlon'});
185    my ($max_e, $max_n) = $proj->forward($input->{'maxlat'}, $input->{'maxlon'});
186
187    my ($width_e, $height_n) = ($max_e - $min_e, $max_n - $min_n);
188
189    return "width is 0" if ($width_e == 0);
190    return "height is 0" if ($height_n == 0);
191
192    my $scale;
193    my $height;
194    my $width;
195
196    if ($input->{"width"} >0)
197    {
198        $width = $input->{"width"};
199        $scale = $width_e / $width; 
200        $height = int($height_n / $scale + .5);
201    }
202    else
203    {
204        $height = $input->{"height"};
205        $scale = $height_n / $height; 
206        $width = int($width_e / $scale + .5);
207    }
208
209    $output->{"width"} = $width;
210
211    my $statusheight = 35;
212    $output->{"height"} = $height + $statusheight;
213
214    # initialize images
215    my $images = {};
216    $images->{0}->{"img"} = new GD::Image($width, $height + $statusheight, 0);
217    for (my $i = 0; $i < scalar(@{$input->{"filedates"}}); $i++)
218    {
219        my $key = $input->{"filedates"}->[$i];
220        $images->{$key}->{"img"} = new GD::Image($width, $height + $statusheight, 0);
221        my ($r, $g, $b) = @{$colormap->{$input->{"color"}}};
222        $images->{$key}->{"col"} = $images->{$key}->{"img"}->colorAllocate($r, $g, $b);
223        $images->{$key}->{"txt"} = $images->{$key}->{"img"}->colorAllocate(255,255,255);
224        $images->{$key}->{"bgr"} = $images->{$key}->{"img"}->colorAllocate(100,100,100);
225    }
226
227    my @tmp = sort keys(%$images);
228    my $minfd = $tmp[1]; 
229    my $maxfd = $tmp[$#tmp];
230    my $request;
231
232    if ($input->{"bgimage"} == 1)
233    {
234        $request = "http://labs.metacarta.com/wms/vmap0?service=WMS&request=GetMap&srs=EPSG:4326&format=image/jpeg&version=1.1.1&layers=basic";
235    }
236    elsif ($input->{"bgimage"} == 2)
237    {
238        $request = "http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers=global_mosaic&styles=&srs=EPSG:4326&format=image/jpeg";
239    }
240    my $image;
241
242    if ($request ne "")
243    {
244        $request = $request . sprintf("&bbox=%f,%f,%f,%f&width=%d&height=%d", 
245                $input->{"minlon"}, $input->{"minlat"}, 
246                $input->{"maxlon"}, $input->{"maxlat"}, $width, $height);
247
248        # print "GET $request\n";
249        my $response = $ua->get($request);
250        # print "response: ".$response->status_line."\n";
251        if (!$response->is_success)
252        {
253            return "WMS server error: ".$response->status_line;
254        }
255        unless ($image = GD::Image->newFromJpegData($response->content, 0))
256        {
257            return "WMS server error: not returned a valid image";
258        }
259    }
260    else
261    {
262        $image = GD::Image->new($width, $height + $statusheight, 0);
263        my $bgr = $image->colorAllocate(100,100,100);
264        $image->filledRectangle(0, 0, $width, $height + $statusheight, $bgr);
265    }
266
267    foreach my $key(keys %$images)
268    {
269        $images->{$key}->{"img"}->copy($image, 0, 0, 0, 0, $width, $height);
270    }
271
272    my @buckets;
273
274    for (my $lat = int($input->{"minlat"}*2); $lat <= int($input->{"maxlat"}*2)+1; $lat++)
275    {
276        for (my $lon = int($input->{"minlon"}*2); $lon <= int($input->{"maxlon"}*2)+1; $lon++)
277        {
278            push(@buckets, ($lat+180)*720+$lon+360);
279        }
280    }
281
282    my $buckets = join(",", @buckets);
283    my $mila = int($input->{"minlat"} * 10000);
284    my $milo = int($input->{"minlon"} * 10000);
285    my $mala = int($input->{"maxlat"} * 10000);
286    my $malo = int($input->{"maxlon"} * 10000);
287
288    my $query =<<EOF;
289select lat, lon, fromdate, todate
290from   nodes
291where  bucket in ($buckets)
292and    fromdate <= $maxfd
293and    todate >= $minfd
294and    lat >= $mila
295and    lat <= $mala
296and    lon >= $milo
297and    lon <= $malo;
298EOF
299
300    #print "$query\n";
301    my $sth = $dbh->prepare($query) or return $dbh->errstr;
302    $sth->execute() or return $dbh->errstr;
303
304    my ($x, $y);
305    my $pixel = $input->{"pixel"};
306
307    while (my $row = $sth->fetchrow_arrayref)
308    {
309        my ($x, $y) = $proj->forward($row->[0] / 10000, $row->[1] / 10000);
310        $x = int(($x-$min_e)/$scale);
311        $y = $height - int(($y-$min_n)/$scale);
312        foreach my $key(keys(%$images))
313        {
314            if ($row->[2] <= $key && $row->[3] >= $key)
315            {
316                if ($pixel == 0)
317                {
318                    $images->{$key}->{"img"}->setPixel($x, $y, $images->{$key}->{"col"});
319                }
320                elsif ($pixel == 1)
321                {
322                    $images->{$key}->{"img"}->rectangle($x, $y, $x+1, $y+1, $images->{$key}->{"col"});
323                }
324                elsif ($pixel == 2)
325                {
326                    $images->{$key}->{"img"}->rectangle($x-1, $y-1, $x+1, $y+1, $images->{$key}->{"col"});
327                }
328                else
329                {
330                    $images->{$key}->{"img"}->filledEllipse($x, $y, 5, 5, $images->{$key}->{"col"});
331                }
332                $images->{$key}->{"cnt"}++;
333            }
334        }
335    }
336
337    my $maxnodes = 0;
338    foreach my $key(keys %$images)
339    {
340        $maxnodes = $images->{$key}->{"cnt"} if ($images->{$key}->{"cnt"} > $maxnodes);
341    }
342    $output->{"max_nodes"} = $maxnodes;
343    my $digitspace = 7 * length($maxnodes);
344    my $finalframe; 
345
346    foreach my $key(sort keys %$images)
347    {
348        my $i = $images->{$key}->{"img"};
349        $finalframe = $i;
350        my $d = sprintf "20%02d-%02d-%02d", $key/10000, ($key%10000)/100, $key%100;
351        my $c = $images->{$key}->{"cnt"};
352
353        my $scaleleft = todays($minfd);
354        my $scaleright = todays($maxfd);
355        my $barwidth = ($width - 120 - $digitspace);
356        my $barscale = $barwidth / ($scaleright - $scaleleft);
357        my $thisbar = (todays($key)-$scaleleft)*$barscale;
358#printf "scale left $scaleleft right $scaleright this date %d gives %d\n", todays($key),$thisbar;
359        $i->filledRectangle(0,$height+1,$width,$height+$statusheight,$images->{$key}->{"bgr"});
360        $i->filledRectangle(110+$digitspace,$height+11,$thisbar+110+$digitspace,$height+20, $images->{$key}->{"txt"});
361
362        $i->string(gdMediumBoldFont, 10, $height + 10, "$d ($c)", $images->{$key}->{"txt"});
363#add_frame_data($i);
364#    $gifdata .= $i->gifanimadd(undef, 0, 0, 100, 1, $prev);
365#    $prev = $i;
366        my $tmp = sprintf("/tmp/hqrun.tmp.$$.frame-%06d.gif", $key);
367        open(BLA, ">$tmp") or return $!;
368        print(BLA $i->gif());
369        close(BLA);
370        push(@tmpfiles, $tmp);
371    }
372
373    system "gifsicle --colors 256 --delay ".$input->{"delay"}." -O2 ".join(" ", @tmpfiles)." > $outfile";
374    foreach my $tmp (@tmpfiles) { unlink $tmp; }
375    $output->{"filename"} = $outfile;
376
377    my $tw = 160;
378    my $th = 160 / $width * ($height);
379    my $thumb = GD::Image->new($tw, $th, 0); 
380    $thumb->copyResampled($finalframe, 0, 0, 0, 0, $tw, $th, $width, $height);
381    open(BLA, ">$thumbfile") or return $!;
382    print(BLA $thumb->gif());
383    close(BLA);
384    $output->{"thumbname"} = $thumbfile;
385   
386    return $output;
387}
388
389sub todays
390{
391    my $d = shift;
392    return 365 * int($d/10000)+30*int(($d%10000)/100)+$d%100;
393}
394
395sub get_filedates
396{
397    my @ret;
398    $sth_planet->execute();
399    while(my $row = $sth_planet->fetchrow_arrayref())
400    {
401        push(@ret, $row->[0]);
402    }
403    return @ret;
404}
Note: See TracBrowser for help on using the repository browser.