GCFiddle is a tool to compute waypoints for Geocaching and show them on a map. It has a build-in interpreter for a simple calculation language similar to the "Wolf Language" used by CacheWolf (CacheWolf Homepage). It can also extract waypoints and variables from geocache descriptions.
GCFiddle Links: Source code, HTML Readme, GCNEW1, GCJVT3, GC45QJ1
- Calculation language similar to "Wolf Language" used by CacheWolf's solver
- Modify variables temporarily and see its effect on the calculation
- Show waypoints on a simple map, Open Street Map or with Google Maps (needs Google API key)
- Extract waypoints and variables from geocache descriptions (preprocessing)
- Load geocache example scripts stored in files or in local storage of the browser
- Runs locally without a server, also on mobile devices
- HTML5 / JavaScript without external libraries
- Simply open index.html in a browser. The user interface shows several boxes which can be shrunk and expanded by pressing the green buttons. There are boxes for Script, Result, Variables, Waypoints, Map and some special boxes for GCFiddle andvanced, Filter, Sort, Logs and Notes.
- The first selection field selects the database. The default is the read only "test DB" defined in file system or on the server and "Saved" in Browser local storage.
- The "Reload" button reloads the page with the current settings. (Please note that changes to the script are lost!) See the list of URL parameters below.
- The "Help" button opens the Readme on the server.
- There are additional buttons with some advanced functionality, which will be shown when you click on "GCFiddle" (not shown here, you can skip it for first reading):
- The "Index" button create an example index and shows it as result. This can be copied into an example index file.
- The "Console" button activates the console for debugging
- Allows to filter the script examples by category, id or title. For example, 7 out of 7 are shown.
- Allows to sort the script examples by id, title or distance. The distance is computed from a location waypoint which can be filled by the location button below.
- The selection field loads a geocache calculation script and executes it
- The input field contains the editable script
- The "Preprocess" button processes the input text (not a script but a textual geocache description copied from geocaching.com) and tries to convert it to a script. This means it comments lines and tries to find variables (e.g. a=...) and waypoints (e.g. N...°...E...°). If the input starts with "<?xml", is is assumed to be a gpx file and parsed as XML (currently to extract waypoints). The resulting script is put in the history and executed.
- The "Execute" button executes the input script and fills the other boxes with the output. It also puts changed input in a history which can be accessed by the "Undo" and "Redo" buttons.
- The "Save" button saves the current input in "Saved" database and selects it. It is stored in browser local storage which means that it is kept also during page reloads.
- The "Delete" button deletes the current geocache in "Saved" database. There is a confirmation dialog to prevent accidential delete.
- Shows the result of the script execution
- If you mark a variable or a waypoint, it will be selected in the variable box or in the waypoint box, respectively. If you do so, the map is centered to the selected waypoint.
- Allows you to select a variable that is found during script execution and fiddle with it. That means you can change it temporarily without changing the script. Changed variables are marked with "[c]".
- Also, the general view type of the variable can be changed. If view type "number" is selected but a variable is not a number, it is still displayed as text. The range slider currently uses the interval 0 to 9999.
-
Allows you to select a waypoint found during script execution and fiddle with it. That means you can change it temporarily without changing the script. Changed waypoints are marked with "[c]".
-
Waypoints are variables that begin with a dollar sign "$": e.g.
$W1
. -
The waypoint format can be changed. This affects the hover popup for the waypoint input field and the marker popups on the map. Usually waypoints are shown in the same format as they were defined. Possible formats:
- "" (Automatic, as input)
- dmm (deg-min.min), e.g.
N 49° 16.130 E 008° 40.453
- dms (deg-min-sec), e.g.
N 49° 16' 07.80" E 008° 40' 27.18"
- dd (decimal degrees), e.g.
N 49.26883° E 008.67422°
- dmmc (deg-min.min with comment), e.g.
N 49° 16.130 E 008° 40.453!category!title
- dmsc (deg-min-sec with comment)
- ddc (decimal degrees with comment)
- To show waypoints on a map.
- The selection field selects a Leaflet or OpenLayers Open Street Map (online), Google Maps (online), a simple map (offline, for testing only), or no map.
- For Google Maps you need to get a Google API key and set it in gcfiddle.js, in gcconfig.js or as a URL parameter.
- Clicking on a waypoint opens a popup (info box) with coordinates and distance and direction information from the preceding waypoint. When you move the waypoint around, the popup is moved as well and its coordinates are updated. Clicking on "x" closes the popup.
- Zooming and moving the map are also possible.
- To show log entries. These are created during preprocessing and put in the scripts metadata.
- The "Remove Logs" button removes the log entries from the scripts metadata "#GC_INFO", if available. This could be useful, if you want to shrink the script metadata comment.
- Allows you to write some notes. (Currently notes are not stored.)
- Advanced, usually not visible. Can be activated for debugging.
- Line comments start with a hash "#":
# comment until end of line
- Numbers are composed of digits 0..9 and a decimal point:
34
or3.14
- Strings are surrounded by quotations:
"3.14"
- Character escaping with backslash in quoted strings:
"a\"b\"\nc"
=>a"b"<newline>c
- Strings can also be surrounded by apostrophes (no escaping):
'3.14'
, can contain quotations:'quotations: "'
- Strings in brackets are concatenated:
\["5" "3." "14"]
="53.14"
- Type conversion: Numbers in brackets are converted to strings:
\[ 5 "3." 14 ]
="53.14"
- Number formatting with suffix pattern:
3.14159:000.00:
=>"003.14"
- Character escaping with backslash in quoted strings:
- Operators +, -, *, / % ^ are used for for numerical addition, subtraction, multiplication, division, modulo and exponential operation.
(Note: Operator "%" is not supported by WolfLanguage, use mod() function, see below.)
- Parenthesis "(", ")" can be used for grouping as usual
- Type conversion: Strings are converted to numbers:
"5"+3.14
=>8.14
,"5"+"3.14"
=8.14
- Variable names start with a character and may contain digits:
a1=3.14
, use:a1
=3.14
- Waypoints are string variables with a special format starting with dollar sign:
$W1="N 49° 16.130 E 008° 40.453"
- Functions can be defined
f()=3.14
or called:f()
=>3.14
- Functions with parameter:
f(x)=3.14*x
, called:f(2)
=>6.28
- Functions with multiple parameters:
f(x,y)=x*y
, called:f(2,3)
=>6
- Functions with parameter:
- If not mentioned otherwise, type conversion is done as needed.
- Functions which are not available in CacheWolf are marked with: "²"
- getconst(s)²: get constant "PI" or "E":
getconst("PI")
=3.141592653589793
,getconst("E")
=2.718281828459045
- d2r(d): convert degrees to radians (d * Math.PI / 180)
- r2d(r): convert radians to degrees (r * 180 / Math.PI)
- sin(d): sine of a number d given in degrees:
sin(90)
=1
- cos(d): cosine of a number d given in degrees:
cos(0)
=1
- tan(d): tangent of a number d given in degrees:
tan(45)=sin(45)/cos(45)
- asin(x): arcsine (in degrees) of a number x
- acos(x): arccosine (in degrees) of a number x
- atan(x): arctangent (in degrees) of a number x:
atan(1)
=45
- abs(x): absolute value of number x:
abs(-3.14)
=3.14
- round(x)²: round x to nearest integer:
round(3.14)
=3
,round(3.54)
=4
, ,round(-3.54)
=-4
- ceil(x)²: ceiling function: round x to nearest integer >= x:
ceil(3.54)
=4
,ceil(-3.54)
=-3
- floor(x)²: floor function: round x to nearest integer <= x:
floor(3.54)
=3
,floor(-3.54)
=-4
- int(x): integer value of x (floor() for x > 0, otherwise ceil()):
int(3.54)
=3
,int(-3.54)
=-3
- mod(x, y): modulo operation x % y, reminder of x / y:
mod(25, 7)
=4
,mod(-13, 64)
=-13
- log(x)²: natural logarithm (base E) of a number x:
log(8)/log(2)
=3
- exp(x)²: exponential function e ^ x:
exp(0)
=1
- sqrt(x): square root of a number x:
sqrt(9)
=3
- min(x, y)²: minimum of numbers x and y:
min(3.14, 4)
=3.14
- max(x, y)²: maximum of numbers x and y:
max(3.14, 4)
=4
- random()²: pseudo-random number (0 <= x < 1):
random()
- gcd(x, y)²: greatest common divisor of x and y:
gcd(1071, 1029)
=21
- fib(n)²: the nth Fibonacci number, the sum of the two preceding ones:
fib(50)
=12586269025
- ct(n): crosstotal of the number n (sum of digits):
ct(1234567890)
=45
- Works also for strings:
ct("1234567890")
=45
- Other characters are ignored:
ct("R9z876gh5432%.*^/+-10")
=45
- Crosstotal of crosstotal:
ct(ct(1234567890))
=9
- Works also for strings:
- cti(n)²: crosstotal iterative of the number n (sum of digits until < 10):
cti("1234567890")
=9
- Other characters are ignored:
cti("R9z876gh5432%.*^/+-10")
=9
- Other characters are ignored:
- (zformat(n, len)²: zero padding to len characters:
zformat(0, 3)
="000"
,zformat(8.2, 5)
="008.2"
)
- val(s): sum of the character values:
val("a")
=1
,val("Z")
=26
- special characters and numbers are ignored:
val("äöüß")
=0
,val(1234567)
=0
- special characters and numbers are ignored:
- sval(s): list of the character values:
sval("ABCDEFGZz")
="01 02 03 04 05 06 07 26 26"
- Special characters are ignored:
sval("ABCxyzäöü")
="01 02 03 24 25 26"
- Special characters are ignored:
- vstr(s, i)²: inverse of sval() with an optional parameter to shift characters by i places.
- encode(s, m1, m2): encode s with character mapping m1 to m2:
encode("ABBA17abba", "AB7", "OS2")
="OSSO12abba"
- instr(s, s2): first index of s2 in s, starting at 1; 0=not found:
instr("abca", "a")
=1
,instr("abca", "d")
=0
- instr(s, s2, i): same as instr(s, s2) but with optional start parameter i > 0 (CacheWolf also supports this variant but expects i as first parameter!)
- len(s): length of string s:
len("abc")
=3
,len("")
=0
- countstr(s, s2)²: Count number of occurrences of substring s2 in s:
count("abba", "a")
=2
. - count(s, c): count individual characters from s2 in string s:
count("abba", "a")
=2
. For multiple characters, list the counts separately:count("abba", "ab")
="a=2 b=2"
. - mid(s, index, len): substring starting at index (>=1) and length:
mid("abcABCabc", 3, 5)
="cABCa"
- uc(s): uppercase string (caution: Chrome converts "ß" to "SS"!):
uc("abcäöüABC")
="ABCÄÖÜABC"
- lc(s): lowercase string:
lc("ABCÄÖÜßabc")
="abcäöüßabc"
- replace(s, s1, r1): replace all occurrences of s1 in s by r1:
replace("abcABCabc", "bc", "Xy")
="aXyABCaXy"
- reverse(s): reverse string s:
reverse("abcZ")
="Zcba"
- rot13(s): rotate the alphabet by 13 positions:
rot13("abcdefghijklmnopqrstuvexyzABC")
="nopqrstuvwxyzabcdefghirklmNOP"
Coordinate formats:
dmm
(degrees, minutes, minutes), e.g."N 49° 16.130 E 008° 40.453"
(default)dms
(degrees, minutes, seconds), e.g."N 49° 16' 07.80\" E 008° 40' 27.18\""
dd
(decimal degrees), e.g."N 49.26883° E 008.67422°"
We assume here:
$W1="N 49° 16.130 E 008° 40.453"
$W2="N 49° 15.903 E 008° 40.777"
- bearing($W1, $W2): bearing between $W1 and $W2 in degrees:
round(bearing($W0, $W1))
=137
- cb($W1, b1, $W1, b2): crossbearing
cb($W1, 78, $W2, 7)
="N 49° 16.182 E 008° 40.830"
- distance($W1, $W2): distance in meters:
distance($W1, $W2)
=575
- project($W1, angle, distance): project from $W1 angle degrees and distance meters
project($W1, 137, 575)
=$W1
- midpoint($W1, $W2)²: midpoint between $W1 and $W2
midpoint($W1, $W2)
=project($W1, bearing($W1,$W2), distance($W1,$W2)/2)
- format($W1, fmt): format waypoint $W1 (dmm, dms, dd):
format($W1, "dmm")
=$W1
="N 49° 16.130 E 008° 40.453"
format($W1, "dms")
="N 49° 16' 07.80\" E 008° 40' 27.18\""
format($W1, "dd")
="N 49.26883° E 008.67422°"
- ic(x): ignore case for variables, 0=false (default), 1 (or number <>0)=true; without x returns status "true" or "false".
The default can also be changed with the setting
ignoreVarCase
. - isequal(x, y)²: ...
- assert(s1, s2)²: asserts that s1 is equal to s2
- parse(s)²: Parses script in s; returns output and possible error messages
- cls(): clear output
- concat(s1, s2, ...)²: internal function to concatenate strings (use brackets to concatenate strings)
- Most of the functions are also available in CacheWolf, so it is possible to write calculation scripts for both interpreters. (Functions which are not available in CacheWolf are marked with ².)
- Please see the examples on the test page GCTEST1.
- Please check the description of the WolfLanguage (only in German).
- Strings can also be surrounded by apostrophes
'
(no character escaping). - To concatenate strings, they must be placed in brackets
\[
...]
. Separation by spaces is not enough - Per default, functions and variables are case-sensitive. This can be changed with a setting or with
ic(0)
for variables. (In WolfLanguage, ignore case is the default.) - Possibility to define new functions, e.g.
f(x,y)=x+y
- Number formatting with suffix pattern may contain zero
0
and dot.
but no hash#
- Geodetic calculation of waypoints uses another model with other formulas, so there are slightly different results
- No statement separator, especially no semicolon
;
- Functions must be used exactly as they are defined, there are no abbreviations or aliases (e.g.
crosstotal
is alwaysct
). Also the case is relevent. - No function:
goto(wp)
,sk(n)
,deg()
,rad()
- No statements:
IF
,THEN
,ENDIF
,STOP
The preprocessing feature allows to scan the input, extract information and convert it into a script. Usually the input is a Copy&Paste text from a geocache description on geocaching.com. It is also possible to use any text or xml or gpx file content with waypoints.
During preprocessing the following steps are done:
- Convert all text into comments
- Extract variables
- If there is an equal
=
character, the left part is assumed to be a variable, the right part can be a single value or an expression without spaces
<variable><space(s)>=<space(s)><exprWithoutSpace>
- Examples:
some text a=12 more text
=>#some text a=12 more text
a=12
- If there is an equal
- Extract waypoints
- Waypoints (especially with formulas) have to fulfill some characteristics to be recognized:
N<expr>°<expr>.<expr>E<expr>°<expr>.<lastExpr>
<expr>
is an expression of variables, numbers, operators and parenthesis, which may contain spaces. If<lastExpr>
contains spaces, some heuristics is used to detect the end of the waypoint. This is not always correct. You can always remove spaces to add following parts to<lastExpr>
or insert a word of at least two characters or a symbol like semicolon;
to end a waypoint.- Degree symbols
°
and dots.
are mandatory (instead of dots, also comma,
can be used) - Instead of
N
andE
, also waypoints withS
andW
are detected - Expressions, and in general waypoints are not checked for validity
- In case of ambiguity, variables are assumed to consist of letters only, e.g.
a7
=>a 7
- A colon
:
is converted into a division character/
- Fractions are detected for numbers only. To minimize conflicts with minutes
.
seconds, they may have at most 2 decimal digits
- Examples:
- Standard format (Degrees Minutes Seconds):
N 49° 16.130 E 008° 40.453
=>
$W1="N 49° 16.130 E 008° 40.453"
- More or less space:
N 49 ° 18.123 E 008 ° 42.456
, or:
N49°18.123E008°42.456
- Multiple waypoints in one line between text:
text1 N 49° 18.123 E 008° 42.456 text2 N 49° 18.789 E 008° 42.987 text3
=>
$W1="N 49° 18.123 E 008° 42.456"
...
$W2="N 49° 18.789 E 008° 42.987"
- Using numbers and variables:
N 49° 18.1a7 E 008° 42.a5b
=>
$W1=["N 49° 18.1" a "7 E 008° 42." a "5" b]
- Using variables and expressions:
N 49° (A-1)(B).(4*A)(B)(A) E 008° (2*A)(5).(A/2)(3*A)(3*A)
=>
$W1=["N 49° " (A-1)(B) "." (4*A)(B)(A) " E 008° " (2*A)(5) "." (A/2)(3*A)(3*A)]
- (For more examples, see Preprocessor.qunit.js, "find waypoints".)
- Standard format (Degrees Minutes Seconds):
- If necessary, modify the input before using preprocessing.
- Waypoints (especially with formulas) have to fulfill some characteristics to be recognized:
- Extract cache information from the sections and put it JSON encoded in a comment line marked with
#GC_INFO:
URL parameters override settings in file gcconfig.js
or gcfiddle.js
.
database=testDB
: Set the databasedatabaseIndex=0dbindex.js
: database index inexampleDir
debug=0
: Set the debug level, 0=off, 1=some messages, 2=some more,...example=
: Set example scriptexampleDir=examples
: example base directoryfilterCategory
: filter by categories (comma separated list, empty means all)filterId
: filter by ID (substring, ignore-case)filterTitle
: filter by title (substring, ignore-case)googleKey
: Set Google API key- Can also be set in file
gcconfig.js
orgcfiddle.js
- Can also be set in file
ignoreFuncCase=false
: ignore case for functionsignoreVarCase=false
: ignore case for variablesleafletMapboxKey
: mapbox access token (for leaflet maps, currently unused)leafletUrl
: Set URL for the Leaflet library- leaflet, https (default)
- or "lib/leaflet.js" (if available locally)
- or "lib/leaflet-src.js" (if available locally, debug sources)
mapType=leaflet
: Set type of map toleaflet
,openlayers
,google
,simple
ornone
.- For map type
google
, an API key must be set with parametergoogleKey
- For map type
openLayersUrl
: Set URL for the OpenLayers library- OpenLayers, https (default)
or OpenLayers (http only)
or "lib/OpenLayers.js" (if available locally)
or "lib/OpenLayers.light.js" (light version with some features missing, e.g. Overview map, keyboard defaults)
- OpenLayers, https (default)
showConsole=false
: Show console box (for debugging messages)showFilter=false
: Show the filter boxshowLogs=true
: Show Example LogsshowMap=true
: Show the map boxshowNotes=true
: Show the notes boxshowResult=true
: Show the result boxshowScript=true
: Show the script boxshowSort=false
: Show the sort detailsshowSpecial=false
: Show special functionalityshowVariable=true
: Show the variable boxshowWaypoint=true
: Show waypoint boxtestIndexedDb=false
: test Index Database (experimental)varMin=0
: minimum value for variablevarMax=9999
: maximum value for variablevarStep=1
: Increment for variable changevarType=number
: Set general type of variables in the variable box tonumber
,text
orrange
- If a variable is not a number,
text
is used
- If a variable is not a number,
waypointFormat
: Set waypoint output format:(empty string)
,dmm
,dms
,dd
,dmmc
,dmsc
,ddc
zoom=15
: Set initial zoom level for Google Maps (usually automatically set)
QUnit test testsuite.qunit.html runs:
- CommonEventHandler.qunit.html
- InputStack.qunit.html
- LatLng.qunit.html
- Model.qunit.html
- Preprocessor.qunit.html
- ScriptParser.qunit.html
- ...
-
CacheWolf, I use it for years now...
-
Description of GCJVT3 with friendly permission by rosszwerg. (Archived cache, solution provided.)
-
Description of GC54QJ1 with friendly permission by kruemelhuepfer. (Archived cache, solution provided.)
-
Formulas for GC5TER7 with friendly permission by Onetrain. (Try to find the solution!)
-
Geodesy tools (c) Chris Veness 2002-2016
- Latitude/longitude spherical geodesy tools
- I picked just the functions that I needed, modified LanLon object to be compatible with Google LatLng object and removed Greek symbols which JSlint does not like.
- latlon-spherical on GitHub
- Thanks for the excellent explanation on geodesy calculations and the library!
-
Peter Olson for an article on How to write a simple interpreter in JavaScript. It was a good starting point for the calculator in GCFiddle.
-
Leaflet and OpenLayers 2 to display the Open Street Map