Ticket #16681: GPXCorrelateV2.patch

File GPXCorrelateV2.patch, 112.1 KB (added by Bjoeni, 7 years ago)
  • data_nodist/ImageCorrelationTest.gpx

     
     1<?xml version='1.0' encoding='UTF-8'?>
     2<gpx version="1.1" creator="JOSM GPX export" xmlns="http://www.topografix.com/GPX/1/1"
     3    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
     5  <metadata>
     6    <bounds minlat="47.1849004" minlon="8.7719297" maxlat="47.2014997" maxlon="8.7984188"/>
     7  </metadata>
     8  <trk>
     9    <trkseg>
     10      <trkpt lat="47.19286847859621" lon="8.79732714034617">
     11        <ele>471.86000000000001</ele>
     12        <time>2016-01-03T11:59:58.000Z</time>
     13      </trkpt>
     14      <trkpt lat="47.192921955138445" lon="8.797342479228973">
     15        <ele>471.43000000000001</ele>
     16        <time>2016-01-03T11:59:59.000Z</time>
     17      </trkpt>
     18      <trkpt lat="47.19297501258552" lon="8.79734423942864">
     19        <ele>470.69</ele>
     20        <time>2016-01-03T12:00:00.000Z</time>
     21      </trkpt>
     22      <trkpt lat="47.19302739948034" lon="8.797332588583231">
     23        <ele>470.94</ele>
     24        <time>2016-01-03T12:00:01.000Z</time>
     25      </trkpt>
     26      <trkpt lat="47.193073416128755" lon="8.797307442873716">
     27        <ele>471.5</ele>
     28        <time>2016-01-03T12:00:02.000Z</time>
     29      </trkpt>
     30      <trkpt lat="47.193113481625915" lon="8.797272993251681">
     31        <ele>471.67000000000002</ele>
     32        <time>2016-01-03T12:00:03.000Z</time>
     33      </trkpt>
     34      <trkpt lat="47.19313560985029" lon="8.797232424840331">
     35        <ele>471.58999999999997</ele>
     36        <time>2016-01-03T12:00:04.000Z</time>
     37      </trkpt>
     38      <trkpt lat="47.19333660788834" lon="8.796738646924496">
     39        <ele>472.44999999999999</ele>
     40        <time>2016-01-03T12:00:15.000Z</time>
     41      </trkpt>
     42      <trkpt lat="47.193504832684994" lon="8.796404711902142">
     43        <ele>472.54000000000002</ele>
     44        <time>2016-01-03T12:00:22.000Z</time>
     45      </trkpt>
     46      <trkpt lat="47.19353936612606" lon="8.79635970108211">
     47        <ele>472.45999999999998</ele>
     48        <time>2016-01-03T12:00:23.000Z</time>
     49      </trkpt>
     50      <trkpt lat="47.19381898641586" lon="8.796017384156585">
     51        <ele>471.38</ele>
     52        <time>2016-01-03T12:00:30.000Z</time>
     53      </trkpt>
     54      <trkpt lat="47.19386676326394" lon="8.795985281467438">
     55        <ele>471.26999999999998</ele>
     56        <time>2016-01-03T12:00:31.000Z</time>
     57      </trkpt>
     58      <trkpt lat="47.19391797669232" lon="8.795968098565936">
     59        <ele>471.36000000000001</ele>
     60        <time>2016-01-03T12:00:32.000Z</time>
     61      </trkpt>
     62      <trkpt lat="47.19474418088794" lon="8.795836586505175">
     63        <ele>473.19999999999999</ele>
     64        <time>2016-01-03T12:00:50.000Z</time>
     65      </trkpt>
     66      <trkpt lat="47.195586981251836" lon="8.795750420540571">
     67        <ele>475.06</ele>
     68        <time>2016-01-03T12:01:09.000Z</time>
     69      </trkpt>
     70      <trkpt lat="47.19563358463347" lon="8.795769028365612">
     71        <ele>474.75</ele>
     72        <time>2016-01-03T12:01:10.000Z</time>
     73      </trkpt>
     74      <trkpt lat="47.19567717052996" lon="8.795795682817698">
     75        <ele>474.62</ele>
     76        <time>2016-01-03T12:01:11.000Z</time>
     77      </trkpt>
     78      <trkpt lat="47.195715978741646" lon="8.79583046771586">
     79        <ele>474.74000000000001</ele>
     80        <time>2016-01-03T12:01:12.000Z</time>
     81      </trkpt>
     82      <trkpt lat="47.19575093127787" lon="8.79587598145008">
     83        <ele>474.06</ele>
     84        <time>2016-01-03T12:01:13.000Z</time>
     85      </trkpt>
     86      <trkpt lat="47.19578169286251" lon="8.795927111059427">
     87        <ele>474</ele>
     88        <time>2016-01-03T12:01:14.000Z</time>
     89      </trkpt>
     90      <trkpt lat="47.195808347314596" lon="8.795980839058757">
     91        <ele>474.58999999999997</ele>
     92        <time>2016-01-03T12:01:15.000Z</time>
     93      </trkpt>
     94      <trkpt lat="47.195833241567016" lon="8.796036075800657">
     95        <ele>474.81999999999999</ele>
     96        <time>2016-01-03T12:01:16.000Z</time>
     97      </trkpt>
     98      <trkpt lat="47.19628603197634" lon="8.797110635787249">
     99        <ele>476.29000000000002</ele>
     100        <time>2016-01-03T12:01:35.000Z</time>
     101      </trkpt>
     102      <trkpt lat="47.19658995978534" lon="8.797826115041971">
     103        <ele>478.48000000000002</ele>
     104        <time>2016-01-03T12:01:50.000Z</time>
     105      </trkpt>
     106      <trkpt lat="47.19703386537731" lon="8.798356018960476">
     107        <ele>481.02999999999997</ele>
     108        <time>2016-01-03T12:02:06.000Z</time>
     109      </trkpt>
     110      <trkpt lat="47.19723687507212" lon="8.79841879941523">
     111        <ele>480</ele>
     112        <time>2016-01-03T12:02:12.000Z</time>
     113      </trkpt>
     114      <trkpt lat="47.19727886840701" lon="8.79838845692575">
     115        <ele>479.58999999999997</ele>
     116        <time>2016-01-03T12:02:13.000Z</time>
     117      </trkpt>
     118      <trkpt lat="47.19731541350484" lon="8.798339758068323">
     119        <ele>478.99000000000001</ele>
     120        <time>2016-01-03T12:02:14.000Z</time>
     121      </trkpt>
     122      <trkpt lat="47.197333350777626" lon="8.798282761126757">
     123        <ele>479.58999999999997</ele>
     124        <time>2016-01-03T12:02:15.000Z</time>
     125      </trkpt>
     126      <trkpt lat="47.19734919257462" lon="8.798161642625928">
     127        <ele>481.18000000000001</ele>
     128        <time>2016-01-03T12:02:18.000Z</time>
     129      </trkpt>
     130      <trkpt lat="47.19734827056527" lon="8.798118894919753">
     131        <ele>481.88</ele>
     132        <time>2016-01-03T12:02:20.000Z</time>
     133      </trkpt>
     134      <trkpt lat="47.19730585813522" lon="8.79802887327969">
     135        <ele>483.11000000000001</ele>
     136        <time>2016-01-03T12:02:24.000Z</time>
     137      </trkpt>
     138      <trkpt lat="47.19727643765509" lon="8.79797455854714">
     139        <ele>484.49000000000001</ele>
     140        <time>2016-01-03T12:02:27.000Z</time>
     141      </trkpt>
     142      <trkpt lat="47.19720158725977" lon="8.797768447548151">
     143        <ele>486.88</ele>
     144        <time>2016-01-03T12:02:35.000Z</time>
     145      </trkpt>
     146      <trkpt lat="47.19708633609116" lon="8.79746401682496">
     147        <ele>488.05000000000001</ele>
     148        <time>2016-01-03T12:02:48.000Z</time>
     149      </trkpt>
     150      <trkpt lat="47.19707007519901" lon="8.79741758108139">
     151        <ele>487.76999999999998</ele>
     152        <time>2016-01-03T12:02:51.000Z</time>
     153      </trkpt>
     154      <trkpt lat="47.19702917151153" lon="8.797250529751182">
     155        <ele>488.95999999999998</ele>
     156        <time>2016-01-03T12:02:57.000Z</time>
     157      </trkpt>
     158      <trkpt lat="47.19699899666011" lon="8.797172158956528">
     159        <ele>488.36000000000001</ele>
     160        <time>2016-01-03T12:03:01.000Z</time>
     161      </trkpt>
     162      <trkpt lat="47.19691224396229" lon="8.796978034079075">
     163        <ele>488.35000000000002</ele>
     164        <time>2016-01-03T12:03:09.000Z</time>
     165      </trkpt>
     166      <trkpt lat="47.19690545462072" lon="8.796931263059378">
     167        <ele>487.19</ele>
     168        <time>2016-01-03T12:03:10.000Z</time>
     169      </trkpt>
     170      <trkpt lat="47.19690595753491" lon="8.796886671334505">
     171        <ele>487.63999999999999</ele>
     172        <time>2016-01-03T12:03:11.000Z</time>
     173      </trkpt>
     174      <trkpt lat="47.19690511934459" lon="8.796837385743856">
     175        <ele>487.55000000000001</ele>
     176        <time>2016-01-03T12:03:12.000Z</time>
     177      </trkpt>
     178      <trkpt lat="47.19690562225878" lon="8.796793716028333">
     179        <ele>488.39999999999998</ele>
     180        <time>2016-01-03T12:03:13.000Z</time>
     181      </trkpt>
     182      <trkpt lat="47.196887601166964" lon="8.796751135960221">
     183        <ele>489.18000000000001</ele>
     184        <time>2016-01-03T12:03:15.000Z</time>
     185      </trkpt>
     186      <trkpt lat="47.1968892775476" lon="8.796689361333847">
     187        <ele>490.73000000000002</ele>
     188        <time>2016-01-03T12:03:18.000Z</time>
     189      </trkpt>
     190      <trkpt lat="47.196868155151606" lon="8.79647453315556">
     191        <ele>491.24000000000001</ele>
     192        <time>2016-01-03T12:03:33.000Z</time>
     193      </trkpt>
     194      <trkpt lat="47.19686932861805" lon="8.796442430466413">
     195        <ele>490.25</ele>
     196        <time>2016-01-03T12:03:34.000Z</time>
     197      </trkpt>
     198      <trkpt lat="47.19686849042773" lon="8.796406639739871">
     199        <ele>490.00999999999999</ele>
     200        <time>2016-01-03T12:03:35.000Z</time>
     201      </trkpt>
     202      <trkpt lat="47.196873016655445" lon="8.796368166804314">
     203        <ele>489.54000000000002</ele>
     204        <time>2016-01-03T12:03:36.000Z</time>
     205      </trkpt>
     206      <trkpt lat="47.19687905162573" lon="8.796329610049725">
     207        <ele>489.66000000000003</ele>
     208        <time>2016-01-03T12:03:37.000Z</time>
     209      </trkpt>
     210      <trkpt lat="47.196886762976646" lon="8.796280743554235">
     211        <ele>489.06</ele>
     212        <time>2016-01-03T12:03:38.000Z</time>
     213      </trkpt>
     214      <trkpt lat="47.19695775769651" lon="8.795829126611352">
     215        <ele>490.08999999999997</ele>
     216        <time>2016-01-03T12:03:48.000Z</time>
     217      </trkpt>
     218      <trkpt lat="47.1969928778708" lon="8.795709516853094">
     219        <ele>489.41000000000003</ele>
     220        <time>2016-01-03T12:03:52.000Z</time>
     221      </trkpt>
     222      <trkpt lat="47.19698550179601" lon="8.795667607337236">
     223        <ele>489.17000000000002</ele>
     224        <time>2016-01-03T12:03:53.000Z</time>
     225      </trkpt>
     226      <trkpt lat="47.19697644934058" lon="8.795624608173966">
     227        <ele>488.87</ele>
     228        <time>2016-01-03T12:03:54.000Z</time>
     229      </trkpt>
     230      <trkpt lat="47.19696890562773" lon="8.795590326189995">
     231        <ele>489.37</ele>
     232        <time>2016-01-03T12:03:55.000Z</time>
     233      </trkpt>
     234      <trkpt lat="47.19696664251387" lon="8.795558391138911">
     235        <ele>488.94999999999999</ele>
     236        <time>2016-01-03T12:03:56.000Z</time>
     237      </trkpt>
     238      <trkpt lat="47.19695256091654" lon="8.795536765828729">
     239        <ele>488.93000000000001</ele>
     240        <time>2016-01-03T12:03:57.000Z</time>
     241      </trkpt>
     242      <trkpt lat="47.196956500411034" lon="8.795507680624723">
     243        <ele>488.88999999999999</ele>
     244        <time>2016-01-03T12:03:58.000Z</time>
     245      </trkpt>
     246      <trkpt lat="47.19695859588683" lon="8.79548110999167">
     247        <ele>488.86000000000001</ele>
     248        <time>2016-01-03T12:03:59.000Z</time>
     249      </trkpt>
     250      <trkpt lat="47.19696907326579" lon="8.795452527701855">
     251        <ele>489.19999999999999</ele>
     252        <time>2016-01-03T12:04:00.000Z</time>
     253      </trkpt>
     254      <trkpt lat="47.19697988592088" lon="8.79541271366179">
     255        <ele>489.29000000000002</ele>
     256        <time>2016-01-03T12:04:01.000Z</time>
     257      </trkpt>
     258      <trkpt lat="47.19698726199567" lon="8.795355297625065">
     259        <ele>488.95999999999998</ele>
     260        <time>2016-01-03T12:04:02.000Z</time>
     261      </trkpt>
     262      <trkpt lat="47.19698960892856" lon="8.795302575454116">
     263        <ele>489.10000000000002</ele>
     264        <time>2016-01-03T12:04:03.000Z</time>
     265      </trkpt>
     266      <trkpt lat="47.19690981321037" lon="8.79494265653193">
     267        <ele>492.19</ele>
     268        <time>2016-01-03T12:04:14.000Z</time>
     269      </trkpt>
     270      <trkpt lat="47.19696622341871" lon="8.794532027095556">
     271        <ele>492.12</ele>
     272        <time>2016-01-03T12:04:25.000Z</time>
     273      </trkpt>
     274      <trkpt lat="47.19697737134993" lon="8.79450285807252">
     275        <ele>493.06999999999999</ele>
     276        <time>2016-01-03T12:04:26.000Z</time>
     277      </trkpt>
     278      <trkpt lat="47.19699212349951" lon="8.794450974091887">
     279        <ele>492.58999999999997</ele>
     280        <time>2016-01-03T12:04:27.000Z</time>
     281      </trkpt>
     282      <trkpt lat="47.19699405133724" lon="8.794399006292224">
     283        <ele>492.38999999999999</ele>
     284        <time>2016-01-03T12:04:28.000Z</time>
     285      </trkpt>
     286      <trkpt lat="47.19698860310018" lon="8.794350139796734">
     287        <ele>492.94</ele>
     288        <time>2016-01-03T12:04:29.000Z</time>
     289      </trkpt>
     290      <trkpt lat="47.19698214903474" lon="8.794298926368356">
     291        <ele>492.47000000000003</ele>
     292        <time>2016-01-03T12:04:30.000Z</time>
     293      </trkpt>
     294      <trkpt lat="47.19697737134993" lon="8.794246790930629">
     295        <ele>492.50999999999999</ele>
     296        <time>2016-01-03T12:04:31.000Z</time>
     297      </trkpt>
     298      <trkpt lat="47.19698206521571" lon="8.794189291074872">
     299        <ele>492.73000000000002</ele>
     300        <time>2016-01-03T12:04:32.000Z</time>
     301      </trkpt>
     302      <trkpt lat="47.196985417976975" lon="8.794133719056845">
     303        <ele>492.63</ele>
     304        <time>2016-01-03T12:04:33.000Z</time>
     305      </trkpt>
     306      <trkpt lat="47.19698768109083" lon="8.794077644124627">
     307        <ele>493</ele>
     308        <time>2016-01-03T12:04:34.000Z</time>
     309      </trkpt>
     310      <trkpt lat="47.19699136912823" lon="8.794022323563695">
     311        <ele>493.00999999999999</ele>
     312        <time>2016-01-03T12:04:35.000Z</time>
     313      </trkpt>
     314      <trkpt lat="47.196987848728895" lon="8.793976558372378">
     315        <ele>493.19999999999999</ele>
     316        <time>2016-01-03T12:04:36.000Z</time>
     317      </trkpt>
     318      <trkpt lat="47.19698550179601" lon="8.793926937505603">
     319        <ele>493.18000000000001</ele>
     320        <time>2016-01-03T12:04:37.000Z</time>
     321      </trkpt>
     322      <trkpt lat="47.196980556473136" lon="8.793885698541999">
     323        <ele>493</ele>
     324        <time>2016-01-03T12:04:38.000Z</time>
     325      </trkpt>
     326      <trkpt lat="47.19698307104409" lon="8.793837334960699">
     327        <ele>493.20999999999998</ele>
     328        <time>2016-01-03T12:04:39.000Z</time>
     329      </trkpt>
     330      <trkpt lat="47.196992291137576" lon="8.793786959722638">
     331        <ele>493.11000000000001</ele>
     332        <time>2016-01-03T12:04:40.000Z</time>
     333      </trkpt>
     334      <trkpt lat="47.19699547626078" lon="8.793743625283241">
     335        <ele>493.30000000000001</ele>
     336        <time>2016-01-03T12:04:41.000Z</time>
     337      </trkpt>
     338      <trkpt lat="47.19700268469751" lon="8.793694507330656">
     339        <ele>493.50999999999999</ele>
     340        <time>2016-01-03T12:04:42.000Z</time>
     341      </trkpt>
     342      <trkpt lat="47.19700511544943" lon="8.793357806280255">
     343        <ele>493</ele>
     344        <time>2016-01-03T12:04:50.000Z</time>
     345      </trkpt>
     346      <trkpt lat="47.19702162779868" lon="8.793316148221493">
     347        <ele>492.37</ele>
     348        <time>2016-01-03T12:04:51.000Z</time>
     349      </trkpt>
     350      <trkpt lat="47.19704459421337" lon="8.793262336403131">
     351        <ele>492.30000000000001</ele>
     352        <time>2016-01-03T12:04:52.000Z</time>
     353      </trkpt>
     354      <trkpt lat="47.19706906937063" lon="8.793201064690948">
     355        <ele>492.04000000000002</ele>
     356        <time>2016-01-03T12:04:53.000Z</time>
     357      </trkpt>
     358      <trkpt lat="47.19708985649049" lon="8.793123783543706">
     359        <ele>491.37</ele>
     360        <time>2016-01-03T12:04:54.000Z</time>
     361      </trkpt>
     362      <trkpt lat="47.19710913486779" lon="8.79304625093937">
     363        <ele>491.06999999999999</ele>
     364        <time>2016-01-03T12:04:55.000Z</time>
     365      </trkpt>
     366      <trkpt lat="47.19713117927313" lon="8.792974585667253">
     367        <ele>490.39999999999998</ele>
     368        <time>2016-01-03T12:04:56.000Z</time>
     369      </trkpt>
     370      <trkpt lat="47.197186248376966" lon="8.792809881269932">
     371        <ele>489.75</ele>
     372        <time>2016-01-03T12:04:58.000Z</time>
     373      </trkpt>
     374      <trkpt lat="47.19720753841102" lon="8.79271550104022">
     375        <ele>489.87</ele>
     376        <time>2016-01-03T12:04:59.000Z</time>
     377      </trkpt>
     378      <trkpt lat="47.19722296111286" lon="8.792620282620192">
     379        <ele>488.95999999999998</ele>
     380        <time>2016-01-03T12:05:00.000Z</time>
     381      </trkpt>
     382      <trkpt lat="47.19733930192888" lon="8.792043440043926">
     383        <ele>485.85000000000002</ele>
     384        <time>2016-01-03T12:05:06.000Z</time>
     385      </trkpt>
     386      <trkpt lat="47.1974522061646" lon="8.791516218334436">
     387        <ele>482.81</ele>
     388        <time>2016-01-03T12:05:11.000Z</time>
     389      </trkpt>
     390      <trkpt lat="47.197455475106835" lon="8.79138101823628">
     391        <ele>481.99000000000001</ele>
     392        <time>2016-01-03T12:05:12.000Z</time>
     393      </trkpt>
     394      <trkpt lat="47.197490092366934" lon="8.79095789976418">
     395        <ele>478.92</ele>
     396      </trkpt>
     397      <trkpt lat="47.19753225333989" lon="8.790533943101764">
     398        <ele>476</ele>
     399      </trkpt>
     400      <trkpt lat="47.19762864522636" lon="8.789889458566904">
     401        <ele>474.38</ele>
     402        <time>2016-01-03T12:05:23.000Z</time>
     403      </trkpt>
     404      <trkpt lat="47.19763744622469" lon="8.789792899042368">
     405        <ele>474.35000000000002</ele>
     406        <time>2016-01-03T12:05:24.000Z</time>
     407      </trkpt>
     408      <trkpt lat="47.1976438164711" lon="8.789720982313156">
     409        <ele>474.12</ele>
     410        <time>2016-01-03T12:05:25.000Z</time>
     411      </trkpt>
     412      <trkpt lat="47.19764859415591" lon="8.789367768913507">
     413        <ele>472.52999999999997</ele>
     414        <time>2016-01-03T12:05:33.000Z</time>
     415      </trkpt>
     416      <trkpt lat="47.19765613786876" lon="8.78931068815291">
     417        <ele>472.75</ele>
     418        <time>2016-01-03T12:05:34.000Z</time>
     419      </trkpt>
     420      <trkpt lat="47.1976903360337" lon="8.789105415344238">
     421        <ele>472.19</ele>
     422        <time>2016-01-03T12:05:37.000Z</time>
     423      </trkpt>
     424      <trkpt lat="47.197700729593635" lon="8.78903266042471">
     425        <ele>471.92000000000002</ele>
     426        <time>2016-01-03T12:05:38.000Z</time>
     427      </trkpt>
     428      <trkpt lat="47.197715900838375" lon="8.78876687027514">
     429        <ele>471.98000000000002</ele>
     430        <time>2016-01-03T12:05:41.000Z</time>
     431      </trkpt>
     432      <trkpt lat="47.19775462523103" lon="8.788432851433754">
     433        <ele>473.49000000000001</ele>
     434        <time>2016-01-03T12:05:47.000Z</time>
     435      </trkpt>
     436      <trkpt lat="47.197777507826686" lon="8.78841600380838">
     437        <ele>473.44999999999999</ele>
     438        <time>2016-01-03T12:05:48.000Z</time>
     439      </trkpt>
     440      <trkpt lat="47.19780064187944" lon="8.788405358791351">
     441        <ele>473.45999999999998</ele>
     442        <time>2016-01-03T12:05:49.000Z</time>
     443      </trkpt>
     444      <trkpt lat="47.197963669896126" lon="8.788386499509215">
     445        <ele>470.27999999999997</ele>
     446        <time>2016-01-03T12:05:53.000Z</time>
     447      </trkpt>
     448      <trkpt lat="47.1981308888644" lon="8.788295891135931">
     449        <ele>467.20999999999998</ele>
     450        <time>2016-01-03T12:05:57.000Z</time>
     451      </trkpt>
     452      <trkpt lat="47.19813633710146" lon="8.788262866437435">
     453        <ele>466.89999999999998</ele>
     454        <time>2016-01-03T12:05:58.000Z</time>
     455      </trkpt>
     456      <trkpt lat="47.19812661409378" lon="8.788229255005717">
     457        <ele>466.76999999999998</ele>
     458        <time>2016-01-03T12:05:59.000Z</time>
     459      </trkpt>
     460      <trkpt lat="47.19810306094587" lon="8.788186172023416">
     461        <ele>466.25</ele>
     462        <time>2016-01-03T12:06:00.000Z</time>
     463      </trkpt>
     464      <trkpt lat="47.19808369874954" lon="8.788127414882183">
     465        <ele>465.23000000000002</ele>
     466        <time>2016-01-03T12:06:01.000Z</time>
     467      </trkpt>
     468      <trkpt lat="47.19807816669345" lon="8.788059940561652">
     469        <ele>464.12</ele>
     470        <time>2016-01-03T12:06:02.000Z</time>
     471      </trkpt>
     472      <trkpt lat="47.19808881171048" lon="8.787991376593709">
     473        <ele>463.68000000000001</ele>
     474        <time>2016-01-03T12:06:03.000Z</time>
     475      </trkpt>
     476      <trkpt lat="47.19811093993485" lon="8.787914346903563">
     477        <ele>462.5</ele>
     478        <time>2016-01-03T12:06:04.000Z</time>
     479      </trkpt>
     480      <trkpt lat="47.19815100543201" lon="8.78783798776567">
     481        <ele>462.45999999999998</ele>
     482        <time>2016-01-03T12:06:05.000Z</time>
     483      </trkpt>
     484      <trkpt lat="47.19819492660463" lon="8.787756934762001">
     485        <ele>461.56999999999999</ele>
     486        <time>2016-01-03T12:06:06.000Z</time>
     487      </trkpt>
     488      <trkpt lat="47.1982860378921" lon="8.787589464336634">
     489        <ele>461.14999999999998</ele>
     490        <time>2016-01-03T12:06:08.000Z</time>
     491      </trkpt>
     492      <trkpt lat="47.19831814058125" lon="8.7874944973737">
     493        <ele>460.19</ele>
     494        <time>2016-01-03T12:06:09.000Z</time>
     495      </trkpt>
     496      <trkpt lat="47.1983309648931" lon="8.787389053031802">
     497        <ele>459.83999999999997</ele>
     498        <time>2016-01-03T12:06:10.000Z</time>
     499      </trkpt>
     500      <trkpt lat="47.198331551626325" lon="8.787284530699253">
     501        <ele>460.49000000000001</ele>
     502        <time>2016-01-03T12:06:11.000Z</time>
     503      </trkpt>
     504      <trkpt lat="47.198325265198946" lon="8.787185624241829">
     505        <ele>460.23000000000002</ele>
     506        <time>2016-01-03T12:06:12.000Z</time>
     507      </trkpt>
     508      <trkpt lat="47.19824245199561" lon="8.78635254688561">
     509        <ele>460.56999999999999</ele>
     510        <time>2016-01-03T12:06:22.000Z</time>
     511      </trkpt>
     512      <trkpt lat="47.198192747309804" lon="8.78586145117879">
     513        <ele>457.79000000000002</ele>
     514        <time>2016-01-03T12:06:27.000Z</time>
     515      </trkpt>
     516      <trkpt lat="47.19819249585271" lon="8.78536943346262">
     517        <ele>454.66000000000003</ele>
     518        <time>2016-01-03T12:06:31.000Z</time>
     519      </trkpt>
     520    </trkseg>
     521  </trk>
     522  <trk>
     523    <trkseg>
     524      <trkpt lat="47.18660652637482" lon="8.796921372413635">
     525        <ele>624.7421875</ele>
     526      </trkpt>
     527      <trkpt lat="47.186644077301025" lon="8.7968248128891">
     528        <ele>626.015625</ele>
     529      </trkpt>
     530      <trkpt lat="47.18669772148132" lon="8.796712160110474">
     531        <ele>627.0625</ele>
     532      </trkpt>
     533      <trkpt lat="47.18676209449768" lon="8.796610236167908">
     534        <ele>627.3671875</ele>
     535      </trkpt>
     536      <trkpt lat="47.1868371963501" lon="8.796519041061401">
     537        <ele>626.90234375</ele>
     538      </trkpt>
     539      <trkpt lat="47.186912298202515" lon="8.796401023864746">
     540        <ele>626.11328125</ele>
     541      </trkpt>
     542      <trkpt lat="47.18698740005493" lon="8.796277642250061">
     543        <ele>625.33203125</ele>
     544      </trkpt>
     545      <trkpt lat="47.18707859516144" lon="8.796148896217346">
     546        <ele>623.90625</ele>
     547      </trkpt>
     548      <trkpt lat="47.18710541725159" lon="8.796095252037048">
     549        <ele>623.66796875</ele>
     550      </trkpt>
     551      <trkpt lat="47.187126874923706" lon="8.796030879020691">
     552        <ele>623.71484375</ele>
     553      </trkpt>
     554      <trkpt lat="47.187132239341736" lon="8.795977234840393">
     555        <ele>623.75</ele>
     556      </trkpt>
     557      <trkpt lat="47.187132239341736" lon="8.795923590660095">
     558        <ele>623.9375</ele>
     559      </trkpt>
     560      <trkpt lat="47.187132239341736" lon="8.795859217643738">
     561        <ele>624.1640625</ele>
     562      </trkpt>
     563      <trkpt lat="47.18711078166962" lon="8.795735836029053">
     564        <ele>625.234375</ele>
     565      </trkpt>
     566      <trkpt lat="47.18710005283356" lon="8.795607089996338">
     567        <ele>626</ele>
     568      </trkpt>
     569      <trkpt lat="47.18709468841553" lon="8.795521259307861">
     570        <ele>626.3515625</ele>
     571      </trkpt>
     572      <trkpt lat="47.18710541725159" lon="8.795440793037415">
     573        <ele>626.14453125</ele>
     574      </trkpt>
     575      <trkpt lat="47.187126874923706" lon="8.795360326766968">
     576        <ele>625.6640625</ele>
     577      </trkpt>
     578      <trkpt lat="47.187164425849915" lon="8.79528522491455">
     579        <ele>624.7890625</ele>
     580      </trkpt>
     581      <trkpt lat="47.1872341632843" lon="8.795183300971985">
     582        <ele>623.23046875</ele>
     583      </trkpt>
     584      <trkpt lat="47.18729317188263" lon="8.795086741447449">
     585        <ele>622.09375</ele>
     586      </trkpt>
     587      <trkpt lat="47.18736290931702" lon="8.794984817504883">
     588        <ele>620.9765625</ele>
     589      </trkpt>
     590      <trkpt lat="47.187416553497314" lon="8.794904351234436">
     591        <ele>620.23828125</ele>
     592      </trkpt>
     593      <trkpt lat="47.18746483325958" lon="8.794845342636108">
     594        <ele>619.42578125</ele>
     595      </trkpt>
     596      <trkpt lat="47.18752384185791" lon="8.79479706287384">
     597        <ele>617.7734375</ele>
     598      </trkpt>
     599      <trkpt lat="47.18756139278412" lon="8.794743418693542">
     600        <ele>616.8671875</ele>
     601      </trkpt>
     602      <trkpt lat="47.1875935792923" lon="8.794695138931274">
     603        <ele>616.09765625</ele>
     604      </trkpt>
     605      <trkpt lat="47.18760967254639" lon="8.794630765914917">
     606        <ele>615.87890625</ele>
     607      </trkpt>
     608      <trkpt lat="47.187620401382446" lon="8.7945556640625">
     609        <ele>615.3984375</ele>
     610      </trkpt>
     611      <trkpt lat="47.187636494636536" lon="8.794485926628113">
     612        <ele>614.76953125</ele>
     613      </trkpt>
     614      <trkpt lat="47.187674045562744" lon="8.794400095939636">
     615        <ele>613.47265625</ele>
     616      </trkpt>
     617      <trkpt lat="47.18769550323486" lon="8.79430890083313">
     618        <ele>612.72265625</ele>
     619      </trkpt>
     620      <trkpt lat="47.18770086765289" lon="8.794185519218445">
     621        <ele>612.4609375</ele>
     622      </trkpt>
     623      <trkpt lat="47.18770086765289" lon="8.79407823085785">
     624        <ele>611.85546875</ele>
     625      </trkpt>
     626      <trkpt lat="47.187684774398804" lon="8.793997764587402">
     627        <ele>611.90625</ele>
     628      </trkpt>
     629      <trkpt lat="47.187663316726685" lon="8.793933391571045">
     630        <ele>612.27734375</ele>
     631      </trkpt>
     632      <trkpt lat="47.18761503696442" lon="8.793869018554688">
     633        <ele>613.66796875</ele>
     634      </trkpt>
     635      <trkpt lat="47.18758285045624" lon="8.79381537437439">
     636        <ele>614.62890625</ele>
     637      </trkpt>
     638      <trkpt lat="47.18756675720215" lon="8.793767094612122">
     639        <ele>615.0703125</ele>
     640      </trkpt>
     641      <trkpt lat="47.18757212162018" lon="8.793713450431824">
     642        <ele>614.72265625</ele>
     643      </trkpt>
     644      <trkpt lat="47.18758821487427" lon="8.793681263923645">
     645        <ele>614.26171875</ele>
     646      </trkpt>
     647      <trkpt lat="47.187641859054565" lon="8.793681263923645">
     648        <ele>612.06640625</ele>
     649      </trkpt>
     650      <trkpt lat="47.18770086765289" lon="8.793708086013794">
     651        <ele>609.6875</ele>
     652      </trkpt>
     653      <trkpt lat="47.18778133392334" lon="8.793751001358032">
     654        <ele>606.83984375</ele>
     655      </trkpt>
     656      <trkpt lat="47.18785107135773" lon="8.79380464553833">
     657        <ele>604.671875</ele>
     658      </trkpt>
     659      <trkpt lat="47.187920808792114" lon="8.793842196464539">
     660        <ele>602.52734375</ele>
     661      </trkpt>
     662      <trkpt lat="47.18800127506256" lon="8.793911933898926">
     663        <ele>600.78515625</ele>
     664      </trkpt>
     665      <trkpt lat="47.18811392784119" lon="8.794013857841492">
     666        <ele>598.078125</ele>
     667      </trkpt>
     668      <trkpt lat="47.188151478767395" lon="8.79406213760376">
     669        <ele>597.1953125</ele>
     670      </trkpt>
     671      <trkpt lat="47.1881890296936" lon="8.794153332710266">
     672        <ele>596.5234375</ele>
     673      </trkpt>
     674      <trkpt lat="47.18821585178375" lon="8.794239163398743">
     675        <ele>595.74609375</ele>
     676      </trkpt>
     677      <trkpt lat="47.1882426738739" lon="8.794351816177368">
     678        <ele>594.82421875</ele>
     679      </trkpt>
     680      <trkpt lat="47.18826413154602" lon="8.794426918029785">
     681        <ele>594.10546875</ele>
     682      </trkpt>
     683      <trkpt lat="47.18829095363617" lon="8.794475197792053">
     684        <ele>593.2109375</ele>
     685      </trkpt>
     686      <trkpt lat="47.18830704689026" lon="8.794523477554321">
     687        <ele>592.6875</ele>
     688      </trkpt>
     689      <trkpt lat="47.18831241130829" lon="8.794614672660828">
     690        <ele>592.5390625</ele>
     691      </trkpt>
     692      <trkpt lat="47.18830704689026" lon="8.79479706287384">
     693        <ele>592.7578125</ele>
     694      </trkpt>
     695      <trkpt lat="47.18830704689026" lon="8.794888257980347">
     696        <ele>592.77734375</ele>
     697      </trkpt>
     698      <trkpt lat="47.18831241130829" lon="8.794941902160645">
     699        <ele>592.63671875</ele>
     700      </trkpt>
     701      <trkpt lat="47.18833386898041" lon="8.794995546340942">
     702        <ele>592.06640625</ele>
     703      </trkpt>
     704      <trkpt lat="47.188366055488586" lon="8.7950599193573">
     705        <ele>591.2578125</ele>
     706      </trkpt>
     707      <trkpt lat="47.188403606414795" lon="8.795113563537598">
     708        <ele>590.46875</ele>
     709      </trkpt>
     710      <trkpt lat="47.188435792922974" lon="8.795167207717896">
     711        <ele>589.7578125</ele>
     712      </trkpt>
     713      <trkpt lat="47.18845188617706" lon="8.795226216316223">
     714        <ele>589.359375</ele>
     715      </trkpt>
     716      <trkpt lat="47.18846261501312" lon="8.79529058933258">
     717        <ele>589.05859375</ele>
     718      </trkpt>
     719      <trkpt lat="47.18845188617706" lon="8.795354962348938">
     720        <ele>589.21875</ele>
     721      </trkpt>
     722      <trkpt lat="47.188430428504944" lon="8.795451521873474">
     723        <ele>589.59375</ele>
     724      </trkpt>
     725      <trkpt lat="47.188408970832825" lon="8.7955641746521">
     726        <ele>589.98046875</ele>
     727      </trkpt>
     728      <trkpt lat="47.188403606414795" lon="8.795655369758606">
     729        <ele>589.51953125</ele>
     730      </trkpt>
     731      <trkpt lat="47.188408970832825" lon="8.795746564865112">
     732        <ele>588.796875</ele>
     733      </trkpt>
     734      <trkpt lat="47.188435792922974" lon="8.795859217643738">
     735        <ele>587.4375</ele>
     736      </trkpt>
     737      <trkpt lat="47.18847870826721" lon="8.795971870422363">
     738        <ele>585.70703125</ele>
     739      </trkpt>
     740      <trkpt lat="47.18850553035736" lon="8.79605233669281">
     741        <ele>584.48046875</ele>
     742      </trkpt>
     743      <trkpt lat="47.18852162361145" lon="8.796132802963257">
     744        <ele>583.328125</ele>
     745      </trkpt>
     746      <trkpt lat="47.18852162361145" lon="8.796197175979614">
     747        <ele>582.69921875</ele>
     748      </trkpt>
     749      <trkpt lat="47.18851625919342" lon="8.79628300666809">
     750        <ele>581.96875</ele>
     751      </trkpt>
     752      <trkpt lat="47.18850016593933" lon="8.796379566192627">
     753        <ele>581.3359375</ele>
     754      </trkpt>
     755      <trkpt lat="47.18848943710327" lon="8.796465396881104">
     756        <ele>580.6796875</ele>
     757      </trkpt>
     758      <trkpt lat="47.18848943710327" lon="8.796524405479431">
     759        <ele>580.33984375</ele>
     760      </trkpt>
     761      <trkpt lat="47.18850016593933" lon="8.796578049659729">
     762        <ele>580.0234375</ele>
     763      </trkpt>
     764      <trkpt lat="47.18852162361145" lon="8.796631693840027">
     765        <ele>579.5078125</ele>
     766      </trkpt>
     767      <trkpt lat="47.1885484457016" lon="8.796685338020325">
     768        <ele>578.890625</ele>
     769      </trkpt>
     770      <trkpt lat="47.18856990337372" lon="8.796749711036682">
     771        <ele>578.34375</ele>
     772      </trkpt>
     773      <trkpt lat="47.18858063220978" lon="8.79681944847107">
     774        <ele>577.984375</ele>
     775      </trkpt>
     776      <trkpt lat="47.18857526779175" lon="8.796899914741516">
     777        <ele>577.90234375</ele>
     778      </trkpt>
     779      <trkpt lat="47.18858599662781" lon="8.796991109848022">
     780        <ele>577.50390625</ele>
     781      </trkpt>
     782      <trkpt lat="47.18859672546387" lon="8.79704475402832">
     783        <ele>577.20703125</ele>
     784      </trkpt>
     785      <trkpt lat="47.188623547554016" lon="8.797119855880737">
     786        <ele>576.6171875</ele>
     787      </trkpt>
     788      <trkpt lat="47.188666462898254" lon="8.797189593315125">
     789        <ele>575.82421875</ele>
     790      </trkpt>
     791      <trkpt lat="47.18870937824249" lon="8.797211050987244">
     792        <ele>575.125</ele>
     793      </trkpt>
     794      <trkpt lat="47.18871474266052" lon="8.797157406806946">
     795        <ele>575.0546875</ele>
     796      </trkpt>
     797      <trkpt lat="47.18872547149658" lon="8.79705548286438">
     798        <ele>574.89453125</ele>
     799      </trkpt>
     800      <trkpt lat="47.18873620033264" lon="8.796937465667725">
     801        <ele>574.75</ele>
     802      </trkpt>
     803      <trkpt lat="47.18875765800476" lon="8.79681408405304">
     804        <ele>574.6484375</ele>
     805      </trkpt>
     806      <trkpt lat="47.18879520893097" lon="8.796685338020325">
     807        <ele>574.26953125</ele>
     808      </trkpt>
     809      <trkpt lat="47.18883812427521" lon="8.796588778495789">
     810        <ele>573.72265625</ele>
     811      </trkpt>
     812      <trkpt lat="47.188907861709595" lon="8.796438574790955">
     813        <ele>572.4296875</ele>
     814      </trkpt>
     815      <trkpt lat="47.18901515007019" lon="8.796240091323853">
     816        <ele>570.828125</ele>
     817      </trkpt>
     818      <trkpt lat="47.18906342983246" lon="8.796154260635376">
     819        <ele>570.1015625</ele>
     820      </trkpt>
     821      <trkpt lat="47.189154624938965" lon="8.795987963676453">
     822        <ele>568.7734375</ele>
     823      </trkpt>
     824      <trkpt lat="47.18921899795532" lon="8.795869946479797">
     825        <ele>567.8125</ele>
     826      </trkpt>
     827      <trkpt lat="47.18926191329956" lon="8.795778751373291">
     828        <ele>567.25390625</ele>
     829      </trkpt>
     830      <trkpt lat="47.18928337097168" lon="8.795714378356934">
     831        <ele>567.09765625</ele>
     832      </trkpt>
     833      <trkpt lat="47.18929409980774" lon="8.795660734176636">
     834        <ele>567.1640625</ele>
     835      </trkpt>
     836      <trkpt lat="47.18929946422577" lon="8.795580267906189">
     837        <ele>567.546875</ele>
     838      </trkpt>
     839      <trkpt lat="47.18929946422577" lon="8.795451521873474">
     840        <ele>567.86328125</ele>
     841      </trkpt>
     842      <trkpt lat="47.18929409980774" lon="8.7953120470047">
     843        <ele>568.2890625</ele>
     844      </trkpt>
     845      <trkpt lat="47.18929409980774" lon="8.795210123062134">
     846        <ele>568.49609375</ele>
     847      </trkpt>
     848      <trkpt lat="47.1893048286438" lon="8.795135021209717">
     849        <ele>568.33203125</ele>
     850      </trkpt>
     851      <trkpt lat="47.18934237957001" lon="8.794904351234436">
     852        <ele>566.84765625</ele>
     853      </trkpt>
     854      <trkpt lat="47.18934774398804" lon="8.794845342636108">
     855        <ele>566.609375</ele>
     856      </trkpt>
     857      <trkpt lat="47.18933701515198" lon="8.794738054275513">
     858        <ele>566.94140625</ele>
     859      </trkpt>
     860      <trkpt lat="47.18933701515198" lon="8.794657588005066">
     861        <ele>566.88671875</ele>
     862      </trkpt>
     863      <trkpt lat="47.18935310840607" lon="8.79457712173462">
     864        <ele>566.27734375</ele>
     865      </trkpt>
     866      <trkpt lat="47.189374566078186" lon="8.794502019882202">
     867        <ele>565.48046875</ele>
     868      </trkpt>
     869      <trkpt lat="47.189428210258484" lon="8.794384002685547">
     870        <ele>563.5</ele>
     871      </trkpt>
     872      <trkpt lat="47.18945503234863" lon="8.7943035364151">
     873        <ele>562.51953125</ele>
     874      </trkpt>
     875      <trkpt lat="47.18947112560272" lon="8.794206976890564">
     876        <ele>561.9453125</ele>
     877      </trkpt>
     878      <trkpt lat="47.18948185443878" lon="8.79407286643982">
     879        <ele>561.85546875</ele>
     880      </trkpt>
     881      <trkpt lat="47.18949794769287" lon="8.793911933898926">
     882        <ele>561.7578125</ele>
     883      </trkpt>
     884      <trkpt lat="47.18950867652893" lon="8.79378855228424">
     885        <ele>561.765625</ele>
     886      </trkpt>
     887      <trkpt lat="47.18952476978302" lon="8.793686628341675">
     888        <ele>561.453125</ele>
     889      </trkpt>
     890      <trkpt lat="47.18955159187317" lon="8.79356861114502">
     891        <ele>560.6015625</ele>
     892      </trkpt>
     893      <trkpt lat="47.18958377838135" lon="8.793466687202454">
     894        <ele>559.65234375</ele>
     895      </trkpt>
     896      <trkpt lat="47.189615964889526" lon="8.793386220932007">
     897        <ele>558.7578125</ele>
     898      </trkpt>
     899      <trkpt lat="47.189658880233765" lon="8.793278932571411">
     900        <ele>557.66015625</ele>
     901      </trkpt>
     902      <trkpt lat="47.18971252441406" lon="8.793187737464905">
     903        <ele>556.35546875</ele>
     904      </trkpt>
     905      <trkpt lat="47.18976080417633" lon="8.793118000030518">
     906        <ele>555.2265625</ele>
     907      </trkpt>
     908      <trkpt lat="47.18983054161072" lon="8.79304826259613">
     909        <ele>553.53125</ele>
     910      </trkpt>
     911      <trkpt lat="47.189921736717224" lon="8.792962431907654">
     912        <ele>551.265625</ele>
     913      </trkpt>
     914      <trkpt lat="47.18997538089752" lon="8.792903423309326">
     915        <ele>549.92578125</ele>
     916      </trkpt>
     917      <trkpt lat="47.1900075674057" lon="8.792855143547058">
     918        <ele>549.140625</ele>
     919      </trkpt>
     920      <trkpt lat="47.19003438949585" lon="8.792780041694641">
     921        <ele>548.48828125</ele>
     922      </trkpt>
     923      <trkpt lat="47.19004511833191" lon="8.792726397514343">
     924        <ele>548.0078125</ele>
     925      </trkpt>
     926      <trkpt lat="47.19005584716797" lon="8.792635202407837">
     927        <ele>547.39453125</ele>
     928      </trkpt>
     929      <trkpt lat="47.19005584716797" lon="8.79256546497345">
     930        <ele>547.15234375</ele>
     931      </trkpt>
     932      <trkpt lat="47.19005048274994" lon="8.792501091957092">
     933        <ele>547.08203125</ele>
     934      </trkpt>
     935      <trkpt lat="47.19001829624176" lon="8.792366981506348">
     936        <ele>547.55078125</ele>
     937      </trkpt>
     938      <trkpt lat="47.18994319438934" lon="8.792104125022888">
     939        <ele>548.69921875</ele>
     940      </trkpt>
     941      <trkpt lat="47.189932465553284" lon="8.792034387588501">
     942        <ele>548.76953125</ele>
     943      </trkpt>
     944      <trkpt lat="47.189932465553284" lon="8.791970014572144">
     945        <ele>548.51953125</ele>
     946      </trkpt>
     947      <trkpt lat="47.18994319438934" lon="8.791900277137756">
     948        <ele>547.88671875</ele>
     949      </trkpt>
     950      <trkpt lat="47.18997001647949" lon="8.79183053970337">
     951        <ele>546.7265625</ele>
     952      </trkpt>
     953      <trkpt lat="47.19000220298767" lon="8.791755437850952">
     954        <ele>545.3984375</ele>
     955      </trkpt>
     956      <trkpt lat="47.19003975391388" lon="8.791680335998535">
     957        <ele>543.87890625</ele>
     958      </trkpt>
     959      <trkpt lat="47.190120220184326" lon="8.791535496711731">
     960        <ele>540.6484375</ele>
     961      </trkpt>
     962      <trkpt lat="47.19023287296295" lon="8.79129409790039">
     963        <ele>536.4296875</ele>
     964      </trkpt>
     965      <trkpt lat="47.19025433063507" lon="8.791224360466003">
     966        <ele>536.046875</ele>
     967      </trkpt>
     968      <trkpt lat="47.19027042388916" lon="8.791149258613586">
     969        <ele>535.765625</ele>
     970      </trkpt>
     971      <trkpt lat="47.19027578830719" lon="8.791015148162842">
     972        <ele>535.71875</ele>
     973      </trkpt>
     974      <trkpt lat="47.19027578830719" lon="8.790768384933472">
     975        <ele>535.55859375</ele>
     976      </trkpt>
     977      <trkpt lat="47.19026505947113" lon="8.790435791015625">
     978        <ele>535.359375</ele>
     979      </trkpt>
     980      <trkpt lat="47.1902596950531" lon="8.790162205696106">
     981        <ele>534.5234375</ele>
     982      </trkpt>
     983      <trkpt lat="47.1902596950531" lon="8.789920806884766">
     984        <ele>534.2578125</ele>
     985      </trkpt>
     986      <trkpt lat="47.19025433063507" lon="8.789674043655396">
     987        <ele>535.1328125</ele>
     988      </trkpt>
     989      <trkpt lat="47.19025433063507" lon="8.78955602645874">
     990        <ele>535.46875</ele>
     991      </trkpt>
     992      <trkpt lat="47.19025433063507" lon="8.789491653442383">
     993        <ele>535.04296875</ele>
     994      </trkpt>
     995      <trkpt lat="47.19027042388916" lon="8.789438009262085">
     996        <ele>534.04296875</ele>
     997      </trkpt>
     998      <trkpt lat="47.19030797481537" lon="8.789384365081787">
     999        <ele>532.234375</ele>
     1000      </trkpt>
     1001      <trkpt lat="47.19035625457764" lon="8.789357542991638">
     1002        <ele>530.2109375</ele>
     1003      </trkpt>
     1004      <trkpt lat="47.190393805503845" lon="8.789357542991638">
     1005        <ele>528.7890625</ele>
     1006      </trkpt>
     1007      <trkpt lat="47.190425992012024" lon="8.789373636245728">
     1008        <ele>527.69140625</ele>
     1009      </trkpt>
     1010      <trkpt lat="47.1904581785202" lon="8.789411187171936">
     1011        <ele>526.76171875</ele>
     1012      </trkpt>
     1013      <trkpt lat="47.19048500061035" lon="8.789459466934204">
     1014        <ele>526.1171875</ele>
     1015      </trkpt>
     1016      <trkpt lat="47.19050645828247" lon="8.789529204368591">
     1017        <ele>525.83984375</ele>
     1018      </trkpt>
     1019      <trkpt lat="47.19052255153656" lon="8.789609670639038">
     1020        <ele>525.51171875</ele>
     1021      </trkpt>
     1022      <trkpt lat="47.19053328037262" lon="8.789727687835693">
     1023        <ele>525.34375</ele>
     1024      </trkpt>
     1025      <trkpt lat="47.19054400920868" lon="8.78982961177826">
     1026        <ele>525.18359375</ele>
     1027      </trkpt>
     1028      <trkpt lat="47.19058692455292" lon="8.790022730827332">
     1029        <ele>524.3515625</ele>
     1030      </trkpt>
     1031      <trkpt lat="47.190635204315186" lon="8.790242671966553">
     1032        <ele>524.41015625</ele>
     1033      </trkpt>
     1034      <trkpt lat="47.190672755241394" lon="8.790398240089417">
     1035        <ele>524.47265625</ele>
     1036      </trkpt>
     1037      <trkpt lat="47.19072639942169" lon="8.79054844379425">
     1038        <ele>524.02734375</ele>
     1039      </trkpt>
     1040      <trkpt lat="47.19078004360199" lon="8.790677189826965">
     1041        <ele>523.09375</ele>
     1042      </trkpt>
     1043      <trkpt lat="47.19083368778229" lon="8.79082202911377">
     1044        <ele>521.92578125</ele>
     1045      </trkpt>
     1046      <trkpt lat="47.190876603126526" lon="8.790961503982544">
     1047        <ele>520.87109375</ele>
     1048      </trkpt>
     1049      <trkpt lat="47.190908789634705" lon="8.791095614433289">
     1050        <ele>520.51953125</ele>
     1051      </trkpt>
     1052      <trkpt lat="47.19093561172485" lon="8.791192173957825">
     1053        <ele>520.2578125</ele>
     1054      </trkpt>
     1055      <trkpt lat="47.19097316265106" lon="8.791267275810242">
     1056        <ele>519.6640625</ele>
     1057      </trkpt>
     1058      <trkpt lat="47.19103217124939" lon="8.791337013244629">
     1059        <ele>518.5703125</ele>
     1060      </trkpt>
     1061      <trkpt lat="47.191112637519836" lon="8.791401386260986">
     1062        <ele>517.04296875</ele>
     1063      </trkpt>
     1064      <trkpt lat="47.19128429889679" lon="8.791524767875671">
     1065        <ele>513.03125</ele>
     1066      </trkpt>
     1067      <trkpt lat="47.191407680511475" lon="8.791610598564148">
     1068        <ele>510.19921875</ele>
     1069      </trkpt>
     1070      <trkpt lat="47.19148814678192" lon="8.791669607162476">
     1071        <ele>508.5</ele>
     1072      </trkpt>
     1073      <trkpt lat="47.1915203332901" lon="8.791696429252625">
     1074        <ele>507.8828125</ele>
     1075      </trkpt>
     1076      <trkpt lat="47.19157934188843" lon="8.791739344596863">
     1077        <ele>506.71875</ele>
     1078      </trkpt>
     1079      <trkpt lat="47.191627621650696" lon="8.79179835319519">
     1080        <ele>506.03125</ele>
     1081      </trkpt>
     1082      <trkpt lat="47.191659808158875" lon="8.791851997375488">
     1083        <ele>505.5390625</ele>
     1084      </trkpt>
     1085      <trkpt lat="47.19168663024902" lon="8.791916370391846">
     1086        <ele>504.96875</ele>
     1087      </trkpt>
     1088      <trkpt lat="47.1917188167572" lon="8.792018294334412">
     1089        <ele>504.28125</ele>
     1090      </trkpt>
     1091      <trkpt lat="47.19175100326538" lon="8.792141675949097">
     1092        <ele>503.6640625</ele>
     1093      </trkpt>
     1094      <trkpt lat="47.19179928302765" lon="8.79229724407196">
     1095        <ele>502.578125</ele>
     1096      </trkpt>
     1097      <trkpt lat="47.19184219837189" lon="8.792458176612854">
     1098        <ele>500.921875</ele>
     1099      </trkpt>
     1100      <trkpt lat="47.191869020462036" lon="8.79257082939148">
     1101        <ele>499.85546875</ele>
     1102      </trkpt>
     1103      <trkpt lat="47.191879749298096" lon="8.792662024497986">
     1104        <ele>499.40234375</ele>
     1105      </trkpt>
     1106      <trkpt lat="47.191890478134155" lon="8.792763948440552">
     1107        <ele>498.96875</ele>
     1108      </trkpt>
     1109      <trkpt lat="47.191895842552185" lon="8.792887330055237">
     1110        <ele>497.8828125</ele>
     1111      </trkpt>
     1112      <trkpt lat="47.191895842552185" lon="8.79306435585022">
     1113        <ele>496.2265625</ele>
     1114      </trkpt>
     1115      <trkpt lat="47.191901206970215" lon="8.793182373046875">
     1116        <ele>494.9609375</ele>
     1117      </trkpt>
     1118      <trkpt lat="47.191906571388245" lon="8.793257474899292">
     1119        <ele>494.13671875</ele>
     1120      </trkpt>
     1121      <trkpt lat="47.191928029060364" lon="8.793343305587769">
     1122        <ele>493.6015625</ele>
     1123      </trkpt>
     1124      <trkpt lat="47.19196021556854" lon="8.793472051620483">
     1125        <ele>492.828125</ele>
     1126      </trkpt>
     1127      <trkpt lat="47.19199282117188" lon="8.793616723269224">
     1128        <ele>492.1015625</ele>
     1129      </trkpt>
     1130      <trkpt lat="47.19200849533081" lon="8.793686628341675">
     1131        <ele>491.76953125</ele>
     1132      </trkpt>
     1133      <trkpt lat="47.19204068183899" lon="8.793852925300598">
     1134        <ele>490.83984375</ele>
     1135      </trkpt>
     1136      <trkpt lat="47.19206213951111" lon="8.793992400169373">
     1137        <ele>490.23828125</ele>
     1138      </trkpt>
     1139      <trkpt lat="47.19207286834717" lon="8.7940514087677">
     1140        <ele>489.96484375</ele>
     1141      </trkpt>
     1142      <trkpt lat="47.19208359718323" lon="8.794147968292236">
     1143        <ele>489.703125</ele>
     1144      </trkpt>
     1145      <trkpt lat="47.192121148109436" lon="8.795000910758972">
     1146        <ele>484.7109375</ele>
     1147      </trkpt>
     1148      <trkpt lat="47.192137241363525" lon="8.79530131816864">
     1149        <ele>482.328125</ele>
     1150      </trkpt>
     1151      <trkpt lat="47.192137241363525" lon="8.795451521873474">
     1152        <ele>481.04296875</ele>
     1153      </trkpt>
     1154      <trkpt lat="47.192137241363525" lon="8.79553735256195">
     1155        <ele>480.3046875</ele>
     1156      </trkpt>
     1157      <trkpt lat="47.192126512527466" lon="8.795607089996338">
     1158        <ele>479.70703125</ele>
     1159      </trkpt>
     1160      <trkpt lat="47.19211041927338" lon="8.795682191848755">
     1161        <ele>478.984375</ele>
     1162      </trkpt>
     1163      <trkpt lat="47.19208896160126" lon="8.795746564865112">
     1164        <ele>478.4609375</ele>
     1165      </trkpt>
     1166      <trkpt lat="47.19203531742096" lon="8.795832395553589">
     1167        <ele>479.1015625</ele>
     1168      </trkpt>
     1169      <trkpt lat="47.19198167324066" lon="8.795896768569946">
     1170        <ele>480.359375</ele>
     1171      </trkpt>
     1172      <trkpt lat="47.19194948673248" lon="8.795934319496155">
     1173        <ele>481.19140625</ele>
     1174      </trkpt>
     1175      <trkpt lat="47.191906571388245" lon="8.795993328094482">
     1176        <ele>482.2890625</ele>
     1177      </trkpt>
     1178      <trkpt lat="47.191869020462036" lon="8.79606306552887">
     1179        <ele>483.28125</ele>
     1180      </trkpt>
     1181      <trkpt lat="47.19184756278992" lon="8.796138167381287">
     1182        <ele>483.69921875</ele>
     1183      </trkpt>
     1184      <trkpt lat="47.19184219837189" lon="8.796213269233704">
     1185        <ele>483.4609375</ele>
     1186      </trkpt>
     1187      <trkpt lat="47.19184219837189" lon="8.79628300666809">
     1188        <ele>483.0390625</ele>
     1189      </trkpt>
     1190      <trkpt lat="47.19185829162598" lon="8.796374201774597">
     1191        <ele>481.9140625</ele>
     1192      </trkpt>
     1193      <trkpt lat="47.191885113716125" lon="8.796454668045044">
     1194        <ele>480.515625</ele>
     1195      </trkpt>
     1196      <trkpt lat="47.191917300224304" lon="8.796513676643372">
     1197        <ele>479.16796875</ele>
     1198      </trkpt>
     1199      <trkpt lat="47.19198703765869" lon="8.796631693840027">
     1200        <ele>476.74609375</ele>
     1201      </trkpt>
     1202      <trkpt lat="47.19206750392914" lon="8.796760439872742">
     1203        <ele>474.3515625</ele>
     1204      </trkpt>
     1205      <trkpt lat="47.192131876945496" lon="8.796835541725159">
     1206        <ele>473.28515625</ele>
     1207      </trkpt>
     1208      <trkpt lat="47.19219088554382" lon="8.796894550323486">
     1209        <ele>472.39453125</ele>
     1210      </trkpt>
     1211      <trkpt lat="47.19225525856018" lon="8.796948194503784">
     1212        <ele>471.3671875</ele>
     1213      </trkpt>
     1214      <trkpt lat="47.19234645366669" lon="8.797001838684082">
     1215        <ele>470.0390625</ele>
     1216      </trkpt>
     1217      <trkpt lat="47.192426919937134" lon="8.79704475402832">
     1218        <ele>468.76171875</ele>
     1219      </trkpt>
     1220      <trkpt lat="47.19250738620758" lon="8.797082304954529">
     1221        <ele>467.3671875</ele>
     1222      </trkpt>
     1223      <trkpt lat="47.19255566596985" lon="8.797114491462708">
     1224        <ele>466.60546875</ele>
     1225      </trkpt>
     1226      <trkpt lat="47.1927273273468" lon="8.797253966331482">
     1227        <ele>464.65625</ele>
     1228      </trkpt>
     1229      <trkpt lat="47.19280779361725" lon="8.79730761051178">
     1230        <ele>463.62109375</ele>
     1231      </trkpt>
     1232      <trkpt lat="47.19286604784429" lon="8.79733837209642">
     1233        <ele>462.84375</ele>
     1234      </trkpt>
     1235      <trkpt lat="47.19286596402526" lon="8.797338204458356">
     1236        <ele>462.84765625</ele>
     1237      </trkpt>
     1238    </trkseg>
     1239  </trk>
     1240  <trk>
     1241    <trkseg>
     1242      <trkpt lat="47.18561486341059" lon="8.796475538983941">
     1243        <ele>647.81640625</ele>
     1244      </trkpt>
     1245      <trkpt lat="47.185668759047985" lon="8.796514933928847">
     1246        <ele>646.87109375</ele>
     1247      </trkpt>
     1248      <trkpt lat="47.18571729026735" lon="8.796522812917829">
     1249        <ele>646.1953125</ele>
     1250      </trkpt>
     1251      <trkpt lat="47.185757691040635" lon="8.796562207862735">
     1252        <ele>645.5859375</ele>
     1253      </trkpt>
     1254      <trkpt lat="47.18580354005098" lon="8.796577882021666">
     1255        <ele>644.8203125</ele>
     1256      </trkpt>
     1257      <trkpt lat="47.185914013534784" lon="8.796581821516156">
     1258        <ele>642.9765625</ele>
     1259      </trkpt>
     1260      <trkpt lat="47.18596254475415" lon="8.796625155955553">
     1261        <ele>641.796875</ele>
     1262      </trkpt>
     1263      <trkpt lat="47.186081148684025" lon="8.796644853428006">
     1264        <ele>639.4296875</ele>
     1265      </trkpt>
     1266      <trkpt lat="47.186186257749796" lon="8.7967315223068">
     1267        <ele>636.4921875</ele>
     1268      </trkpt>
     1269      <trkpt lat="47.186264377087355" lon="8.796790530905128">
     1270        <ele>634.1328125</ele>
     1271      </trkpt>
     1272      <trkpt lat="47.18639915809035" lon="8.796892957761884">
     1273        <ele>629.55859375</ele>
     1274      </trkpt>
     1275      <trkpt lat="47.186458418145776" lon="8.7969284132123">
     1276        <ele>627.55078125</ele>
     1277      </trkpt>
     1278      <trkpt lat="47.18660661019385" lon="8.796955989673734">
     1279        <ele>624.0234375</ele>
     1280      </trkpt>
     1281    </trkseg>
     1282  </trk>
     1283  <trk>
     1284    <trkseg>
     1285      <trkpt lat="47.18490038998425" lon="8.796944171190262">
     1286        <ele>663.90234375</ele>
     1287      </trkpt>
     1288      <trkpt lat="47.18495160341263" lon="8.796790530905128">
     1289        <ele>662.74609375</ele>
     1290      </trkpt>
     1291      <trkpt lat="47.18495696783066" lon="8.796640913933516">
     1292        <ele>662.1328125</ele>
     1293      </trkpt>
     1294      <trkpt lat="47.184981275349855" lon="8.796550389379263">
     1295        <ele>661.39453125</ele>
     1296      </trkpt>
     1297      <trkpt lat="47.18511060811579" lon="8.796479478478432">
     1298        <ele>658.98828125</ele>
     1299      </trkpt>
     1300      <trkpt lat="47.18521839939058" lon="8.7964085675776">
     1301        <ele>657.47265625</ele>
     1302      </trkpt>
     1303      <trkpt lat="47.18536122702062" lon="8.796420386061072">
     1304        <ele>654.22265625</ele>
     1305      </trkpt>
     1306      <trkpt lat="47.18553640879691" lon="8.796440083533525">
     1307        <ele>650.0703125</ele>
     1308      </trkpt>
     1309      <trkpt lat="47.185609163716435" lon="8.796475538983941">
     1310        <ele>647.890625</ele>
     1311      </trkpt>
     1312    </trkseg>
     1313  </trk>
     1314  <trk>
     1315    <trkseg>
     1316      <trkpt lat="47.20138901844621" lon="8.774476982653141">
     1317        <ele>421.52999999999997</ele>
     1318        <time>2016-01-03T12:08:53.000Z</time>
     1319      </trkpt>
     1320      <trkpt lat="47.201492534950376" lon="8.773281471803784">
     1321        <ele>423.57999999999998</ele>
     1322        <time>2016-01-03T12:09:10.000Z</time>
     1323      </trkpt>
     1324      <trkpt lat="47.2014878410846" lon="8.772208672016859">
     1325        <ele>423</ele>
     1326        <time>2016-01-03T12:09:26.000Z</time>
     1327      </trkpt>
     1328      <trkpt lat="47.2014997433871" lon="8.772082105278969">
     1329        <ele>423.07999999999998</ele>
     1330        <time>2016-01-03T12:09:28.000Z</time>
     1331      </trkpt>
     1332      <trkpt lat="47.2014896851033" lon="8.772034915164113">
     1333        <ele>423.02999999999997</ele>
     1334        <time>2016-01-03T12:09:29.000Z</time>
     1335      </trkpt>
     1336      <trkpt lat="47.20144324935973" lon="8.77200884744525">
     1337        <ele>422.26999999999998</ele>
     1338        <time>2016-01-03T12:09:31.000Z</time>
     1339      </trkpt>
     1340      <trkpt lat="47.201405949890614" lon="8.7720338255167">
     1341        <ele>421.35000000000002</ele>
     1342        <time>2016-01-03T12:09:42.000Z</time>
     1343      </trkpt>
     1344      <trkpt lat="47.20132657326758" lon="8.771982276812196">
     1345        <ele>421.75</ele>
     1346        <time>2016-01-03T12:10:04.000Z</time>
     1347      </trkpt>
     1348      <trkpt lat="47.20126815140247" lon="8.77192972227931">
     1349        <ele>421.48000000000002</ele>
     1350        <time>2016-01-03T12:10:23.000Z</time>
     1351      </trkpt>
     1352    </trkseg>
     1353  </trk>
     1354</gpx>
     1355 No newline at end of file
  • src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.gpx;
     3
     4import java.util.ArrayList;
     5import java.util.Comparator;
     6import java.util.Date;
     7import java.util.List;
     8import java.util.concurrent.TimeUnit;
     9
     10import org.openstreetmap.josm.gui.layer.geoimage.CorrelateGpxWithImages;
     11import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
     12import org.openstreetmap.josm.spi.preferences.Config;
     13import org.openstreetmap.josm.tools.Logging;
     14import org.openstreetmap.josm.tools.Pair;
     15
     16/**
     17 * Correlation logic for {@link CorrelateGpxWithImages}
     18 */
     19public class GpxImageCorrelation {
     20
     21    /**
     22     * Match a list of photos to a gpx track with a given offset.
     23     * All images need a exifTime attribute and the List must be sorted according to these times.
     24     * @param images images to match
     25     * @param selectedGpx selected GPX data
     26     * @param offset offset
     27     * @param forceTags force tagging of all photos, otherwise prefs are used
     28     * @return number of matched points
     29     * @since xxx
     30     */
     31    public static int matchGpxTrack(List<ImageEntry> images, GpxData selectedGpx, long offset, boolean forceTags) {
     32        int ret = 0;
     33
     34        long prevWpTime = 0;
     35        WayPoint prevWp = null;
     36
     37        List<List<List<WayPoint>>> trks = new ArrayList<>();
     38
     39        for (GpxTrack trk : selectedGpx.tracks) {
     40            List<List<WayPoint>> segs = new ArrayList<>();
     41            for (GpxTrackSegment seg : trk.getSegments()) {
     42                List<WayPoint> wps = new ArrayList<>(seg.getWayPoints());
     43                if (!wps.isEmpty()) {
     44                    //remove waypoints at the beginning of the track/segment without timestamps
     45                    int wp;
     46                    for (wp = 0; wp < wps.size(); wp++) {
     47                        if (wps.get(wp).setTimeFromAttribute() != null) {
     48                            break;
     49                        }
     50                    }
     51                    if (wp == 0) {
     52                        segs.add(wps);
     53                    } else if (wp < wps.size()) {
     54                        segs.add(wps.subList(wp, wps.size()));
     55                    }
     56                }
     57            }
     58            //sort segments by first waypoint
     59            if (!segs.isEmpty()) {
     60                segs.sort(new Comparator<List<WayPoint>>() {
     61                    @Override
     62                    public int compare(List<WayPoint> arg0, List<WayPoint> arg1) {
     63                        if (arg0.isEmpty() || arg1.isEmpty() || arg0.get(0).time == arg1.get(0).time)
     64                            return 0;
     65                        return arg0.get(0).time < arg1.get(0).time ? -1 : 1;
     66                    }
     67                });
     68                trks.add(segs);
     69            }
     70        }
     71        //sort tracks by first waypoint of first segment
     72        trks.sort(new Comparator<List<List<WayPoint>>>() {
     73            @Override
     74            public int compare(List<List<WayPoint>> arg0, List<List<WayPoint>> arg1) {
     75                if (arg0.isEmpty() || arg0.get(0).isEmpty()
     76                        || arg1.isEmpty() || arg1.get(0).isEmpty()
     77                        || arg0.get(0).get(0).time == arg1.get(0).get(0).time)
     78                    return 0;
     79                return arg0.get(0).get(0).time < arg1.get(0).get(0).time ? -1 : 1;
     80            }
     81        });
     82
     83        boolean trkInt, trkTag, segInt, segTag;
     84        int trkTime, trkDist, trkTagTime, segTime, segDist, segTagTime;
     85
     86        if (forceTags) { //temporary option to override advanced settings and activate all possible interpolations / tagging methods
     87            trkInt = trkTag = segInt = segTag = true;
     88            trkTime = trkDist = trkTagTime = segTime = segDist = segTagTime = Integer.MAX_VALUE;
     89        } else {
     90            // Load the settings
     91            trkInt = Config.getPref().getBoolean("geoimage.trk.int", false);
     92            trkTime = Config.getPref().getBoolean("geoimage.trk.int.time", false) ? Config.getPref().getInt("geoimage.trk.int.time.val", 60) : Integer.MAX_VALUE;
     93            trkDist = Config.getPref().getBoolean("geoimage.trk.int.dist", false) ? Config.getPref().getInt("geoimage.trk.int.dist.val", 50) : Integer.MAX_VALUE;
     94
     95            trkTag = Config.getPref().getBoolean("geoimage.trk.tag", true);
     96            trkTagTime = Config.getPref().getBoolean("geoimage.trk.tag.time", true) ? Config.getPref().getInt("geoimage.trk.tag.time.val", 2) : Integer.MAX_VALUE;
     97
     98            segInt = Config.getPref().getBoolean("geoimage.seg.int", true);
     99            segTime = Config.getPref().getBoolean("geoimage.seg.int.time", true) ? Config.getPref().getInt("geoimage.seg.int.time.val", 60) : Integer.MAX_VALUE;
     100            segDist = Config.getPref().getBoolean("geoimage.seg.int.dist", true) ? Config.getPref().getInt("geoimage.seg.int.dist.val", 50) : Integer.MAX_VALUE;
     101
     102            segTag = Config.getPref().getBoolean("geoimage.seg.tag", true);
     103            segTagTime = Config.getPref().getBoolean("geoimage.seg.tag.time", true) ? Config.getPref().getInt("geoimage.seg.tag.time.val", 2) : Integer.MAX_VALUE;
     104        }
     105        boolean isFirst = true;
     106
     107        for (int t = 0; t < trks.size(); t++) {
     108            List<List<WayPoint>> segs = trks.get(t);
     109            for (int s = 0; s < segs.size(); s++) {
     110                List<WayPoint> wps = segs.get(s);
     111                for (int i = 0; i < wps.size(); i++) {
     112                    WayPoint curWp = wps.get(i);
     113                    Date parsedTime = curWp.setTimeFromAttribute();
     114                    // Interpolate timestamps in the segment, if one or more waypoints miss them
     115                    if (parsedTime == null) {
     116                        //check if any of the following waypoints has a timestamp...
     117                        if (i > 0 && wps.get(i - 1).time != 0) {
     118                            long prevWpTimeNoOffset = wps.get(i - 1).getTime().getTime();
     119                            double totalDist = 0;
     120                            List<Pair<Double, WayPoint>> nextWps = new ArrayList<>();
     121                            for (int j = i; j < wps.size(); j++) {
     122                                totalDist += wps.get(j - 1).getCoor().greatCircleDistance(wps.get(j).getCoor());
     123                                nextWps.add(new Pair<>(totalDist, wps.get(j)));
     124                                final Date nextTime = wps.get(j).setTimeFromAttribute();
     125                                if (nextTime != null) {
     126                                    // ...if yes, interpolate everything in between
     127                                    long timeDiff = nextTime.getTime() - prevWpTimeNoOffset;
     128                                    for (Pair<Double, WayPoint> pair : nextWps) {
     129                                        pair.b.setTime(new Date((long) (prevWpTimeNoOffset + (timeDiff * (pair.a / totalDist)))));
     130                                    }
     131                                    break;
     132                                }
     133                            }
     134                            parsedTime = curWp.setTimeFromAttribute();
     135                            if (parsedTime == null) {
     136                                break; //It's pointless to continue with this segment, because none of the following waypoints had a timestamp
     137                            }
     138                        } else {
     139                            continue; // Timestamps on waypoints without preceding timestamps in the same segment can not be interpolated, so try next one
     140                        }
     141                    }
     142
     143                    final long curWpTime = parsedTime.getTime() + offset;
     144                    boolean interpolate = true;
     145                    int tagTime = 0;
     146                    if (i == 0) {
     147                        if (s == 0) { //First segment of the track, so apply settings for tracks
     148                            if (!trkInt || isFirst || prevWp == null || Math.abs(curWpTime - prevWpTime) > TimeUnit.MINUTES.toMillis(trkTime) || prevWp.getCoor().greatCircleDistance(curWp.getCoor()) > trkDist) {
     149                                isFirst = false;
     150                                interpolate = false;
     151                                if (trkTag) {
     152                                    tagTime = trkTagTime;
     153                                }
     154                            }
     155                        } else { //Apply settings for segments
     156                            if (!segInt || prevWp == null || Math.abs(curWpTime - prevWpTime) > TimeUnit.MINUTES.toMillis(segTime) || prevWp.getCoor().greatCircleDistance(curWp.getCoor()) > segDist) {
     157                                interpolate = false;
     158                                if (segTag) {
     159                                    tagTime = segTagTime;
     160                                }
     161                            }
     162                        }
     163                    }
     164                    ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, offset, interpolate, tagTime, false);
     165                    prevWp = curWp;
     166                    prevWpTime = curWpTime;
     167                }
     168            }
     169        }
     170        if (trkTag) {
     171            ret += matchPoints(images, prevWp, prevWpTime, prevWp, prevWpTime, offset, false, trkTagTime, true);
     172        }
     173        return ret;
     174    }
     175
     176    private static Double getElevation(WayPoint wp) {
     177        String value = wp.getString(GpxConstants.PT_ELE);
     178        if (value != null && !value.isEmpty()) {
     179            try {
     180                return Double.valueOf(value);
     181            } catch (NumberFormatException e) {
     182                Logging.warn(e);
     183            }
     184        }
     185        return null;
     186    }
     187
     188    private static int matchPoints(List<ImageEntry> images, WayPoint prevWp, long prevWpTime, WayPoint curWp, long curWpTime,
     189            long offset, boolean interpolate, int tagTime, boolean isLast) {
     190
     191        int ret = 0;
     192
     193        // i is the index of the timewise last photo that has the same or earlier EXIF time
     194        int i;
     195        if (isLast) {
     196            i = images.size() - 1;
     197        } else {
     198            i = getLastIndexOfListBefore(images, curWpTime);
     199        }
     200
     201        // no photos match
     202        if (i < 0)
     203            return 0;
     204
     205        Double speed = null;
     206        Double prevElevation = null;
     207
     208        if (prevWp != null && interpolate) {
     209            double distance = prevWp.getCoor().greatCircleDistance(curWp.getCoor());
     210            // This is in km/h, 3.6 * m/s
     211            if (curWpTime > prevWpTime) {
     212                speed = 3600 * distance / (curWpTime - prevWpTime);
     213            }
     214            prevElevation = getElevation(prevWp);
     215        }
     216
     217        Double curElevation = getElevation(curWp);
     218
     219        if (!interpolate || isLast) {
     220            final long half = Math.abs(curWpTime - prevWpTime) / 2;
     221            while (i >= 0) {
     222                final ImageEntry curImg = images.get(i);
     223                final ImageEntry curTmp = curImg.getTmp();
     224                final long time = curImg.getExifTime().getTime();
     225                if ((!isLast && time > curWpTime) || time < prevWpTime) {
     226                    break;
     227                }
     228                long tagms = TimeUnit.MINUTES.toMillis(tagTime);
     229                if (curTmp.getPos() == null &&
     230                        (Math.abs(time - curWpTime) <= tagms
     231                        || Math.abs(prevWpTime - time) <= tagms)) {
     232                    if (prevWp != null && time < curWpTime - half) {
     233                        curTmp.setPos(prevWp.getCoor());
     234                    } else {
     235                        curTmp.setPos(curWp.getCoor());
     236                    }
     237                    curTmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
     238                    curTmp.flagNewGpsData();
     239                    ret++;
     240                }
     241                i--;
     242            }
     243        } else if (prevWp != null) {
     244            // This code gives a simple linear interpolation of the coordinates between current and
     245            // previous track point assuming a constant speed in between
     246            while (i >= 0) {
     247                ImageEntry curImg = images.get(i);
     248                ImageEntry curTmp = curImg.getTmp();
     249                final long imgTime = curImg.getExifTime().getTime();
     250                if (imgTime < prevWpTime) {
     251                    break;
     252                }
     253                if (curTmp.getPos() == null) {
     254                    // The values of timeDiff are between 0 and 1, it is not seconds but a dimensionless variable
     255                    double timeDiff = (double) (imgTime - prevWpTime) / Math.abs(curWpTime - prevWpTime);
     256                    curTmp.setPos(prevWp.getCoor().interpolate(curWp.getCoor(), timeDiff));
     257                    curTmp.setSpeed(speed);
     258                    if (curElevation != null && prevElevation != null) {
     259                        curTmp.setElevation(prevElevation + (curElevation - prevElevation) * timeDiff);
     260                    }
     261                    curTmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
     262                    curTmp.flagNewGpsData();
     263
     264                    ret++;
     265                }
     266                i--;
     267            }
     268        }
     269        return ret;
     270    }
     271
     272    private static int getLastIndexOfListBefore(List<ImageEntry> images, long searchedTime) {
     273        int lstSize = images.size();
     274
     275        // No photos or the first photo taken is later than the search period
     276        if (lstSize == 0 || searchedTime < images.get(0).getExifTime().getTime())
     277            return -1;
     278
     279        // The search period is later than the last photo
     280        if (searchedTime > images.get(lstSize - 1).getExifTime().getTime())
     281            return lstSize-1;
     282
     283        // The searched index is somewhere in the middle, do a binary search from the beginning
     284        int curIndex;
     285        int startIndex = 0;
     286        int endIndex = lstSize-1;
     287        while (endIndex - startIndex > 1) {
     288            curIndex = (endIndex + startIndex) / 2;
     289            if (searchedTime > images.get(curIndex).getExifTime().getTime()) {
     290                startIndex = curIndex;
     291            } else {
     292                endIndex = curIndex;
     293            }
     294        }
     295        if (searchedTime < images.get(endIndex).getExifTime().getTime())
     296            return startIndex;
     297
     298        // This final loop is to check if photos with the exact same EXIF time follows
     299        while ((endIndex < (lstSize - 1)) && (images.get(endIndex).getExifTime().getTime()
     300                == images.get(endIndex + 1).getExifTime().getTime())) {
     301            endIndex++;
     302        }
     303        return endIndex;
     304    }
     305
     306}
  • src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

     
    55import static org.openstreetmap.josm.tools.I18n.trn;
    66
    77import java.awt.BorderLayout;
     8import java.awt.Component;
    89import java.awt.Cursor;
    910import java.awt.Dimension;
    1011import java.awt.FlowLayout;
     
    4344import javax.swing.BorderFactory;
    4445import javax.swing.JButton;
    4546import javax.swing.JCheckBox;
     47import javax.swing.JComponent;
    4648import javax.swing.JFileChooser;
    4749import javax.swing.JLabel;
    4850import javax.swing.JList;
     
    5153import javax.swing.JScrollPane;
    5254import javax.swing.JSeparator;
    5355import javax.swing.JSlider;
     56import javax.swing.JSpinner;
    5457import javax.swing.ListSelectionModel;
    5558import javax.swing.MutableComboBoxModel;
     59import javax.swing.SpinnerNumberModel;
    5660import javax.swing.SwingConstants;
     61import javax.swing.border.Border;
    5762import javax.swing.event.ChangeEvent;
    5863import javax.swing.event.ChangeListener;
    5964import javax.swing.event.DocumentEvent;
     
    6166
    6267import org.openstreetmap.josm.actions.DiskAccessAction;
    6368import org.openstreetmap.josm.actions.ExtensionFileFilter;
    64 import org.openstreetmap.josm.data.gpx.GpxConstants;
    6569import org.openstreetmap.josm.data.gpx.GpxData;
     70import org.openstreetmap.josm.data.gpx.GpxImageCorrelation;
    6671import org.openstreetmap.josm.data.gpx.GpxTrack;
    6772import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
    6873import org.openstreetmap.josm.data.gpx.WayPoint;
     
    7479import org.openstreetmap.josm.gui.io.importexport.NMEAImporter;
    7580import org.openstreetmap.josm.gui.layer.GpxLayer;
    7681import org.openstreetmap.josm.gui.layer.Layer;
     82import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
     83import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
     84import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
     85import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
    7786import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
    7887import org.openstreetmap.josm.gui.widgets.FileChooserManager;
    7988import org.openstreetmap.josm.gui.widgets.JosmComboBox;
     
    8392import org.openstreetmap.josm.io.IGpxReader;
    8493import org.openstreetmap.josm.io.nmea.NmeaReader;
    8594import org.openstreetmap.josm.spi.preferences.Config;
     95import org.openstreetmap.josm.spi.preferences.IPreferences;
    8696import org.openstreetmap.josm.tools.GBC;
    8797import org.openstreetmap.josm.tools.ImageProvider;
    8898import org.openstreetmap.josm.tools.JosmRuntimeException;
     
    102112    private final transient GeoImageLayer yLayer;
    103113    private transient Timezone timezone;
    104114    private transient Offset delta;
     115    private static boolean forceTags = false;
    105116
    106117    /**
    107118     * Constructs a new {@code CorrelateGpxWithImages} action.
     
    111122        super(tr("Correlate to GPX"));
    112123        new ImageProvider("dialogs/geoimage/gpx2img").getResource().attachImageIcon(this, true);
    113124        this.yLayer = layer;
     125        MainApplication.getLayerManager().addLayerChangeListener(new GpxLayerAddedListener());
    114126    }
    115127
    116128    private final class SyncDialogWindowListener extends WindowAdapter {
     
    322334        }
    323335    }
    324336
     337    private class AdvancedSettingsActionListener implements ActionListener {
     338
     339        private class CheckBoxActionListener implements ActionListener {
     340            private JComponent[] comps;
     341
     342            CheckBoxActionListener(JComponent... c) {
     343                comps = c;
     344            }
     345
     346            @Override
     347            public void actionPerformed(ActionEvent arg0) {
     348                setEnabled((JCheckBox) arg0.getSource());
     349            }
     350
     351            public void setEnabled(JCheckBox cb) {
     352                for (JComponent comp : comps) {
     353                    if (comp instanceof JSpinner) {
     354                        comp.setEnabled(cb.isSelected());
     355                    } else if (comp instanceof JPanel) {
     356                        boolean en = cb.isSelected();
     357                        for (Component c : comp.getComponents()) {
     358                            if (c instanceof JSpinner) {
     359                                c.setEnabled(en);
     360                            } else {
     361                                c.setEnabled(cb.isSelected());
     362                                if (en && c instanceof JCheckBox) {
     363                                    en = ((JCheckBox) c).isSelected();
     364                                }
     365                            }
     366                        }
     367                    }
     368                }
     369
     370            }
     371        }
     372
     373        private void addCheckBoxActionListener(JCheckBox cb, JComponent... c) {
     374            CheckBoxActionListener listener = new CheckBoxActionListener(c);
     375            cb.addActionListener(listener);
     376            listener.setEnabled(cb);
     377        }
     378
     379        @Override
     380        public void actionPerformed(ActionEvent arg0) {
     381
     382            IPreferences s = Config.getPref();
     383            JPanel p = new JPanel(new GridBagLayout());
     384
     385            Border border1 = BorderFactory.createEmptyBorder(0, 20, 0, 0);
     386            Border border2 = BorderFactory.createEmptyBorder(10, 0, 5, 0);
     387            Border border = BorderFactory.createEmptyBorder(0, 40, 0, 0);
     388            FlowLayout layout = new FlowLayout();
     389
     390            JLabel l = new JLabel(tr("Segment settings"));
     391            l.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
     392            p.add(l, GBC.eol());
     393            JCheckBox cInterpolSeg = new JCheckBox(tr("Interpolate between segments"), s.getBoolean("geoimage.seg.int", true));
     394            cInterpolSeg.setBorder(border1);
     395            p.add(cInterpolSeg, GBC.eol());
     396
     397            String[] trs = tr("only when the segments are less than # minutes apart").split("#");
     398            JCheckBox cInterpolSegTime = new JCheckBox(trs[0].trim(), s.getBoolean("geoimage.seg.int.time", true));
     399            JSpinner sInterpolSegTime = new JSpinner(new SpinnerNumberModel(s.getInt("geoimage.seg.int.time.val", 60), 0, Integer.MAX_VALUE, 1));
     400            ((JSpinner.DefaultEditor) sInterpolSegTime.getEditor()).getTextField().setColumns(3);
     401            JLabel lInterpolSegTime = new JLabel(trs.length >= 2 ? trs[1].trim() : "");
     402            JPanel pInterpolSegTime = new JPanel(layout);
     403            pInterpolSegTime.add(cInterpolSegTime);
     404            pInterpolSegTime.add(sInterpolSegTime);
     405            pInterpolSegTime.add(lInterpolSegTime);
     406            pInterpolSegTime.setBorder(border);
     407            p.add(pInterpolSegTime, GBC.eol());
     408
     409            trs = tr("only when the segments are less than # metres apart").split("#");
     410            JCheckBox cInterpolSegDist = new JCheckBox(trs[0].trim(), s.getBoolean("geoimage.seg.int.dist", true));
     411            JSpinner sInterpolSegDist = new JSpinner(new SpinnerNumberModel(s.getInt("geoimage.seg.int.dist.val", 50), 0, Integer.MAX_VALUE, 1));
     412            ((JSpinner.DefaultEditor) sInterpolSegDist.getEditor()).getTextField().setColumns(3);
     413            JLabel lInterpolSegDist = new JLabel(trs.length >= 2 ? trs[1].trim() : "");
     414            JPanel pInterpolSegDist = new JPanel(layout);
     415            pInterpolSegDist.add(cInterpolSegDist);
     416            pInterpolSegDist.add(sInterpolSegDist);
     417            pInterpolSegDist.add(lInterpolSegDist);
     418            pInterpolSegDist.setBorder(border);
     419            p.add(pInterpolSegDist, GBC.eol());
     420
     421            JCheckBox cTagSeg = new JCheckBox(tr("Tag images at the closest end of a segment, when not interpolated"), s.getBoolean("geoimage.seg.tag", true));
     422            cTagSeg.setBorder(border1);
     423            p.add(cTagSeg, GBC.eol());
     424
     425            trs = tr("only within # minutes of the closest trackpoint").split("#");
     426            JCheckBox cTagSegTime = new JCheckBox(trs[0].trim(), s.getBoolean("geoimage.seg.tag.time", true));
     427            JSpinner sTagSegTime = new JSpinner(new SpinnerNumberModel(s.getInt("geoimage.seg.tag.time.val", 2), 0, Integer.MAX_VALUE, 1));
     428            ((JSpinner.DefaultEditor) sTagSegTime.getEditor()).getTextField().setColumns(3);
     429            JLabel lTagSegTime = new JLabel(trs.length >= 2 ? trs[1].trim() : "");
     430            JPanel pTagSegTime = new JPanel(layout);
     431            pTagSegTime.add(cTagSegTime);
     432            pTagSegTime.add(sTagSegTime);
     433            pTagSegTime.add(lTagSegTime);
     434            pTagSegTime.setBorder(border);
     435            p.add(pTagSegTime, GBC.eol());
     436
     437            l = new JLabel(tr("Track settings (note that multiple tracks can be in one GPX file)"));
     438            l.setBorder(border2);
     439            p.add(l, GBC.eol());
     440            JCheckBox cInterpolTrack = new JCheckBox(tr("Interpolate between tracks"), s.getBoolean("geoimage.trk.int", false));
     441            cInterpolTrack.setBorder(border1);
     442            p.add(cInterpolTrack, GBC.eol());
     443
     444            trs = tr("only when the tracks are less than # minutes apart").split("#");
     445            JCheckBox cInterpolTrackTime = new JCheckBox(trs[0].trim(), s.getBoolean("geoimage.trk.int.time", false));
     446            JSpinner sInterpolTrackTime = new JSpinner(new SpinnerNumberModel(s.getInt("geoimage.trk.int.time.val", 60), 0, Integer.MAX_VALUE, 1));
     447            ((JSpinner.DefaultEditor) sInterpolTrackTime.getEditor()).getTextField().setColumns(3);
     448            JLabel lInterpolTrackTime = new JLabel(trs.length >= 2 ? trs[1].trim() : "");
     449            JPanel pInterpolTrackTime = new JPanel(layout);
     450            pInterpolTrackTime.add(cInterpolTrackTime);
     451            pInterpolTrackTime.add(sInterpolTrackTime);
     452            pInterpolTrackTime.add(lInterpolTrackTime);
     453            pInterpolTrackTime.setBorder(border);
     454            p.add(pInterpolTrackTime, GBC.eol());
     455
     456            trs = tr("only when the tracks are less than # metres apart").split("#");
     457            JCheckBox cInterpolTrackDist = new JCheckBox(trs[0].trim(), s.getBoolean("geoimage.trk.int.dist", false));
     458            JSpinner sInterpolTrackDist = new JSpinner(new SpinnerNumberModel(s.getInt("geoimage.trk.int.dist.val", 50), 0, Integer.MAX_VALUE, 1));
     459            ((JSpinner.DefaultEditor) sInterpolTrackDist.getEditor()).getTextField().setColumns(3);
     460            JLabel lInterpolTrackDist = new JLabel(trs.length >= 2 ? trs[1].trim() : "");
     461            JPanel pInterpolTrackDist = new JPanel(layout);
     462            pInterpolTrackDist.add(cInterpolTrackDist);
     463            pInterpolTrackDist.add(sInterpolTrackDist);
     464            pInterpolTrackDist.add(lInterpolTrackDist);
     465            pInterpolTrackDist.setBorder(border);
     466            p.add(pInterpolTrackDist, GBC.eol());
     467
     468            JCheckBox cTagTrack = new JCheckBox(tr("<html>Tag images at the closest end of a track, when not interpolated<br>" +
     469                    "(also applies before the first and after the last track)</html>"), s.getBoolean("geoimage.trk.tag", true));
     470            cTagTrack.setBorder(border1);
     471            p.add(cTagTrack, GBC.eol());
     472
     473            trs = tr("only within # minutes of the closest trackpoint").split("#");
     474            JCheckBox cTagTrackTime = new JCheckBox(trs[0].trim(), s.getBoolean("geoimage.trk.tag.time", true));
     475            JSpinner sTagTrackTime = new JSpinner(new SpinnerNumberModel(s.getInt("geoimage.trk.tag.time.val", 2), 0, Integer.MAX_VALUE, 1));
     476            ((JSpinner.DefaultEditor) sTagTrackTime.getEditor()).getTextField().setColumns(3);
     477            JLabel lTagTrackTime = new JLabel(trs.length >= 2 ? trs[1].trim() : "");
     478            JPanel pTagTrackTime = new JPanel(layout);
     479            pTagTrackTime.add(cTagTrackTime);
     480            pTagTrackTime.add(sTagTrackTime);
     481            pTagTrackTime.add(lTagTrackTime);
     482            pTagTrackTime.setBorder(border);
     483            p.add(pTagTrackTime, GBC.eol());
     484
     485            l = new JLabel(tr("Advanced"));
     486            l.setBorder(border2);
     487            p.add(l, GBC.eol());
     488            JCheckBox cForce = new JCheckBox(tr("<html>Force tagging of all pictures (temporarily overrides the settings above)<br>This option will not be saved permanently</html>"), forceTags);
     489            cForce.setBorder(BorderFactory.createEmptyBorder(0, 20, 10, 0));
     490            p.add(cForce, GBC.eol());
     491
     492            addCheckBoxActionListener(cInterpolSegTime, sInterpolSegTime);
     493            addCheckBoxActionListener(cInterpolSegDist, sInterpolSegDist);
     494            addCheckBoxActionListener(cInterpolSeg, pInterpolSegTime, pInterpolSegDist);
     495
     496            addCheckBoxActionListener(cTagSegTime, sTagSegTime);
     497            addCheckBoxActionListener(cTagSeg, pTagSegTime);
     498
     499            addCheckBoxActionListener(cInterpolTrackTime, sInterpolTrackTime);
     500            addCheckBoxActionListener(cInterpolTrackDist, sInterpolTrackDist);
     501            addCheckBoxActionListener(cInterpolTrack, pInterpolTrackTime, pInterpolTrackDist);
     502
     503            addCheckBoxActionListener(cTagTrackTime, sTagTrackTime);
     504            addCheckBoxActionListener(cTagTrack, pTagTrackTime);
     505
     506
     507            ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), tr("Advanced settings"), tr("OK"), tr("Cancel"))
     508                            .setButtonIcons("ok", "cancel").setContent(p);
     509            if (ed.showDialog().getValue() == 1) {
     510
     511                s.putBoolean("geoimage.seg.int", cInterpolSeg.isSelected());
     512                s.putBoolean("geoimage.seg.int.dist", cInterpolSegDist.isSelected());
     513                s.putInt("geoimage.seg.int.dist.val", (int) sInterpolSegDist.getValue());
     514                s.putBoolean("geoimage.seg.int.time", cInterpolSegTime.isSelected());
     515                s.putInt("geoimage.seg.int.time.val", (int) sInterpolSegTime.getValue());
     516                s.putBoolean("geoimage.seg.tag", cTagSeg.isSelected());
     517                s.putBoolean("geoimage.seg.tag.time", cTagSegTime.isSelected());
     518                s.putInt("geoimage.seg.tag.time.val", (int) sTagSegTime.getValue());
     519
     520                s.putBoolean("geoimage.trk.int", cInterpolTrack.isSelected());
     521                s.putBoolean("geoimage.trk.int.dist", cInterpolTrackDist.isSelected());
     522                s.putInt("geoimage.trk.int.dist.val", (int) sInterpolTrackDist.getValue());
     523                s.putBoolean("geoimage.trk.int.time", cInterpolTrackTime.isSelected());
     524                s.putInt("geoimage.trk.int.time.val", (int) sInterpolTrackTime.getValue());
     525                s.putBoolean("geoimage.trk.tag", cTagTrack.isSelected());
     526                s.putBoolean("geoimage.trk.tag.time", cTagTrackTime.isSelected());
     527                s.putInt("geoimage.trk.tag.time.val", (int) sTagTrackTime.getValue());
     528
     529                forceTags = cForce.isSelected(); // This setting is not supposed to be saved permanently
     530
     531                statusBarUpdater.updateStatusBar();
     532                yLayer.updateBufferAndRepaint();
     533            }
     534        }
     535
     536    }
     537
    325538    /**
    326539     * This action listener is called when the user has a photo of the time of his GPS receiver. It
    327540     * displays the list of photos of the layer, and upon selection displays the selected photo.
     
    525738        }
    526739    }
    527740
     741    private class GpxLayerAddedListener implements LayerChangeListener {
     742        @Override
     743        public void layerAdded(LayerAddEvent e) {
     744            if (syncDialog != null && syncDialog.isVisible()) {
     745                Layer layer = e.getAddedLayer();
     746                if (layer instanceof GpxLayer) {
     747                    GpxLayer gpx = (GpxLayer) layer;
     748                    GpxDataWrapper gdw = new GpxDataWrapper(gpx.getName(), gpx.data, gpx.data.storageFile);
     749                    gpxLst.add(gdw);
     750                    MutableComboBoxModel<GpxDataWrapper> model = (MutableComboBoxModel<GpxDataWrapper>) cbGpx.getModel();
     751                    if (gpxLst.get(0).file == null) {
     752                        gpxLst.remove(0);
     753                        model.removeElementAt(0);
     754                    }
     755                    model.addElement(gdw);
     756                }
     757            }
     758        }
     759        @Override
     760        public void layerRemoving(LayerRemoveEvent e) {}
     761        @Override
     762        public void layerOrderChanged(LayerOrderChangeEvent e) {}
     763    }
     764
    528765    @Override
    529766    public void actionPerformed(ActionEvent ae) {
    530767        // Construct the list of loaded GPX tracks
     
    606843        JButton buttonAdjust = new JButton(tr("Manual adjust"));
    607844        buttonAdjust.addActionListener(new AdjustActionListener());
    608845
     846        JButton buttonAdvanced = new JButton(tr("Advanced settings..."));
     847        buttonAdvanced.addActionListener(new AdvancedSettingsActionListener());
     848
    609849        JLabel labelPosition = new JLabel(tr("Override position for: "));
    610850
    611851        int numAll = getSortedImgList(true, true).size();
     
    666906        gbc.weightx = 0.5;
    667907        panelTf.add(buttonViewGpsPhoto, gbc);
    668908
     909
    669910        gbc = GBC.std().fill(GBC.BOTH).insets(5, 5, 5, 5);
    670         gbc.gridx = 2;
     911        gbc.gridx = 1;
    671912        gbc.gridy = y++;
    672913        gbc.weightx = 0.5;
     914        panelTf.add(buttonAdvanced, gbc);
     915
     916        gbc.gridx = 2;
    673917        panelTf.add(buttonAutoGuess, gbc);
    674918
    675919        gbc.gridx = 3;
     
    715959        cbTaggedImg.addItemListener(statusBarUpdaterWithRepaint);
    716960
    717961        statusBarUpdater.updateStatusBar();
     962        yLayer.updateBufferAndRepaint();
    718963
    719964        outerPanel = new JPanel(new BorderLayout());
    720965        outerPanel.add(statusBar, BorderLayout.PAGE_END);
     
    8071052            if (selGpx == null)
    8081053                return tr("No gpx selected");
    8091054
    810             final long offsetMs = ((long) (timezone.getHours() * TimeUnit.HOURS.toMillis(1))) + delta.getMilliseconds(); // in milliseconds
    811             lastNumMatched = matchGpxTrack(dateImgLst, selGpx.data, offsetMs);
     1055            final long offsetMs = ((long) (timezone.getHours() * TimeUnit.HOURS.toMillis(-1))) + delta.getMilliseconds(); // in milliseconds
     1056            lastNumMatched = GpxImageCorrelation.matchGpxTrack(dateImgLst, selGpx.data, offsetMs, forceTags);
    8121057
    8131058            return trn("<html>Matched <b>{0}</b> of <b>{1}</b> photo to GPX track.</html>",
    8141059                    "<html>Matched <b>{0}</b> of <b>{1}</b> photos to GPX track.</html>",
     
    10361281            yLayer.updateBufferAndRepaint();
    10371282        }
    10381283    }
    1039 
    10401284    private List<ImageEntry> getSortedImgList() {
    10411285        return getSortedImgList(cbExifImg.isSelected(), cbTaggedImg.isSelected());
    10421286    }
     
    10871331        return (GpxDataWrapper) item;
    10881332    }
    10891333
    1090     /**
    1091      * Match a list of photos to a gpx track with a given offset.
    1092      * All images need a exifTime attribute and the List must be sorted according to these times.
    1093      * @param images images to match
    1094      * @param selectedGpx selected GPX data
    1095      * @param offset offset
    1096      * @return number of matched points
    1097      */
    1098     static int matchGpxTrack(List<ImageEntry> images, GpxData selectedGpx, long offset) {
    1099         int ret = 0;
    1100 
    1101         for (GpxTrack trk : selectedGpx.tracks) {
    1102             for (GpxTrackSegment segment : trk.getSegments()) {
    1103 
    1104                 long prevWpTime = 0;
    1105                 WayPoint prevWp = null;
    1106 
    1107                 for (WayPoint curWp : segment.getWayPoints()) {
    1108                     final Date parsedTime = curWp.setTimeFromAttribute();
    1109                     if (parsedTime != null) {
    1110                         final long curWpTime = parsedTime.getTime() + offset;
    1111                         ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, offset);
    1112 
    1113                         prevWp = curWp;
    1114                         prevWpTime = curWpTime;
    1115                         continue;
    1116                     }
    1117                     prevWp = null;
    1118                     prevWpTime = 0;
    1119                 }
    1120             }
    1121         }
    1122         return ret;
    1123     }
    1124 
    1125     private static Double getElevation(WayPoint wp) {
    1126         String value = wp.getString(GpxConstants.PT_ELE);
    1127         if (value != null && !value.isEmpty()) {
    1128             try {
    1129                 return Double.valueOf(value);
    1130             } catch (NumberFormatException e) {
    1131                 Logging.warn(e);
    1132             }
    1133         }
    1134         return null;
    1135     }
    1136 
    1137     static int matchPoints(List<ImageEntry> images, WayPoint prevWp, long prevWpTime,
    1138             WayPoint curWp, long curWpTime, long offset) {
    1139         // Time between the track point and the previous one, 5 sec if first point, i.e. photos take
    1140         // 5 sec before the first track point can be assumed to be take at the starting position
    1141         long interval = prevWpTime > 0 ? Math.abs(curWpTime - prevWpTime) : TimeUnit.SECONDS.toMillis(5);
    1142         int ret = 0;
    1143 
    1144         // i is the index of the timewise last photo that has the same or earlier EXIF time
    1145         int i = getLastIndexOfListBefore(images, curWpTime);
    1146 
    1147         // no photos match
    1148         if (i < 0)
    1149             return 0;
    1150 
    1151         Double speed = null;
    1152         Double prevElevation = null;
    1153 
    1154         if (prevWp != null) {
    1155             double distance = prevWp.getCoor().greatCircleDistance(curWp.getCoor());
    1156             // This is in km/h, 3.6 * m/s
    1157             if (curWpTime > prevWpTime) {
    1158                 speed = 3600 * distance / (curWpTime - prevWpTime);
    1159             }
    1160             prevElevation = getElevation(prevWp);
    1161         }
    1162 
    1163         Double curElevation = getElevation(curWp);
    1164 
    1165         // First trackpoint, then interval is set to five seconds, i.e. photos up to five seconds
    1166         // before the first point will be geotagged with the starting point
    1167         if (prevWpTime == 0 || curWpTime <= prevWpTime) {
    1168             while (i >= 0) {
    1169                 final ImageEntry curImg = images.get(i);
    1170                 long time = curImg.getExifTime().getTime();
    1171                 if (time > curWpTime || time < curWpTime - interval) {
    1172                     break;
    1173                 }
    1174                 if (curImg.tmp.getPos() == null) {
    1175                     curImg.tmp.setPos(curWp.getCoor());
    1176                     curImg.tmp.setSpeed(speed);
    1177                     curImg.tmp.setElevation(curElevation);
    1178                     curImg.tmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
    1179                     curImg.tmp.flagNewGpsData();
    1180                     ret++;
    1181                 }
    1182                 i--;
    1183             }
    1184             return ret;
    1185         }
    1186 
    1187         // This code gives a simple linear interpolation of the coordinates between current and
    1188         // previous track point assuming a constant speed in between
    1189         while (i >= 0) {
    1190             ImageEntry curImg = images.get(i);
    1191             long imgTime = curImg.getExifTime().getTime();
    1192             if (imgTime < prevWpTime) {
    1193                 break;
    1194             }
    1195 
    1196             if (prevWp != null && curImg.tmp.getPos() == null) {
    1197                 // The values of timeDiff are between 0 and 1, it is not seconds but a dimensionless variable
    1198                 double timeDiff = (double) (imgTime - prevWpTime) / interval;
    1199                 curImg.tmp.setPos(prevWp.getCoor().interpolate(curWp.getCoor(), timeDiff));
    1200                 curImg.tmp.setSpeed(speed);
    1201                 if (curElevation != null && prevElevation != null) {
    1202                     curImg.tmp.setElevation(prevElevation + (curElevation - prevElevation) * timeDiff);
    1203                 }
    1204                 curImg.tmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
    1205                 curImg.tmp.flagNewGpsData();
    1206 
    1207                 ret++;
    1208             }
    1209             i--;
    1210         }
    1211         return ret;
    1212     }
    1213 
    1214     private static int getLastIndexOfListBefore(List<ImageEntry> images, long searchedTime) {
    1215         int lstSize = images.size();
    1216 
    1217         // No photos or the first photo taken is later than the search period
    1218         if (lstSize == 0 || searchedTime < images.get(0).getExifTime().getTime())
    1219             return -1;
    1220 
    1221         // The search period is later than the last photo
    1222         if (searchedTime > images.get(lstSize - 1).getExifTime().getTime())
    1223             return lstSize-1;
    1224 
    1225         // The searched index is somewhere in the middle, do a binary search from the beginning
    1226         int curIndex;
    1227         int startIndex = 0;
    1228         int endIndex = lstSize-1;
    1229         while (endIndex - startIndex > 1) {
    1230             curIndex = (endIndex + startIndex) / 2;
    1231             if (searchedTime > images.get(curIndex).getExifTime().getTime()) {
    1232                 startIndex = curIndex;
    1233             } else {
    1234                 endIndex = curIndex;
    1235             }
    1236         }
    1237         if (searchedTime < images.get(endIndex).getExifTime().getTime())
    1238             return startIndex;
    1239 
    1240         // This final loop is to check if photos with the exact same EXIF time follows
    1241         while ((endIndex < (lstSize-1)) && (images.get(endIndex).getExifTime().getTime()
    1242                 == images.get(endIndex + 1).getExifTime().getTime())) {
    1243             endIndex++;
    1244         }
    1245         return endIndex;
    1246     }
    12471334}
  • src/org/openstreetmap/josm/gui/layer/geoimage/Timezone.java

     
    55
    66import java.text.ParseException;
    77import java.util.Objects;
     8import java.util.regex.Matcher;
     9import java.util.regex.Pattern;
    810
    911/**
    1012 * Timezone in hours.<p>
     
    4951    }
    5052
    5153    static Timezone parseTimezone(String timezone) throws ParseException {
    52 
    5354        if (timezone.isEmpty())
    5455            return ZERO;
    5556
    56         String error = tr("Error while parsing timezone.\nExpected format: {0}", "+H:MM");
     57        Matcher m = Pattern.compile("^([\\+\\-]?)(\\d{1,2})(?:\\:([0-5]\\d))?$").matcher(timezone);
    5758
    58         char sgnTimezone = '+';
    59         StringBuilder hTimezone = new StringBuilder();
    60         StringBuilder mTimezone = new StringBuilder();
    61         int state = 1; // 1=start/sign, 2=hours, 3=minutes.
    62         for (int i = 0; i < timezone.length(); i++) {
    63             char c = timezone.charAt(i);
    64             switch (c) {
    65                 case ' ':
    66                     if (state != 2 || hTimezone.length() != 0)
    67                         throw new ParseException(error, i);
    68                     break;
    69                 case '+':
    70                 case '-':
    71                     if (state == 1) {
    72                         sgnTimezone = c;
    73                         state = 2;
    74                     } else
    75                         throw new ParseException(error, i);
    76                     break;
    77                 case ':':
    78                 case '.':
    79                     if (state == 2) {
    80                         state = 3;
    81                     } else
    82                         throw new ParseException(error, i);
    83                     break;
    84                 case '0':
    85                 case '1':
    86                 case '2':
    87                 case '3':
    88                 case '4':
    89                 case '5':
    90                 case '6':
    91                 case '7':
    92                 case '8':
    93                 case '9':
    94                     switch (state) {
    95                         case 1:
    96                         case 2:
    97                             state = 2;
    98                             hTimezone.append(c);
    99                             break;
    100                         case 3:
    101                             mTimezone.append(c);
    102                             break;
    103                         default:
    104                             throw new ParseException(error, i);
    105                     }
    106                     break;
    107                 default:
    108                     throw new ParseException(error, i);
    109             }
    110         }
    111 
    112         int h = 0;
    113         int m = 0;
     59        ParseException pe = new ParseException(tr("Error while parsing timezone.\nExpected format: {0}", "±HH:MM"), 0);
    11460        try {
    115             h = Integer.parseInt(hTimezone.toString());
    116             if (mTimezone.length() > 0) {
    117                 m = Integer.parseInt(mTimezone.toString());
     61            if (m.find()) {
     62                int sign = m.group(1) == "-" ? -1 : 1;
     63                int hour = Integer.parseInt(m.group(2));
     64                int min = m.groupCount() > 3 ? Integer.parseInt(m.group(3)) : 0;
     65                return new Timezone(sign * hour + min / 60.0);
    11866            }
    119         } catch (NumberFormatException nfe) {
    120             // Invalid timezone
    121             throw (ParseException) new ParseException(error, 0).initCause(nfe);
     67        } catch (IndexOutOfBoundsException | NumberFormatException ex) {
     68            pe.initCause(ex);
    12269        }
    123 
    124         if (h > 12 || m > 59)
    125             throw new ParseException(error, 0);
    126         else
    127             return new Timezone((h + m / 60.0) * (sgnTimezone == '-' ? -1 : 1));
     70        throw pe;
    12871    }
    12972
    13073    @Override
  • test/unit/org/openstreetmap/josm/data/gpx/GpxImageCorrelationTest.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.gpx;
     3
     4import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertFalse;
     6import static org.junit.Assert.assertTrue;
     7
     8import java.util.Arrays;
     9import java.util.List;
     10
     11import org.junit.BeforeClass;
     12import org.junit.Rule;
     13import org.junit.Test;
     14import org.openstreetmap.josm.data.coor.CachedLatLon;
     15import org.openstreetmap.josm.gui.layer.geoimage.ImageEntry;
     16import org.openstreetmap.josm.io.GpxReaderTest;
     17import org.openstreetmap.josm.spi.preferences.Config;
     18import org.openstreetmap.josm.spi.preferences.IPreferences;
     19import org.openstreetmap.josm.testutils.JOSMTestRules;
     20import org.openstreetmap.josm.tools.date.DateUtils;
     21import org.openstreetmap.josm.tools.date.DateUtilsTest;
     22
     23import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     24
     25/**
     26 * Unit tests of {@link GpxImageCorrelation} class.
     27 */
     28public class GpxImageCorrelationTest {
     29
     30    /**
     31     * Setup test.
     32     */
     33    @Rule
     34    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     35    public JOSMTestRules test = new JOSMTestRules();
     36
     37    /**
     38     * Setup test.
     39     */
     40    @BeforeClass
     41    public static void setUp() {
     42        DateUtilsTest.setTimeZone(DateUtils.UTC);
     43    }
     44
     45    /**
     46     * Tests matching of images to a GPX track.
     47     * @throws Exception if the track cannot be parsed
     48     */
     49    @Test
     50    public void testMatchGpxTrack() throws Exception {
     51        IPreferences s = Config.getPref();
     52        final GpxData gpx = GpxReaderTest.parseGpxData("data_nodist/ImageCorrelationTest.gpx");
     53        assertEquals(5, gpx.tracks.size());
     54        assertEquals(1, gpx.tracks.iterator().next().getSegments().size());
     55        assertEquals(128, gpx.tracks.iterator().next().getSegments().iterator().next().getWayPoints().size());
     56
     57        final ImageEntry ib = new ImageEntry();
     58        ib.setExifTime(DateUtils.fromString("2016:01:03 11:54:58")); // 5 minutes before start of GPX
     59        ib.createTmp();
     60        final ImageEntry i0 = new ImageEntry();
     61        i0.setExifTime(DateUtils.fromString("2016:01:03 11:59:54")); // 4 sec before start of GPX
     62        i0.createTmp();
     63        final ImageEntry i1 = new ImageEntry();
     64        i1.setExifTime(DateUtils.fromString("2016:01:03 12:04:01"));
     65        i1.createTmp();
     66        final ImageEntry i2 = new ImageEntry();
     67        i2.setExifTime(DateUtils.fromString("2016:01:03 12:04:57"));
     68        i2.createTmp();
     69        final ImageEntry i3 = new ImageEntry();
     70        i3.setExifTime(DateUtils.fromString("2016:01:03 12:05:05"));
     71        i3.createTmp();
     72        final ImageEntry i4 = new ImageEntry(); //Image close to two points with elevation, but without time
     73        i4.setExifTime(DateUtils.fromString("2016:01:03 12:05:20"));
     74        i4.createTmp();
     75        final ImageEntry i5 = new ImageEntry(); //between two tracks, closer to first
     76        i5.setExifTime(DateUtils.fromString("2016:01:03 12:07:00"));
     77        i5.createTmp();
     78        final ImageEntry i6 = new ImageEntry(); //between two tracks, closer to second (more than 1 minute from any track)
     79        i6.setExifTime(DateUtils.fromString("2016:01:03 12:07:45"));
     80        i6.createTmp();
     81
     82        List<ImageEntry> images = Arrays.asList(ib, i0, i1, i2, i3, i4, i5, i6);
     83
     84        // TEST #1: default settings
     85        // tag images within 2 minutes to tracks/segments, interpolate between segments only
     86        assertEquals(7, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     87        assertEquals(null, ib.getPos());
     88        assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), i0.getPos()); // start of track
     89        assertEquals(new CachedLatLon(47.196979885920882, 8.79541271366179), i1.getPos()); // exact match
     90        assertEquals(new CachedLatLon(47.197319911792874, 8.792139580473304), i3.getPos()); // exact match
     91        assertEquals(new CachedLatLon((47.197131179273129 + 47.197186248376966) / 2, (8.792974585667253 + 8.792809881269932) / 2), i2.getPos()); // interpolated
     92        assertEquals(new CachedLatLon(47.197568312311816, 8.790292849679897), i4.getPos()); // interpolated between points without timestamp
     93        assertEquals(new CachedLatLon(47.19819249585271, 8.78536943346262), i5.getPos()); // tagged to last WP of first track, because closer and within 2 min (default setting)
     94        assertEquals(new CachedLatLon(47.20138901844621, 8.774476982653141), i6.getPos()); // tagged to first WP of second track, because closer and within 2 min (default setting)
     95        assertFalse(ib.hasNewGpsData());
     96        assertTrue(i0.hasNewGpsData() && i1.hasNewGpsData() && i2.hasNewGpsData() && i3.hasNewGpsData()
     97                && i4.hasNewGpsData() && i5.hasNewGpsData() && i6.hasNewGpsData());
     98        // First waypoint has no speed in matchGpxTrack(). Speed is calculated
     99        // and not taken from GPX track.
     100        assertEquals(null, ib.getSpeed());
     101        assertEquals(null, i0.getSpeed());
     102        assertEquals(Double.valueOf(11.675317966018756), i1.getSpeed(), 0.000001);
     103        assertEquals(Double.valueOf(24.992418392716967), i2.getSpeed(), 0.000001);
     104        assertEquals(Double.valueOf(27.307968754679223), i3.getSpeed(), 0.000001);
     105        assertEquals(null, ib.getElevation());
     106        assertEquals(null, i0.getElevation());
     107        assertEquals(Double.valueOf(489.29), i1.getElevation(), 0.000001);
     108        assertEquals(Double.valueOf((490.40 + 489.75) / 2), i2.getElevation(), 0.000001);
     109        assertEquals(Double.valueOf(486.368333333), i3.getElevation(), 0.000001);
     110        assertEquals(Double.valueOf(475.393978719), i4.getElevation(), 0.000001); //interpolated elevation between trackpoints with interpolated timestamps
     111        assertEquals(null, i5.getElevation());
     112        assertEquals(null, i6.getElevation());
     113
     114        assertEquals(null, ib.getGpsTime());
     115        assertEquals(DateUtils.fromString("2016:01:03 11:59:54"), i0.getGpsTime()); // original time is kept
     116        assertEquals(DateUtils.fromString("2016:01:03 12:04:01"), i1.getGpsTime());
     117        assertEquals(DateUtils.fromString("2016:01:03 12:04:57"), i2.getGpsTime());
     118        assertEquals(DateUtils.fromString("2016:01:03 12:05:05"), i3.getGpsTime());
     119
     120        clearTmp(images);
     121
     122        // TEST #2: Disable all interpolation and tagging close to tracks. Only i1-i4 are tagged
     123
     124        s.putBoolean("geoimage.trk.tag", false);
     125        s.putBoolean("geoimage.trk.int", false);
     126        s.putBoolean("geoimage.seg.tag", false);
     127        s.putBoolean("geoimage.seg.int", false);
     128
     129        assertEquals(4, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     130        assertEquals(null, ib.getPos());
     131        assertEquals(null, i0.getPos());
     132        assertEquals(new CachedLatLon(47.196979885920882, 8.79541271366179), i1.getPos());
     133        assertEquals(new CachedLatLon((47.197131179273129 + 47.197186248376966) / 2, (8.792974585667253 + 8.792809881269932) / 2), i2.getPos());
     134        assertEquals(new CachedLatLon(47.197319911792874, 8.792139580473304), i3.getPos());
     135        assertEquals(new CachedLatLon(47.197568312311816, 8.790292849679897), i4.getPos());
     136        assertEquals(null, i5.getPos());
     137        assertEquals(null, i6.getPos());
     138
     139        clearTmp(images);
     140
     141        // TEST #3: Disable all interpolation and allow tagging within 1 minute of a track. i0-i5 are tagged.
     142        // i6 will not be tagged, because it's 68 seconds away from the next waypoint in either direction
     143
     144        s.putBoolean("geoimage.trk.tag", true);
     145        s.putBoolean("geoimage.trk.tag.time", true);
     146        s.putInt("geoimage.trk.tag.time.val", 1);
     147
     148        s.putBoolean("geoimage.trk.int", false);
     149        s.putBoolean("geoimage.seg.tag", false);
     150        s.putBoolean("geoimage.seg.int", false);
     151
     152        assertEquals(6, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     153        assertEquals(null, ib.getPos());
     154        assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), i0.getPos());
     155        assertEquals(new CachedLatLon(47.196979885920882, 8.79541271366179), i1.getPos());
     156        assertEquals(new CachedLatLon((47.197131179273129 + 47.197186248376966) / 2, (8.792974585667253 + 8.792809881269932) / 2), i2.getPos());
     157        assertEquals(new CachedLatLon(47.197319911792874, 8.792139580473304), i3.getPos());
     158        assertEquals(new CachedLatLon(47.197568312311816, 8.790292849679897), i4.getPos());
     159        assertEquals(new CachedLatLon(47.19819249585271, 8.78536943346262), i5.getPos());
     160        assertEquals(null, i6.getPos());
     161
     162        clearTmp(images);
     163
     164        // TEST #4: Force tagging (parameter forceTags=true, no change of configuration). All images will be tagged
     165        // i5-i6 will now be interpolated, therefore it will have an elevation and different coordinates than in tests above
     166
     167        assertEquals(8, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, true));
     168        assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), ib.getPos());
     169        assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), i0.getPos());
     170        assertEquals(new CachedLatLon(47.196979885920882, 8.79541271366179), i1.getPos());
     171        assertEquals(new CachedLatLon((47.197131179273129 + 47.197186248376966) / 2, (8.792974585667253 + 8.792809881269932) / 2), i2.getPos());
     172        assertEquals(new CachedLatLon(47.197319911792874, 8.792139580473304), i3.getPos());
     173        assertEquals(new CachedLatLon(47.197568312311816, 8.790292849679897), i4.getPos());
     174        assertEquals(new CachedLatLon(47.198845306804905, 8.783144918860685), i5.getPos()); // interpolated between tracks
     175        assertEquals(new CachedLatLon(47.19985828931693, 8.77969308585768), i6.getPos()); // different values than in tests #1 and #3!
     176
     177        assertEquals(Double.valueOf(447.894014085), i5.getElevation(), 0.000001);
     178        assertEquals(Double.valueOf(437.395070423), i6.getElevation(), 0.000001);
     179
     180        clearTmp(images);
     181
     182        // TEST #5: Force tagging (parameter forceTags=false, but configuration changed).
     183        // Results same as #4
     184
     185        s.putBoolean("geoimage.trk.tag", true);
     186        s.putBoolean("geoimage.trk.tag.time", false);
     187        s.putBoolean("geoimage.trk.int", true);
     188        s.putBoolean("geoimage.trk.int.time", false);
     189        s.putBoolean("geoimage.trk.int.dist", false);
     190        s.putBoolean("geoimage.seg.tag", false);
     191        s.putBoolean("geoimage.seg.int", false);
     192        s.putBoolean("geoimage.seg.tag.time", false);
     193        s.putBoolean("geoimage.seg.int", true);
     194        s.putBoolean("geoimage.seg.int.time", false);
     195        s.putBoolean("geoimage.seg.int.dist", false);
     196
     197        assertEquals(8, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     198        assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), ib.getPos());
     199        assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), i0.getPos());
     200        assertEquals(new CachedLatLon(47.196979885920882, 8.79541271366179), i1.getPos());
     201        assertEquals(new CachedLatLon((47.197131179273129 + 47.197186248376966) / 2, (8.792974585667253 + 8.792809881269932) / 2), i2.getPos());
     202        assertEquals(new CachedLatLon(47.197319911792874, 8.792139580473304), i3.getPos());
     203        assertEquals(new CachedLatLon(47.197568312311816, 8.790292849679897), i4.getPos());
     204        assertEquals(new CachedLatLon(47.198845306804905, 8.783144918860685), i5.getPos());
     205        assertEquals(new CachedLatLon(47.19985828931693, 8.77969308585768), i6.getPos());
     206
     207        assertEquals(Double.valueOf(447.894014085), i5.getElevation(), 0.000001);
     208        assertEquals(Double.valueOf(437.395070423), i6.getElevation(), 0.000001);
     209
     210        clearTmp(images);
     211
     212        // TEST #6: Disable tagging but allow interpolation when tracks are less than 500m apart. i0-i4 are tagged.
     213        // i5-i6 will not be tagged, because the tracks are 897m apart.
     214        // not checking all the coordinates again, did that 5 times already, just the number of matched images
     215
     216        s.putBoolean("geoimage.trk.tag", false);
     217        s.putBoolean("geoimage.trk.int", true);
     218        s.putBoolean("geoimage.trk.int.time", false);
     219        s.putBoolean("geoimage.trk.int.dist", true);
     220        s.putInt("geoimage.trk.int.dist.val", 500);
     221        s.putBoolean("geoimage.seg.tag", false);
     222        s.putBoolean("geoimage.seg.int", false);
     223
     224        assertEquals(4, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     225        clearTmp(images);
     226
     227        // TEST #7: Disable tagging but allow interpolation when tracks are less than 1000m apart. i0-i6 are tagged.
     228        // i5-i6 will be tagged, because the tracks are 897m apart.
     229
     230        s.putInt("geoimage.trk.int.dist.val", 1000);
     231
     232        assertEquals(6, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     233        clearTmp(images);
     234
     235        // TEST #8: Disable tagging but allow interpolation when tracks are less than 2 min apart. i0-i4 are tagged.
     236        // i5-i6 will not be tagged, because the tracks are 2.5min apart.
     237
     238        s.putBoolean("geoimage.trk.tag", false);
     239        s.putBoolean("geoimage.trk.int", true);
     240        s.putBoolean("geoimage.trk.int.time", true);
     241        s.putInt("geoimage.trk.int.time.val", 2);
     242        s.putBoolean("geoimage.trk.int.dist", false);
     243        s.putBoolean("geoimage.seg.tag", false);
     244        s.putBoolean("geoimage.seg.int", false);
     245
     246        assertEquals(4, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     247        clearTmp(images);
     248
     249        // TEST #9: Disable tagging but allow interpolation when tracks are less than 3 min apart. i0-i6 are tagged.
     250        // i5-i6 will be tagged, because the tracks are 2.5min apart.
     251
     252        s.putInt("geoimage.trk.int.time.val", 3);
     253
     254        assertEquals(6, GpxImageCorrelation.matchGpxTrack(images, gpx, 0, false));
     255
     256    }
     257
     258    private void clearTmp(List<ImageEntry> imgs) {
     259        for (ImageEntry i : imgs) {
     260            i.discardTmp();
     261            i.createTmp();
     262        }
     263    }
     264}
  • test/unit/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImagesTest.java

     
    22package org.openstreetmap.josm.gui.layer.geoimage;
    33
    44import static org.junit.Assert.assertEquals;
    5 import static org.junit.Assert.assertFalse;
    6 import static org.junit.Assert.assertTrue;
    75
    8 import java.util.Arrays;
    96import java.util.Collections;
    107
    118import org.junit.BeforeClass;
    129import org.junit.Rule;
    1310import org.junit.Test;
    14 import org.openstreetmap.josm.data.coor.CachedLatLon;
    1511import org.openstreetmap.josm.data.gpx.GpxData;
    1612import org.openstreetmap.josm.io.GpxReaderTest;
    1713import org.openstreetmap.josm.testutils.JOSMTestRules;
     
    4238    }
    4339
    4440    /**
    45      * Tests matching of images to a GPX track.
    46      * @throws Exception if the track cannot be parsed
    47      */
    48     @Test
    49     public void testMatchGpxTrack() throws Exception {
    50         final GpxData gpx = GpxReaderTest.parseGpxData("data_nodist/2094047.gpx");
    51         assertEquals(4, gpx.tracks.size());
    52         assertEquals(1, gpx.tracks.iterator().next().getSegments().size());
    53         assertEquals(185, gpx.tracks.iterator().next().getSegments().iterator().next().getWayPoints().size());
    54 
    55         final ImageEntry ib = new ImageEntry();
    56         ib.setExifTime(DateUtils.fromString("2016:01:03 11:54:58")); // 5 minutes before start of GPX
    57         ib.createTmp();
    58         final ImageEntry i0 = new ImageEntry();
    59         i0.setExifTime(DateUtils.fromString("2016:01:03 11:59:54")); // 4 sec before start of GPX
    60         i0.createTmp();
    61         final ImageEntry i1 = new ImageEntry();
    62         i1.setExifTime(DateUtils.fromString("2016:01:03 12:04:01"));
    63         i1.createTmp();
    64         final ImageEntry i2 = new ImageEntry();
    65         i2.setExifTime(DateUtils.fromString("2016:01:03 12:04:57"));
    66         i2.createTmp();
    67         final ImageEntry i3 = new ImageEntry();
    68         i3.setExifTime(DateUtils.fromString("2016:01:03 12:05:05"));
    69         i3.createTmp();
    70 
    71         assertEquals(4, CorrelateGpxWithImages.matchGpxTrack(Arrays.asList(ib, i0, i1, i2, i3), gpx, 0));
    72         assertEquals(new CachedLatLon(47.19286847859621, 8.79732714034617), i0.getPos()); // start of track
    73         assertEquals(new CachedLatLon(47.196979885920882, 8.79541271366179), i1.getPos()); // exact match
    74         assertEquals(new CachedLatLon(47.197319911792874, 8.792139580473304), i3.getPos()); // exact match
    75         assertEquals(new CachedLatLon((47.197131179273129 + 47.197186248376966) / 2, (8.792974585667253 + 8.792809881269932) / 2),
    76                 i2.getPos()); // interpolated
    77         assertFalse(ib.hasNewGpsData());
    78         assertTrue(i0.hasNewGpsData());
    79         assertTrue(i1.hasNewGpsData());
    80         assertTrue(i2.hasNewGpsData());
    81         assertTrue(i3.hasNewGpsData());
    82         // First waypoint has no speed in matchGpxTrack(). Speed is calculated
    83         // and not taken from GPX track.
    84         assertEquals(null, ib.getSpeed());
    85         assertEquals(null, i0.getSpeed());
    86         assertEquals(Double.valueOf(11.675317966018756), i1.getSpeed(), 0.000001);
    87         assertEquals(Double.valueOf(24.992418392716967), i2.getSpeed(), 0.000001);
    88         assertEquals(Double.valueOf(27.307968754679223), i3.getSpeed(), 0.000001);
    89         assertEquals(null, ib.getElevation());
    90         assertEquals(Double.valueOf(471.86), i0.getElevation(), 0.000001);
    91         assertEquals(Double.valueOf(489.29), i1.getElevation(), 0.000001);
    92         assertEquals(Double.valueOf((490.40 + 489.75) / 2), i2.getElevation(), 0.000001);
    93         assertEquals(Double.valueOf(486.368333333), i3.getElevation(), 0.000001);
    94         assertEquals(null, ib.getGpsTime());
    95         assertEquals(DateUtils.fromString("2016:01:03 11:59:54"), i0.getGpsTime()); // original time is kept
    96         assertEquals(DateUtils.fromString("2016:01:03 12:04:01"), i1.getGpsTime());
    97         assertEquals(DateUtils.fromString("2016:01:03 12:04:57"), i2.getGpsTime());
    98         assertEquals(DateUtils.fromString("2016:01:03 12:05:05"), i3.getGpsTime());
    99     }
    100 
    101     /**
    10241     * Tests automatic guessing of timezone/offset
    10342     * @throws Exception if an error occurs
    10443     */