Tuesday, 26 July 2016

TrafficControl: MapQuest/OSM needs API Key

For the last time, I've been working experimenting with maps using QML and MapQuest/Open Street Maps. The application logic is still in C++ but the map handling is in QML, where the map is rendered. Unfortunately, API keys are needed for applications using OSM  since July 11th this year.

The consequence of this is that the map tiles applications get from OSM contains no useful map information:
Before, the center of Malmö was shown


The issue is also affecting the default Qt examples, and there is a bug report addressing this issue: https://bugreports.qt.io/browse/QTBUG-5459. Currently, it isn't clear how to add that API key in Qt/QML programs. For the Qt version 5.6, API keys aren't supported, but hopefully the Qt developers may provide a patch for that.

I assume that OSM has introduced this API key requirement to reduce traffic to the servers and to have some control of which software packages that can access the servers. Providing servers and storage for maps are very resource demanding.

For my program, I can still investigate the implementation, where I'm trying to figure out how to add tracks to QML dynamically when the program reads the KML file. I am considering some C++ model that is interacting with a QML view.

Update:
The lesson of this is that software depending on external parties needs to be revised on a regular basis, since there will be changes to external interfaces.

Saturday, 9 July 2016

TrafficControl: Calculating Distances between Coordinates on the Surface of a Sphere

Distance calculations will be essential for the TrafficControl program. In a flat world, Pythagoras theorem would do just fine, but the calculations will be done on the surface of a sphere.

Starting from Paris, moving 2000 km north and after that 1000 km to the east, you will end up close to Rovaniemi, Finland. Moving 1000 km east from Paris and then 2000 km north, you will end up south of the national park of Sarek, 400 km off. This happens as the distance around the world along a certain latitude is smaller when moving away from the equator.

The Haversine formula takes all this into account. The implementation I use is:

def haversine(lon1, lat1, lon2, lat2):  #From rosettacode.org

  R = 6372.8 # Earth radius in kilometers
  dLat = radians(lat2 - lat1)
  dLon = radians(lon2 - lon1)
  lat1 = radians(lat1)
  lat2 = radians(lat2)

  a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
  c = 2*asin(sqrt(a))

  return R * c

Here, the distance between the coordinates (lon1, lat1) and (lon2, lat2) is R*c.

Keep in mind to check whether the coordinates are sent with longitude first and latitude last or the other way around. That will reduce the risk of tricky bugs.

Saturday, 14 May 2016

TrafficControl: Mapping Stations to Tracks from a KML File

The longlat coordinates for several existing and closed tracks and stations in Skåne, Sweden are stored in a KML file from Google Earth (blog post here). That file had some 420 tracks and stations.

The script scans the file for all stations and saves that information to a two-dimensional array that contains station name and coordinates.

After that, the script scans the file for all tracks and calculates the total distance of the tracks using the Haversine formula (Pythagoras' theorem won't do as the coordinate system is on the surface of a sphere). The name of the track, the length and the start and end coordinates are saved to a two-dimensional array. For each track, the station that is closest to the start and end points are found. If those candidates are closer than a predefined distance (in my case 100 meters), the track is connected to that station.

Finally, the script printed out the ADD STATION statements, ADD TRACK statements and CONNECT statements for the found connections.

The result file will look like:
ADD STATION Lund_C COORDINATES 55.70606862405453 13.18645933296118
ADD STATION Stångby COORDINATES 55.75072435969958 13.19996121860929
ADD TRACK dLun-StaN 5159 COORDINATES  55.70646523436889 13.18632710260987 55.71072132192893 13.18584908014066 55.71279148452389 13.18540683116051 55.71523576518295 13.18491978947624 55.71697139241737 13.18451423725925 55.71820550069631 13.18422078540084 55.71863549188491 13.18410509912514 55.72015263051769 13.18387805907402 55.72100614423973 13.18374645589791 55.72250595277901 13.18351438987617 55.72459782468813 13.18323899923316 55.72555794818392 13.18311356441235 55.72702138992866 13.18290315672957 55.72790621390291 13.18281900842842 55.72871601698184 13.18290611634804 55.72962139952958 13.18317702257096 55.7303726493431 13.18355658336061 55.73124798036218 13.18419008179007 55.73260471604188 13.18527763612758 55.73399029217104 13.18644576538502 55.7352346199416 13.18742225161641 55.73714017430663 13.18899079381876 55.73972705840463 13.19107073602017 55.74120631439643 13.19228528053877 55.74469495391181 13.19510449129269 55.75071735799666 13.19995102503562
ADD TRACK dLun-StaS 5159 COORDINATES 55.75071735799666 13.19995102503562 55.74469495391181 13.19510449129269 55.74120631439643 13.19228528053877 55.73972705840463 13.19107073602017 55.73714017430663 13.18899079381876 55.7352346199416 13.18742225161641 55.73399029217104 13.18644576538502 55.73260471604188 13.18527763612758 55.73124798036218 13.18419008179007 55.7303726493431 13.18355658336061 55.72962139952958 13.18317702257096 55.72871601698184 13.18290611634804 55.72790621390291 13.18281900842842 55.72702138992866 13.18290315672957 55.72555794818392 13.18311356441235 55.72459782468813 13.18323899923316 55.72250595277901 13.18351438987617 55.72100614423973 13.18374645589791 55.72015263051769 13.18387805907402 55.71863549188491 13.18410509912514 55.71820550069631 13.18422078540084 55.71697139241737 13.18451423725925 55.71523576518295 13.18491978947624 55.71279148452389 13.18540683116051 55.71072132192893 13.18584908014066 55.70646523436889 13.18632710260987 
CONNECT TRACK dLun-StaN FROM Lund_C TO Stångby DEFAULT
CONNECT TRACK dLun-StaN FROM Stångby TO Lund_C
CONNECT TRACK dLun-StaS FROM Stångby TO Lund_C DEFAULT
CONNECT TRACK dLun-StaS FROM Lund_C TO Stångby

The python scripts are available in the scripts section in my Gtihub repo:


Thursday, 29 October 2015

TrafficControl: How KML Files Represent Coordinates

In two blog posts: Continuing Blog and TrafficControl: Looking into Javascript, I discussed the KML file that contains the coordinates tracks and stations in Skåne.

That KML file is essentially a XML file and contains stations and tracks as placemarks:

The coordinates for Lund_C are highlighted.

The coordinates for Stångby are highlighted
The tracks are represented as an array of coordinates:

The coordinate for the track from Lund C to Stångby
The track is shown below.

The track dLunStaN leaves from Lund_C and arrices at Stangby.
I created a script that mapped the start and end of each track to the closest station. In this case, Lund C and Stånby were connected to LunStaN.

For this example, the script created three eight lines of code that will be used in TrafficControl:
ADD STATION Lund_C
ADD STATION Stångby
ADD TRACK dLun-StaN 5159
ADD TRACK dLun-StaS 5159
CONNECT TRACK dLun-StaN FROM Lund_C TO Stångby WITH PRIORITY
CONNECT TRACK dLun-StaN FROM Stångby TO Lund_C
CONNECT TRACK dLun-StaN FROM Stångby TO Lund_C
CONNECT TRACK dLun-StaS FROM Stångby TO Lund_C WITH PRIORITY

The "WITH PRIORITY" tag indicates that the track will have the prioritized direction from Lund_C to Stångby.

The naming convention of the tracks is for example: dCph-JHylWW
  • d indicates that the track is a double track (create a corresponding track in the eastbound direction). 
  • Cph indicates the first station is a station.
  • JHylW is the name of the end junction. J indicates junction and W indicates the location related to Hyllie.
  • W is the direction of the track.

I'll discuss the algorithm in detail in a future blog post.


Saturday, 19 September 2015

Genealogy: Anatomy of the ScanGed Python Script

The algorithm for scanning GED files is quite simple and it is based on recursion:

Start from a person in the family tree,
Collect the desired information about that person and print it to a a line.
Repeat for father, if found.
Repeat for mother, if found.

I've used dictionaries in Python, so that the script will know what line to look for a persons/familys section in the GED file. This will make the program much faster.

The source can be found on my public DropBox.


Monday, 31 August 2015

Genealogy: Creating Compact Ancestral Charts from Gedfiles

I've spent several hours doing some genealogical research for my ancestors. The most interesting finding so far is a remote relative (my mother's cousin's grand-grand-grand-grand-grandfather Caspar Mathisson), who was the pilot onboard the ship when the ship ran aground half a mile900 m from Göteborg in 1743 after a trip to China. https://en.wikipedia.org/wiki/G%C3%B6theborg_(ship)

Using Ancestry.com, and the Gramps software, I've found lots of persons back to the 17th century. 

However, I lacked one visualization tool for the shoe box situation: 
Often, one very proactive person does a lot of research. After a while, the results will end up in a shoe box on the attic for some decades. In the case of papers and photographies, it is easy to resume the research. In the case of data files, it will be much harder (just imagine how to retrieve data from a computer of the '80s). Therefore, the data must be in printed form, independent of computers or programs.

On the other hand, a family tree will be hard to read if  there are many persons in it. And printing a 100-person GEDCOM file will require 40 pages, and that is too much. 

I'll print the final results of the file now (for privacy reasons, this example starts with my grand-grandfather) and I'll describe the function and anatomy of the program later:

Monday, 15 June 2015

South Africa: My First (and Only) Bungy Jump

After being harassed baboons but before being hunted by elephants, I did my first bungy jump from the Bloukrants Bridge on the Garden Route in South Africa.


With a height of 216 meters, it is one of the highest jumps in the world - and an excellent excuse not to do more jumps. "Naah, I will only be dissapointed jumping 192 meters".





The jump took approximately five seconds, but felt more like twenty. Falling through the air was definitely worth it!