Weblog Tomasza Przechlewskiego [Zdjęcie T. Przechlewskiego]


scrum
random image [Photo gallery]
Zestawienie tagów
1-wire | 18b20 | 1wire | 2140 | 3rz | adamowicz | afera | alsamixer | amazon | amber | amman | anniversary | antypis | apache | api | applebaum | arm | armenia | astronomy | asus | atom.xml | awk | aws | bachotek | bakłażan | balcerowicz | balta | banan | bash | batumi | berlin | białowieża | białystok | bibtex | bieszczady | birzeit | biznes | blogger | blogging | blosxom | bme280 | bono | borne-sulinowo | breugel | bt747 | budapeszt | budyniowo | budyń | bursztyn | campagnolo | canon | cedewu | chaos | chello | chiller | chillerpl | chown | christophe dominici | chujowetaśmy | ciasto | cmentarz | contour | coronavirus | covi19 | covid | covid19 | cron | css | csv | cukinia | curl | cycling | d54250wykh | darkages | dbi | debian | dejavu | dhcp | dht22 | dia | docbook | dom | dp1500 | ds18b20 | duda | dulkiewicz | dulkiewiczowa | dyndns | dynia | ebay | economy | ecowitt | ekonomia | elka | elm | emacs | emacs23 | english | ep | erasmus | erasmusplus | ess | eu | eurostat | excel | exif | exiftool | f11 | fc | fc11 | fc15 | fc29 | fc5 | fc8 | fedora | fedora21 | fenix | ffmpeg | finepix | firefox | flickr | folau | fontforge | fontspec | fonty | food | fop | forms | foto | france | francja | fripp | froggit | fuczki | fuji | fuse | gammu | garden | garmin | gas | gawk | gazwyb | gdańsk | gdynia | gender | geo | geocoding | georgia | gft | ggplot | ghost | git | github | gmail | gmaps | gnokii | gnus | google | google apps script | googlecl | googleearth | googlemaps | gotowanie | gphoto | gphoto2 | gps | gpsbabel | gpsphoto | gpx | gpx-viewer | greasemonkey | gruzja | grzyby | gus | gw1000 | haldaemon | handbrake | helsinki | hhi | historia | history | hitler | holocaust | holokaust | hp1000se | hpmini | humour | iblue747 | ical | iiyama | ikea | imagemagick | imap | inkscape | inne | internet | j10i2 | javascript | jhead | jifna | jordania | k800i | kajak | kamera | karob | kibbeh | kleinertest | kml | kmobiletools | knuth | kociewie kołem | kod | kolibki | komorowski | konwersja | krutynia | krynki | kuchnia | kurski | kłamstwo | latex | latex2rtf | latex3 | lcd | legend | lenny | lesund | lewactwo | lgbt-folly | liban | liberation | linksys | linux | lisp | lisrel | litwa | lizbona | logika | ltr | lubowla | lwp | lwów | m2wś | malta | mapquest | mapsource | maradona | marchew | marimekko | marvell | math | mathjax | mazury | mbank | mediolan | mencoder | mevo | mex | mh17 | michalak | michlmayr | microsoft | monitor | mp4box | mplayer | ms | msc | mssql | msw | mswindows | mtkbabel | museum | muzyka | mymaps | mysql | mz | nafisa | nanopi | natbib | navin | neapol | nekrolog | neo | neopi | netbook | niemcy | niemieckie zbrodnie | nikon | nmea | nowazelandia | nuc | nxml | oauth | oauth2 | obituary | ocr | odessa | okular | olympus | ooffice | ooxml | opera | osm | otf | otftotfm | other | ov5647 | overclocking | ozbekiston | padwa | palestyna | panoramio | paryż | pdf | pdfpages | pdftex | pdftk | pedophilia | perl | photo | photography | pi | picasa | picasaweb | pim | pine | pis | pit | pizero | plain | plotly | pls | plugin | po | podcast | podlasie | podróże | pogoda | politics | polityka | polsat | portugalia | postęp | powerpoint | połtawa | prelink | problem | propaganda | pseudointeligencja | pstoedit | putin | python | pywws | r | r1984 | radio | random | raspberry | raspberry pi | raspberrypi | raspbian | refugees | relaxng | ridley | router | rower | rowery | roztocze | rpi | rsync | rtf | ruby | rugby | rumunia | russia | rwc | rwc2007 | rwc2011 | rwc2019 | ryga | rzym | salerno | samba | sds011 | selenium | sem | senah | sernik | sheevaplug | sienkiewicz | signature | sikorski | sks | skype | skytraq | smoleńsk | sqlite | srtm | sshfs | ssl | staszek wawrykiewicz | statistcs | statistics | stats | statystyka | stix | stretch | supraśl | suwałki | svg | svn | swanetia | swornegacie | szwajcaria | słowacja | tallin | tbilisi | terrorism | tesseract | tex | texgyre | texlive | thunderbird | tomato | totalnaopozycja | tourism | tramp | trang | transylwania | truetype | trzaskowski | ttf | turcja | turkey | turystyka | tusk | tv | tv5monde | tweepy | twitter | tykocin | typetools | ubuntu | uchodźcy | udev | ue | ukraina | umap | unix | upc | updmap | ups | utf8 | uzbekistan | varia | video | vienna | virb edit | virbedit | vostro | wammu | wdc | wdfs | weather | weathercloud | webcam | webdav | webscrapping | weewx | wenecja | wh2080 | wiedeń | wikicommons | wilno | win10 | windows | windows8 | wine | wioślarstwo | wojna | word | wordpress | wrt54gl | ws1080 | wtyczka | wunderground | ww2 | www | wybory | wybory2015 | włochy | węgry | xemex | xetex | xft | xhtml | xine | xml | xmllint | xsd | xslt | xvidtune | youtube | yum | zaatar | zakopane | zakupy | zawodzie | zdf | zdrowie | zeropi | zgarden | zgony | zprojekt | łeba | łotwa | świdnica | żywność
Archiwum
06/2023 | 02/2023 | 01/2023 | 11/2022 | 10/2022 | 09/2022 | 07/2022 | 06/2022 | 04/2022 | 03/2022 | 02/2022 | 12/2021 | 09/2021 | 03/2021 | 01/2021 | 12/2020 | 11/2020 | 10/2020 | 09/2020 | 08/2020 | 07/2020 | 04/2020 | 03/2020 | 02/2020 | 01/2020 | 12/2019 | 11/2019 | 10/2019 | 09/2019 | 08/2019 | 07/2019 | 06/2019 | 04/2019 | 02/2019 | 01/2019 | 12/2018 | 11/2018 | 10/2018 | 09/2018 | 08/2018 | 07/2018 | 05/2018 | 04/2018 | 03/2018 | 02/2018 | 01/2018 | 11/2017 | 10/2017 | 09/2017 | 08/2017 | 07/2017 | 06/2017 | 05/2017 | 04/2017 | 03/2017 | 02/2017 | 01/2017 | 12/2016 | 11/2016 | 10/2016 | 09/2016 | 08/2016 | 06/2016 | 05/2016 | 04/2016 | 02/2016 | 12/2015 | 11/2015 | 09/2015 | 07/2015 | 06/2015 | 05/2015 | 02/2015 | 01/2015 | 12/2014 | 09/2014 | 07/2014 | 06/2014 | 04/2014 | 02/2014 | 01/2014 | 12/2013 | 11/2013 | 10/2013 | 09/2013 | 08/2013 | 07/2013 | 05/2013 | 04/2013 | 03/2013 | 02/2013 | 01/2013 | 12/2012 | 11/2012 | 10/2012 | 09/2012 | 08/2012 | 07/2012 | 05/2012 | 03/2012 | 02/2012 | 01/2012 | 12/2011 | 11/2011 | 10/2011 | 09/2011 | 08/2011 | 07/2011 | 06/2011 | 05/2011 | 04/2011 | 03/2011 | 02/2011 | 01/2011 | 12/2010 | 11/2010 | 10/2010 | 09/2010 | 08/2010 | 07/2010 | 06/2010 | 05/2010 | 04/2010 | 03/2010 | 02/2010 | 01/2010 | 12/2009 | 11/2009 | 10/2009 | 09/2009 | 08/2009 | 07/2009 | 06/2009 | 05/2009 | 04/2009 | 03/2009 | 02/2009 | 01/2009 | 12/2008 | 11/2008 | 10/2008 | 09/2008 | 08/2008 | 07/2008 | 06/2008 | 05/2008 | 04/2008 | 03/2008 | 02/2008 | 01/2008 | 12/2007 | 11/2007 | 10/2007 | 09/2007 | 08/2007 | 07/2007 |
O stronie
wykorzystywany jest blosxom plus następujące wtyczki: tagging, flatarchives, rss10, lastbuilddatexhtmlmime. Niektóre musiałem dopasować nieco do swoich potrzeb. Więcej o blosxom jest tutaj
Subskrypcja
RSS 1.0
Wyświetlanie plików KML na umap.fr

Powiększ/Enlarge

W nawiązaniu do narzekań z poprzedniego wpisu spróbowałem alternatywy pn. umap.fr.

Na umap.fr można wyświetlać zawartość plików KML równie prosto jak na mymaps google. Jedyne co trzeba zmienić, to zawartość elementu description, który ma zawierać zamiast HTMLa podzbiór/wariant markdowna. Konkretnie ma być:

<description>
{{URL-do-miniatury-zdjęcia}}
[[URL-do-strony-zdjęcia|enlarge/powiększ]]
</description>

zamiast:

<description><![CDATA[
    <a href='URL-do-strony-zdjęcia' target='_blank'>
     <img src='URL-do-miniatury-zdjęcia' />enlarge/powiększ
     </a>]]>
  </description>

Tak zmieniony plik importujemy, zapisujemy, a osiągnięty rezultat jest do obejrzenia w ramce obok.

url | Tue, 16/02/2016 17:08 | tagi: , ,
Importowanie i wyświetlanie plików KML w Google Maps

Wycieczka do Mediolanu/Bergamo

Wkurzające są ciągłe udoskonalenia usług Google, których obocznym skutkiem jest niekompatybilność i/lub konieczność zmiany narzędzi, które działały kiedyś i nagle przestały działać. Taka przykrość spotkała mnie wczoraj i dotyczyła importu plików KML do myMaps/Mojemapy google.

Otóż kiedyś działało coś takiego (opisującego miejsce zrobienia zdjęcia):

<Placemark><name>epl316_2135207.jpg</name>
  <description><![CDATA[
    <a href='https://www.flickr.com/photos/tprzechlewski/24967425626/' target='_blank'>
     <img src='https://farm2.staticflickr.com/1508/24967425626_2166aceb85_m.jpg' />epl316_2135207.jpg
     </a>]]>
  </description>
  <Point><coordinates>9.20398056,45.48436667</coordinates>
  </Point>
</Placemark>

dziś przestało. Po kliknięciu w pinezkę, otwiera się okienko z informacją o zdjęciu, ale miniaturka zdjęcia nie jest wyświetlana.

Za pomocą reverse-engineering ustaliłem (być może nie jest to rozwiązanie optymalne), że działa poniższe:

  ... jak poprzednio ...
</description>
<ExtendedData><Data name='gx_media_links'>
<value>https://farm2.staticflickr.com/1508/24967425626_2166aceb85_m.jpg</value>
</Data></ExtendedData>
<Point> ...itd...

tzn po elemencie description trzeba wstawić ExtendedData, z zawartością jak wyżej.

Por także: Importowanie i wyświetlanie plików KML w Google Maps oraz Keyhole Markup Language/Adding Custom Data.

W promocji (w ramce po prawej) mapka wycieczki do Mediolanu/Bergamo zaimportowana w opisany wyżej sposób.

url | Sun, 14/02/2016 14:39 | tagi: , ,
Google Maps brzydko kombinuje z formatem KML

Google wyświetla coś takiego kiedy oglądam mapę z ostatniego wyjazdu:

Jedna z funkcji Map Google używanych na tej stronie wkrótce się zmieni. Konieczne będzie przeniesienie zawartości niestandardowej mapy.

Klikam w Dowiedz się więcej:

Po lutym 2015 roku nie będzie już można wyświetlać niestandardowej zawartości plików KML w klasycznej wersji Map Google. KML to format pliku używany przez Google Earth do wymiany informacji geograficznych.

Dalej nie bardzo wiadomo w czym będzie problem, ale przynajmniej powiedzieli, że to już niedługo, jak przestanie działać. Jeszcze jeden klik i w końcu wiadomo o co chodzi (ale po angielsku):

From February 2015, maps created in the classic Google Maps -- https://maps.google.com/ -- will no longer load KML/KMZ files from external websites. However, we know that KML files are a really useful way to work with geographic data, so we've added KML to Google My Maps, and continue to support this format with other Google Maps APIs. We hope that one of these options will meet your needs.

A więc google zmienił zdanie. Kiedyś twierdził, że cyt: KML upload and rendering has always been problematic with Maps i że lepiej (jeżeli już), to nie importować KML tylko wyświetlić go podając URL do dokumentu KML jako wartość parametru q, przykładowo:

https://mapy.google.pl/maps?q=http://pinkaccordions.homelinux.org/PLIK.kml

A teraz że wręcz przeciwnie: parametr q w ogóle nie zadziała.

Wraz ze zmianą zdania trzeba przyznać poprawiono wsparcie dla KML w Google Maps -- teraz już nie jest problematic (sprawdziłem jest OK).

Google wreszcie ustalił, że można korzystać z Google Maps bez zakładania konta Google i podjął stosowne działania? Nieładnie.

Zatem trzeba będzie zmienić sposób w jakim są wyświetlane pliki KML na Google Maps (teraz to się nazywa zdaje się Moje Mapy/My Maps). Na szczęście nie jest tego w moim przypadku za dużo.

url | Sun, 18/01/2015 20:21 | tagi: , ,
New Year in Vienna

With ZK and his family we have spent 3 days in Vienna. If you are interested click the map below to see journey GPX track and photos.

We visited Schönbrunn Palace (a former imperial summer residence), Stephansdom, and Kunsthistorisches museum (where one can see Pieter Bruegel's famous paintings including: The Tower of Babel, The Fight Between Carnival and Lent, and The Hunters in the Snow).

We also visited Flak Towers which are enormous concrete bunkers constructed during 2nd world war. FLAK stands for Flug Abwehr Kanone (or Flugzeugabwehrkanone) and Flak Towers were a part (not particularly effective--mobile system is always better for obvious reason) of German air defence system intended to protect cities and residential areas from Allied air raids. Their construction was planned in September 1942 and Vienna was the third city after Berlin and Hamburg that got them.

The Flak Towers fulfilled two purposes (cf. Flak-Türme Towers, Vienna: Nazi concrete heritage at Vienna's heart): They held cannons and spotlights that should fight airplanes from the ground; and they were important bunkers with an autonomous electricity, air and water supply system. They were built in pairs, comprising of larger Gefechtsturm (Combat Tower) and a smaller Leitturm (Fire-control tower). The three pairs of Vienna can be found in the Augarten in the second district, the Arenberg Park in the third district and one each in the Esterhazypark in the sixth and the Stiftskaserne in the seventh.

We visited Augarten and Arenberg towers.

url | Tue, 06/01/2015 11:49 | tagi: , , , , , ,
Trip to Georgia

I have just returned from a week-long trip to Georgia. We have visited Borjomi, Tbilisi, Kazbegi (Stepancminda) and Kutaisi (click the map to see journey track and photos).

On arriving to Kutaisi airport we went straight to the famous Borjomi resort where Russian Emperors once rested. We walked in the park tasting Borjomi mineral spring water, and swimming in hot water pool. From Borjomi we visited cave-city and monastery ensemble Vardzia where there was other hot water pool (with even hotter water). After 2 days in Borjomi we went to Tbilisi where we stayed 1 day (walking in old town). Next morning we drove to Caucasus mountains along Georgian military road via ancient Capital of Georgia -- Mtskheta (unfortunately we did not stop there). We stayed 2 days in Kazbegi where we hiked to Gergeti Trinity Church at 2170m and attended rugby union game Kazbegi vs Tbilisi Crusaiders (among other things:-). Finally we returned to Kutaisi where we visited Gelati and Motsameta Monastyrs as well as Sataplia caves...

We stayed in Leo's Homestay/Guesthouse in Borjomi, Why Not? Legend Hostel in Tbilisi and Hostel Kutaisi by Kote in Kutaisi. We recommend all of them.

The guesthouse we stayed in Kazbegi is not recommended so we do not mention it:-(

More details later...

url | Fri, 05/09/2014 13:13 | tagi: , , , , ,
Importowanie i wyświetlanie plików KML w Google Maps

Ubocznym skutkiem dodania współrzędnych geograficznych do zdjęć za pomocą skryptu gpsPhoto.pl jest plik w formacie KML. Każde zdjęcie w takim pliku jest oznakowane jak na przykładzie:


#1: Import do GMaps

#2: Z pinkaccordions

#3: Z sites.google.com

#4: Z sites.google.com

#5: Z serwera chello.pl
 <Placemark>
   <name>s300013_08275298.jpg</name>
   <description><![CDATA[<a href="/home/tomek/Obrazy/s300013_08275298.jpg">
    <img src="/home/tomek/Obrazy/s300013_08275298.jpg" width="200" /></a><br>
    <a href="/home/tomek/Obrazy/s300013_08275298.jpg">full size</a>]]>
   </description>
   <Point>
     <altitudeMode>clampToGround</altitudeMode>
     <coordinates>16.496808361,53.466461571,122</coordinates>
   </Point>

Dawno temu zrobiłem skrypt, który podmienia adres w lokalnym systemie plików (taki jak /home/tomek/Obrazy/s300013_08275298.jpg) na tenże plik, ale umieszczony na moim koncie w serwisie flickr.com:

 <Placemark>
   <name>s300013_08275298.jpg</name>
   <description><![CDATA[<a href="http://www.flickr.com/tprzechlewski/9615076609/">
    <img src="http://static.flickr.com/7411/9615076609_a243eed0f1_m.jpg" width="200" /></a><br>
    <a href="http://www.flickr.com/tprzechlewski/9615076609/">full size</a>]]>
   </description>
   ... itd ...

Taki plik za pomocą kilku klików importowałem do mapy Google (Mapy→Moje Miejsca → utwórz w klasycznej wersji Moich map) i działało -- do zeszłego piątku, kiedy to plik KML z wycieczki do Nadarzyc uparcie nie chciał się poprawnie wyświetlić (#1 -- obcięty ślad w okolicach Nadarzyc).

Konsultując problem via Google dowiedziałem się, że cyt KML upload and rendering has always been problematic with Maps i że lepiej (jeżeli już) to nie importować KML tylko wyświetlić go podając URL do dokumentu KML jako wartość parametru q. Przykład:

https://mapy.google.pl/maps?q=http://pinkaccordions.homelinux.org/Geo/kml/20130828__MP.kml

Działa (rys. #2). Ponieważ serwer pinkaccordions.homelinux.org jest rachityczny pomyślałem, że dobrze by było plik KML umieścić w jakimś lepszym miejscu, np. na witrynie sites.google.com. Jest nawet dedykowany -- i niestary bo z 2010 roku -- dokument w temacie pn. Using Google Sites to Host Your KML

Niestety plik KML pobierany z http://sites.google.com/site/ nie wyświetla się poprawnie. Po kliknięciu w ikonę niektórych zdjęć otwiera się okno ale jest ono puste (#3) i/lub nie wskazuje na stosowne miejsce na mapie (por. #4). Kombinowałem jak toto poprawić ale nie doszedłem do żadnych pozytywnych wniosków: połączenie GMaps + KML + sites.google.com nie działa.

PS: przypomniałem sobie, że mój Internet Provider daje w pakiecie konto na serwerze WWW z limitem 200Mb (z którego do tej pory mało korzystałem)... Sprawdziłem -- działa. Będę zatem tam trzymał pliki KML/KMZ (Rys. #5.)

url | Sat, 31/08/2013 18:34 | tagi: ,
Import KML files to GoogleMaps

The nuisance of GoogleMaps is that it does not know GPX and only KML/GeoRSS files can be uploaded. Fortunately it is easy to convert GPX to KML with gpsbabel:

gpsbabel -i gpx -f file.gpx -x simplify,count=333  -o kml -F file.kml

If there are several files they have to be convert one-by-one and then upload to Google. It would be more comfortable to merge them first and upload it in one go rather than uploading each individually.

As I could not find how to merge serveral GPX files into one using gpsbabel (merge option in gpsbabel puts all track points from all tracks into a single track and sorts them by time stamp. Points with identical time stamps will be dropped) I worked out the following simple Perl script:

#!/usr/bin/perl
#
# Combine GPX files into one
# usage: gpxmerge file1 file2 file3 ....
#
use XML::DOM;
binmode(STDOUT, ":utf8");

my $parser = new XML::DOM::Parser;

for my $file2parse (@ARGV) {
  my $doc = $parser->parsefile ($file2parse);

  for my $w ( $doc->getElementsByTagName ("wpt") ) {  $waypoints .= $w->toString() . "\n"; }
  for my $r ( $doc->getElementsByTagName ("rte") ) {  $routes .= $r->toString() . "\n"; }
  for my $t ( $doc->getElementsByTagName ("trk") ) {  $tracks .= $t->toString() . "\n"; }
}

print "<?xml version='1.0' encoding='UTF-8' ?>
<gpx version='1.1' creator='GPXmerger'
     xmlns='http://www.topografix.com/GPX/1/1'
     xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
     xsi:schemaLocation='http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd'>\n
<author>tomasz przechlewski </author>
<email>tprzechlewski[at]acm.org</email>
<url>http://pinkaccordions.homelinux.org/Geo/gpx/</url>";

print "$waypoints\n$routes\n$tracks\n";

print "</gpx>\n";

The resulting file structure is as follows: first all waypoints, then all routes and finally all tracks. This is perfectly legal GPX file.

Now I convert GPX to KML using gpsbabel:

gpsbabel -i gpx -f file.gpx -x simplify,count=333  -o kml -F file.kml

Since gpsbabel generates pretty verbose KML files I simplify them using XSLT stylesheet (perhaps this step is superfluous):

xsltproc -o simplified.kml kml2kml.xsl file.kml

and the stylesheet looks like:


<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:kml="http://www.opengis.net/kml/2.2" >

<xsl:output method="xml"  indent='yes' />

<xsl:template match="/">

<!-- ;; http://www.jonmiles.co.uk/2007/07/using-xpaths-text-function/ ;; -->

<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Document>


<Folder>
  <name>Waypoints</name>

  <xsl:for-each select="//kml:Folder[kml:name/text()='Waypoints']/kml:Placemark//kml:Point">
     <Placemark>
        <!-- <name><xsl:value-of select='../kml:name'/></name> --><!-- niepotrzebne -->
	<Point>
	  <coordinates>
	    <xsl:value-of select="kml:coordinates"/>
	  </coordinates>
	</Point>
     </Placemark>
  </xsl:for-each>

</Folder>


<Folder>
  <name>Tracks</name> 
 
  <xsl:for-each select="//kml:Placemark//kml:LineString">
    
    <Placemark>
      <name>Path</name>
    
      <LineString>
	<tessellate>1</tessellate>
	<coordinates>
	
	  <xsl:value-of select="kml:coordinates"/>
	
	</coordinates>
      </LineString>
    </Placemark>
  
  </xsl:for-each>

</Folder>

</Document>
</kml>

</xsl:template>
</xsl:stylesheet>

Now KML file is ready to be imported to Google maps via Maps → My Places → Create map.

The result of example conversion can be be found here.

url | Wed, 07/03/2012 23:37 | tagi: , , , ,
Where they came from?

Google fusion tables another excercise.

Two data sets describe football players who plays in Polish t-Mobile ekstraklasa (1st division) and Pierwsza Liga (2nd division) in 2011/2012 (autumn).

To show from where the player came a straight line is drawn from a player's birthplace to club's stadium, the player plays for.

Figure 1. 1st division.

Figure 2. 2nd division.

Players from 2nd division seems to be born closer to the clubs they play for:-)

Warning: in considerable number of cases the geocoding as performed by Google maybe wrong due to poor data quality--have no time to check/correct.

Raw data are available here: div#1 and div#2.

url | Thu, 09/02/2012 10:41 | tagi: , , , , ,
Google Fusion Tables map rendering issue?

Yet another excercise, which tests Google Fusion Tables.

The data set contains--among other things--birth place for 600+ rugby players who last year take part in Rugby World Cup in New Zealand. The raw data is available here and here.

On the following diagram (cf. Figure 1) the players are mapped by column containing birthplace coordinates

Figure 1. World's concentration of top Rugby Union players.

The map do not show which player plays for which country. To show that a straight line is drawn from each player's birthplace to the country's capital, the player plays for (cf. Figure 2).

Figure 2. The origin of top Rugby Union players by federation.

Some lines look strange and the problem is particularly evident around New-Zealand-Samoa-Tonga-Fiji. For example it seems that many Samoan players were born at high ocean (cf. Figure 3).

Figure 3. The origin of top Rugby Union Samoan players.

BTW mapping Samoans one-by-one is OK (try it). The problem is when all rows are mapped together by Visualize→Map function.

Accidentaly around 600 miles to the East of New Zealand lies antipodal meridian ie. a meridian which is diametrically opposite the Greenwich meridian (a pime one). The longitude of points lying on antipodal meridian can be referenced (at least in GoogleMaps) both as -180° or 180° (ie. -36,-180° and -36,+180° refers to the same place). Perhaps it is the cause of observed errors...

url | Mon, 06/02/2012 10:54 | tagi: , , , , , ,
Trzecie ćwiczenie z Google Fusion Tables - sejm RP siódmej kadencji

Wprawdzie Sejm RP szybkimi krokami zmierza w stronę wybranego w 1936 r. Reichstagu określanego jako ,,najlepiej opłacany męski chór ma świecie'' (The best paid male chorus in the world -- określenie użyte podobno w amerykańskim czasopiśmie The Literary Digest) i być może już w kadencji ósmej ten stan ideału zostanie osiągnięty. Ale zanim to nastąpi zbierzmy dane dotyczące posłów wybranych do Sejmu 7 kadencji.

Zaczynam od ściągnięcia listy stron bibliograficznych posłów:

## Najpierw zestawienie posłów:
wget -U XX http://www.sejm.gov.pl/sejm7.nsf/poslowie.xsp?type=A -O lista-poslow.html
## Potem dla każdego posła z zestawiena:
cat lista-poslow.html | perl -e ' 
undef $/; 
$_ = <>; 
s/\n/ /g;

while ($_ =~ m@href="/sejm7.nsf/posel.xsp\?id=([0-9]+)\&amp;type=A@g ) {
    $id = $1; ## id posła
    $pos = "http://www.sejm.gov.pl//sejm7.nsf/posel.xsp?id=$id&amp;type=A";
    print STDERR $pos, "\n";
    system ('wget', '-U', 'XXX', "-O", "7_$id.html", $pos);
    sleep 3; ## --let's be a little polite--
}

Powyższe pobiera 460 stron, każda zawierająca biografię jakiegoś posła.

Z kolei poniższy skrypt wydłubuje co trzeba (data scraping) ze strony zawierających biografię pojedynczego posła (np. tego).

#!/usr/bin/perl
#
use Storable;
use Google::GeoCoder::Smart;
$geo = Google::GeoCoder::Smart->new();

# Domyślny kraj
my $GeoCodeCacheName = 'geocode.cache';
my $NewCoordinatesFetched=0; # global flag
my $kraj = 'Polska';
my $SLEEP_TIME = 3 ;
# Rok wyborów
my $baseyr = 2011; 
my ($data_day, $data_mc, $data_yr);

undef $/;
$_ = <>;
s/\n/ /g;

# Retrieve geocode cash (if exists)
# http://curiousprogrammer.wordpress.com/2011/05/11/faking-image-based-programming-in-perl/
my %hash = %{ retrieve("$GeoCodeCacheName") } if ( -f "$GeoCodeCacheName" ) ;

if (m@<h2>([^<>]+)</h2>@) { $posel = recode($1); }

# zgadnij płeć patrząc na imię (jeżeli kończy się na a->kobieta):
my @tmp_posel = split " ",  $posel;
if ( $tmp_posel[0] =~ m/a$/ ) { $sex='K' } else { $sex='M' }

# id posła:
if (m@http://www.sejm.gov.pl/sejm7.nsf/posel.xsp\?id=([0-9]+)@) {$id = $1; }

# liczba oddanych na posła głosów:
if (m@<p class="left">Liczba g\&#322;os\&oacute;w:</p>[ \n\t]*<p class="right">([^<>]+)</p>@) {
   $glosy = $1 ; }

# Data i miejsce urodzenia:</p><p class="right">29-06-1960<span>,&nbsp;</span>Gda&#324;sk</p>
if (m@Data i miejsce urodzenia:[ \n\t]*</p>[ \n\t]*<p class="right">([0-9\-]+)<span>,[ \n\t]*\&nbsp;[ \n\t]*</span>([^<>]+)</p>@ ) {
  $data = recode ($1); 
  ($data_day, $data_mc, $data_yr) = split "-", $data;
  ##print STDERR "R/M/D: $data_day, $data_mc, $data_yr\n";
  $mce = recode ($2);
}

# Zawód:
if (m@<p class="left">Zaw\&oacute;d:</p>[ \nt]*<p class="right">([^<>]+)</p>@ ) { $zawod = recode($1) ; }

if (m@klub.xsp\?klub=([^"<>]+)@ ) { $klub = recode($1); }

# Klub poselski:
if (m@Okr\&#281;g wyborczy:</p>[ \t\n]*<p class="right">([^<>]+)</p>@) {
  $okr = recode($1);
  ## Pierwszy wyraz to numer okręgu, reszta nazwa (może być wielowyrazowa)
  ($okrnr, $okrnz) =  $okr =~ m/([^ \n\t]+)[ \n\t]+(.+)/; ## -- sprawdzić czy działa --
}

# Poprawienie błędów
if ($mce =~ /Ostrowiec Świetokrzyski/) {$mce = 'Ostrowiec Świętokrzyski' }
elsif ($mce =~ /Stargard Szaczeciński/) {$mce = 'Stargard Szczeciński' ; }
elsif ($mce =~ /Białograd/ ) {$mce = 'Białogard'; }
elsif ($mce=~ /Szwajcaria/) {$mce = 'Szwajcaria,Suwałki' }
elsif ($mce=~ /Kocierz Rydzwałdzki/) { $mce= "Kocierz Rychwałdzki" }
elsif ($mce=~ /Stąporów/) { $mce= "Stąporków" }
elsif ($mce=~ /Szmotuły/) { $mce= "Szamotuły" }

# Wyjątki:
if ($posel=~ /Arkady Fiedler/ ) {$kraj = 'Wielka Brytania' }
elsif ($posel=~ /Vincent-Rostowski/) {$kraj = 'Wielka Brytania' }
elsif ($mce=~ /Umuahia/) {$kraj = 'Nigeria' }
elsif ($posel=~ /Munyama/) {$kraj ='Zambia'; }
## Imię kończy się na `A' ale to facet:
elsif ($posel=~ /Kosma Złotowski/ ) {$sex = "M"}

# Sprawdź czy data jest zawsze w formacie dd-mm-yyyy:
if ($data_yr < 1900) { print STDERR "*** $data_yr: $data for $posel ($id)\n"; }

# geokodowanie (uwaga na limit) 
my $coords = addr2coords($mce);
my $wiek =  $baseyr - $data_yr;
my $coords_okr = addr2coords($okrnz, 'r'); ($tmp_lat, $tmp_lng) = split " ", $coords;

my $kml_line = "<LineString><coordinates>$tmp_lng,$tmp_lat $coords_okr</coordinates></LineString>";

print STDERR "$id : $sex : $posel : $wiek\n";
print "$id;$sex;$posel;$data;$wiek;$mce,$kraj;$coords;$klub;$glosy;$zawod;$okrnr;$okrnz;$kml_line\n";

## Retrieve geocode cash
if ($NewCoordinatesFetched) { store(\%hash, "$GeoCodeCacheName"); }

## ## ## ## ## ##
sub recode {
  my $s = shift;

  $s =~ s/\&nbsp;/ /g; $s =~ s/\&#322;/ł/g; $s =~ s/\&oacute;/ó/g;
  $s =~ s/\&#324;/ń/g; $s =~ s/\&#321;/Ł/g; $s =~ s/\&#378;/ź/g;
  $s =~ s/\&#380;/ż/g; $s =~ s/\&#346;/Ś/g; $s =~ s/\&#379;/Ż/g;
  $s =~ s/\&#281;/ę/g; $s =~ s/\&#261;/ą/g; $s =~ s/\&#347;/ś/g;
  $s =~ s/\&#263;/ć/g; $s =~ s/[ \t\n]+/ /g;

  return $s;
}

## ## ## ## ## ##
sub addr2coords {
 my $a = shift ;
 my $r = shift || 'n';
 my ($lat, $lng) ;

 ##consult cache first
 if (exists $GeoCodeCache{"$a"} ) {
   ($lat,$lng) = split (" ", $GeoCodeCache{"$a"} );
 }
 else {
   my ($resultnum, $error, @results, $returncontent) = $geo->geocode("address" => "$a");
   $resultnum--; 
   $resultNo=$resultnum ;

   if (resultNo > 0) { print STDERR "** Location $a occured more than once! **" }
   if ($error eq 'OK') {
     $NewCoordinatesFetched=1;
     for $num(0 .. $resultnum) {
       $lat = $results[$num]{geometry}{location}{lat};
       $lng = $results[$num]{geometry}{location}{lng};
       ##print "*** LAT/LNG:$lat $lng ERROR: $error RES: $resultNo ***\n";
     }
   } else { print STDERR "** Location $a not found! due to $error **"  }
 }

 $GeoCodeCache{"$a"} = "$lat $lng"; ## store in cache
 sleep $SLEEP_TIME;

 if ($r eq 'r' ) { return "$lng,$lat"; } # w formacie KML
 else { return "$lat $lng"; }
}

Skrypt wydłubuje id posła (id), imię i nazwisko (imnz), datę urodzenia (data_ur), miejsce urodzenia (mce_ur), skrót nazwy partii do której należy (partia), liczbę oddanych na niego głosów (log), zawód (zawod), numer okręgu wyborczego (nrokregu) i nazwę okręgu (nzokregu). Do tego zgadywana jest płeć posłanki/posła oraz obliczany jest wiek w chwili wyboru jako $baseyr - $data_yr, gdzie $data_yr to rok urodzenia.

Miejsce urodzenia oraz nazwa okręgu są geokodowane. Współrzędne miejsca urodzenia są zapisywane jako zmienna wsp. Jako zmienna odleglosc zapisywana jest linia definiowana (w formacie KML) jako: współrzędne miejsce urodzenia--współrzędne okręgu wyborczego.

<LineString><coordinates>lng1,lat1 lng2,lat2</coordinates></LineString>

Zamiana kupy śmiecia (tj. wszystkich 460 plików HTML) na plik CSV zawierający wyżej opisane dane sprowadza się teraz do wykonania:

for i in 7_*html ; do perl extract.pl $i >> lista_poslow_7_kadencji.csv ; done

Jako ciekawostkę można zauważyć, że strony sejmowe zawierają 6 oczywistych błędów: Ostrowiec Świetokrzyski, Stargard Szaczeciński, Białograd, Kocierz Rydzwałdzki, Stąporów oraz Szmotuły. Ponadto wieś Szwajcaria k. Suwałk wymagała doprecyzowania. Czterech posłów urodziło się za granicą a pan Kosma jest mężczyzną i prosta reguła: jeżeli pierwsze imię kończy się na ,,a'' to poseł jest kobietą zawiodła.

Ostatecznie wynik konwersji wygląda jakoś tak (cały plik jest tutaj):

id;plec;imnz;dat_ur;wiek;mce_ur;wsp;partia;log;zawod;nrokregu;nzokregu;odleglosc
001;M;Adam Abramowicz;10-03-1961;50;Biała Podlaska,Polska;52.0324265 23.1164689;PiS;\
  12708;przedsiębiorca;7;Chełm;<LineString><coordinates>23.1164689,52.0324265 23.4711986,51.1431232</coordinates></LineString>
 ...

Teraz importuję plik jako arkusz kalkulacyjny do GoogleDocs, a następnie, na podstawie tego arkusza tworzę dokument typu FusionTable. Po wizualizacji na mapie widać parę problemów -- ktoś się urodził niespodziewanie w USA a ktoś inny za Moskwą. Na szczęście takich omyłek jest tylko kilka...

Geocoder nie poradził sobie z miejscowościami: Model/prem. Pawlak, Jarosław/posłowie: Kulesza/Golba/Kasprzak, Orla/Eugeniusz Czykwin, Koło/Roman Kotliński, Lipnica/J. Borkowski, Tarnów/A. Grad. We wszystkich przypadkach odnajdywane były miejsca poza Polską -- przykładowo Orly/k Paryża zamiast Orli. Ponadto pani poseł Józefa Hrynkiewicz została prawidłowo odnaleziona w Daniuszewie ale się okazało, że ta miejscowość leży na Białorusi a nie w Polsce. Też ręcznie poprawiłem...

Ewidentnie moduł Google::GeoCoder::Smart ustawia geocoder w trybie partial match, w którym to trybie Google intelligently handles incomplete input aka stara się być mądrzejszym od pytającego. Może w trybie full match byłoby lepiej, ale to by wymagało doczytania. Na dziś, po prostu poprawiłem ręcznie te kilka ewidentnie błędnych przypadków.

Po poprawkach wszystko -- przynajmniej na pierwszy rzut -- oka wygląda OK

Link do tabeli jest zaś tutaj.

Nawiasem mówiąc kodowanie dokumentów na stronach www.sejm.gov.pl jest co najmniej dziwaczne.

url | Sun, 29/01/2012 21:31 | tagi: , , , , , ,
Drugie ćwiczenie z Google Fusion Tables - mapa zatopionych Ubootów

Klasyczny zbiór danych pn. niemieckie łodzie podwodne z 2WWŚ wg. typu, liczby patroli, zatopionych statków i okrętów oraz -- dodane dziś -- miejsca zatopienia (źródło: www.uboat.net). W zbiorze są 1152 okręty (pomięto 14, które były eksploatowane przez Kriegsmarine ale nie były konstrukcjami niemieckimi), z tego 778 ma określoną pozycję, na której zostały zatopione (z czego kilkadziesiąt w ramach operacji DeadLight). Można zatem powiedzieć, że dane dotyczące miejsca zatopienia/zniszczenia są w miarę kompletne, bo np. Kemp (1997) podaje liczbę 784 U-bootów zniszczonych w czasie 2WWŚ (dane są różne w zależności od źródła.)

Jeżeli U-boot zaginął/przepadł bez wieści/został zniszczony, ale nie wiadomo dokładnie gdzie, to nie występuje na mapie. Operacja DeadLight to ta wielka kupa kropek ,,nad'' Irlandią....

Link do danych/mapy na serwerze Google jest tutaj.

Dane były tylko zgrubie weryfikowane, więc mogą zawierać błędy (ale ,,na oko'' jest ich niewiele)...

Literatura

Kemp Paul, U-Boats Destroyed: German Submarine Losses in World Wars, US Naval Institute Press, 1997 (isbn: 1557508593)

url | Wed, 11/01/2012 21:23 | tagi: , , , , , ,
Pierwsze próby z Google Fusion Tables

Pod tym adresem umieściłem moje ślady GPS (głównie rowerowe) z lat 2010--2012. W formacie KML bo to jedyny -- z tego co mi się wydaje -- obsługiwany przez Google Fusion Tables (GFT).

Moja procedura skopiowania danych z urządzenia GPS (zwykle jest to Garmin Legend) do GFT jest następująca:

  1. Skryptem obsługującym program gpsbabel pobieram dane z urządzenia GPS do pliku w formacie GPX.

  2. Skryptem kml2kml.sh zamieniam plik GPX otrzymany w pierwszym kroku na plik w formacie KML. Ponieważ plik ten jest ogromy (przykładowo z 60 kilowego pliku GPX gpsbabel wygenerował plik o wielkości ponad 500 kb) zostaje on za pomocą trywialnego arkusza XSLT zamieniony na znacznie mniejszą wersję uproszczoną:

    #!/bin/bash
    #
    KMLSTYLE=~/share/xml/kml2kml.xsl
    #
    # Domyslna liczba punktow na sladzie
    COUNT=99
    ## Domyslna nazwa Placemarka
    NAME=`date +%Y%m%d_%H`;
    
    while test $# -gt 0; do
      case "$1" in
    
        -name)  shift; NAME="$1";;
        -name*) NAME="`echo :$1 | sed 's/^:-name//'`";;
    
        -max)  shift; COUNT="$1";;
        -max*) COUNT="`echo :$1 | sed 's/^:-max//'`";;
        *)   FILE="$1";;
      esac
      shift
    done
    
    ## Usun rozszerzenie z nazwy pliku wejsciowego
    OUT_FILE="${FILE%.*}"
    
    TMP_FILE=/tmp/${OUT_FILE}.kml.tmp
    
    echo "Converting $FILE to ${TMP_FILE}..."
    
    if [ -f $FILE ] ; then
      ## Konwersja GPX->KML
      gpsbabel -i gpx -f $FILE -x simplify,count=$COUNT  -o kml -F $TMP_FILE
    else
      echo "*** ERROR *** File $FILE not found.... ***" ; exit 
    fi
    
    ## Konwersja do uproszczonego KMLa (KML->KML)
    echo "Converting $TMP_FILE to ${OUT_FILE}.kml with maximum $COUNT points..."
     
    echo "KML' Placemark name is: $NAME..."
    xsltproc --stringparam FileName "$NAME" -o ${OUT_FILE}.kml $KMLSTYLE $TMP_FILE
    
    echo "Done..."
    

    Zawartość arkusza XSLT zamieszczono na końcu tej notki.

  3. Do interakcji z Fusion Tables wykorzystam zmodyfikowany skrypt (nazwany ftquery.sh) znaleziony na stronach code.google.com:

    #!/bin/bash
    #
    # Copyright 2011 Google Inc. All Rights Reserved.
    # Author: arl@google.com (Anno Langen)
    # http://code.google.com/intl/pl/apis/fusiontables/docs/samples/curl.html
    # -- Modified by TP --
    MY_QUERY=$*
    
    function ClientLogin() {
      password='?1234567890?'
      email='looseheadprop1@gmail.com'
      local service=$1
      curl -s -d Email=$email -d Passwd=$password -d \
        service=$service https://www.google.com/accounts/ClientLogin | tr ' ' \n | grep Auth= | sed -e 's/Auth=//'
    }
    
    function FusionTableQuery() {
      local sql=$1
      curl -L -s -H "Authorization: GoogleLogin auth=$(ClientLogin fusiontables)" \
       --data-urlencode sql="$sql" https://www.google.com/fusiontables/api/query
    }
    
    FusionTableQuery "$MY_QUERY"
    
  4. Teraz tworzę nową tabelę (wyklikowując co trzeba w przeglądarce) MyTracks o następującej strukturze:

    ## Korzystamy z skryptu ftquery.sh
    ./ftquery.sh SHOW TABLES
    table id,name
    2590817,MyTracks
    ## Tabela MyTracks ma zatem id=2590817
    ./ftquery.sh DESCRIBE 2590817
    column id,name,type
    col4,Date,string
    col0,Start,string
    col1,Stop,string
    col2,Location,location
    col3,Description,string
    

    Kolumny zawierają odpowiednio: datę (Date), czas pierwszego wpisu na śladzie GPX (Start), czas ostatniego wpisu na śladzie GPX (Stop), ślad (Location) oraz opis (Description).

    Kolumny Tabeli w Google Fusin Tables mogą być albo napisami (STRING), liczbami (NUMBER), zawierać dane przestrzenne (LOCATION) albo czas (DATETIME). Wstępne eksperymenty z typem DATETIME wskazują, że jest z nim jakiś problem. Primo format czasu jest dość dziwaczny (np. gpsbabelowy zapis: 2012-01-07T09:19:47Z nie jest rozpoznawany). Także późniejsze filtrowanie w oparciu o kolumnę DATETIME też jakoś nie wychodzi, nawet jak zapisałem datę w formacie YYY.MM.DD, który wg. dokumentacji powinien być rozpoznawany. Nie badając sprawy dogłębnie, zmieniłem po prostu typ kolumn Date, Start, Stop na STRING.

  5. Cytując za dokumentacją GFT: In a column of type LOCATION, the value can be a string containing an address, city name, country name, or latitude/longitude pair. The string can also use KML code to specify a point, line, or polygon... (cf. SQL API: Reference ). Zatem żeby wstawić linię śladu wystarczy przesłać napis zawierający współrzędne opakowane w następujący sposób:

    <lineString><coordinates>lng,lat[,alt] lng,lat[,alt]...<coordinates></lineString>
    

    Do tego służy następujący skrypt:

    #!/bin/bash
    #
    STYLE=~/share/xml/gpxtimestamp.xsl
    MYTRACKS_TABLE_ID="2590817"
    GPX_FILE=$1
    KML_FILE="${GPX_FILE%.*}".kml
    
    ## Ustal czas od--do sladu 
    STARTTIME=`xsltproc --param Position '"First"' $STYLE $GPX_FILE`
    STOPTIME=`xsltproc --param Position '"Last"' $STYLE $GPX_FILE`
    DATE=`xsltproc --param Position '"First"' --param Mode '"Date"' $STYLE $GPX_FILE`
    
    if [ ! -f $GPX_FILE ] ; then echo "*** Error *** No GPX file: $GPX_FILE" ; exit ; fi
    if [ ! -f $KML_FILE ] ; then echo "*** Error *** No KML file: $KML_FILE" ; exit ; fi
    
    ## ## Wycinamy nastepujacym skryptem z uproszczonego pliku KML:
    TRACK=`perl -e 'undef $/; $t = <>; $t =~ m/(<coordinates>.*<\/coordinates>)/s; \
        $t = $1; $t =~ s/[ \t\n]+/ /gm; print $t;' $KML_FILE`
    TRACK="<LineString>$TRACK</LineString>"
    
    ftquery.sh "INSERT INTO $MYTRACKS_TABLE_ID (Date, Start, Stop, Location, Description) 
      VALUES ('$DATE', '$STARTTIME', '$STOPTIME', '$TRACK', '') "
    

    I działa, tj. przesyła co trzeba na moje konto Google.

Google Fusion Table map view in Chrome
GFT map view in Chrome

Google się chwali, że GFT radzi sobie z ogromnymi zbiorami danych. Mój ma -- na tem chwilem -- ponad 150 wierszy, a w każdym 99 punktów na śladzie, co daje łącznie approx 15,000 punktów do wykreślenia. Firefox/Opera coś tam wyświetla ale niewiele widać. Chrome radzi sobie najlepiej -- faktycznie da się to obejrzeć, przesuwać, powiększać... Wprawdzie nic z tych danych nie wynika, ale to już nie jest pytanie do Google.

Także filtr w połączeniu z mapą działa w Firefoksie i Operze tak sobie. Wybieram zbiór tras, np. za pomocą warunku Date < 20100901 (na tem chwilem jest to 7 wierszy) następnie klikam Visualise Map i guzik -- nic nie widać. Ale znowu w Chrome jest znacznie lepiej. Dowód w postaci zrzutu ekranu obok. Także wklejony poniżej link do mapy (pobrany przez kliknięcie w guzik Get embeddable link) daje pozytywny wynik:

Przynajmniej w mojej wersji FF (8.0).

Arkusze XSLT wykorzystane w skryptach

Zamiana pliku KML na uproszczony plik KML:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:kml="http://www.opengis.net/kml/2.2" >

<xsl:output method="xml"/>
<xsl:param name='FileName' select="'??????'"/>

<xsl:template match="/">

<kml xmlns="http://www.opengis.net/kml/2.2"
	xmlns:gx="http://www.google.com/kml/ext/2.2">
<Document>
<Placemark>

<name><xsl:value-of select="$FileName"/></name>

<MultiGeometry><LineString>
<tessellate>1</tessellate>
<coordinates>

<xsl:for-each select="//kml:Placemark//kml:LineString">

<xsl:value-of select="kml:coordinates"/>

</xsl:for-each>

</coordinates></LineString></MultiGeometry></Placemark>
</Document></kml>

</xsl:template>
</xsl:stylesheet>

Wydrukowanie daty/czasu z pliku w formacie GPX:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:gpx="http://www.topografix.com/GPX/1/0">

<xsl:output method="text"/>
<xsl:param name='Position' select="'First'"/>
<xsl:param name='Mode' select="'Time'"/>

<xsl:template match="/" >

<xsl:for-each select='//*[local-name()="trkpt"]'> 

  <xsl:choose>
    <xsl:when test="position()=1 and $Position='First' and $Mode='Time'">
      <xsl:value-of select='substring(*[local-name()="time"], 12, 8)'/> 
      <xsl:text>
</xsl:text>
    </xsl:when>
    <xsl:when test="position()=1 and $Position='First' and $Mode='Date'">
      <xsl:value-of select='translate(substring(*[local-name()="time"], 1, 10), "-", "")'/>
      <xsl:text>
</xsl:text>
    </xsl:when>
    <xsl:when test="position()=last() and $Position='Last'">
      <xsl:value-of select='substring(*[local-name()="time"], 12, 8)'/>
      <xsl:text>
</xsl:text>
    </xsl:when>
  </xsl:choose>  

</xsl:for-each>
  
</xsl:template>
</xsl:stylesheet>

Dokumentacja

  1. SQL API: Developer's Guide.

  2. SQL API: Reference .

  3. Google fusion tables cheat sheet.

url | Mon, 09/01/2012 11:51 | tagi: , , , , ,
Wycieczka do Wilna
Wilno, Ostra Brama

W tym roku w tzw. długi weekend pojechaliśmy na wycieczkę (samochodem) na Litwę, a konkretnie w zamiarze zwiedzania Wilna i Troków.

Ślady GPX z wycieczki są tutaj: 20100430201005012010050220100503. Więcej zdjęć jest na flickr.com. Ślady w formacie KML są tutaj: 20100430201005012010050220100503.

url | Wed, 05/05/2010 14:17 | tagi: , , , , , , ,
Zbędne deklaracje xmlns przy zamianie KML→GPX

Z pliku XML w wersji KML, tj. googleearth chcę wydłubać współrzędne punktów MyPlaces oraz zapisać je w formacie GPX (celem późniejszego załadowania do Garmina). Używam do tego następującego arkusza XSLT:



  

  
    

        
    
  

  
    
      
        
      
      
        
      
      
        
      
      
        
      
    
  

]]>

Gdyby w powyższym arkuszu XSLT zamiast

    <wpt xsl:exclude-result-prefixes="gpx kml" 
         xmlns='http://www.topografix.com/GPX/1/0'>
    ...

było po prostu:

    <wpt xsl:exclude-result-prefixes="gpx kml" 
    ...

to znaczy zostałaby pominięta deklaracja przestrzeni nazw elementu wpt, wtedy procesor XSLT zapisałby na wyjściu coś w rodzaju:

 <wpt xmlns="" lat="19.35304208110762" lon="54.35681836243874">
   ...

A to oznacza, że wpt pochodziłby z pustej przestrzeni nazw, xmlns="". Niby proste, ale nie jest oczywiste jak usunąć -- na pierwszy rzut oka zbędne (a tak na prawdę błędne) -- wpisy xmlns="".

url | Wed, 31/03/2010 09:21 | tagi: , , ,
Publikowanie ciekawych miejsc z Googleearth

Jak w googleearth doda się żółtą pinezkę (dodaj oznaczenie miejsca), to zaznaczone miejsce jest zapisywane w pliku ~/.googleearth/myplaces.kml. Plik ten oprócz informacji o pinezkach zawiera różne inne informacje. Poniższy skrypt upraszcza myplaces.kml usuwając wszystko za wyjątkiem węzłów Document/Folder/Placemark jeżeli element Folder zawiera napis "Moje miejsca":

<?xml version="1.0" encoding="iso-8859-2"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:kml="http://earth.google.com/kml/2.2" version="1.0" >
  
  <xsl:output method="xml" indent="yes" />

  <xsl:template match='/'>
    <kml xmlns="http://earth.google.com/kml/2.2">
      <Document>
	<name>Ciekawe miejsca Tomasza Przechlewskiego</name>
	<xsl:apply-templates select='//kml:Document/kml:Folder[kml:name/text()="Moje miejsca"]/kml:Placemark' />
      </Document>
    </kml>
  </xsl:template>

  <xsl:template match="kml:Document/kml:Folder/kml:Placemark">
    <xsl:copy-of select="."/>
  </xsl:template>
</xsl:stylesheet>

Koniecznie trzeba używać przestrzeni nazwa. Inaczej nie działa: kml:Document oraz Document to dwie różne rzeczy.

Moje miejsca są tutaj.

url | Thu, 08/05/2008 12:50 | tagi: , ,
Wycieczka do Kilonii
U-995
U-boot Ehrenmal
Königsstuhl
Königsstuhl

W tzw. długi weekend pojechaliśmy na wycieczkę (samochodem) do północnych Niemiec: Kilonia, Lubeka, wyspa Rugia. Pod Kilonią w miejscowości Laboe jest Das Technische Museum, pod którą to nazwą kryje się U-Boot udostępniony do zwiedzania. Jest to okręt typu VIIC o numerze 995, czyli trzeba wpisać U-995 do Google jakby ktoś chciał poszukać w Internecie więcej informacji na ten temat. Obok jest coś w rodzaju mauzoleum (Marine-Ehrenmal) i wieża. Nic ciekawego--jakaś ekspozycja nt. Bundesmarine + modele okrętów + coś tam jeszcze. Opisy wyłącznie po niemiecku... Można sobie śmiało darować. Z wieży oczywiście lepiej widać okolicę, więc jak ktoś jest ciekaw to może sobie wjechać windą.

Obok Laboe, bliżej Kilonii, w miejscowości Möltenort jest jeszcze jedno mauzoleum. Upamiętnia ono załogi okrętów podwodnych Kriegsmarine (U-boot Ehrenmal). Dla niezorientowanych: 80% U-Bootów, tj. około 840 z 1100, które weszły do służby zostało zatopionych. Wiele łodzi zostało zniszczonych w pierwszym rejsie, często pierwszy kontakt z wrogiem był dla załogi kontaktem śmiertelnym i ostatnim. Z tego co pamiętam około 40% łodzi nie zatopiło żadnego statku. Zginęło ok. 28000 spośród ok. 40000 marynarzy. Do tego cała sprawa była z góry przegrana (wojny o Atlantyk Ubootwaffe nie mogła wygrać), a poświęcenie tych ludzi z góry skazane na niepowodzenie i bezsensowne.

Zwiedzanie U-boota było w czwartek, w piątek pojechaliśmy do Lubeki i cały dzień zwiedzaliśmy stare miasto, szczególnie zwracając uwagę na kościół St Marien Kirche w którym Orgelmeisterem był Dietrich Buxtehude, (cf. Buxtehude -- zapomniany geniusz z Lubeki). BTW organów mistrza już nie ma bo się spaliły w 1942 roku w czasie nalotu RAF.

Wreszcie w sobotę jeździliśmy po Rugii. Byliśmy w Narodowym Parku Jasmund i oglądaliśmy Königsstuhl. Okazało się, że w Sassnitz stoi przycumowany jeszcze jeden okręt podwodny: HMS Otus. Dużo większy od U-995, bo to powojenna konstrukcja--nie zwiedzaliśmy. Potem zamek myśliwski Jagdschloss Granitz i powrót do domu z noclegiem u znajomych w Świnoujściu.

Zrobiłem dużo zdjęć ale wyszły tak sobie. Specjalnie na U-boota kupiłem lampę (FL-36, używaną na Allego), którą zresztą mało nie rozbiłem przez nieuwagę. Ostatecznie straciłem tam tylko jeden akumulator AA, który wtoczył się pod pokrywy podłogi i przepadł w czeluściach okrętu.

Ślad GPX z wycieczki jest tutaj. Więcej zdjęć jest na flickr.com. Ślad w formacie KML w przygotowaniu...

Dopisane 8 maja 2008: Przebytą trasę rejestrowałem moim bt747 (aka Iblue 747); teoretycznie logger powinien zmieścić zapis 20 godzinny ale dla pewności zgrywałem ślad codziennie. Po przyjeździe zagregowałem całość używając gpsbabela:

#!/bin/bash
gpsbabel -t -i gpx -f 20080501.gpx -i gpx -f 20080502.gpx \
   -i gpx -f 20080503.gpx -i gpx -f 20080504.gpx \
   -x track,merge,title="Trip to Laboe 30/4--4/5 2008" \
   -x simplify,count=2000 -o gpx -F sopot-laboe-sopot.gpx && \
grep -v '<course>0.000000</course>\|<fix>2d</fix>\|<ele>0.000000</ele>' \
   sopot-laboe-sopot.gpx > sopot-laboe-sopot_s.gpx

Teraz używając opisanych na innych stronach tego bloga skryptu gpsPhoto.pl dodałem współrzędne geograficzne do zdjęć. Kilkanaście zdjęć nie zostało oznakowanych -- wszystkie nieoznakowane były robione wewnątrz U-boota. Nic dziwnego zresztą bo toto ma podwójny stalowy kadłub w tym wewnętrzny dość gruby. Nie pamiętam ile konkretnie milimetrów, ale U-booty potrafiły się zanurzać na ponad 250 metrów, szacun!

Oczywistym rozwiązaniem jest dodanie współrzędnych ze zdjęć zrobionych w tym samym miejscu w momencie gdy GPS logger ,,widział'' niebo. Używając exiftool jest to banalnie proste:

#!/bin/bash
exiftool -TagsFromFile plik-bez-wsp -GPSLatitude -GPSLongitude -GPSLatitudeRef -GPSLongitudeRef plik-z-wsp

Dodałem też możliwość uruchomienia ww. skryptu moim w trybie Emacsa służącym do ładowania zdjęć na flickr.com. Działa to w ten sposób, że kopiowane są współrzędne GPS z pliku podanego w wierszu minibufora do pliku, którego nazwa znajduje się w wierszu bieżącym (tj. wierszu, w którym jest kursor).

Na ,,odcinku'' ładowania zdjęć też się popsuło. Mój skrypt przestał obracać zdjęcia zrobione w układzie portretowym. Przestała działać metoda flickr.photos.transform.rotate i to w dość dziwny sposób: zwracany komunikat jest OK, ale obrazek nie jest obracany. Do tego wykonanie flickr.photos.transform.rotate oddzielnym skryptem działa. Podejrzewam braci Flickr, że coś zmienili na serwerze i namieszali. Ostatecznie zmieniłem strategię: zdjęcia są obracane ,,fizycznie'', z użyciem jpegtran wywołanym z ,,wnętrza'' skryptu perlowego za pomocą system().

Po załadowaniu zdjęć na flickr.com. Poprawiłem plik KML używając do tego skryptów kml-adjust-urls/kml-skip-deadlinks.

Plik są tutaj: KML oraz GPX.

url | Wed, 07/05/2008 12:28 | tagi: , , , , , ,
Google earth w Fedora Core 8

Googleearth wersja na linuksa nie działa `out of the box'. Bardzo wolno startuje, a na ekranie pojawia się komunikat:

do_wait: drmWaitVBlank returned -1, IRQs don't seem to be working correctly.
Try running with LIBGL_THROTTLE_REFRESH and LIBL_SYNC_REFRESH unset.

Sądząc z liczby stron w Google jest to problem wielu użytkowników. Rozwiązanie znalazłem tutaj (pomocne mogą być też uwagi z tej strony). Na wszelki wypadek zniknięcia oryginału w czeluściach Internetu poniżej kopiuję co trzeba zrobić. Otóż do pliku drm_nowaitVblank.c wpisujemy:

#include <sys/time.h>
#include <unistd.h>
#include <string.h>

#define	DELAY	33333

int drmWaitVBlank(void)
{
	static struct timeval last = { 0, 0 };
	static struct timeval now  = { 0, 0 };
	int udiff;
	
	gettimeofday(&now, NULL);
	udiff = (int)now.tv_usec - (int)last.tv_usec;
	if (udiff < 0)
		udiff += 1000000;
	udiff -= DELAY;
	if (udiff < 0)
		usleep(-udiff);
	memcpy(&last, &now, sizeof(struct timeval));
	
	return 0;
}

Plik należy skompilować, uruchamiając gcc w następujący sposób:

gcc -o drm_nowaitVblank.so -shared -fPIC -ldl drm_nowaitVblank.c

Plik należy umieścić tam gdzie znajduje się plik googleearth-bin, u mnie jest to /opt/google-earth/. Teraz trzeba zmienić skrypt googleearth w wierszu zwierającym exec "./googleearth-bin" "$@" (jest tylko jeden wiersz z exec w skrypcie googleearth) na:

LD_PRELOAD="./drm_nowaitVblank.so" exec "./googleearth-bin" $*

Googleearth wyświetla też komunikat o brakujących fontach. To akurat jest łatwe do poprawienia:

yum -y install bitstream-vera-fonts 

Teraz mogę w komfortowy sposób oglądać swoje zdjęcia z samodzielnie wygenerowanych, przy pomocy GPSbabela plików KML (sposób jaki w jaki to robię opisałem wcześniej). Tutaj są próbki a jednocześnie propozycje ciekawych do zwiedzania miejsc w okolicach Sopotu (więcej wkrótce): Oliwa, Dolina Radości | Rezerwat Kacze Łęgi, Witomino | Elekrownia Rutki, Jar Raduni | Z Gdyni do Sopotu wzdłuż plaży | wzdłuż Potoku Oliwskiego, potem Sopot. Więcej jest tutaj.

url | Sun, 10/02/2008 20:15 | tagi: , , ,
Szybsze geokodowanie zdjęć: podsumowanie

W okresie świątecznym i na przełomie roku wykonałem kilka eksperymentów weryfikujących jakość dodawania współrzędnych za pomocą synchronizacji czasu odbiornika GPS i aparatu. Dokładnie siedem prób (odpowiednio data: zdjęcia ogółem/zdjęcia oznaczone): 20071226: 61/61, 20071228: 11/11, 20071229: 29/29, 20071230: 71/71, 20071230: 48/48, 20080101: 30/30, 20080102: 8/22. Łącznie zdjęć było zatem 260 z czego 16 (6,1%) nie zostało zsynchronizowanych. Większość zdjęć została oznakowana z zadowalającą albo nawet dobrą dokładnością. Niektóre trasy były łatwe: płaski teren. Ale trasa z 31.12 prowadziła w sporej części przez gęsty las a GPS się nie pogubił. Dziś poszedłem jeszcze dalej do lasu, no i GPS tym razem odmówił kooperacji. A GPSa -- zgodnie z zaleceniem, żeby był jak najwyżej -- noszę pod czapką!

Przerobiłem swoje skrypty, oraz bibliotekę dla Emacsa. Aby odróżnić zdjęcia zawierające zdefiniowane tagi EXIF ze współrzędnymi geograficznymi od tych, które tej informacji nie zawierają, generowana miniatura zdjęcia zawiera czerwony prostokąt w lewym górnym rogu (jeżeli zdjęcie jest już geotagowane). No tak to sobie wymyśliłem.

Niektóre ślady GPS na mojej stronie zawierają teraz miniatury zdjęć. Publikuję też dane w formacie KML. Uaktualniony opis jest tutaj. Detaliczna instrukcja jak używać GPSphoto. jest zaś tutaj.

Dopisane 8 maja 2008/Zmodyfikowane 27 sierpnia 2008: Podsumowanie procedury pobrania śladu z urządzenia GPS i ich zamiany na ślad w formacie GPX/KML:

  1. Ślad z urządzenia jest pobierany albo za pomocą gpsbabela albo programu  bt747.

  2. Skrypt nmea2gpx zamienia dane w formacie NMEA na GPS w razie potrzeby wycinając fragment śladu i upraszczając go (opcja -max liczba-punktów). Skrypt akceptuje także inne formaty danych wejściowych (opcja -format):

    nmea2gpx -od czas -do czas -max liczba [-format format ] [-U ] [-out plik.gpx] plik
    
  3. Skrypt My-photo-sync.sh (wykorzystujący gpsPhoto.pl) ,,synchronizuje'' ślad ze zdjęciami i generuje plik w formacie KML:

    My-photo-sync.sh -d katalog-zdjęć -f plik.gpx -t różnica-czasów
    

    różnica czasów jest obliczana za pomocą skryptu exif_datetime.pl

    exif_datetime -b czas_z_GPSa -f zdjęcie -o GMT_offset_in_seconds
    

    gdzie: zdjęcie, to nazwa pliku ze zdjęciem ekranu GPSa; czas_z_GPS, to czas wyświetlany przez GPSa na ww. zdjęciu; GMT_offset_in_seconds, różnica między czasem lokalnym a GMT (niektóry GPSy to wyświetlają, a jak nie to łatwo jest to obliczyć). Ponieważ uruchamianie exif_datetime w ww. sposób dla każdej sesji zdjęciowej jest pracochłonne można też napisać:

    exif_datetime 
    

    Powyższe wyświetli przesunięcia czasowe zapisywane w pliku ~/.time_offset. Ponieważ czas w aparatach rozsynchronizowuje się w miarę wolno, wystarczy co kilka tygodni aktualizować ~/.time_offset.

    Można też napisać:

    My-photo-sync.sh -d katalog-zdjęć -f plik.gpx -a
    

    Przesunięcie zostanie pobrane automatycznie z pliku ~/.time_offset. [Nie trzeba uruchamiać exif_datetime .]

  4. W wyniku wykonania My-photo-sync.sh powstaje także plik .kml. Skrypt perlowy kml-adjust-urls zamienia linki do zdjęć w pliku KML, tak aby wskazywały na zdjęcia umieszczone w serwisie flickr.com (skrypt My-photo-sync.sh oryginalnie wstawia linki lokalne). Przed wykonaniem kml-adjust-urls należy wykonać flickr_update_kb bo kml-adjust-urls pobiera informacje nt. zdjęć lokalnie z bazy utworzonej przez flickr_update_kb.

    kml-adjust-urls plik.kml
    

    Ubocznym efektem działania kml-adjust-urls jest plik plik.wpts zawierający elementy <wpt> określające linki do zdjęć umieszczonych na flickr.com. Zawartość tego pliku można dodać do pliku plik.gpx uzskanego w kroku #2. Ślad -- wyświetlony w googlemaps -- będzie wtedy zawierał ,,pinezki'' z minaturami zdjęć.

    Niektóre zdjęcia z lokalnego katalogu nie są umieszczone na flickr.com. Skrypt kml-skip-deadlinks usuwa takie zdjęcia z pliku KML. Mało eleganckie rozwiązanie -- jeden skrypt by wystarczył, ale nie mam czasu w tej chwili poprawiać skryptu kml-adjust-urls: Skrypt kml-adjust-urls usuwa takie zdjęcia z pliku .kml.

url | Wed, 02/01/2008 17:04 | tagi: , , , ,
Szybsze geokodowanie zdjęć: gpsPhoto.pl

Wprawdzie jestem/byłem sceptyczny co do rezultatów, ale postanowiłem sprawdzić empirycznie ile warte jest dodanie współrzędnych geograficznych przy wykorzystaniu techniki zsynchronizowania czasów GPSa i aparatu. Ustawiłem czas Geko na Paryż. To co odbiornik wyświetlał z grubsza się zgadzało z czasem na zegarku. No akurat wiem, że GPS z definicji może ,,robić'' za ultra dokładny zegarek. Z aparatem było gorzej--wyświetla tylko godziny i minuty. Ustawiłem czas na tyle dokładnie na ile się dało.

Po zapisaniu śladu do pliku GPX okazało się, że czas zapisany przez Geko jest circa godzinę do tyłu w porównaniu do tego co jest wyświetlane. Wyświetla czas lokalny a zapisuje UTC? Chyba tak, bo w dokumentacji skryptu GPSphoto jest o czymś takim wspomniane. Zdjęcie z kolei jest oznaczone czasem lokalnym i taki czas jest zapisywany. No i dodatkowo jest pewna różnica wynikająca z niezbyt precyzyjnego zgrania obu urządzeń. Prosty pomysł jak je zgrać dokładnie podano w dokumentacji GPSphoto: po prostu trzeba zrobić zdjęcie Geko z wyświetlonym na ekranie czasem. Faktycznie, prościej chyba się nie da:-) Ale nie do zastosowania w urządzeniach GPS bez ekranu (por. komentarz z tego bloga.)

Żeby sobie ułatwić skrypt zrobiłem wykorzystujący Image::ExifTool. Na wejściu pobiera nazwę pliku ze zdjęciem, a wypisuje zawartość pola DateTimeOriginal. Jeżeli podam -- jako drugi parametr -- czas w notacji gg:mm:ss, to skrypt wypisze też różnicę w sekundach:

exif_datetime.pl  -f dscf2451.jpg -b 15:49:20

Wyszło 44 sekundy. Dodałem 3600 sekund jako różnicę między czasem aparatu a czasem garmina, wpisując z wiersza poleceń:

perl gpsPhoto.pl --dir=jpgs --gpsfile=20071228.gpx --timeoffset=-3644 \
  --kml 20071228.kml

Szczerze mówiąc za pierwszym razem nie dodałem znaku minus przed wartością 3644. W rezultacie większość zdjęć została pominięta. Ale kilka zostało oznaczonych. Uruchomiłem gpsPhoto drugi raz, tym razem poszło lepiej. Powstały plik wyświetliłem w googleearth i konsternacja: część zdjęć jest oznaczona prawidłowo, ale kilka ma współrzędne kompletnie do kitu. Do tego ślad jak zwykle jest przerwany i ma jeden gigatyczny ,,odlot'' od prawdziwego przebiegu trasy. Najbardziej zdumiewało mnie jednak to, że zdjęcia na śladzie nie były wstawione chronologicznie, tylko przemieszane. Niechybnie oznaczało to, że coś namieszałem.

Straciłem sporo czasu kombinując czemu tak się stało. Wreszcie wróciłem do źródeł, czyli zacząłem studiować dokumentację gpsPhoto.pl. Dodałem opcję --overwrite-geotagged, słusznie mniemając, że skoro jest taka opcja, to geo-oznakowane pliki nie są domyślnie brane pod uwagę. Ostatecznie zatem uruchomiłem gpsPhoto w następujący sposób:

perl gpsPhoto.pl --dir=jpgs --gpsfile=20071228.gpx --timeoffset=-3644 \
  --overwrite-geotagged --kml 20071228.kml

Wynikowy plik 20071228.kml pokazuje, że współrzędne geograficze poszczególnych zdjęć są całkiem precyzyje. Tak się jednak stało, że w wszystkich miejscach gdzie robiłem zdjęcia garmin nie miał problemów z rejestrowaniem śladu. Zobaczymy jak będzie np. w lesie, albo w mieście, przy wysokich budowlach.

Reasumując, muszę odszczekać to co napisałem wcześniej no i być mniej sarkastyczny. Ślad z mojego pierwszego eksperymentu jest tutaj. Na razie nie ma na nim zaznaczonych zdjęć; są dostępne na flickr.com. Muszę też doczytać na temat formatu KML.

url | Mon, 31/12/2007 12:16 | tagi: , , , ,