These notes on the ChaiScript language may help when using it in <script> sections in CartoType import rules. Here are some external links to some other useful resources:

ChaiScript Overview and Tutorial

ChaiScript Tutorial: the link is to the first of a series of articles.

ChaiScript Keyword Reference

ChaiScript built-in types and functions

General nature of the language

ChaiScript is a strongly typed declarative language with syntax similar to C++. Important differences from C++ are:

  • All statements are legal at file scope, outside any function.
  • Variables have no type until they are first given a value, either at the time of declaration or later.
  • Flow-of-control constructs like if, for and while take blocks enclosed in { … }; they cannot take single statements.
  • There are no postincrement or postdecrement operators (++ and -- after the variable name).

Character set

ChaiScript uses 7-bit ASCII characters only in keywords, identifiers and other syntax elements like operators. ChaiScript program code is a series of 8-bit bytes. The ChaiScript parser assumes the ASCII or encoding (i.e., the first 127 codepoints of Unicode). Byte values greater than 127 can be used but their interpretation is the choice of the programmer. (CartoType-specific note: strings passed from or to CartoType, e.g., by getting an input field or setting a map object attribute, are encoded as UTF-8).

Tokens

Identifiers are case-sensitive sequences of characters starting with a letter (a…z, A…Z) or an underscore (_), and continuing with zero or more letters, underscores and digits (0…9). The format is identical to that of C++ and C. The following keywords are recognised:

attr auto break case catch class continue def default else finally for global if return switch try var while

There are some special identifiers which are not strictly keywords but have reserved meanings:

_ __CLASS__ Infinity false __FILE__ __FUNC__ __LINE__ Nan true

The following punctuation tokens are recognised:

:: ( ) : { } [ ] . ,

The following operator tokens are recognised:

? || && | ^ & == != < <= > >= << >> + - * / % ++ -- ! ~

Line breaks are marked by either a single linefeed or a carriage return followed by a linefeed.

Integer literals are as in C++. Decimal binary, octal and hexadecimal integer literals are all supported.

Floating-point number literals are as in C++, but C++17 hexadecimal floating-point literals are not supported.

String literals are sequences of characters enclosed in double quotes. Double quotes can be put in a string using the sequence \”. String literals may contain interpolations, which are enclosed in ${ … } and may contain unescaped double quotes. Interpolations may be nested. They are used as code literals and interpreted as ChaiScript code by the built-in print function.

Operator literals are operators enclosed in back ticks, like `+`. They are function objects referring to operators.

Comments are as in C++. That is, a comment lasting to the end of the current line starts with //, and a multi-line comment is of the form /* … */.

Annotations are special single-line comments starting with #. A function’s annotation can be retrieved programmatically.

Statements and declarations

Statements and declarations are terminated either by the end of a line or by a semicolon. Multi-line statements are parsed greedily; if the parser has not encountered a semicolon or other delimiter indicating the end of a statement when it reaches the end of a line, it moves on to the next line. Unlike in C++, semicolons are not mandatory.

Programs

A ChaiScript program is a sequence of statements and declarations. Unlike in C++, statements may exist outside any function. A program to print ‘Hello World’ can therefore be expressed as the one-line program

puts(“Hello World”)

Built-in types

The following types are built in, and have constructors (e.g., uint32_t(), int(45), etc.) with the same name:

Boolean types

bool

integer types

int long unsigned_int unsigned_long long_long unsigned_long_long size_t int8_t int16_t int32_t int64_t uint8_t uint16_t uint32_t uint64_t

floating point types

double long_double float

character types

char wchar_t char16_t char32_t

Standard library types

These types are provided by the standard library, which is automatically loaded by ChaiScript.

string types

string: very similar to C++’s std::string

aggregate types

Vector

Map

Pair

other types

future

Creating variables: auto and var

Variables are declared using auto, or var, which is a synonym of auto. The syntax is:

auto <name>

or

auto <name> = <expression>

and the type of the variable is deduced from that of the expression if any. If no expression is given, the type is determined the first time the variable is assigned.

Examples:

auto n = 3
var f = 56.78
auto s = “abc”
auto u = unsigned_int() // sets u to 0

 

 

Sometimes you will need the capabilities of a full programming language to accomplish complicated data import tasks. For instance, you might need to extract all input fields of a certain type and add them as map object attributes; or you might want to use loops, variables or functions. The ability to use ChaiScript code in the import rules system adds a full programming language to the system. The language itself is documented elsewhere; the page you are reading deals with how CartoType uses it.

Even if you don't want to do anything complex you might prefer using a full programming language to XML. You can do anything in ChaiScript that you can do in ordinary XML import rules, except for <file>, <file_type> and <dbf>, which have to be in XML.

ChaiScript code interoperates freely and seamlessly with the XML import rules system. You can write makemap files composed of mixed XML rules and ChaiScript code as convenient.

Using the ChaiScript language: <script>

The CartoType import rules system can use ChaiScript , which is a simple C++-like scripting language. Anywhere in an import rules (.makemap) file where you would write a series of rules like <set>, <set_layer>, <commit>, etc., you can insert a <script> element like this:

<script>
... ChaiScript code ...
</script>

It's often a good idea to enclose your ChaiScript code in a CDATA section so that you can use characters like < and > without needing cumbersome XML entity references like &lt; and &gt;. Here's what it looks like:

<script>
<![CDATA
... ChaiScript code ...
]]>
</script>

Every <script> section is enclosed (by the CartoType import rules parser) in a block, that is, a pair of curly brackets { ... }. This causes local variables you create in a <script> section to have the scope of that script section.

Global variables

The CartoType import rules system adds the following global variables to ChaiScript. They are cleared before each imported record is processed, just as the values set by <set_layer>, etc., are cleared. The Chaiscript vaues are connected to the XML values; <set_layer> sets the layer variable, and the other way around, and the same is true for object_type and attrib, and for values set using functions, like the road type and integer attribute.

layer is a string containing the layer name. Assign to it to set the layer.

object_type is an integer containing the current map object type. Assign one of the constants POINT, OBJECT and LINE to it to set the map object type.

attrib is a ChaiScript Map object containing the map object attributes. You can set attributes like this: attrib["attrib_name"] = 3 * 19;. You can assign a value of any type to any attribute, but values other than strings and numbers are ignored. Use the "name" attribute for the map object's standard name or label.

Functions

The CartoType import rules system adds the following functions to ChaiScript.

set(string aAttribName,aValue) sets a map object attribute to aValue; the same as attrib[aAttribName] = aValue; You can assign a value of any type to any attribute, but values other than strings and numbers are ignored.

in(string aFieldName) returns the value of the field aFieldName in the input record
in(string aFieldName,size_t aSubscript) returns the value of the field aFieldName, subscripted by aSubscript, in the input record; subscripted fields are used for associated DBF files with multiple records for a single key in the main input record.

exists(string aFieldName) returns true if the field aFieldName exists in the input record
exists(string aFieldName,size_t aSubscript) returns true if aFieldName, subscripted by aSubscript, exists in the input record; subscripted fields are used for associated DBF files with multiple records for a single key in the main input record.

dbf_record_count(string aPrefix) returns the number of records for the current key, for the DBF file with the specified prefix. Values from 0 to the number of records minus one may be used as subscripts when getting fields. See the <dbf> element in the XML import rules.

commit() creates a new output data object by copying current values (layer, object type, and attributes), and adds it to the list of output data objects to be made into map objects.
commit(string aLayer) is a variant of commit() that overrides the current layer with a layer specified as a function parameter.
commit(string aLayer,string aOsmType) is a variant of commit() that overrides the current layer and OSM type with a layer and OSM type specified as function parameters.

copy(string aName) sets the string attribute(s) named by aName, which may contain wild cards, to the same string attributes in the output object. The name 'name' copies the 'name' attribute to the unnamed output attribute, which by convention is the name.
copy(string aPrefix,string aName) is a variant of copy() that prefixes aPrefix to the copied output attributes.

set_int(uint32_t aValue,uint32_t aMask,int32_t aShift) sets the integer attribute, masked by aMask, to aValue shifted left by aShift.
set_int(uint32_t aValue,uint32_t aMask) sets the integer attribute, masked by aMask, to aValue (i.e., aShift = 0).
set_int(uint32_t aValue) sets the integer attribute to aValue (i.e, aMask = 0xFFFFFFFF and aShift = 0).

set_int_low(uint32_t aValue) is the same as set_int(aValue,0x1FFFF,0); it sets the low 17 bits of the integer attribute.

set_road(uint32_t aValue,uint32_t aMask,int32_t aShift) sets the road attribute, masked by aMask, to aValue shifted left by aShift.
set_road(uint32_t aValue,uint32_t aMask) sets the road attribute, masked by aMask, to aValue (i.e., aShift = 0).
set_road(uint32_t aValue) sets the road attribute to aValue (i.e, aMask = 0xFFFFFFFF and aShift = 0).

set_one_way_forward() and set_one_way() are the same as set_road(16,48,0) and set the one-way state to forwards.
set_one_way_backward() is the same as set_road(32,48,0) and sets the one-way state to backwards.
set_roundabout() is the same as set_road(4,4,0) and sets the roundabout flag.
set_toll() is the same as set_road(2,2,0) and sets the toll flag.
set_level(int32_t aLevel) is the same as set_road(uint32_t(aLevel),0xF000,12) and sets the level, which must be in the range -8...7.
set_bridge() is the same as set_road(0x1000,0x1000,0) and sets the bridge flag.
set_tunnel() is the same as set_road(1,1,0) and sets the tunnel flag.

set_road_type(string aName) Sets the road type (by convention, bits 6...11 of the road attribute) to the predefined value in aName, which must be one of Motorway, MotorwayLink, TrunkRoad, TrunkRoadLink, PrimaryRoad, PrimaryRoadLink, SecondaryRoad, SecondaryRoadLink, TertiaryRoad, TertiaryRoadLink, UnclassifiedRoad, ResidentialRoad, Track, ServiceRoad, PedestrianRoad, VehicularFerry, PassengerFerry, Other0 ... Other7. Case is insignificant, and values are matched on the first five characters of aName, plus a suffix of 'link' to indicate a link road, or a digit suffix to indicate a road of type other0...other7.

start_group() and end_group() work like the <group> ... </group> element in the XML import rules.

is_osm_node() returns true if the input object is an OSM node.
is_osm_way() returns true if the input object is an OSM way.
is_osm_relation() returns true if the input object is an OSM relation.

filename() returns the current input file name if known.

size() returns the size of an object in meters, measured as the diagonal of its bounding box.

 

This release on 26th April 2019 based on mainline revision 8175.

Previous release 5.6 on 11th February 2019 based on mainline revision 7972.

General

Turn instructions now work properly for contraction hierarchy routing.
The navigation states have been changed; there are different states and their meanings are different.

The Maps App

The style sheet editor is now a non-modal dialog.

Framework API

Added functions to display turn instructions during navigation, including a turn diagram.
Made the current view state serialisable so that it can be saved and reloaded by apps.

C++ API

Deprecated synonyms for enum class constants have been removed.
TPerspectiveParam now stores its terrain position in degrees for convenient serialisation.
TViewState now stores its terrain position in degrees for convenient serialisation.
Removed CFramework::Name(), which was redundant.
Added functions to enable and disable turn instruction display, and to override automatic turn instructions.
AddNavigatorObserver now takes a weak pointer, not a raw pointer.
Added setters and getters for the navigation parameters.
Removed deprecated function GetNearestRoad; use FindNearestRoad.

.NET API

The NavigationState enum class has changed in both its state constants and their meanings.
Added the PerspectiveParam class to allow setting and getting of perspective parameters.
Added the ViewState class to allow setting and getting of the view state.
Added the NavigatorParam class to allow setting and getting of the navigator parameters.
Added SetTurnInstructions, EnableTurnInstructions, SetTurnInstructionText and TurnInstructionText to control the display of turn instructions.
Added the CreateWritableMap, MapHandle, MapIsWritable, and EnableAllMaps functions to control the current maps.
Added a LoadFont overload which takes data in memory.
Added a SetPerspective overload which takes a PerspectiveParam object, and GetPerspectiveParam to return the current perspective parameters.
Added RotateAndZoom to rotate and zoom simultaneously.
Added a SetView overload with a ViewState parameter to set the view to a view state, and GetViewState to get the current view state.
Removed the deprecated GetNearestRoad function; use FindNearestRoad.
Added AddTurnLine to the Legend class to allow turn instructions to be added to a legend notice.

Android API

The NavigationState enum class has changed in both its state constants and their meanings.
Added the PerspectiveParam class to allow setting and getting of perspective parameters.
Added the ViewState class to allow setting and getting of the view state.
Added the NavigatorParam class to allow setting and getting of the navigator parameters.
Simplified the names of the RoadType constants and added useful new ones matching those in the C++ API.
Added setTurnInstructions, enableTurnInstructions, setTurnInstructionText and turnInstructionText to control the display of turn instructions.
Added resolutionDpi to get the display resolution.
Added a setPerspective which takes a PerspectiveParam object, and getPerspectiveParam to return the current perspective parameters.
Added a setView overload with a ViewState parameter to set the view to a view state, and getViewState to get the current view state.
Added setNavigatorParam and getNavigatorParam to set and get the navigator parameters.
Removed the unneeded positionKnown function.
Added onTap, onDoubleTap and onLongPress as overridable functions to MapView to allow apps to respond to tap, double tap and long press gestures more easily.

iOS API

The CartoTypeNavigationState enum struct has changed in both its state constants and their meanings.
Added the CartoTypePerspectiveParam class to allow setting and getting of perspective parameters.
Added the CartoTypeViewState class to allow setting and getting of the view state.
Added the CartoTypeNavigatorParam class to allow setting and getting of the navigator parameters.
Added setTurnInstructions, enableTurnInstructions, setTurnInstructionText and turnInstructionText to control the display of turn instructions.
Added a setPerspective overload which takes a CartoTypePerspectiveParam object, and getPerspectiveParam to return the current perspective parameters.
Added a setView overload with a CartoTypeViewState parameter to set the view to a view state, and getViewState to get the current view state.
Removed the unneeded navigationPositionKnown function.
Added setNavigatorParam and getNavigatorParam to set and get the navigator parameters.
Removed the deprecated getNearestRoad function; use findNearestRoad.
CartoTypeViewController now handles a transition to a new display size, as caused by rotating a phone from portrait to landscape, correctly.

Important changes made during the lifetime of release 5.6

fixed case 2451: slow text search when map split into contours and main data
the route table start position is now zero when it was not written because there were no routable objects; that causes it to be ignored, as desired
fixed very large road lengths in turn-expanded router caused by part of road seeming longer than the whole road when measured in a different way, causing a negative length for the second part which wrapped round to large positive because it was unsigned
fixed case 2452: turn-expanded router cannot calculate a route ending on a restricted road
initial fix for case 2219: hill shading is offset; not perfect but an improvement
added support for fling gestures (pan with momentum) to the Android and iOS UI code, and changed the demo programs to use the new system
fixed case 2454: loading a second map enables notices erroneously
added support for turn instruction display
fixed case 2456: casting NaN to integer causes floating point exception on Embarcadero
fixed case 2458: iOS map renderer doesn't handle change from portrait to landscape
added functions to set and get the view state and perspective parameters to all APIs
added functions to serialise the view state and perspective parameters to all APIs
added setters and getters for navigation parameters to all APIs
fixed assertion in CFastPath when a contour had no points
fixed incorrect roundabout exit numbers
fixed case 2468: empty legend causes crash
makemap didn't compile using GCC 8.2.1 because of an incorrect template argument
determination of whether a road was a link was wrong in CRoute::AppendSegment
fixed case 2474: turn instructions are wrong when using CH routing
improved turn instructions for the turn-expanded router
ctm1_info can now suppress layer information and apply an extent
some roofs were not displayed properly (e.g., main dome of St Pauls) because of conversion from double to float causing unexpected comparison result
ctm1_info ran out of memory on map of Britain and Ireland so added 64-bit configuration
fixed case 2477: some building walls missing in 3D mode
added overridable gesture handlers to MapView on Android
fixed case 2483: black background when world map is zoomed out
simplified road type names in the Android SDK and added missing flags and types
fixed case 2482: flickering on Android when perspective angle is 20 degrees
fixed case 2487: some island names are duplicated and many point islands were not converted to polygons
shifts were not applied to the set_int instruction in the import rules language
implemented case 2488: use Zlevels.shp to offset roads by their level when importing Navstreets data
the framework observer is now a weak pointer to avoid dereferencing a freed pointer; fixes case 2489: iOS framework crashes when deallocating the framework

 

Release date: 12th February 2019

Previous release: 5.4, 23rd October 2018

General

Isochrones (travel ranges) now work for the turn-expanded router

Turn-expanded router data can now be stored in serialized form, for fast loading, in CTM1 (map) files

Address data can be added to map objects at data preparation time for use by a new function, GetAddressFast, which uses data only from the map object for which an address is required

 

makemap

Turn-expanded routing data can now be created in serialized form as part of a CTM1 (map) file using /route=t; it is loaded automatically by the framework if present

Different extents can now be applied to different input files by appending the extent, after a comma, to the filename

A new option, /setaddresslayers= adds address data for use by GetAddressFast

Framework API

Added ExpiryDate and AppBuildDate

Added a SetView function which takes a geometry object

Added SetViewToWholeMap, which replaces SetViewToFillMap where present

Added SetViewToRoute

Added InsertPushPin

Added GetAddressFast, which uses information added by the /setaddresslayers makemap option

FindNearestRoad replaces GetNearestTRoad, which is now deprecated, and optionally displays the found position

C++ API

Standard integer types (uint8_t, int32_t, etc.) are used in the public API instead of the equivalent CartoType-specific types (CartoType::uint8, CartoType::int32, etc.), which are now obsolete and used internally only.

Abolished CBitmapGraphicsContext; CGraphicsContext is now a bitmap GC class

 

Changes made during the lifetime of the previous release, 5.4

fixed memory leak caused by failure to delete CNotice objects
fixed case 2365: triangle on boxed label causes hang; parser didn't handle syntactically incorrect labelFormat attribute properly
one overload of readMap in Android was public, not private as it should have been
fixed case 2366: windows demo turns legend on when the style sheet is reloaded
fixed case 2280: when two graphics accelerated windows are open in the Windows demo, one or both redraw slowly
fixed case 1944: (regression) forbidden areas didn't work properly with pedestrian routes
reduced the default vector tile cache size and made it adapt to the number of tiles needed to cover the display; saves about 200Mb of RAM per map on Windows
repeated SVG symbols were drawn in the wrong place in graphics-accelerated mode
fixed case 2369: reloading a style sheet turns off the GL style sheet variable
forbidden areas no longer change the road type to 'unknown', which might prevent some route profiles from working; and overlapping speed restrictions now cause the greater restriction to be used
fixed case 2372: repeated symbols using SVG are sometimes drawn transparently when graphics acceleration is used
fixed cases 2373 and 2376: Android version crashed when creating a RouteProfile or FindParam object
fixed case 2374: access violation with multiple maps on Windows
fixed case 2375: FindAddress suppresses the building number, and returned items are duplicated
fixed case 2385: MapRenderer.Valid() returns false on .NET even if the map renderer is correctly constructed
navigation, rotation and zoom now work properly in the Swift demo
the turn-expanded router now supports forbidden areas
fixed case 2401: findStreetAddresses hangs; simplified complicated clip paths and restricted the maximum internal number of map objects to be found
new feature: changes to the map view are smoothly animated during navigation; animation can also be turned on at other times
fixed case 2406: setting the map view to a map object didn;t work properly when the map was rotated, or in perspective mode
added dependencies to the EGL libraries to the windows demo projects
new feature: changes to the current location, when displayed using the route-vector layer, are smoothly animated
simplified the way the standard style sheet displays the route and vehicle location
headings were not matched properly when finding the nearest road
fixed case 2430: CProj4Projection is not thread safe
made it illegal to create a TBitmap from a CBitmap, to avoid errors caused by using a TBitmap instead of a CBitmap to receive return values from functions returning CBitmap
fixed case 2435: SetLegend causes a crash in .NET
fixed case 2436: crash in iOS when zooming out a lot during navigation
fixed case 2439: and don't always work properly with graphics acceleration
setViewObjects now works correctly in Java

 

Release date: 23rd October 2018

Previous release: 5.2, 12th July 2018

Summary of changes

SetScaleBar, SetLegend, SetCopyright and other new functions allow scale bars, legends (map keys) and copyright notices to be added to the map easily, and to be displayed properly when using hardware graphics acceleration.

Boxed labels for point objects can now optionally have small triangular pointers which indicate the exact position of the point object.

The makemap tool can now write multiple output maps from the same set of input data; any number of pairs of extent and output file name can be provided.

There are geodesic functions (straight-line distance between two points, and the azimuth functions) which use accurate functions based on the WGS84 ellipsoid, not spherical approximations. The spherical approximation is still used internally where speed is more important than accuracy.

The Android API now mostly uses enums, not integer constants.

 

It's possible to use the makemap tool to create very large CartoType maps (CTM1 files), up to and including a map of the whole world using the full OpenStreetMap data file planet.osm. The easiest and fastest way is to use lots of RAM.

... 

CartoType's graphics acceleration system gives you a smooth, fast, fluid user experience, with no delays when panning or zooming the map. Drawing speeds of up to 30 frames per second are supported.

... 

This document explains the CartoTypeRouteProfile XML format, used in .ctprofile files. These files are used to store route profiles, which are used to customize the behavior of the route calculation system. For example, it's possible to make some types of roads more or less preferable than others, or to forbid them entirely, and to set the type of vehicle, for instance to a car, heavy goods vehicle or bicycle.

... 

Here are answers to some questions frequently asked about CartoType.

... 

CartoType uses a standard set of map layers and attributes. These are used by the import rules built into makemap, and by the standard style sheet. You can override them completely by using your own import rules and style sheets, but it is better to use the standard set, adding new layers and attributes where needed, or omitting unnecessary ones. The reason for using the standard set is that they used by the address searching system. In general, attributes and layers are described according to how they are imported from OpenStreetMap data.

... 

Apple introduced the Swift programming language in 2014. It has now largely replaced Objective C to become the language of choice for iOS applications. However, CartoType's iOS API is written in Objective C. This article explains how to use the CartoType iOS SDK in a Swift project. You can use CartoType completely from Swift. There is no need to write any Objective C.

... 

There are several standard platform SDKS. This page tells you what languages they support and the files they consist of.

... 

CartoType uses XML style sheets to control the appearance of maps. Features that can be controlled include the following:

  • selection of layers
  • colors
  • transparency
  • size of features
  • SVG icons
  • lettering style and positioning
  • scales at which features appear

Style Sheets Directory

You can create CartoType maps (CTM1 files) from OpenStreetMap data, ESRI shapefiles, SRTM elevation data and other sources using the makemap tool.

... 

fast offline routing

The standard routing system, suitable for any maps on desktop platforms and servers, and city maps on mobile devices, is flexible and fast.

route profiles

Route profiles tell CartoType how fast you expect to travel on different types of road, and also allow you to add weightings to indicate your preference. The free Maps app, available for Windows, Mac OS X and Linux, provides an easy way to try out different route profiles. You can choose from four standard profiles, and an editable custom profile, using the Route menu (first image below). The command 'Edit Custom Route Profile...' brings up the Route Profile Editor dialog (second image below).

... 

CartoType can show terrain on a map in various different ways:

height coloring: using different colors for different heights. Colors can be blended or drawn as distinct steps. All this is controlled using a height ramp in the style sheet.

nz terrain height coloring

... 

We supply a full Android Java API for CartoType which provides the same functionality as the C++ API. The SDK, which you can download here, includes an AAR file (Android library) which you can easily add to your Android Studio project. You can also access a sample CartoType project, which contains the source code and project files for a simple program called TestGL, which displays a map using CartoType's hardware graphics acceleration system.

Use the free Android Studio IDE for developing Android applications.

... 

The usual way to develop apps for iOS, the operating system used on Apple's iPhone and iPad devices, is by means of XCode, a free development environment which runs on Mac OS. We provide an iOS framework for CartoType. It allows you to use both Swift and Objective C to create CartoType apps.

A simple test app

You can download the source code of a simple test app which uses the CartoType evaluation library.

First get the test project source files for either Swift or Objective C.

Open the project in Xcode on a Macintosh.

Add the CartoType evaluation framework to the project.

Add the map, style sheet and font to the project.

You can then run it in the simulator or on an iOS device. The CartoType evaluation library is built for, and works on, both the 32-bit (Arm7) and 64-bit (Arm64) iOS environments.

The code is largely self-explanatory. It loads and displays a map, and allows the user to pan, zoom and rotate the map using gestures. You can create a route by clicking successively on two points It is designed as a minimal app, and therefore is deliberately very simple.

...