G-Punch Orienteering


GP Loader


User Guide

Updated 2021-09-26
www.LandNavApp.com
 
Refresh this page for the latest updates
SE FI NO FR IT JA DK
DE NL ES HU HR SI CZ
RU CN TW PL SG PT GR
TH BR ID IL MS SK KO

Table of Contents

 

G-Punch Orienteering

Version 2.0.4 (2021-09-25)

Overview

This app allows you to run GPS-based Orienteering or Land Navigation courses!

It's meant to be used with a physical map and compass out in nature. Course data can be manually entered into the app via the settings, or if you have a newer model Garmin watch, downloaded from a web location using the free companion app GP Loader.

The app presents the user with MGRS coordinates, latitude & longitude, or Orienteering clues, depending on settings. The user has to navigate to the control checkpoints to complete the activity and win. (From this point forward in these instructions, virtual control checkpoints in the woods will be referred to as controls.)

When the user navigates to within a certain proximity of a control (15-40 m), the watch will beep/vibrate and show an arrow pointing towards that control. The user must move closer (5-9 m) to the control in order to identify it, punch it, and begin the next leg. Depending upon the course, the user is alerted if they arrive at an incorrect point. After completing the activity, results are shown on the app and uploaded to Garmin Connect.

G-Punch supports classic (ordered), score-o (random order) as well as hybrid course formats like control boxes and butterfly loops. It also supports control score values, time limit, and penalties for finishing over the time limit. You can now change Precision level in the settings, and switch between Lap Pace & Heart Rate, and between Time of Day & Countdown Timer during navigation.

GPS-based Orienteering may be less precise than regular Orienteering, but we hope this app will inspire more people to experience Orienteering, improve map and compass skills, or just get outside and have some fun!

1.1 Step-By-Step Walkthrough

LOADING COURSE DATA image

When you first run the app, it will begin loading a course from the settings.

PRESS START image

The checkmarks indicate the course is loaded and GPS signal is good.

Press START\STOP to proceed.

LAP TO START image

Course details are shown in green. Press LAP (or BACK on some watches) to continue, or START/STOP to return to the previous screen.

Once you continue to the next screen, the watch will enter Navigation Mode, and will remain in that mode until you complete the course.

While in Navigation Mode, the BACK button will not exit the activity. To exit press MENU. On some watches with no MENU button (i.e., 735xt) you must press and hold the UP button.

GRAY ARROW TO START image

When you first enter Navigation Mode, you will see an arrow and a small control. The arrow will point you towards the first control (in this case "START"), no matter how far away it is.

After punching the first control, the arrow and small control will only reappear once you get close to a control. It may help to think of the arrow and small control as an indicator that you can see a control from your current location, but that you need to get closer to identify which control it is.

When you get close enough to see the arrow and small control, the watch will also repetitively beep and/or vibrate (depending upon the capabilities of the watch). Press LAP to silence the alert.

ARRIVED AT START image

When you arrive at the control, it will show a large control and the name of the control. If the control is the correct one, it will show an empty square beneath the name.

Press LAP to punch it and record your arrival.

PUNCHED START image

After punching the control, a check will appear in the box on the icon, and the clue and lower half will automatically update to the next control "31".

ORDERED CONTROL image       RANDOM CONTROL image  

If no controls are nearby, Lap Pace or Heart Rate is shown in the upper area. Press START/STOP to switch between the two.

At the bottom of the display is the Time of Day or Countdown Timer. Press START/STOP to switch between the two.

Press UP and DOWN to scroll through other controls, if the course allows it. Compare the icons at the bottom left of both screens.

ORDERED CONTROL cutout

Ordered (Classic) Controls must be navigated to in order. You cannot scroll to the next control until you punch the current control.

RANDOM CONTROL cutout

Random-Order (Score-O) Controls can be navigated to in any order. You can scroll to the next control before punching the current control.

RED ARROW TO 31 image

Again we see the arrow and a small control flag, indicating we are nearby a control.

When moving at speed, the arrow is red, indicating the direction is based on your movement.

When you move slowly, the arrow will be gray, indicating the internal compass is being used.

ARRIVED AT 31 image

Upon arriving at the correct control, it will show an empty box beneath the name.

Press LAP to punch the control.

PUNCHED 31 image

After punching "31", the clue box and lower half will update to show the next control "32".

If the next controls are Random-Order (Score-O), you can press UP and DOWN to scroll through them.

ARRIVED AT FINISH image

If you arrive at the wrong control (in this case "FINISH"), it will show an "X" on the icon, instead of an empty box.

Press LAP to punch the "FINISH" control and end the course early.

RESULTS MP image

After punching the last control, the watch exits Navigation Mode. The top two lines in white are your results. The course details are shown again in green. For more details on your run open Garmin Connect.

GARMIN CONNECT 1 image

On Garmin Connect Mobile, select the second tab and scroll down to the bottom to see the overall results.

GARMIN CONNECT 2 image

Select the third tab (laps) then rotate your device if needed, scroll to the far right to see the split times and other details.

If the course does not include Orienteering Clues, the user can select MGRS, Latitude & Longitude or No Clues. Below is what the display looks like for MGRS.

MGRS NAVIGATION imageMGRS RED ARROW imageMGRS ARRIVING TO 31 imageMGRS PUNCHED 31 imageMGRS ARRIVED TO FINISH image

1.2 Settings

The following options can be set in the app Settings. Settings must be changed before running the program.

Point Data is where all the controls are located.

Course Data contains only the controls you want to include in your course, in the order you specify.

Random Order is a yes/no toggle that sets the default for the controls in the course, either yes for score-o (random order) courses or no for classic (ordered) courses.

Time gives you a countdown alarm to complete the course. The app sounds an alarm if you run out of time.

Score sets the default Point Score for the controls. It also sets the score value you are penalized for every minute you finish after the time has run out.

Display lets the user pick which control clues are displayed during an activity. The options are None, Orienteering Clues if the course has them, Latitude and Longitude, or Military Grid Reference System MGRS. If you select Orienteering Clues but the course does not have any, the app will display 'None' instead.

Precision sets the distance range at which you can discover controls. This setting also affects how close you must get in order to punch controls.

Magnetic Declination enables magnetic declination adjustment for azimuths. This is for when your map is not declinated to magnetic north but grid north, or when close enough to controls to see distance and direction.

1.2.1 Point Data

The Point data is where all the GPS controls are located. It should contain the name, latitude and longitude for every virtual control in the event, including any extra dummy controls not included in your specific course.

For each control the data must appear in this order: (1) name, (2) latitude, (3) longitude. But the overall controls can be in any order. Entries must be separated by a comma (,) and terminated with a semicolon (;). For best results minimize extra whitespace. Name values must be 6 characters or less. The app has been tested to work with over 65 controls.

Point Data Format:
NAME_1,LATITUDE_1,LONGITUDE_1; NAME_3,LATITUDE_3,LONGITUDE_3; NAME_2,LATITUDE_2,LONGITUDE_2;

Decimal latitude/longitude format is the only accepted format. Negative values should be used for longitudes in the western hemisphere and latitudes in the southern hemisphere.

The Start and Finish controls can be in the exact same location if they are two separate controls, or they can be the same control. However, no other controls can be close to the Finish or an error will occur. To ensure the app works as it was intended, every control (including extra dummy controls) should be no less than 50 meters apart from other controls.

Point Data Example:
31,38.990121,-76.897368; 32,38.988225,-76.897995; 33,38.988005,-76.893808; 34,38.990232,-76.892706; 35,38.992676,-76.894360; 36,38.993103,-76.892885; 37,38.993519,-76.891097; 38,38.986696,-76.894299; 39,38.984962,-76.897303; FINISH,38.993841,-76.894417; START,38.993841,-76.894417;

1.2.2 Course Data

The Course data contains only the controls you want to include into your course, in the order you specify. It contains the names of controls that appear in your course, in the same order you want them to appear in your course. Each control name must be followed by a semicolon (;).

Course Data Format:
NAME_1;NAME_2;NAME_3;

Any controls listed in the Course data must also be listed in the Point data. However, controls in the Point data do not have to be included in the Course data. The first and last entries are important, because they are interpreted as the Start and Finish controls respectively. In these examples we will always label them "START" and "FINISH", for simplicity.

Course Data Example:
START;31;32;33;34;FINISH;

The following example shows how you would implement a butterfly loop in the Course data, at control 32. The user must visit control 32 twice during the course.

Course Data Example:
START;31;32;33;34;35;32;36;FINISH;

The Course data can include additional parameters, as described in the Random Order and Score sections below.

1.2.3 Random Order

Random Order sets the default behavior for controls. Each control is either ordered/classic or random-order/score, with the exception of the first/Start and last/Finish controls which are always ordered/classic.

If Random Order is disabled, your overall course will default to an ordered "classic" course, where the controls must be visited in order from start to finish. If Random Order is enabled, your overall course will default to a random-order "score-o" course, where the controls can be visited in any order.

To set individual controls differently from the default, you must add parameters to the Course data. The format is comma (,) followed by an "O" or an "R" to indicate ordered or random-order. The letter can be uppercase or lowercase.

In the below formatting example, NAME_1 and NAME_5 will remain ordered, because they are the first and last controls. NAME_3 control is set to whatever the default is. The NAME_2 control is set to ordered, and the NAME_4 control is set to random-order.

Course Data Format Example:
NAME_1;NAME_2,O;NAME_3;NAME_4,R;NAME_5;

Let's say you wanted to design a hybrid course, with a few ordered controls, and several random-order controls. You would enable Random Order in the settings, then add some additional ordered controls to the Course Data. In the below example, the user punches Start then must punch control 31. Then they can go to any control from 32 to 36 in any order, or go straight to 37. The user must punch 37 before punching the Finish.

Course Data Example:
START;31,o;32;33;34;35;36;37,o;FINISH;

Let's say you wanted to design a course with two control "boxes". The user can visit the controls inside each box, in any order, however they must visit the intermediate ordered controls between each box, and they must visit each overall box, in order. The following two examples demonstrate different ways of doing this. Both examples will result in the exact same course for the user:

In the first example, Random Order is disabled, making it an ordered "classic" course by default. Additional parameters here define individual controls as random-order. Controls 31, 35 and 39 remain ordered and must be visited in order.

Course Data Example, Variant 1:
START;31;32,r;33,r;34,r;35;36,r;37,r;38,r;39;FINISH;

In the next example, Random Order is enabled, making it a random-ordered "score-o" course by default. The additional parameters here mark controls as ordered. Controls 32-34 and 36-38 remain random-order and can be visited in any order.

Course Data Example, Variant 2:
START;31,o;32;33;34;35,o;36;37;38;39,o;FINISH;

If the user skips an ordered/classic control the results will indicate "Missed Point", but not if they skip a random-order/score-o control. Random order points are treated as optional controls, so if the user does not visit every Random order point in the course, the results will NOT indicate "Missed Point". An examination of the results (in the Garmin Connect Lap review) will indicate which controls in particular, and how many controls in total, were visited.

1.2.4 Time

Time gives you a countdown timer to complete the course. When you run out of time, the app sounds an alarm.

If your course includes score point values for controls and you run out of time, you will be penalized the default Score value for each additional minute it takes you to complete the course.

There is no way to disable the countdown timer. However if you do not want to be penalized for exceeding the time limit, simply change Score to 0, and it will not penalize you for finishing the course late. Alternatively, you can set Time to a very high value such as 180 minutes, equivalent to 3 hours, or 360 minutes, equivalent to 6 hours.

1.2.5 Score

Score sets the default score point value for controls. To set individual control scores differently from the default, you must add parameters to the Course data. The format to add a parameter is comma (,) followed by a numeric value to indicate the point value for that control. Score values will always be 0 for the first (Start) and last (Finish) controls.

Score also sets the point penalty for each minute you finish late, sometimes used in random-order "score-o" courses. If your course has no score point values, set this to 0. You will not receive any score penalty for finishing late.

In the below formatting example, NAME_1 and NAME_5 will remain 0 points, because they are the first and last controls. NAME_3 control will be worth whatever the default point value is. The NAME_2 control is 30 points, and the NAME_4 control is 40 points.

Course Data Format Example:
NAME_1;NAME_2,30;NAME_3;NAME_4,40;NAME_5;

Let's say you wanted to design a Random-order (score-o) course, where the controls have different point values. You would set the Random Order to enabled, then add additional parameters with the score values after each control in the Course data. In this example, controls 31 thru 33 are worth 30 points, controls 34 through 36 are worth 40 points.

Course Data Example:
START;31,30;32,30;33,30;34,40;35,40;36,40;FINISH;

You can also combine score and random-order parameters in the Course data. Just include another comma (,) and the second parameter. The parameters can be in any order, as seen in the following two examples. Both examples variations create the exact same course for the user.

In this first example, Random Order is enabled and Score is 100. Controls 32, 33, 34 are default random-order controls each worth the default amount, 100 points. Controls 31, 35 are ordered controls worth 0 points.

Course Data Example, Variant 1:
START;31,o,0;32;33;34;35,0,o;FINISH;

In this second example, Random Order is disabled and Score is 0. Controls 31, 35 are default ordered controls each worth the default amount, 0 points. Controls 32, 33, 34 are random-order controls each worth 100 points.

Course Data Example, Variant 2:
START;31;32,r,100;33,100,r;34,100,r;35;FINISH;

Any score values in the Course data will make the app calculate total score, even if the default Score is set to 0.

If you wanted to include score points in your course, but didn't want to implement a time limit and score penalty system for finishing late, set the Time to a very high value such as 180 minutes, equivalent to 3 hours, or 360 minutes, equivalent to 6 hours.

1.2.6 Display

Display lets the user pick how to display the control clues during the activity. The options available are:

If the user selects orienteering clues, but there are no orienteering clues in the Point data, then the display will switch to None, and no clues will be shown.

1.2.7 Precision

Precision sets the distance range users can "discover" controls. The actual distance is a random value between the low and high value of the range. This setting also affects how close you have to get to identify and punch controls.

Precision Level Distance Range to
Discover Controls
Distance Range to
Identify & Punch Controls
Low 25-40 meters 9 meters
Normal 15-40 meters 7 meters
High 15-30 meters 5 meters

Due to present-day GPS accuracy limitations, Normal or even Low setting is recommended for use in places where GPS accuracy is less effective, for instance in areas of dense forest or in terrain with a great deal of topographic variation, especially if the course is based on a non-virtual/real orienteering course with controls assigned to smaller objects. This is because orienteers moving towards actual controls may be surprised to learn the GPS is slightly off. Orienteers will arrive at what they believe to be the control location (especially if a physical control is also located there). When the GPS says they have to move further away to "approach" the virtual point – or worse, that they aren't even nearby a control – it can be frustrating.

Orienteers who are determined to improve at navigation are encouraged to keep the Normal setting, or terrain permitting, set it to High. Once running, the settings cannot be changed, so adjust the settings before you begin.

Smarter navigation remains the most effective method to finding controls. Once you discover a control, move to wherever the GPS indicates the control is, which in the case of non-virtual/real orienteering courses, is not always in the same location the clue description describes.

1.2.8 Magnetic Declination

Most orienteering maps account for magnetic declination, but some do not. Also, if you travel long distances to attend orienteering events, it is important to adjust for changes in magnetic declination.

The Magnetic Declination setting is for when your map is not declinated to magnetic but grid north, and you are using a compass that does not have an adjustment for magnetic declination. This setting affects the numerical azimuth shown when the user gets close to a control, or whenever the app shows distance and direction as a clue. The setting does not affect which direction the gray or red arrows point.

1.3 Orienteering Clues

This app supports orienteering clues or symbols for most newer Garmin watches (for a list of compatible watches scroll to the end of the document). To enable orienteering clues in the app, the course designer or you must manually enter the clues in advance.

ARRIVED AT 31 image

Orienteering clues are included after the longitude in the Point data section.

Point Data Format:
NAME_1,LATITUDE_1,LONGITUDE_1,CLUES_1; NAME_3,LATITUDE_3,LONGITUDE_3,CLUES_3; NAME_2,LATITUDE_2,LONGITUDE_2,CLUES_2;

Because of watch screen size, only five clues are allowed per control. A space designates a blank space in the clue. If you do not include spaces, all clues will appear left-justified during the activity. The following example shows some sample orienteering clues, visible as clues with the proper font installed to the computer.

Point Data Example:
31,39.163775,-76.720700,¬àáą ; 32,39.164208,-76.721928, àĆ ; 33,39.164470,-76.723166, à ĕ; 34,39.162430,-76.718717,¨ ê Ċ; FINISH,39.163435,-76.721300, ºóœċ; START,39.163435,-76.721300, ºóœċ;

As shown below, the orienteering clues appear as extended Unicode characters if you do not switch to W font. For those who cannot install the W font, this is unavoidable.

Point Data Example:
31,39.163775,-76.720700,¬àáą ; 32,39.164208,-76.721928, àĆ ; 33,39.164470,-76.723166, à ĕ; 34,39.162430,-76.718717,¨ ê Ċ; FINISH,39.163435,-76.721300, ºóœċ; START,39.163435,-76.721300, ºóœċ;

When designing a course, to be able to read the symbols correctly, download, install and change the text to the W font, located at fontSample.zip. The font includes all of the below orienteering clues. If you cannot install the font, then simply copy and paste orienteering clues from the below chart.

W Font Orienteering Symbols:
¢£¤¥ ¦§¨©ª«¬­®¯° ±²³´µ¶·¸¹º»¼½¾¿À ÁÂÃÄÅÆÇÈÉÊ ËÌÍÎÏÐÑÒÓÔÕ Ö×ØÙÚÛÜÝÞß àáâãäåæçèéêëìíîïðñòóôõö÷ø ùúûüýþÿĀāĂă ĄąĆ ćĈĉĊċČčĎ ďĐđĒēĔĕĖ ėĘęĚěĜĝĞ ğĠġĢģĤĥĦ ħĨĩĪīĬĭĮ įİıIJijĴĵĶ ķĸĹĺĻļĽľĿ ŀŁłŃńŅņŇ ňʼnŊŋŌ ōŎŏ ŐőŒœŔŕŖŗŘřŚś ŜŝŞşŠšŢţŤťŦŧŨũŪ ūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ

Note: If the above three blocks contain a bunch of random letters instead of Orienteering Symbols, it means for some reason you are unable to view the symbols on this webpage. If you are viewing a translation of this webpage, see if the original (English) version shows the proper symbols. If that does not work, download the W font, located at fontSample.zip and try to open the sample file in another viewer.















 

GP Loader

Version 1.0.6 (2021-08-29)

Overview

The GP Loader app loads courses from the internet into the G-Punch Orienteering app.

Rather than having to manually enter data into the G-Punch app settings whenever you want to run a course, now you can quickly load preexisting data from a web server. Write your own courses in JSON, or convert to JSON format from formats like International Orienteering Federation IOF version 3.0 XML, Condes XML, Purple Pen XML, even Google KML. The only requirements are the file be in JSON format, and that the server support HTTPS security.

GP Loader can only load files from a web server. It cannot load files directly from your computer or mobile device.

There is no password protection for course files. Once users are given the URL they will have access to the course data.

2.1 Step-By-Step Walkthrough

  1. Download the latest versions of GP Loader and G-Punch Orienteering apps

  2. Create a log file for GP Loader and G-Punch Orienteering apps

  3. Download all sample files

  4. Create a JSON course file, or convert an existing KML/XML course file into JSON format, making edits as necessary

  5. Upload the JSON file to a HTTPS-compliant web server

  6. Enter the URL for your JSON file into the app Settings for GP Loader

  7. Run the GP Loader app, press MENU (or hold the UP button) and select Load course

  8. The app will prompt you to select a Course

  9. When asked if you want to launch the G-Punch Orienteering app, confirm

  10. Once G-Punch Orienteering app loads the course, you will be able to run it

2.2 Creating a Log File

Creating a GP Loader log file allows you to receive additional feedback when a course contains errors. Additionally, if you create a log file for the G-Punch Orienteering app, it will save a copy of the last course loaded. This is useful because GP Loader overwrites the previous Point and Course data each time it loads the G-Punch Orienteering app.

To create a log file, plug your Garmin device into a computer to access the files via USB. Go to the D:\GARMIN\APPS\ subdirectory. You need to figure out which PRG file corresponds to the GP Loader app (the files are named randomly). Once you determine the filename, go to the D:\GARMIN\APPS\LOGS\ subdirectory and create a blank text file using the same name, but with ".LOG" as the file type. For example, if your GP Loader app is named ABC12345.PRG, create a blank text file in the D:\GARMIN\APPS\LOGS\ subdirectory and rename it ABC12345.LOG. If you don't know which app corresponds to the GP Loader app, just create a log file for every app.

Complete the same steps to create a log file for the G-Punch Orienteering app.

Whenever you uninstall and reinstall these apps, you will also have to rename the log file(s) so they correspond to the filename of the watch app(s).

Running the apps will populate the log files. To view the log files, plug your device to into your computer via USB connection and edit the files using Notepad. The log files themselves do not require deletion, because they overwrite themselves after several usages. Going in and editing or clearing the contents of the log file is allowed.

2.3 Converting to JSON

Course files from Condes and PurplePen can be saved to IOF Version 3.0 XML file format. Google KML files are in another XML format. To convert XML files into JSON format, search the web for "convert XML to JSON". Use the web to convert the file, and save the output to a JSON file, (select 'no' if it asks to add prefixes in front of attributes during conversion).

Some converted files may require additional edits. For example, when converting KML files for MapRun Scatter or Score courses, you may need to manually add "Random", "Score" or other fields into the JSON file. KML files loaded from OpenOrienteeringMap should work as-is, but changes can of course be made. See KML samples below.

When converting from IOF file format, the geocoordinates in the XML file must be in Latitude-Longitude format. Sometimes in older versions of IOF course files, these coordinates were not Latitude-Longitude but another format. For example, "38.990232, -76.892706" is correct, but "4317396, 336078" with no decimal point, will not work. To convert these geocoordinates to latitude-longitude requires additional research. You may be able to use the G-Punch Data Generator to convert data from EPSG-coded IOF-XML file, thanks to Andreas T.

You can also remove several unused fields from IOF formatted files to save memory, see details in IOF section below.

Orienteering Clues are not natively included in IOF or KML files. To add Orienteering Clues to your file so the watch will show them in your event, you will need to manually enter them into the JSON file. Refer to the Orienteering Clues section above for more information.

After making edits to your JSON file, upload the contents to JSONLint.com to check it for JSON syntax errors.

Finally, save the JSON file to a HTTPS web location where others can access it. Enter the URL for the file into the Settings. When you run the app it should load the course file or produce an error message indicating what's wrong.

If you need assistance, click "Contact Developer" on the Garmin App store page, explain the problem and include your email address so the developers can send you a reply.

Download all example files at samples.zip.

2.4 JSON Syntax Basics

GP Loader reads JSON files, which are essentially a regular-text formatted collection of name/value pairs. In these instructions, we use green font to identify the 'name' or 'keyword' portion of name/value pairs. When you run GP Loader, it will interpret these keywords in particular ways. Hence, keywords must be spelled correctly. The spelling and capitalization of keywords must also be consistent across the file.

JSON Name/Value Pair Example:
"Id": "Test"

JSON files are further organized through curly braces { } and square brackets [ ]. Each of these structures contain one or more name/value pairs.

Entries surrounded by { braces } are called a dictionary. In the below example, the "Position" keyword is paired with a dictionary containing two name/value pairs.

"Position": { "lon": "-76.894417", "lat": "38.993841" }

Dictionaries are unordered, meaning the name/value pairs inside a dictionary can appear in any order.

Entries surrounded by [ brackets ] are called an array. Arrays are ordered, meaning the order of elements in an array is important. Below, the "CourseControl" keyword is paired with an array containing three dictionaries.

"CourseControl": [  { "C": "1" }, { "C": "2" }, { "C": "3" }  ]

Although in this example, these three dictionaries only contain a single name/value pair, arrays often hold dictionaries containing multiple name/value pairs.

A comma ( , ) follows every name/value pair, except the last entry in each level.

"Position": { "lon": "-76.894417", "lat": "38.993841" }, "Id": "Test"

Finally, The entire file must be enclosed in curly brackets. So essentially each JSON file contains one big dictionary.

{
	"Position": { "lon": "-76.894417", "lat": "38.993841" }, "Id": "Test",
	"CourseControl": [  { "C": "1" }, { "C": "2" }, { "C": "3" }  ]
}

The above text is not a valid course file, but it is in valid JSON format. To confirm it is formatted correctly, upload the above lines (including brackets) to JSONLint.com and click 'validate'.

so we can use it to demonstrate a format diagram. The below diagram portrays the structure of the above JSON text.

Example Format


  • Id
  • Position
    • lon/lng
    • lat

  • CourseControl […]
    • C
    • *Score

In the diagram, keywords on the far left are considered "base-level" keywords because they are not located inside other structures.

Indented keywords are located inside other dictionaries or arrays. The "lat" and "lon" entries are located inside the "Position" dictionary. The "C" entry is located in a dictionary, in the "CourseControl" array.

The […] indicates the "CourseControl" keyword contains an (ordered) array holding one or more dictionaries.

An asterisk (*) indicates the entry is optional, a dash (/) indicates other keywords are interchangeable. In all cases, use the prescribed capitalization, or if in doubt Capitalize the first letter of each word, for instance "CourseControl".

2.4.1 Menu Files

Menu files allow you to select amongst a set of files easier. You can select course files, or other menu files.

      Menu Format      


  • *Title
  • Menu
    • Name
    • Url

Menu files must have a "Menu" [ array ] at the base level. Inside the Menu array are one or more dictionaries. Each of the dictionaries must contain "Name" and "Url" fields. Here Url is spelled Url, but URL or url will also work.

When you first run GP Loader, it will begin to load whichever URL is in the app settings. The following URL is what comes pre-loaded when you first install the app.

MENU File: https://www.landnavapp.com/samples/Menu-1.json
{ "Title":"Basic Courses", "Menu": [ { "Name":"Clas SIMPLE", "Url":"https://www.landnavapp.com/samples/1-SIMPLE.json" }, { "Name":"Clas SIMPLE Clue", "Url":"https://www.landnavapp.com/samples/1-SIMPLE-Clue.json" }, { "Name":"Clas SHORT", "Url":"https://www.landnavapp.com/samples/1-SHORT.json" }, { "Name":"Clas SHORT Clue", "Url":"https://www.landnavapp.com/samples/1-SHORT-Clue.json" }, { "Name":"Clas KML Clue", "Url":"https://www.landnavapp.com/samples/1-KML-Clue.json" }, { "Name":"Clas KML OOM", "Url":"https://www.landnavapp.com/samples/1-KML-OOM.json" }, { "Name":"Clas IOf", "Url":"https://www.landnavapp.com/samples/1-IOF.json" }, { "Name":"Clas IOF Crop", "Url":"https://www.landnavapp.com/samples/1-IOF-Crop.json" }, { "Name":"Clas IOF Abr", "Url":"https://www.landnavapp.com/samples/1-IOF-Clue-Abr.json" }, { "Name":"Clas SHORT Abr", "Url":"https://www.landnavapp.com/samples/1-SHORT-Clue-Abr.json" }, { "Name":"Clas SHORT Error", "Url":"https://www.landnavapp.com/samples/1-SHORT-Clue-Error.json" }, { "Name":"Scor SIMPLE Clue", "Url":"https://www.landnavapp.com/samples/2-Simple-Clue.json" }, { "Name":"Scor KML Clue", "Url":"https://www.landnavapp.com/samples/2-KML-Clue.json" }, { "Name":"Scor SHORT Clue", "Url":"https://www.landnavapp.com/samples/2-SHORT-Clue.json" }, { "Name":"Scor IOF Clue", "Url":"https://www.landnavapp.com/samples/2-IOF-Clue.json" }, { "Name":"More Courses", "Url":"https://www.landnavapp.com/samples/Menu-2.json" } ] }

The app first checks the base-level contents of the file for a "Menu" [array]. If it finds one, it knows the file is a Menu file, and not a traditional course file.

It looks inside the "Menu" array for dictionary fields containing "Name" and "Url" fields, and if it can't find them it shows an error. Menus are limited to 16 entries max, but you can use menu files to load other menus files. In the above example, if the user selects the last "More Courses" menu option, it will load this "Menu_2.json" file:

MENU File: https://www.landnavapp.com/samples/Menu-2.json

{ "Title":"More Courses", "Menu": [ { "Name":"Hybr SIMPLE", "Url":"https://www.landnavapp.com/samples/3-SIMPLE.json" }, { "Name":"Hybr SHORT Clue", "Url":"https://www.landnavapp.com/samples/3-SHORT-Clue.json" }, { "Name":"Clas IOF Extra", "Url":"https://www.landnavapp.com/samples/1-IOF-Clue-Extra.json" }, { "Name":"Clas SHORT Extra", "Url":"https://www.landnavapp.com/samples/1-SHORT-Clue-Extra.json" }, { "Name":"Clas IOF LonLat", "Url":"https://www.landnavapp.com/samples/1-IOF-Clue-LonLat.json" }, { "Name":"Clas SHORT LonLat", "Url":"https://www.landnavapp.com/samples/1-SHORT-Clue-LonLat.json" }, { "Name":"Mult IOF", "Url":"https://www.landnavapp.com/samples/4-IOF-Clue.json" }, { "Name":"Mult SHORT", "Url":"https://www.landnavapp.com/samples/4-SHORT-Clue.json" }, { "Name":"Basic Courses", "Url":"https://www.landnavapp.com/samples/Menu-1.json" } ] }

Once you make a selection, the app loads the JSON file at the associated web address, either a course or another menu.

SIMPLE and KML files can only contain one course per file. If you have several unrelated course files, it is recommended to use a menu file, so the user can pick from various courses.

For events with multiple courses that share common controls, a menu is not needed if you use SHORT or IOF format course files. SHORT and IOF format files can contain multiple courses per file, and will also automatically present the user with a choice between those options. For multiple-course file examples, see the #4 examples below in Section 2.5.6.

2.5 Course File Formats

GP Loader can interpret from four JSON file strutures, SIMPLE, SHORT, KML and IOF. Their structures are presented here.

SIMPLE













  • name/Name
  • *Random/R
  • *Time/T
  • *Score/S
  • *Precision/P

  • CourseControl/Legs […]
    • Name/name/Control/C
    • *Random/R
    • *Score/S
    • *Clue/A
    • Location/L


  • *LonLat

SHORT





  • Control […]
    • Id/C
    • *Clue/A
    • Location/L



  • Course {…} or […]
    • name/Name
    • *Random/R
    • *Time/T
    • *Score/S
    • *Precision/P

    • CourseControl/Legs […]
      • Control/C
      • *Random/R
      • *Score/S




  • *LonLat

KML


  • *kml
    • Folder/Document






      • *Style

      • Folder
        • name/Name
        • *Random/R
        • *Time/T
        • *Score/S
        • *Precision/P

        • Placemark/Legs […]
          • Name/name/Control/C
          • *Random/R
          • *Score/S
          • *Clue/A
          • Point
            • Coordinates

    • *LonLat

IOF


  • iofVersion
  • RaceCourseData

    • Control […]
      • Id/C
      • *Clue/A
      • Position/L
        • lat/Lat/LAT
        • lng/Lng/LNG/lon/Lon/LON

    • Course {…} or […]
      • name/Name
      • *RandomOrder/R
      • *Time/T
      • *Score/S
      • *Precision/P

      • CourseControl/Legs […]
        • Control/C
        • *randomOrder/R
        • *Score/S




  • *LonLat

The various formats share several common keywords. Some of the keywords in the above diagrams have been aligned horizontally to make comparing and contrasting easier. To better understand the underlying structure of these files, it may help to think of them in terms of the corresponding G-Punch Orienteering app settings.

In SHORT and IOF formats, the Point data (control labels, coordinates and O-clues) are located in the "Control" dictionary, and the Course data is located in the "Course" and "CourseControl" entries. The Point and Course data is separated, which allows multiple courses to share common controls within a single file.

In contrast, for SIMPLE and KML formats, the Point data and Course data is combined into the "CourseControl" or "Placemark" field. Because of this, only one course is allowed per file in the case of SIMPLE and KML formats.

Course files can seem complex, but don't let them intimidate you. Just pay attention to the JSON syntax. If you are writing your own course, use SIMPLE or SHORT format. If you are converting from KML or IOF, focus on the KML and IOF file formats. You can always manually convert an IOF or KML file into SHORT or SIMPLE format. They're just text files with a "JSON" file extension, and not very difficult to edit.

You can use the keyword "Legs" instead of "CourseControl" or "Placemark" field, no matter which file format you use.

Note the SIMPLE course is the only one with a base-level "name" keyword. This is, in fact, how the app determines if a file is in SIMPLE format. If your course is not in SIMPLE format, make sure there is no base level "name" field in it.

If your KML or other format data contains coordinates in "Longitude,Latitude" format instead of "Latitude,Longitude" order, include "LonLat":"true" at the base-level. It will make GP Loader interpret all coordinates Longitude then Latitude in order.

Setting the precision level for a course is optional, and only recommended for competitions. In all other scenarios, it is recommended to let the user pick their own precision level, by leaving the precision level out of the course data. To include precision level for a course you must use one of three numbers, -1 for high precision, 0 for normal precision, or 1 for low precision. For example "Precision":"1" would set the precision level for the course to low.

In the next sections we will cover four different examples of Orienteering courses/events. Each type of course/event is associated with a number. For example, all the #1 sample files are Classic courses, and so on. Yes, there are multiple file formats to represent the same courses. In fact, every one of the #1 course files below is for the same course. Multiple formats are presented to show that there are multiple ways to save the data, and to show the GP Loader can load a variety of files.

2.5.1 Classic Course (All #1 Examples)

#1 Course 'Classic'

If the file does not contain a Menu, the app will begin interpreting the file as a course.

SIMPLE Format

If the course has a base-level "Name" field, the app will assume the file is in SIMPLE format.

#1 (Classic Course) SIMPLE format: https://www.landnavapp.com/samples/1-Simple.json
{ "Name": "Classic SIMPLE", "CourseControl": [ { "Name": "START", "Location": "38.993841,-76.894417" }, { "Name": "36", "Location": "38.993103,-76.892885" }, { "Name": "33", "Location": "38.988005,-76.893808" }, { "Name": "32", "Location": "38.988225,-76.897995" }, { "Name": "34", "Location": "38.990232,-76.892706" }, { "Name": "31", "Location": "38.990121,-76.897368" }, { "Name": "35", "Location": "38.992676,-76.894360" }, { "Name": "FINISH", "Location": "38.993841,-76.894417" } ] }

Note the omission of orienteering clues in this first example. It means the user will not see o-clues, but instead Lat/Lon, MGRS or no clues when navigating, depending upon the G-Punch app settings. The second example contains o-clues.

#1 (Classic Course) SIMPLE format: https://www.landnavapp.com/samples/1-Simple-Clue.json
{ "Name": "Classic SIMPLE Clue", "CourseControl": [ { "Name": "START", "Location": "38.993841,-76.894417", "Clue": " ê ĉ" }, { "Name": "36", "Location": "38.993103,-76.892885", "Clue": " áĆ " }, { "Name": "33", "Location": "38.988005,-76.893808", "Clue": " áĆ " }, { "Name": "32", "Location": "38.988225,-76.897995", "Clue": " ááą " }, { "Name": "34", "Location": "38.990232,-76.892706", "Clue": " àá Ō" }, { "Name": "31", "Location": "38.990121,-76.897368", "Clue": " áĆ " }, { "Name": "35", "Location": "38.992676,-76.894360", "Clue": " Þ " }, { "Name": "FINISH", "Location": "38.993841,-76.894417", "Clue": " ê ĉ" } ] }

For more information about how to create and add orienteering clues for a course, see the Orienteering Clues section in the first half of these instructions.

SHORT Format

In SHORT format, the Point data is located in the "Control" field and the Course data is located in the "Course" and "CourseControl" fields.

#1 (Classic Course) SHORT format: https://www.landnavapp.com/samples/1-Short.json
{ "Control": [ { "Name": "31", "Location": "38.990121,-76.897368" }, { "Name": "32", "Location": "38.988225,-76.897995" }, { "Name": "33", "Location": "38.988005,-76.893808" }, { "Name": "34", "Location": "38.990232,-76.892706" }, { "Name": "35", "Location": "38.992676,-76.894360" }, { "Name": "36", "Location": "38.993103,-76.892885" }, { "Name": "START", "Location": "38.993841,-76.894417" }, { "Name": "FINISH", "Location": "38.993841,-76.894417" } ], "Course": { "Name": "Classic SHORT", "CourseControl": [ { "Name": "START" }, { "Name": "36" }, { "Name": "33" }, { "Name": "32" }, { "Name": "34" }, { "Name": "31" }, { "Name": "35" }, { "Name": "FINISH" } ] } }

Orienteering clues are omitted from the above example. If the course does not have o-clues, none will be shown during navigation, even if the user has selected "O-Clues" in the Settings.

In the below example, orienteering clues are included. If the user runs GP Loader to launch a course with o-clues, the G-Punch app will display orienteering clues no matter what the user has selected in the app settings.

If the user runs the G-Punch app again without GP Loader, it will revert back to whatever the user previously selected in the G-Punch app settings. If the original setting was "O-Clues" then it will continue to display o-clues during navigation, provided the course includes them.

#1 (Classic Course) SHORT format: https://www.landnavapp.com/samples/1-Short-Clue.json
{ "Control": [ { "Id": "31", "Location": "38.990121,-76.897368", "Clue": " áĆ " }, { "Id": "32", "Location": "38.988225,-76.897995", "Clue": " ááą " }, { "Id": "33", "Location": "38.988005,-76.893808", "Clue": " áĆ " }, { "Id": "34", "Location": "38.990232,-76.892706", "Clue": " àá Ō" }, { "Id": "35", "Location": "38.992676,-76.894360", "Clue": " Þ " }, { "Id": "36", "Location": "38.993103,-76.892885", "Clue": " áĆ " }, { "Id": "START", "Location": "38.993841,-76.894417", "Clue": " ê ĉ" }, { "Id": "FINISH", "Location": "38.993841,-76.894417", "Clue": " ê ĉ" } ], "Course": { "Name": "Classic SHORT Clue", "CourseControl": [ { "Control": "START" }, { "Control": "36" }, { "Control": "33" }, { "Control": "32" }, { "Control": "34" }, { "Control": "31" }, { "Control": "35" }, { "Control": "FINISH" } ] } }

Note that in the "Course" or "Placemark" (Course data) sections, the first and last controls are always interpreted as the Start and Finish. If you were to list control #35 as the last one in the sequence, the app would treat control #35 as the Finish. In all the examples here, we have chosen to label the last control "FINISH" to keep things simple.

KML Format

In KML files there is a base-level "Folder" field, which contains a "Name" field (used for the event name, this field is ignored by GP Loader app), and a second-level "Folder" field (which has the course information). In some KML files there is even another base-level above "Folder" called "kml", but this it not required.

In KML format, the Point data and Course data is combined in the "Placemark" field. The order of the controls matter, because only one course is allowed per KML file. If you are converting from a KML file produced by another program, you may have to make additional changes, such as adding o-clues, as we've done here.

#1 (Classic Course) KML format: https://www.landnavapp.com/samples/1-KML-Clue.json
{ "Folder": { "name": "KML event name (unused by GP-Loader)", "Folder": { "name": "Classic KML Clue", "Placemark": [ { "name": "START", "Point": { "coordinates": "38.993841,-76.894417" }, "clue": " ê ĉ" }, { "name": "36", "Point": { "coordinates": "38.993103,-76.892885" }, "clue": " áĆ " }, { "name": "33", "Point": { "coordinates": "38.988005,-76.893808" }, "clue": " áĆ " }, { "name": "32", "Point": { "coordinates": "38.988225,-76.897995" }, "clue": " ááą " }, { "name": "34", "Point": { "coordinates": "38.990232,-76.892706" }, "clue": " àá Ō" }, { "name": "31", "Point": { "coordinates": "38.990121,-76.897368" }, "clue": " áĆ " }, { "name": "35", "Point": { "coordinates": "38.992676,-76.894360" }, "clue": " Þ " }, { "name": "FINISH", "Point": { "coordinates": "38.993841,-76.894417" }, "clue": " ê ĉ" } ] } } }

Let's say you are creating a course using OpenOrienteerMap (OOM) at https://oomap.co.uk. First, you create the course, then click "KML" in the "MapRunF" section on the right side.

KML button in OOM

It will download a KML file, named oom_XXXXX.kml where the XXXXX is whatever MAP ID is associated with your map. First we need to convert this KML file into JSON format. So, open this KML file in an editor, and copy the contents to a KML to JSON converter webpage. The converted JSON output is shown below. The grayed out lines are unimportant. If you make no changes, this file should work fine with GP Loader, the latest edition.

#1 (Classic Course) KML format: https://www.landnavapp.com/samples/1-KML-OOM.json
{ "kml": { "Document": { "name": "oom_new_controls", "open": "1", "Style": [ { "IconStyle": { "color": "ffff00ff", "scale": "1.8", "Icon": { "href": "http://maps.google.com/mapfiles/kml/paddle/wht-stars.png" }, "hotSpot": { "_x": "0.5", "_y": "0", "_xunits": "fraction", "_yunits": "fraction" } }, "LabelStyle": { "color": "ffff00ff" }, "BalloonStyle": "", "ListStyle": "", "_id": "startfinish" }, { "IconStyle": { "color": "ffff00ff", "scale": "1.0", "Icon": { "href": "http://maps.google.com/mapfiles/kml/paddle/wht-blank.png" }, "hotSpot": { "_x": "0.5", "_y": "0", "_xunits": "fraction", "_yunits": "fraction" } }, "LabelStyle": { "color": "ffff00ff", "scale": "1.0" }, "BalloonStyle": "", "ListStyle": "", "_id": "control" } ], "Folder": { "name": "Controls", "open": "1", "Placemark": [ { "name": "S1", "styleUrl": "#startfinish", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89441712345678,38.99384112345678,0" } }, { "name": "36", "styleUrl": "#control", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89288512345678,38.99310312345678,0" } }, { "name": "33", "styleUrl": "#control", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89380812345678,38.98800512345678,0" } }, { "name": "32", "styleUrl": "#control", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89799512345678,38.98822512345678,0" } }, { "name": "34", "styleUrl": "#control", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89270612345678,38.99023212345678,0" } }, { "name": "31", "styleUrl": "#control", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89736812345678,38.99012112345678,0" } }, { "name": "35", "styleUrl": "#control", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89436012345678,38.99267612345678,0" } }, { "name": "F1", "styleUrl": "#startfinish", "Point": { "drawOrder": { "__text": "1" }, "coordinates": "-76.89441712345678,38.99384112345678,0" } } ] } }, "_xmlns": "http://www.opengis.net/kml/2.2", "_xmlns:gx": "http://www.google.com/kml/ext/2.2", "_xmlns:kml": "http://www.opengis.net/kml/2.2", "_xmlns:atom": "http://www.w3.org/2005/Atom" } }

Because this file is created from another program, there are a few things worth pointing out:

First, there is an extra comma and zero ",0" after the latitude in the "coordinates" field. GP Loader discards the extra second comma and zero.

Second, the default name of the course is "Controls", not "oom_new_controls" which is in a different level. Remember that the course name is in the second-level "Folder" dictionary.

Third, there is a new base field, kml. Because OOM creates this extra field, GP Loader interprets it, although it is optional and does not have to be included if you write your own KML course file..

Finally, the "coordinates" field contains Longitude before Latitude. Ordinarily this would require that you manually include a "LonLat":"true" entry at the base-level, in order for the coordinates to be properly interpreted. (See the LatLon Replacement section further down for more information.)

To make things easier when loading OpenOrienteeringMap course files, GP Loader will check for the existence of a "Style" field in the 1st "Document" or "Folder" dictionary. If it exists, like in the above example, GP Loader will assume the file was produced by OpenOrienteeringMap and it will interpret the coordinates in Longitude before Latitude order. So when you load a course created by OpenOrienteeringMap, no changes are necessary – it should load properly. Of course, you still have to add "Random" or "Score" fields if you want the course to be a Score-O course, see the #2 Score-O samples below.

If you delete this "Style" field, you will have to switch the order of the latitude and longitude, or add a "LonLat":"true" field at the base level, as described in the LatLon Replacement section further down.

IOF Format

IOF format is useful for when you have coursedata in IOF version 3.0 XML format and you need to convert it into JSON. These first samples will duplicate the previous ones, so you can compare and contrast this file with the other formats. Anything not used by GP Loader app have been grayed out to make it easier to read. Omit this data to save memory.

In IOF format, the Point data is located in the "Control" sub-field and the Course data is split in the "Course" and "CourseControl" sub-fields.

#1 (Classic Course) IOF format: https://www.landnavapp.com/samples/1-IOF.json
{ "iofVersion": "3.0", "createTime": "2020-07-27T09:51:11", "creator": "Condes version 10.1.2", "Event": { "Name": "IOF Event name (unused by GP-Loader)" }, "RaceCourseData": { "Control": [ { "Id": "START", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "type": "Start", "modifyTime": "2020-02-26T17:11:31", "MapPosition": { "x": "-288.56", "y": "-76.08" } }, { "Id": "FINISH", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "type": "Finish", "modifyTime": "2020-02-20T17:10:16", "MapPosition": { "x": "-226.37", "y": "-114.92"} }, { "Id": "31", "Position": { "lng": "-76.897368", "lat": "38.990121" }, "type":"Control", "modifyTime": "2020-02-27T17:12:56", "MapPosition": { "x": "-150.11", "y": "-79.77" } }, { "Id": "32", "Position": { "lng": "-76.897995", "lat": "38.988225" }, "type":"Control", "modifyTime": "2020-02-20T17:10:48", "MapPosition": { "x": "-238.11", "y": "-160.34"} }, { "Id": "33", "Position": { "lng": "-76.893808", "lat": "38.988005" }, "type":"Control", "modifyTime": "2020-02-20T17:11:00", "MapPosition": { "x": "-242.21", "y": "-180.75"} }, { "Id": "34", "Position": { "lng": "-76.892706", "lat": "38.990232" }, "type":"Control", "modifyTime": "2020-02-20T17:10:20", "MapPosition": { "x": "-216.21", "y": "-152.76"} }, { "Id": "35", "Position": { "lng": "-76.894360", "lat": "38.992676" }, "type":"Control", "modifyTime": "2020-02-27T17:10:21", "MapPosition": { "x": "-424.87", "y": "-97.81" } }, { "Id": "36", "Position": { "lng": "-76.892885", "lat": "38.993103" }, "type":"Control", "modifyTime": "2020-02-27T17:10:33", "MapPosition": { "x": "-224.80", "y": "-184.80"} } ], "Course": { "Name": "Classic IOF", "Length": "2700", "Climb": "30", "modifyTime": "2020-02-27T02:18:59", "CourseControl": [ { "type": "Start", "Control": "START" }, { "type": "Control", "Control": "36" }, { "type": "Control", "Control": "33" }, { "type": "Control", "Control": "32" }, { "type": "Control", "Control": "34" }, { "type": "Control", "Control": "31" }, { "type": "Control", "Control": "35" }, { "type": "Finish", "Control": "FINISH", "LegLength": "200" } ] } } }

Native IOF XML coursedata files include several extra lines, which are shown in gray in these examples. All these unused fields not used by GP Loader, and can be removed from the file. You do not have to delete these lines, but if your course has over 50 points, you should consider removing extra unused lines to conserve watch/app memory.

For example, you can remove all the "type", "modifyTime" and "mapPosition" fields from IOF files. Any field not listed in the above format diagrams is not interpreted by GP Loader. Fields listed with an asterisk * are optional and can be omitted or removed also.

If you do remove fields from your course file for whatever reason, upload the contents to JSONLint.com to check it for JSON syntax errors. If the course has JSON syntax errors, GP Loader will not be able to load it properly.

The below example shows what would remain of the above 1-IOF.json file if we removed all the unused lines. The file is still loadable by GP Loader because it still contains all the required fields.

#1 (Classic Course) IOF format: https://www.landnavapp.com/samples/1-IOF-Crop.json
{ "iofVersion": "3.0", "RaceCourseData": { "Control": [ { "Id": "START", "Position": { "lng": "-76.894417", "lat": "38.993841" } }, { "Id": "FINISH", "Position": { "lng": "-76.894417", "lat": "38.993841" } }, { "Id": "31", "Position": { "lng": "-76.897368", "lat": "38.990121" } }, { "Id": "32", "Position": { "lng": "-76.897995", "lat": "38.988225" } }, { "Id": "33", "Position": { "lng": "-76.893808", "lat": "38.988005" } }, { "Id": "34", "Position": { "lng": "-76.892706", "lat": "38.990232" } }, { "Id": "35", "Position": { "lng": "-76.894360", "lat": "38.992676" } }, { "Id": "36", "Position": { "lng": "-76.892885", "lat": "38.993103" } } ], "Course": { "Name": "Classic IOF Crop", "CourseControl": [ { "Control": "START" }, { "Control": "36" }, { "Control": "33" }, { "Control": "32" }, { "Control": "34" }, { "Control": "31" }, { "Control": "35" }, { "Control": "FINISH" } ] } } }

In the below example we've replaced several of the above terms with abbreviations and alternate terms. These abbreviations save memory because the file contains less characters. As indicated in the format diagram, the term "Position" can be replaced by "L" (for location), "Control" can be replaced with "C", and "Clue" can be replaced with "A". Note that the keyword "Control" field (in the "RaceCourseData" field in IOF files) cannot be abbreviated, but "CourseControl" can be replaced with "Legs" as shown below. (O-clues also added)

#1 (Classic Course) IOF format: https://www.landnavapp.com/samples/1-IOF-Clue-Abr.json
{ "iofVersion": "3.0", "RaceCourseData": { "Control": [ { "C": "31", "L": { "lng": "-76.897368", "lat": "38.990121" }, "A": " áĆ " }, { "C": "32", "L": { "lng": "-76.897995", "lat": "38.988225" }, "A": " ááą " }, { "C": "33", "L": { "lng": "-76.893808", "lat": "38.988005" }, "A": " áĆ " }, { "C": "34", "L": { "lng": "-76.892706", "lat": "38.990232" }, "A": " àá Ō" }, { "C": "35", "L": { "lng": "-76.894360", "lat": "38.992676" }, "A": " Þ " }, { "C": "36", "L": { "lng": "-76.892885", "lat": "38.993103" }, "A": " áĆ " }, { "C": "START", "L": { "lng": "-76.894417", "lat": "38.993841" }, "A": " ê ĉ" }, { "C": "FINISH", "L": { "lng": "-76.894417", "lat": "38.993841" }, "A": " ê ĉ" } ], "Course": { "Name": "Classic IOF Abr", "Legs": [ { "C": "START" }, { "C": "36" }, { "C": "33" }, { "C": "32" }, { "C": "34" }, { "C": "31" }, { "C": "35" }, { "C": "FINISH" } ] } } }

You can also replace "Id" with "C" in the "Control" [array], as well as "Clue" with "A", "Time" with "T", "Score" with "S", and "RandomOrder" with "Random" or "R". You cannot abbreviate "true" or "false".

By removing the "iofVersion" and "RaceCourseData" fields (and its closing brace), we are left with base-level "Control" and "Course" fields. The file is now in SHORT format, and GP loader can still load it.

#1 (Classic Course) SHORT format: https://www.landnavapp.com/samples/1-SHORT-Clue-Abr.json
{ "Control": [ { "C": "31", "L": { "lng": "-76.897368", "lat": "38.990121" }, "A": " áĆ " }, { "C": "32", "L": { "lng": "-76.897995", "lat": "38.988225" }, "A": " ááą " }, { "C": "33", "L": { "lng": "-76.893808", "lat": "38.988005" }, "A": " áĆ " }, { "C": "34", "L": { "lng": "-76.892706", "lat": "38.990232" }, "A": " àá Ō" }, { "C": "35", "L": { "lng": "-76.894360", "lat": "38.992676" }, "A": " Þ " }, { "C": "36", "L": { "lng": "-76.892885", "lat": "38.993103" }, "A": " áĆ " }, { "C": "START", "L": { "lng": "-76.894417", "lat": "38.993841" }, "A": " ê ĉ" }, { "C": "FINISH", "L": { "lng": "-76.894417", "lat": "38.993841" }, "A": " ê ĉ" } ], "Course": { "Name": "Classic SHORT Abr", "Legs": [ { "C": "START" }, { "C": "36" }, { "C": "33" }, { "C": "32" }, { "C": "34" }, { "C": "31" }, { "C": "35" }, { "C": "FINISH" } ] } }

Again note that the top field "Control" field (at base level in the above example) cannot be abbreviated.

If you make large structural changes to a course file, be sure to check the file for proper json syntax using JSONLint.com. The app will not be able to read your file if there is a syntax error.

Keyword terms must be spelled consistently within the whole file, and switching between abbreviations and whole words within the same structure is not allowed.

For example, if there was a lowercase "c" in the below "CourseControl" [array], it would produce an error during load, because this lowercase "c" is different from the uppercase "C" entries elsewhere in the file, in the "CourseControl" [array]. The error is highlighted below.

Similarly, an error will occur if we leave out the "Clue" fields in one of the control dictionaries, like in the below example for the "FINISH" control. Such an error may cause problems while navigating, so be sure to double-check the keywords and syntax are correct before running the course!

#1 (Classic Course) SHORT format: https://www.landnavapp.com/samples/1-SHORT-Clue-Error.json
{ "Note": "This file contains two errors and will result in an error. See instructions.", "Control": [ { "C": "31", "L": "38.990121,-76.897368", "Clue": " áĆ " }, { "C": "32", "L": "38.988225,-76.897995", "Clue": " ááą " }, { "C": "33", "L": "38.988005,-76.893808", "Clue": " áĆ " }, { "C": "34", "L": "38.990232,-76.892706", "Clue": " àá Ō" }, { "C": "35", "L": "38.992676,-76.894360", "Clue": " Þ " }, { "C": "36", "L": "38.993103,-76.892885", "Clue": " áĆ " }, { "C": "START", "L": "38.993841,-76.894417", "Clue": " ê ĉ" }, { "C": "FINISH", "L": "38.993841,-76.894417" } ], "Course": { "Name": "Classic SHORT Error", "CourseControl": [ { "C": "START" }, { "C": "36" }, { "C": "33" }, { "C": "32" }, { "C": "34" }, { "C": "31" }, { "c": "35" }, { "C": "FINISH" } ] } }

2.5.2 Score-O Course (All #2 Examples)

#2 Course 'Score-O'

SIMPLE Format

If the course has a base-level "Name" field, the app will assume the file is in SIMPLE format.

#2 (Score-O Course) SIMPLE format: https://www.landnavapp.com/samples/2-Simple-Clue.json
{ "Name": "2 Score-O SIMPLE Clue", "Time": "60", "Score": "10", "Random": "true", "CourseControl": [ { "Name": "START", "Location": "38.993841,-76.894417", "Clue": " ê ĉ" }, { "Name": "31", "Location": "38.990121,-76.897368", "Clue": " áĆ ", "Score": "10" }, { "Name": "32", "Location": "38.988225,-76.897995", "Clue": " ááą ", "Score": "15" }, { "Name": "33", "Location": "38.988005,-76.893808", "Clue": " áĆ ", "Score": "15" }, { "Name": "34", "Location": "38.990232,-76.892706", "Clue": " àá Ō", "Score": "10" }, { "Name": "35", "Location": "38.992676,-76.894360", "Clue": " Þ ", "Score": "5" }, { "Name": "36", "Location": "38.993103,-76.892885", "Clue": " áĆ ", "Score": "5" }, { "Name": "FINISH", "Location": "38.993841,-76.894417", "Clue": " ê ĉ" } ] }

The "RandomOrder" field means that controls can be visited in any order, with the exception of the start/first and last/finish controls. The "Time" field gives users 60 minutes to complete the course, or they will incur a penalty for each minute late. The "Score" field means that the per-minute-late penalty is 10 points, and it also sets the default score value for each control to 10 points. Because of this, the "Score" entries for controls 31 and 34 are redundant, because they are also 10 points.

KML Format

In the below KML file we have added "Time", "Score", "Random" and "Clue" entries, since they weren't included with the original KML file.

#2 (Score-O Course) KML format: https://www.landnavapp.com/samples/2-KML-Clue.json
{ "Folder": { "name": "KML event name (unused by GP-Loader)", "Folder": { "name": "Score-O KML Clue", "Time": "60", "Score": "10", "Random": "true", "Placemark": [ { "name": "START", "Point": { "coordinates": "38.993841,-76.894417" }, "Clue": " ê ĉ" }, { "name": "36", "Point": { "coordinates": "38.993103,-76.892885" }, "Clue": " áĆ ", "Score": "5" }, { "name": "33", "Point": { "coordinates": "38.988005,-76.893808" }, "Clue": " áĆ ", "Score": "15" }, { "name": "32", "Point": { "coordinates": "38.988225,-76.897995" }, "Clue": " ááą ", "Score": "15" }, { "name": "34", "Point": { "coordinates": "38.990232,-76.892706" }, "Clue": " àá Ō", "Score": "10" }, { "name": "31", "Point": { "coordinates": "38.990121,-76.897368" }, "Clue": " áĆ ", "Score": "10" }, { "name": "35", "Point": { "coordinates": "38.992676,-76.894360" }, "Clue": " Þ ", "Score": "5" }, { "name": "FINISH", "Point": { "coordinates": "38.993841,-76.894417" }, "Clue": " ê ĉ" } ] } } }

When converting from KML files for MapRun for particular event types, you may need to add some extra fields into the file, because GP Loader does not interpret the filename like MapRun does. For instance, if you were converting a MapRun KML file to JSON, and your course was a "Scatter" (Score) type event (PXAS), you would need to add in "Random":"true", to ensure all controls are random order, like in the above SIMPLE and SHORT examples.

SHORT Format

#2 (Score-O Course) SHORT format: https://www.landnavapp.com/samples/2-SHORT-Clue.json
{ "Control": [ { "C": "31", "L": "38.990121,-76.897368", "A": " áĆ " }, { "C": "32", "L": "38.988225,-76.897995", "A": " ááą " }, { "C": "33", "L": "38.988005,-76.893808", "A": " áĆ " }, { "C": "34", "L": "38.990232,-76.892706", "A": " àá Ō" }, { "C": "35", "L": "38.992676,-76.894360", "A": " Þ " }, { "C": "36", "L": "38.993103,-76.892885", "A": " áĆ " }, { "C": "START", "L": "38.993841,-76.894417", "A": " ê ĉ" }, { "C": "FINISH", "L": "38.993841,-76.894417", "A": " ê ĉ" } ], "Course": { "Name": "Score-O SHORT Clue", "Time": "60", "Score": "10", "Random": "true", "CourseControl": [ { "C": "START" }, { "C": "31", "S": "10" }, { "C": "32", "S": "15" }, { "C": "33", "S": "15" }, { "C": "34", "S": "10" }, { "C": "35", "S": "5" }, { "C": "36", "S": "5" }, { "C": "FINISH" } ] } }

In the below IOF file we have added "Clue", "Time", and "Score" entries, because they didn't come with the original IOF file. Also note that the native IOF format uses "randomOrder" instead of "Random", but will still work if you change it to "Random".

IOF Format

#2 (Score-O Course) IOF format: https://www.landnavapp.com/samples/2-IOF-Clue.json
{ "iofVersion": "3.0", "createTime": "2020-07-27T09:51:11", "creator": "Condes version 10.1.2", "Event": { "Name": "IOF Event name (unused by GP-Loader)" }, "RaceCourseData": { "Control": [ { "Id": "START", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "Clue": " ê ĉ", "type": "Start", "modifyTime": "2020-02-26T17:11:31", "MapPosition": {"x":"unused"} }, { "Id": "FINISH", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "Clue": " ê ĉ", "type": "Finish", "modifyTime": "2020-02-20T17:10:16", "MapPosition": {"x":"unused"} }, { "Id": "31", "Position": { "lng": "-76.897368", "lat": "38.990121" }, "Clue": " áĆ ", "type": "Control", "modifyTime": "2020-02-27T17:12:56", "MapPosition": {"x":"unused"} }, { "Id": "32", "Position": { "lng": "-76.897995", "lat": "38.988225" }, "Clue": " ááą ", "type": "Control", "modifyTime": "2020-02-20T17:10:48", "MapPosition": {"x":"unused"} }, { "Id": "33", "Position": { "lng": "-76.893808", "lat": "38.988005" }, "Clue": " áĆ ", "type": "Control", "modifyTime": "2020-02-20T17:11:00", "MapPosition": {"x":"unused"} }, { "Id": "34", "Position": { "lng": "-76.892706", "lat": "38.990232" }, "Clue": " àá Ō", "type": "Control", "modifyTime": "2020-02-20T17:10:20", "MapPosition": {"x":"unused"} }, { "Id": "35", "Position": { "lng": "-76.894360", "lat": "38.992676" }, "Clue": " Þ ", "type": "Control", "modifyTime": "2020-02-27T17:10:21", "MapPosition": {"x":"unused"} }, { "Id": "36", "Position": { "lng": "-76.892885", "lat": "38.993103" }, "Clue": " áĆ ", "type": "Control", "modifyTime": "2020-02-27T17:10:33", "MapPosition": {"x":"unused"} } ], "Course": { "Name": "Score-O IOF Clue", "Time": "60", "Score": "10", "Length": "2700", "Climb": "30", "modifyTime": "2020-02-27T02:18:59", "CourseControl": [ { "type": "Start", "Control": "START" }, { "type": "Control", "randomOrder": "true", "Control": "31", "Score": "10" }, { "type": "Control", "randomOrder": "true", "Control": "32", "Score": "15" }, { "type": "Control", "randomOrder": "true", "Control": "33", "Score": "15" }, { "type": "Control", "randomOrder": "true", "Control": "34", "Score": "10" }, { "type": "Control", "randomOrder": "true", "Control": "35", "Score": "5" }, { "type": "Control", "randomOrder": "true", "Control": "36", "Score": "5" }, { "type": "Finish", "Control": "FINISH" } ] } } }

As an alternative, we could have replaced the above six "randomOrder" entries with a single "Random":"true" entry on the same line as the course "Name".

In the SHORT and IOF format "Control" sections (like in the Point Data section of the G-Punch app settings) the controls can appear in any order, and you can also include extra dummy controls here.

2.5.3 Hybrid/Combo Courses (All #3 Examples)

Hybrid courses contain both classic/ordered controls, and score/unordered controls.

If the fields "Random" and "Score" are included in individual control {dictionaries} rather than in the overall course [array], it means those modifiers apply to individual control(s) rather than the entire course.

In these Hybrid courses (because they contains classic/ordered along with score/unordered controls), after the user punches the START, they must move to control 35. They can go to 31, 32, 33, 34, and 36 in any order, then they must return to control 35 again, before punching the FINISH.

SIMPLE Format

#3 (Hybrid Course) SIMPLE format: https://www.landnavapp.com/samples/3-SIMPLE.json
{ "Name": "Hybrid SIMPLE", "Time": "60", "Score": "10", "Random": "true", "Points": [ { "Name": "START", "Location": "38.993841,-76.894417" }, { "Name": "35", "Location": "38.992676,-76.894360", "R": "false", "S": "0" }, { "Name": "31", "Location": "38.990121,-76.897368" }, { "Name": "32", "Location": "38.988225,-76.897995" }, { "Name": "33", "Location": "38.988005,-76.893808" }, { "Name": "34", "Location": "38.990232,-76.892706" }, { "Name": "36", "Location": "38.993103,-76.892885" }, { "Name": "35", "Location": "38.992676,-76.894360", "R": "false", "S": "0" }, { "Name": "FINISH", "Location": "38.993841,-76.894417" } ] }

Although this SIMPLE course works with the GP Loader and G-Punch apps, for hybrid courses like this one, it is recommended to use SHORT format for Hybrid courses, because it lists out the controls and course(s) in two [arrays].

#3 (Hybrid Course) SHORT format: https://www.landnavapp.com/samples/3-SHORT-Clue.json
{ "Control": [ { "C": "START", "L": "38.993841, -76.894417", "A": " ê ĉ" }, { "C": "FINISH", "L": "38.993841, -76.894417", "A": " ê ĉ" }, { "C": "31", "L": "38.990121, -76.897368", "A": " áĆ " }, { "C": "32", "L": "38.988225, -76.897995", "A": " ááą " }, { "C": "33", "L": "38.988005, -76.893808", "A": " áĆ " }, { "C": "34", "L": "38.990232, -76.892706", "A": " àá Ō" }, { "C": "35", "L": "38.992676, -76.894360", "A": " Þ " }, { "C": "36", "L": "38.993103, -76.892885", "A": " áĆ " } ], "Course": { "Name": "Hybrid SHORT", "Legs": [ { "C": "START" }, { "C": "35", "R": "false", "S": "0" }, { "C": "31" }, { "C": "32" }, { "C": "33" }, { "C": "34" }, { "C": "36" }, { "C": "35", "R": "false", "S": "0" }, { "C": "FINISH" } ] } }

G-Punch app will always consider the first and last controls as classic/ordered controls, even if we set them to score/unordered in the coursedata. This is because in the "CourseControl" or "Legs" field, the first and last controls are always interpreted to be the Start and Finish controls.

2.5.4 Extra/Dummy Controls

SHORT and IOF format is required when course designers want to include extra/dummy controls.

As an example, control # 55 (highlighted below) has been added to the "Control" [array], and will be discoverable by the user while they run this course. But the user will not need to navigate to or punch control # 55 in order to complete the course, because it is not included in the "CourseControl" [array] – it is an extra dummy control.

#1 (Classic Course) IOF format: https://www.landnavapp.com/samples/1-IOF-Clue-Extra.json
{ "iofVersion": "3.0", "RaceCourseData": { "Control": [ { "Id": "START", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "clue": " ê ĉ" }, { "Id": "FINISH", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "clue": " ê ĉ" }, { "Id": "31", "Position": { "lng": "-76.897368", "lat": "38.990121" }, "clue": " áĆ " }, { "Id": "32", "Position": { "lng": "-76.897995", "lat": "38.988225" }, "clue": " ááą " }, { "Id": "33", "Position": { "lng": "-76.893808", "lat": "38.988005" }, "clue": " áĆ " }, { "Id": "34", "Position": { "lng": "-76.892706", "lat": "38.990232" }, "clue": " àá Ō" }, { "Id": "35", "Position": { "lng": "-76.894360", "lat": "38.992676" }, "clue": " Þ " }, { "Id": "55", "Position": { "lng": "-76.893844", "lat": "38.994162" }, "clue": " áĆ " }, { "Id": "36", "Position": { "lng": "-76.892885", "lat": "38.993103" }, "clue": " áĆ " } ], "Course": { "Name": "Classic IOF Extra", "CourseControl": [ { "Control": "START" }, { "Control": "36" }, { "Control": "33" }, { "Control": "32" }, { "Control": "34" }, { "Control": "31" }, { "Control": "35" }, { "Control": "FINISH" } ] } } }

This is the same course in SHORT format

#1 (Classic Course) SHORT format: https://www.landnavapp.com/samples/1-SHORT-Clue-Extra.json
{ "Control": [ { "Id": "START", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "clue": " ê ĉ" }, { "Id": "FINISH", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "clue": " ê ĉ" }, { "Id": "31", "Position": { "lng": "-76.897368", "lat": "38.990121" }, "clue": " áĆ " }, { "Id": "32", "Position": { "lng": "-76.897995", "lat": "38.988225" }, "clue": " ááą " }, { "Id": "33", "Position": { "lng": "-76.893808", "lat": "38.988005" }, "clue": " áĆ " }, { "Id": "34", "Position": { "lng": "-76.892706", "lat": "38.990232" }, "clue": " àá Ō" }, { "Id": "35", "Position": { "lng": "-76.894360", "lat": "38.992676" }, "clue": " Þ " }, { "Id": "55", "Position": { "lng": "-76.893844", "lat": "38.994162" }, "clue": " áĆ " }, { "Id": "36", "Position": { "lng": "-76.892885", "lat": "38.993103" }, "clue": " áĆ " } ], "Course": { "Name": "Classic SHORT Extra", "CourseControl": [ { "Control": "START" }, { "Control": "36" }, { "Control": "33" }, { "Control": "32" }, { "Control": "34" }, { "Control": "31" }, { "Control": "35" }, { "Control": "FINISH" } ] } }

2.5.5 LatLon Replacement

Let's say your Location field is a single text block that contains the latitude and longitude data separated by a comma. If you accidentally enter the longitude before the latitude (it should be latitude followed by longitude), GP Loader may see no problem, and send the data to G-Punch Orienteering app. It will result in your points being nowhere near where they should be. In order to fix this, rather than having to go through and edit every one, simply add a "LonLat":"true" field at the base level of the file, and GP Loader will switch the order.

#1 (Classic Course) IOF format: https://www.landnavapp.com/samples/1-IOF-Clue-LonLat.json
{ "LonLat": "true", "iofVersion": "3.0", "RaceCourseData": { "Control": [ { "C": "START", "L": "-76.894417, 38.993841", "A": " ê ĉ" }, { "C": "FINISH", "L": "-76.894417, 38.993841", "A": " ê ĉ" }, { "C": "31", "L": "-76.897368, 38.990121", "A": " áĆ " }, { "C": "32", "L": "-76.897995, 38.988225", "A": " ááą " }, { "C": "33", "L": "-76.893808, 38.988005", "A": " áĆ " }, { "C": "34", "L": "-76.892706, 38.990232", "A": " àá Ō" }, { "C": "35", "L": "-76.894360, 38.992676", "A": " Þ " }, { "C": "36", "L": "-76.892885, 38.993103", "A": " áĆ " } ], "Course": { "Name": "Classic IOF LonLat", "Legs": [ { "C": "START" }, { "C": "36" }, { "C": "33" }, { "C": "32" }, { "C": "34" }, { "C": "31" }, { "C": "35" }, { "C": "FINISH" } ] } } }

This is the same course in SHORT format

#1 (Classic Course) SHORT format: https://www.landnavapp.com/samples/1-SHORT-Clue-LonLat.json
{ "LonLat": "true", "Control": [ { "C": "START", "L": "-76.894417, 38.993841", "A": " ê ĉ" }, { "C": "FINISH", "L": "-76.894417, 38.993841", "A": " ê ĉ" }, { "C": "31", "L": "-76.897368, 38.990121", "A": " áĆ " }, { "C": "32", "L": "-76.897995, 38.988225", "A": " ááą " }, { "C": "33", "L": "-76.893808, 38.988005", "A": " áĆ " }, { "C": "34", "L": "-76.892706, 38.990232", "A": " àá Ō" }, { "C": "35", "L": "-76.894360, 38.992676", "A": " Þ " }, { "C": "36", "L": "-76.892885, 38.993103", "A": " áĆ " } ], "Course": { "Name": "Classic SHORT LonLat", "Legs": [ { "C": "START" }, { "C": "36" }, { "C": "33" }, { "C": "32" }, { "C": "34" }, { "C": "31" }, { "C": "35" }, { "C": "FINISH" } ] } }

2.5.6 Multi-Course Events

The "Course" entry is now an [array] and not a {dictionary}, and in the [array] are multiple course {dictionaries}.

#4 (Multi-Course) IOF format: https://www.landnavapp.com/samples/4-IOF-Clue.json
{ "iofVersion": "3.0", "RaceCourseData": { "Control": [ { "Id": "START", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "clue": " ê ĉ" }, { "Id": "FINISH", "Position": { "lng": "-76.894417", "lat": "38.993841" }, "clue": " ê ĉ" }, { "Id": "31", "Position": { "lng": "-76.897368", "lat": "38.990121" }, "clue": " áĆ " }, { "Id": "32", "Position": { "lng": "-76.897995", "lat": "38.988225" }, "clue": " ááą " }, { "Id": "33", "Position": { "lng": "-76.893808", "lat": "38.988005" }, "clue": " áĆ " }, { "Id": "34", "Position": { "lng": "-76.892706", "lat": "38.990232" }, "clue": " àá Ō" }, { "Id": "35", "Position": { "lng": "-76.894360", "lat": "38.992676" }, "clue": " Þ " }, { "Id": "55", "Position": { "lng": "-76.893844", "lat": "38.994162" }, "clue": " áĆ " }, { "Id": "36", "Position": { "lng": "-76.892885", "lat": "38.993103" }, "clue": " áĆ " } ], "Course": [ { "Name": "M-Classic IOF", "CourseControl": [ { "Control": "START" }, { "Control": "36" }, { "Control": "33" }, { "Control": "32" }, { "Control": "34" }, { "Control": "31" }, { "Control": "35" }, { "Control": "FINISH" } ] }, { "Name": "M-Score-O IOF", "Time": "60", "Score": "10", "randomOrder": "true", "CourseControl": [ { "Control": "START" }, { "Control": "31", "score": "10" }, { "Control": "32", "score": "15" }, { "Control": "33", "score": "15" }, { "Control": "34", "score": "10" }, { "Control": "35", "score": "5" }, { "Control": "36", "score": "5" }, { "Control": "FINISH" } ] }, { "Name": "M-Hybrid IOF", "Time": "60", "Score": "10", "randomOrder": "true", "CourseControl": [ { "Control": "START" }, { "Control": "35", "randomOrder": "false", "score": "0" }, { "Control": "31" }, { "Control": "32" }, { "Control": "33" }, { "Control": "34" }, { "Control": "36" }, { "Control": "35", "randomOrder": "false", "score": "0" }, { "Control": "FINISH" } ] }, { "Name": "M-Butterfly IOF", "Time": "180", "Score": "0", "CourseControl": [ { "Control": "START" }, { "Control": "35" }, { "Control": "32" }, { "Control": "36" }, { "Control": "35" }, { "Control": "33" }, { "Control": "34" }, { "Control": "35" }, { "Control": "FINISH" } ] } ] } }

When the app runs this IOF coursedata file, it will present the user with a menu of courses to pick from: "M-Classic IOF", "M-Score-O IOF", "M-Hybrid IOF" or "M-Butterfly IOF". After the user selects one of the course options, the app loads that course into the G-Punch Orienteering app.

During navigation the user will be able to discover extra or dummy controls that were included in the "Control" [array], like control # 55 in this example.

Below is the SHORT format multiple course file, for use in events that share common controls. Note that the "Course" entry is now an [array] and not a {dictionary}, and in the [array] are multiple course {dictionaries}.

When the app runs this SHORT coursedata file, it will present the user with a menu of courses to pick from: "M-Classic SHORT", "M-Score-O SHORT", "M-Hybrid SHORT" or "M-Butterfly SHORT". After the user selects one of the course options, the app loads it into the G-Punch Orienteering app.

#4 (Multi-Course) SHORT format: https://www.landnavapp.com/samples/4-SHORT-Clue.json
{ "Control": [ { "C": "31", "L": "38.990121,-76.897368", "A": " áĆ " }, { "C": "32", "L": "38.988225,-76.897995", "A": " ááą " }, { "C": "33", "L": "38.988005,-76.893808", "A": " áĆ " }, { "C": "34", "L": "38.990232,-76.892706", "A": " àá Ō" }, { "C": "35", "L": "38.992676,-76.894360", "A": " Þ " }, { "C": "36", "L": "38.993103,-76.892885", "A": " áĆ " }, { "C": "START", "L": "38.993841,-76.894417", "A": " ê ĉ" }, { "C": "FINISH", "L": "38.993841,-76.894417", "A": " ê ĉ" } ], "Course": [ { "Name": "M-Classic SHORT", "Hint":"100", "CourseControl": [ { "C": "START" }, { "C": "36" }, { "C": "33" }, { "C": "32" }, { "C": "34" }, { "C": "31" }, { "C": "35" }, { "C": "FINISH" } ] }, { "Name": "M-Score-O SHORT", "Time": "60", "Score": "10", "RandomOrder": "true", "CourseControl": [ { "C": "START" }, { "C": "31", "S": "10" }, { "C": "32", "S": "15" }, { "C": "33", "S": "15" }, { "C": "34", "S": "10" }, { "C": "35", "S": "5" }, { "C": "36", "S": "5" }, { "C": "FINISH" } ] }, { "Name": "M-Hybrid SHORT", "Time": "60", "Score": "10", "RandomOrder": "true", "CourseControl": [ { "C": "START" }, { "C": "35", "R": "false", "S": "0" }, { "C": "31" }, { "C": "32" }, { "C": "33" }, { "C": "34" }, { "C": "36" }, { "C": "35", "R": "false", "S": "0" }, { "C": "FINISH" } ] }, { "Name": "M-Butterfly SHORT", "Time": "180", "Score": "0", "CourseControl": [ { "C": "START" }, { "C": "35" }, { "C": "32" }, { "C": "36" }, { "C": "35" }, { "C": "33" }, { "C": "34" }, { "C": "35" }, { "C": "FINISH" } ] } ] }

The first course in this example contains the field "Hint":"100". When the user's next leg is under 100 meters distance, rather than showing the regular clue, it will show the distance and direction to the next control (including declination adjustments if the user entered a declination into the G-Punch settings). If the user presses START/STOP the display will return to its regular view. More information about this feature is below.

2.6 Distance & Direction Option

Sometimes people prefer to view the distance and direction from the last control to the next control. Course designers can use this feature to help quickly move competitors away from a particularly difficult-to-find control, or the control at the end of a long leg. For example, lets say leg 3 (control 122 to control 123) is 730 m long, and leg 4 (control 123 to control 124) is 75 m long. To prevent participants from gathering together at control 123 while they figure out where to go next, the course designer can provide participants with this information up front, so they can quickly move out and away from control 123.

The app will allow any legs under a certain length (up to 200m) to display distance and (declinated) direction hint in addition to regular clues. The distance and direction hint is only enabled in the following conditions:

Unfortunately, "Hint" option is ONLY available through courses launched via GP Loader.

To demonstrate the functionality of the "Hint" Option, include it in the Course info, as shown in the "M-Classic SHORT" course, in the last sample file, above.

2.7 Troubleshooting Courses

Confirm the URL for your coursefile is correct in the GP Loader app settings. Check that the URLs in Menu files are correctly spelled. Some spaces ( ) are allowed in URLs, but for best results minimize their usage because they are loaded differently. Garmin requires that the website support HTTPS security. In other words, the URL must begin with https:// and not http://. Trying to access a file on http:// website will produce an error.

Paste the file into JSONLint.com and click "validate JSON" to inspect it for common JSON syntax errors.

If GP Loader has trouble loading the file, it probably has something to do with the coursedata/menu/URL. Pay particular attention to capitalization and spelling of terms in the coursedata file. Check that each Control (name) in the Course section corresponds to a Control (name) in the Control section, and that both are spelled the same way. Misspellings and/or differences in capitalization are not allowed. Check the terminology used in the coursedata file is the same throughout the file. If for one control you use (lowercase) "clue", you should use that form everywhere in the file, and using "Clue" (with a capital C) elsewhere in the same file will produce an error. For certain key terms like "Folder", "RaceCourseData", "CourseControl" or "Placemark" they must be capitalized as they appear here, and alternate versions are not accepted. See the format diagram for a list of key words.

If you can load the file into G-Punch Orienteering, but the app crashes during navigation, check the locations to ensure no two controls (other than start and finish points) are located within 50 meters of eachother, and that no point is close to the last point in the Controls section, other than the Start (which is allowed to be near the Finish).

Check the Log file to ensure the coordinates are properly loading. If you discover that the coordinates are loading in reverse order (i.e., Longitude followed by Latitude), it is an easy fix. Just add a "LonLat":"true" entry at the base level of your file. GP Loader will load the coordinates in reverse. (This only works if longitude and latitude are in a single text field; if they are separately labeled Lon and Lat, you have to manually change those labels).

If you still can't determine what's wrong, click "Contact Developer" on the Garmin App store page and explain the problem. Include your email address so the developers can send you a reply.

2.8 Tips for Course Designers

When designing for virtual Orienteering, it is better to select larger features for controls (e.g., hilltop) instead of smaller ones (e.g., pit). It is also better to select features which do not border inaccessible or off-limits areas. This is because GPS inaccuracies may "place" the control several meters from the actual feature.

For courses with complex scoring schemas like "parity", "even-odd", "bones" events, manual calculation of results may be required. A listing of which controls the user visited is viewable in Garmin Mobile app in the "review lap" section.

During course design, if you use the internet to obtain Lat-Lon geocoordinates, you may obtain ones that look like "38.99023202651540, -76.8927068142461" with over ten digits after the decimal point. Only the first five to six digits after the decimal are important, since GPS technology itself is only precise to about that level. To save memory it is recommended to round the coordinates to a maximum of six digits after the decimal like "38.990232, -76.892709".

Use G-Punch Data Generator here to create courses from EPSG-coded IOF-XML files, thanks to Andreas T.

Use Routebuilder spreadsheet here to help you create routes, thanks to Colin B.

3 Compatible Watch List

ModelG-Punch OrienteeringGP Loader
approachs60OKOK
approachs62OKOK
d2bravolow memory - no O-Cluesolder firmware - watch
does not support launcher app
d2bravo_titaniumlow memory - no O-Cluesolder firmware - watch
does not support launcher app
d2charlieOKOK
d2deltaOKOK
d2deltapxOKOK
d2deltasOKOK
descentmk1OKOK
edge_1000OKOK
edge_520OKOK
edge1030OKOK
edge1030bontragerOKOK
edge130OKOK
edge520plusOKOK
edge530OKOK
edge820OKOK
edge830OKOK
edgeexploreOKOK
epixolder firmware - cannot save
unique fields to FIT file
older firmware - watch
does not support launcher app
fenix3/quatix3/tactixBravolow memory - no O-Cluesolder firmware - watch
does not support launcher app
fenix3_hrlow memory - no O-Cluesolder firmware - watch
does not support launcher app
fenix5/quatix5OKOK
fenix5plusOKOK
fenix5sOKOK
fenix5splusOKOK
fenix5x/tactixCharlieOKOK
fenix5xplusOKOK
fenix6/solar/dualpwrOKOK
fenix6pro/dualpwr/quatix6OKOK
fenix6s/6sSolar/6DualPwrOKOK
fenix6spro/saphr/…OKOK
fenix6xproOKOK
fenixchronosOKOK
fr230low memory - no O-Cluesolder firmware - watch
does not support launcher app
fr235low memory - no O-Cluesolder firmware - watch
does not support launcher app
fr245OKOK
fr245mOKOK
fr45watch
does not support ConnectIQ apps
watch
does not support ConnectIQ apps
fr630low memory - no O-Cluesolder firmware - watch
does not support launcher app
fr645OKOK
fr645mOKOK
fr735xtOKOK
fr920xtlow memory - no O-Cluesolder firmware - watch
does not support launcher app
fr935OKOK
fr945OKOK
garminswim2watch
does not support ConnectIQ apps
watch
does not support ConnectIQ apps
gpsmap66OKOK
gpsmap86OKOK
Instinctwatch
does not support ConnectIQ apps
watch
does not support ConnectIQ apps
legacyherocaptainmarvelOKOK
legacyherofirstavengerOKOK
legacysagadarthvaderOKOK
legacysagareyOKOK
marqadventurerOKOK
marqathleteOKOK
marqaviatorOKOK
marqcaptainOKOK
marqcommanderOKOK
marqdriverOKOK
marqexpeditionOKOK
marqgolferOKOK
MontanaOKOK
oregon7xxOKOK
rino7xxOKOK
venuOKOK
vivoactivelow memory - no O-Clueswatch
does not support launcher app
vivoactive_hrOKOK
vivoactive3OKOK
vivoactive3d (MB/M/...)OKOK
vivoactive3mOKOK
vivoactive3mlteOKOK
vivoactive4OKOK
vivoactive4sOKOK
vivolifewatch
does not support ConnectIQ apps
watch
does not support ConnectIQ apps

If you have Feedback or Questions

Click "Contact Developer" in the App Store. Include your email address so we can write you back!

About the Developer

The primary developer Michael (Mqbfxw) belongs to the Quantico Orienteering Club (QOC) and considers California his home.

Special Thanks To

Thanks to Andreas T, you can use G-Punch Data Generator to create courses from EPSG-coded IOF-XML files, at this link


Thanks to Colin B, you can use this Routebuilder spreadsheet to help you create routes at this link