CAMotics Online

2 TPLang

2.1 About TPLang

TPLang (Tool Path Language) is a programming language that makes toolpaths for CNC machines. A TPLang program is a JavaScript program. TPLang adds functions that move the tool, set the feed rate, select tools and do other machine operations.

The output of a TPLang program is G-code. CAMotics reads this G-code in the same way as a G-code file that you write yourself. Thus, you can use all of JavaScript to calculate a toolpath: variables, loops, functions, objects and the Math object.

The authority for the language is tplang.org. This chapter tells how TPLang operates in CAMotics Online. Where CAMotics Online is different from the desktop version, this chapter tells you.

TPL files have the extension .tpl. In the project file list, a TPL file is a program, the same as a G-code file.

2.2 How a TPL program runs

When you update the toolpath, the server runs each TPL program in the project file list. The server runs the programs in a sandbox. The sandbox has no network connection and no access to other files on the server.

  1. The server starts the program at the first line.
  2. Each move function, for example cut(), writes one or more lines of G-code.
  3. When the program ends, the server reads the G-code that the program made.
  4. CAMotics makes the toolpath from this G-code, together with the other programs in the project.

The G-code always starts with G21 G90 (millimeters, absolute positions) and ends with M2. CAMotics writes all positions in millimeters, also when the program uses inches.

If the program has an error, the toolpath stops. CAMotics shows the error message with the file name and the line number. Errors in a module that you load with require() show the line in that module.

The JavaScript engine is V8. Thus, you can use modern JavaScript, for example let, const, arrow functions and template strings.

2.3 A first program

This program cuts a square of 10 mm by 10 mm, 3 mm deep. Each line has a comment that tells what it does.

square.tpl
units(METRIC);   // Use millimeters
feed(400);       // Set the feed rate to 400 mm/min
tool(1);         // Select tool 1 from the tool table

rapid({z: 5});        // Move up to a safe height of 5 mm
rapid({x: 1, y: 1});  // Move to the start position
speed(2000);          // Turn the spindle clockwise at 2000 RPM

cut({z: -3});   // Cut down to the depth
cut({x: 11});   // Cut to the second corner
cut({y: 11});   // Cut to the third corner
cut({x: 1});    // Cut to the fourth corner
cut({y: 1});    // Cut back to the start

rapid({z: 5});  // Move up to the safe height
speed(0);       // Stop the spindle

To run this program, do these steps:

  1. Click Open as a project above the program.
  2. Update the toolpath.
  3. Simulate the toolpath.

2.4 Functions and arguments

Most TPLang functions have named arguments. You can give the arguments in two ways:

  • In order, as in JavaScript: rapid(5, 10, 15).
  • As an object with the names of the arguments: rapid({x: 5, y: 10, z: 15}).

With an object, you can give only the arguments that you need, in any order. The other arguments keep their default values. These three calls do the same thing:

TPL
rapid(5, 10, 15);
rapid({x: 5, y: 10, z: 15});
rapid({z: 15, x: 5, y: 10});

The reference gives the arguments of each function, with their names, types and default values.

2.5 Units

A TPL program starts in metric units. In metric units, lengths are in millimeters and feed rates are in millimeters per minute.

To use inches, call units(IMPERIAL). After this call, all lengths that you give and all positions that you get are in inches. Feed rates are in inches per minute. To go back to millimeters, call units(METRIC).

When you read a DXF or STL file, the numbers in the file have no units. Use the units that the file was drawn in. For example, if the drawing is in millimeters, call units(METRIC) before you cut it.

2.6 Coordinates and positions

TPLang uses the same axes as G-code. The linear axes are X, Y and Z. The rotary axes are A, B and C. U, V and W are secondary linear axes. All move functions accept the nine axes x, y, z, a, b, c, u, v and w.

Positions are absolute: cut({x: 10}) moves the tool to X = 10. An axis that you do not give stays at its current position.

The functions irapid() and icut() use incremental positions. icut({x: 10}) moves the tool 10 units in the positive X direction from its current position. You can also give incremental: true to rapid() or cut().

To get the current position, use position(). It returns an object with the nine axes, for example {x: 1, y: 1, z: -3, a: 0, ...}. This is the position in the program's coordinates, before the transforms.

A program starts at position 0 on all axes.

2.7 The tool and the tool table

The project has a tool table. Each tool in the table has a number, a shape, a diameter and a length. Edit the tool table in the project settings.

To select a tool, call tool(number). This writes M6 Tn to the G-code. The simulation uses the shape of this tool from the tool table.

tool() also returns the data of the tool from the tool table. With no argument, it returns the data of the current tool. Use this data to calculate offsets from the tool size:

TPL
tool(1);
var radius = tool().diameter / 2;

If the tool table does not have the tool, tool() returns undefined.

2.8 Feed rate and spindle speed

The feed rate is the speed of the tool in cut moves. Set it with feed(rate). The feed rate stays the same until you set it again.

The spindle speed is in revolutions per minute (RPM). Set it with speed(rate). A positive speed turns the spindle clockwise (M3). A negative speed turns it counterclockwise (M4). A speed of zero stops the spindle (M5).

TPL
feed(600);     // 600 mm/min
speed(12000);  // 12000 RPM, clockwise

2.9 Rapid moves and cut moves

A rapid move (rapid(), G0) moves the tool at the maximum speed of the machine. Use rapid moves only when the tool is out of the material.

A cut move (cut(), G1) moves the tool in a straight line at the feed rate. Use cut moves when the tool is in the material.

A typical pattern is:

  1. Move up to a safe height with rapid({z: zSafe}).
  2. Move above the start point with rapid(x, y).
  3. Move down into the material with cut({z: zCut}).
  4. Cut along the shape with cut(), icut() or arc().
  5. Move up to the safe height with rapid({z: zSafe}).

2.10 Arcs and helixes

The arc() function moves the tool on an arc or a full circle at the feed rate. If you give a Z offset, the move is a helix.

The arguments x and y give the position of the center, relative to the current position. The angle argument gives the angle of rotation in radians. Math.PI * 2 is one full turn.

helix.tpl
feed(300);
rapid({z: 3});
rapid(-5, 0);   // The center of the hole is at (0, 0)
cut({z: 0});

// Three turns down to Z = -3, then one turn at Z = -3
arc({x: 5, z: -3, angle: Math.PI * 2 * 3});
arc({x: 5, angle: Math.PI * 2});

rapid({z: 3});

A positive angle makes a clockwise arc (G2). A negative angle makes a counterclockwise arc (G3). To cut part of a circle, calculate the points and use cut() for each point:

TPL
// A quarter circle, counterclockwise, radius 10, center (0, 0)
var steps = 30;
for (var i = 0; i <= steps; i++) {
  var a = Math.PI / 2 * i / steps;
  cut(10 * Math.cos(a), 10 * Math.sin(a));
}

2.11 Transforms

A transform changes the positions of all moves that come after it. With transforms, you can write a shape one time and cut it at different positions, angles and sizes.

  • translate(x, y, z) moves the origin of the moves.
  • rotate(angle) turns the moves about the Z axis through the current origin. A positive angle turns counterclockwise.
  • scale(x, y, z) makes the moves larger or smaller.

The transforms add to each other. To go back to an earlier transform, save it with pushMatrix() and restore it with popMatrix():

squares.tpl
function square(size, depth, safe) {
  cut({z: depth});    // Cut down to the depth
  icut({x: size});    // Cut to the second corner
  icut({y: size});    // Cut to the third corner
  icut({x: -size});   // Cut to the fourth corner
  icut({y: -size});   // Cut back to the start
  rapid({z: safe});   // Move up to the safe height
}

feed(400);
tool(1);
rapid({z: 5});

for (var i = 0; i < 12; i++) {
  pushMatrix();                // Save the transform
  rotate(Math.PI * 2 * i / 12);
  translate(5, 0);
  rapid(0, 0);
  square(10, -1, 5);
  popMatrix();                 // Restore the transform
}

Some rules tell how the transforms add to each other:

  • translate() moves the origin in the current coordinates. If you call rotate() before translate(), the translation turns too.
  • rotate() turns about an axis through the current origin. To turn about a different point, give that point in the arguments a, b and c.
  • scale() changes all distances from the machine origin, also the distances that translate() set before or after it.

The transforms change the G-code positions. They do not change the positions that you give or get in the program: position() and getXYZ() return the positions before the transform.

2.12 Offsets

The offset() function makes a polygon larger or smaller by a distance. It uses the Clipper library. Use it to calculate a toolpath at the correct distance from a shape, or to make a pocket.

A polygon is an array of points. A point is {x: 1, y: 2} or [1, 2]. offset() takes an array of polygons and returns an array of polygons. A positive distance makes the polygons larger. A negative distance makes them smaller. If the distance is too large, the result is an empty array.

This program cuts a square pocket. It cuts the outline of the pocket, then smaller outlines until nothing is left.

pocket.tpl
var zSafe = 3;
var depth = -2;
var step = 1.5;  // Less than the tool diameter

var outline = [[{x: 0, y: 0}, {x: 30, y: 0}, {x: 30, y: 20},
                {x: 0, y: 20}]];

feed(500);
tool(1);
rapid({z: zSafe});

// The first path is half the tool diameter inside the outline
var polys = offset(outline, -tool().diameter / 2);

while (polys.length) {
  for (var poly of polys) {
    rapid({z: zSafe});
    rapid(poly[0].x, poly[0].y);
    cut({z: depth});
    for (var p of poly) cut(p.x, p.y);
    cut(poly[0].x, poly[0].y);  // Close the polygon
  }
  polys = offset(polys, -step);
}

rapid({z: zSafe});

2.13 DXF files

A DXF file is a 2D drawing. To read a DXF file, load the dxf module with require('dxf'). Then call dxf.open(path).

  1. Add the DXF file to the project.
  2. In the TPL program, load the module: var dxf = require('dxf');
  3. Read the file: var layers = dxf.open('drawing.dxf');
  4. Cut a layer with a function of the module, for example dxf.layer_cut().

dxf.open() returns an object with one property for each layer of the drawing. The name of the property is the name of the layer. Each layer is an array of the entities in that layer: points, lines, arcs, polylines and splines.

TPL
var dxf = require('dxf');
var layers = dxf.open('logo.dxf');

units(METRIC);  // Use the units of the drawing
feed(1600);
rapid({z: 3});

// Cut the layer "Outline" 1.5 mm deep, 0.5 mm outside the lines
dxf.cut_layer_offset(layers.Outline, 0.5, 3, -1.5);
rapid({z: 3});

The dxf module has functions that cut layers, change layers to polygons and offset them. See the DXF reference.

2.14 STL files

An STL file is a 3D surface made of triangles. Load the stl module with require('stl') and read a file with stl.open(path).

The module calculates contours: the lines where a horizontal plane cuts the surface. Use the contours to cut a 3D shape in layers.

TPL
var stl = require('stl');
var model = stl.open('part.stl');
var bounds = stl.bounds(model);   // [[minX, minY, minZ], [maxX, maxY, maxZ]]

var levels = stl.contour({stl: model, start: bounds[1][2],
                          end: bounds[0][2], steps: 20});

feed(400);
for (var level of levels)
  for (var c of level.contours) {
    rapid({z: level.Z + 1});
    rapid(c[0].X, c[0].Y);
    cut({z: level.Z});
    for (var p of c) cut(p.X, p.Y);
  }

STL files can be large. A large file can make the program slow or use too much memory. See Limits.

2.15 G-code in a TPL program

You can put G-code into a TPL program in two ways:

  • gcode(path) reads a G-code file from the project and runs it.
  • gexec(code) runs the G-code in a string.

CAMotics reads the G-code and writes the moves again in its own format. It does not copy the G-code text. Thus, the codes that CAMotics does not run are lost. See the G-code chapter.

TPL
gexec('G0 X0 Y0');
gcode('engrave.nc');

2.16 Modules

A module is a file of code or data that a program loads with require(). Use modules to share functions between programs.

A module can be:

  • A .tpl or .js file. CAMotics runs the code. The module gives its values to the program in module.exports.
  • A .json file. CAMotics reads the data.
  • A directory with a package.json file. The main property of package.json gives the file to load.

For example, a module shapes.tpl:

TPL
module.exports = {
  square: function (size) {
    icut({x: size}); icut({y: size});
    icut({x: -size}); icut({y: -size});
  }
};

A program loads it with a path that starts with ./:

TPL
var shapes = require('./shapes.tpl');
shapes.square(10);

In CAMotics Online, require() loads only these modules:

  • Files in the project, with a path that starts with ./.
  • The modules of CAMotics: dxf and stl, and the TPL library that comes with CAMotics.

If modules load each other in a loop, a value can be undefined while a module loads. See tplang.org for an example.

2.17 Comments, messages and the log

  • comment(text) writes a G-code comment, for example (Pocket 1).
  • message(text) writes a G-code message, (MSG, text).
  • console.warn() and console.error() write a warning. CAMotics shows it with the file name and the line number.
  • console.log() and console.debug() write to the log. CAMotics Online does not show the log.

2.18 Limits

CAMotics Online sets limits on a TPL program. These limits stop a program that does not end or that is too large.

LimitDefault valueWhat occurs
G-code lines50 000 000 linesThe program stops with the error "TPL program exceeded the limit of ... G-code lines".
Memory512 MB for JavaScriptThe program stops with the error "TPL program ran out of memory".
TimeSet by the serverThe job stops.
FilesOnly the project and the TPL libraryThe function stops with the error "only files in the project and the TPL library are allowed".

The server can use different values. A program that stops at a limit makes no toolpath.

2.19 Reference: tool movement

2.19.1 rapid()

Syntax
rapid(x, y, z, a, b, c, u, v, w, incremental=false)

Moves the tool in a straight line at the rapid speed (G0).

NameTypeDefaultDescription
x … wnumbercurrent positionThe position on that axis. Give only the axes that move.
incrementalbooleanfalseIf true, the values are distances from the current position.

Returns nothing. If a value is not a finite number, the program stops with an error.

TPL
rapid(0, 0, 0);         // Move to x = 0, y = 0, z = 0
rapid(10, 10);          // Move to x = 10, y = 10; z stays at 0
rapid({z: 10, y: 20});  // Move to y = 20, z = 10; x stays at 10

2.19.2 irapid()

Syntax
irapid(x, y, z, a, b, c, u, v, w, incremental=true)

The same as rapid(), but the values are distances from the current position.

TPL
irapid({z: 5});  // Move up 5 units

2.19.3 cut()

Syntax
cut(x, y, z, a, b, c, u, v, w, incremental=false)

Moves the tool in a straight line at the feed rate (G1). The arguments are the same as for rapid().

NameTypeDefaultDescription
x … wnumbercurrent positionThe position on that axis.
incrementalbooleanfalseIf true, the values are distances from the current position.

Returns nothing.

TPL
feed(400);
cut({z: -1});   // Move down into the material
cut(20, 0);     // Cut to x = 20, y = 0

2.19.4 icut()

Syntax
icut(x, y, z, a, b, c, u, v, w, incremental=true)

The same as cut(), but the values are distances from the current position.

TPL
icut({x: 10});   // Cut 10 units in the +X direction
icut({y: -5});   // Cut 5 units in the -Y direction

2.19.5 arc()

Syntax
arc(x=0, y=0, z=0, angle=Math.PI*2, plane=XY, incremental=true)

Moves the tool on an arc or a helix at the feed rate (G2 or G3). See Arcs and helixes.

NameTypeDefaultDescription
x, ynumber0The center of the arc, relative to the current position.
znumber0The change in height. If it is not zero, the move is a helix.
anglenumber (radians)Math.PI * 2The angle of rotation. Positive is clockwise (G2). Negative is counterclockwise (G3). More than one turn is permitted.
planeconstantXYThe plane of the arc: XY, XZ or YZ.
incrementalbooleantrueIf false, x, y and z give the absolute position of the center.

Returns nothing.

TPL
rapid(-10, 0);
cut({z: -1});
arc({x: 10, angle: Math.PI * 2});  // A circle of radius 10 about (0, 0)

2.19.6 probe()

Syntax
probe(x, y, z, a, b, c, u, v, w, port=0, active=true, error=true)

Moves the tool toward a position until the probe input changes. On a real machine, this measures the position of the workpiece.

NameTypeDefaultDescription
x … wnumbercurrent positionThe position to move to.
portnumber0The input to monitor.
activebooleantrueIf true, stop on contact. If false, stop when the contact is lost.
errorbooleantrueIf true, it is an error if the input does not change.

Returns nothing.

TPL
feed(100);
probe({z: -10});  // Move down until the probe touches

2.19.7 dwell()

Syntax
dwell(seconds)

Stops all axes for a time (G4). The spindle continues to turn.

NameTypeDefaultDescription
secondsnumbernoneThe time to wait, in seconds. Fractions are permitted.

Returns nothing.

TPL
speed(10000);
dwell(2);  // Wait 2 seconds for the spindle to get to its speed

2.20 Reference: machine state

2.20.1 feed()

Syntax
feed(rate, mode)

Sets the feed rate for the cut moves that come after it (F).

NameTypeDefaultDescription
ratenumbernoneThe feed rate, in units per minute.
modeconstantno changeFEED_UNITS_PER_MIN (G94), FEED_INVERSE_TIME (G93) or FEED_UNITS_PER_REV (G95).

Returns the feed rate. With no arguments, it does not change the feed rate and returns [rate, mode].

In FEED_INVERSE_TIME mode, each move takes 1/rate minutes. In FEED_UNITS_PER_REV mode, the rate is in units per revolution of the spindle.

TPL
feed(400);             // 400 units per minute
var rate = feed()[0];  // Get the feed rate

2.20.2 speed()

Syntax
speed(rate, surface, max)

Sets the spindle speed and direction (S with M3, M4 or M5).

NameTypeDefaultDescription
ratenumbernoneRevolutions per minute. Positive is clockwise, negative is counterclockwise, zero stops the spindle.
surfaceanynoneIf you give it, the speed is a constant surface speed (G96): rate is in meters per minute (metric) or feet per minute (imperial).
maxnumbernoneWith surface: the maximum RPM.

Returns the speed. With no arguments, it returns [rate, mode], and the maximum RPM if there is one.

TPL
speed(1000);    // 1000 RPM, clockwise
speed(-20000);  // 20000 RPM, counterclockwise
speed(0);       // Stop the spindle

2.20.3 tool()

Syntax
tool(number)

Selects a tool from the tool table (M6 Tn).

NameTypeDefaultDescription
numbernumbernoneThe tool number. With no number, the current tool does not change.

Returns the data of the tool, or undefined if the tool table does not have the tool:

PropertyDescription
numberThe tool number.
shapeCYLINDRICAL, CONICAL, BALLNOSE, SPHEROID or SNUBNOSE.
lengthThe length of the tool, in the current units.
diameterThe diameter of the tool, in the current units.
angleOnly for CONICAL: the angle of the point, in degrees.
snub_diameterOnly for SNUBNOSE: the diameter of the tip.
TPL
tool(2);
var radius = tool().diameter / 2;

2.20.4 units()

Syntax
units(type)

Sets the units of the program.

NameTypeDefaultDescription
typeconstantnoneMETRIC (millimeters) or IMPERIAL (inches).

With no argument, it returns the current units, METRIC or IMPERIAL. See Units.

TPL
units(IMPERIAL);
if (units() == IMPERIAL) feed(20);

2.20.5 pause()

Syntax
pause(optional=false)

Stops the program until the operator starts it again (M0, or M1 if optional).

NameTypeDefaultDescription
optionalbooleanfalseIf true, the machine stops only when its optional stop switch is on.

Returns nothing.

TPL
pause();  // Stop here so that the operator can turn the workpiece

2.20.6 workpiece()

Syntax
workpiece()

Returns the dimensions and the position of the workpiece from the project settings, in the current units:

TPL
var w = workpiece();
// {dims: {x: 100, y: 100, z: 10}, offset: {x: -50, y: -50, z: -10}}

offset is the corner of the workpiece with the minimum X, Y and Z.

2.20.7 position()

Syntax
position()

Returns the current position as an object: {x, y, z, a, b, c, u, v, w}. The position is before the transforms.

TPL
var p = position();
cut(p.x + 10, p.y);

2.21 Reference: transforms

The transform functions have an optional last argument matrix. It selects the transform of a group of axes: 0 for X, Y and Z (the default), 1 for A, B and C, 2 for U, V and W.

2.21.1 pushMatrix()

Syntax
pushMatrix(matrix)

Saves a copy of the current transform. popMatrix() restores it. You can save more than one transform.

TPL
pushMatrix();
translate(50, 0);
cutShape();
popMatrix();  // The origin is back at (0, 0)

2.21.2 popMatrix()

Syntax
popMatrix(matrix)

Restores the transform that the last pushMatrix() saved. If no transform is saved, the program stops with the error "Transform stack empty".

2.21.3 loadIdentity()

Syntax
loadIdentity(matrix)

Removes all transforms from the current transform. The saved transforms do not change.

2.21.4 translate()

Syntax
translate(x=0, y=0, z=0, matrix)

Moves the origin of the moves that come after it.

NameTypeDefaultDescription
x, y, znumber0The distance to move the origin.
TPL
translate(20, 10);
cut(0, 0);  // Cuts to (20, 10)

2.21.5 rotate()

Syntax
rotate(angle, x=0, y=0, z=1, a=0, b=0, c=0, matrix)

Turns the moves that come after it about an axis.

NameTypeDefaultDescription
anglenumber (radians)noneThe angle. Positive is counterclockwise when you look from the positive end of the axis.
x, y, znumber0, 0, 1The direction of the axis. The default is the Z axis.
a, b, cnumber0, 0, 0A point on the axis, in the current coordinates.

If the direction is (0, 0, 0), the program stops with an error.

TPL
rotate(Math.PI / 2);  // Turn 90 degrees counterclockwise about Z
cut(10, 0);           // Cuts to (0, 10)

2.21.6 scale()

Syntax
scale(x=1, y=1, z=1, matrix)

Makes the moves that come after it larger or smaller. The scale applies from the machine origin.

NameTypeDefaultDescription
x, y, znumber1The scale on each axis. A negative value mirrors that axis. Zero is not permitted.
TPL
scale(2, 2);   // Two times larger in X and Y
scale(-1);     // Mirror in X

2.21.7 setMatrix()

Syntax
setMatrix(m, matrix)

Sets the current transform to the 4 × 4 matrix m, an array of four rows of four numbers.

TPL
setMatrix([[1, 0, 0, 5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]);

2.21.8 getMatrix()

Syntax
getMatrix(matrix)

Returns the current transform as an array of four rows of four numbers.

TPL
var m = getMatrix();  // [[1, 0, 0, 0], [0, 1, 0, 0], ...]

2.21.9 getXYZ()

Syntax
getXYZ()

Returns the current position of X, Y and Z as an array [x, y, z], before the transforms.

2.21.10 getX(), getY(), getZ()

Syntax
getX()
getY()
getZ()

Each returns the current position on one axis, before the transforms.

TPL
cut({z: getZ() - 1});  // Cut 1 unit deeper

2.22 Reference: G-code and output

2.22.1 gcode()

Syntax
gcode(path)

Reads a G-code file and runs it. The path is relative to the TPL file. The file must be in the project.

TPL
gcode('engrave.nc');

2.22.2 gexec()

Syntax
gexec(code)

Runs the G-code in a string.

TPL
gexec('G0 X100 Y200');

2.22.3 comment()

Syntax
comment(...)

Writes each argument as a G-code comment on its own line.

TPL
comment('Pocket 1');  // (Pocket 1)

2.22.4 message()

Syntax
message(...)

Writes each argument as a G-code message, (MSG, text). Some machine controllers show the message to the operator.

TPL
message('Change to tool 2');

2.22.5 print()

Syntax
print(...)

Writes the arguments as text.

2.22.6 console.log(), console.warn()

Syntax
console.log(...)
console.debug(...)
console.warn(...)
console.error(...)

Writes the arguments to the log. CAMotics Online shows the output of console.warn() and console.error() as warnings, with the file name and the line number. It does not show the output of console.log() and console.debug().

TPL
console.warn('The depth is', depth);

2.23 Reference: offsets and modules

2.23.1 offset()

Syntax
offset(polys, delta, join, limit=1000, autoFix=true, scale=1000000)

Makes polygons larger or smaller. See Offsets.

NameTypeDefaultDescription
polysarraynoneAn array of polygons. Each polygon is an array of points, {x, y} or [x, y].
deltanumbernoneThe distance. Positive makes the polygons larger, negative makes them smaller.
joinconstantJOIN_ROUNDThe shape of the corners: JOIN_ROUND, JOIN_MITER or JOIN_SQUARE.
limitnumber1000With JOIN_MITER: the maximum distance of a corner.
autoFixbooleantrueCorrects the direction of the polygons and removes points that are the same.
scalenumber1000000Clipper calculates with integers. The points are multiplied by this value.

Returns an array of polygons, in the same point format as polys.

TPL
var square = [[[0, 0], [10, 0], [10, 10], [0, 10]]];
var inside = offset(square, -1);  // [[[9, 9], [1, 9], [1, 1], [9, 1]]]

2.23.2 require()

Syntax
require(path)

Loads a module and returns its module.exports. See Modules.

NameTypeDefaultDescription
pathstringnone'dxf', 'stl', a module of the TPL library, or a project file with a path that starts with ./. The extension .tpl, .js or .json is optional.
TPL
var dxf = require('dxf');
var lib = require('./lib.tpl');

2.24 Reference: DXF module

Load the module with var dxf = require('dxf');. The functions below are the ones that you use most. The module has more functions; see the file tpl_lib/dxf/dxf.tpl in the CAMotics source.

In this module, a polygon is an array of points {x, y, z}. A layer is an array of entities from dxf.open().

2.24.1 dxf.open()

Syntax
dxf.open(path)

Reads a DXF file. The path is relative to the TPL file. Returns an object with one array of entities for each layer. Each entity has a type:

TypeProperties
dxf.POINTx, y, z
dxf.LINEstart, end: points
dxf.ARCcenter: a point; radius; startAngle, endAngle: in degrees; clockwise
dxf.POLYLINEvertices: an array of points
dxf.SPLINEdegree; ctrlPts: an array of points; knots: an array of numbers
TPL
var layers = dxf.open('drawing.dxf');
var outline = layers.Outline;  // The layer "Outline"
var first = layers[0];         // A layer with the name "0"

2.24.2 dxf.layer_cut()

Syntax
dxf.layer_cut(layer, zSafe, zCut, res)

Cuts along all entities of a layer. It starts with the entity that is nearest to the tool and goes to the next nearest entity. Between entities that do not touch, it moves up to zSafe.

NameTypeDefaultDescription
layerarraynoneThe entities to cut.
zSafenumbernoneThe safe height.
zCutnumbernoneThe depth of the cut.
resnumber1 mmThe length of the segments for splines.
TPL
dxf.layer_cut(layers[0], 3, -1.5);

2.24.3 dxf.layer_cut_step()

Syntax
dxf.layer_cut_step(layer, zSafe, zCut, maxZStep, res)

The same as dxf.layer_cut(), in more than one pass. Each pass cuts at most maxZStep deeper than the pass before it.

TPL
dxf.layer_cut_step(layers[0], 3, -6, 2);  // Three passes, 2 mm each

2.24.4 dxf.layer_to_polys()

Syntax
dxf.layer_to_polys(layer)

Changes the entities of a layer to polygons. Entities that touch become one polygon. Arcs become straight segments. Returns an array of polygons.

2.24.5 dxf.offset_polys()

Syntax
dxf.offset_polys(polys, delta)

Applies offset() to each polygon. Returns an array of polygons.

2.24.6 dxf.cut_polys()

Syntax
dxf.cut_polys(polys, zSafe, zCut, zFeed, close=true, leadin=0, cut_cb)

Cuts polygons. It starts with the polygon that is nearest to the tool.

NameTypeDefaultDescription
polysarraynoneThe polygons to cut.
zSafenumbernoneThe safe height. If you do not give it, the tool does not move up between polygons.
zCutnumbernoneThe depth of the cut.
zFeednumbercurrent feed rateThe feed rate to move down to zCut.
closebooleantrueCuts back to the first point of each polygon.
leadinnumber0Starts each polygon at this distance inside it.
cut_cbfunctionnoneCalled with true before and false after each polygon.

2.24.7 dxf.cut_layer_offset()

Syntax
dxf.cut_layer_offset(layer, delta, zSafe, zCut=0, steps=1, zFeed, close, leadin, cut_cb)

Changes a layer to polygons, offsets them by delta and cuts them in steps passes down to zCut. The other arguments are the same as for dxf.cut_polys().

TPL
// Cut 0.5 mm outside the lines, 1.5 mm deep
dxf.cut_layer_offset(layers.Outline, 0.5, 3, -1.5);

2.24.8 dxf.cut_layer()

Syntax
dxf.cut_layer(layer, config)

Cuts the polygons of a layer with a ramp down into the material. It can leave tabs that hold the part.

Property of configDefaultDescription
delta0The offset of the polygons.
zSafe5The safe height.
zStart0The height where the ramp starts.
zEnd0The final depth.
zMax3The maximum depth of one pass.
zSlope1/3The slope of the ramp.
tabs[]The tabs: each one has ratio (position on the path, 0 to 1) or position, and height.
TPL
dxf.cut_layer(layers.Outline, {zEnd: -6, tabs: [{ratio: 0.25, height: 2}]});

2.24.9 dxf.layer_bounds()

Syntax
dxf.layer_bounds(layer)
dxf.layer_center(layer)
dxf.layer_dims(layer)

dxf.layer_bounds() returns the box around a layer: {min: {x, y, z}, max: {x, y, z}}. dxf.layer_center() returns the center of this box. dxf.layer_dims() returns its size.

TPL
var c = dxf.layer_center(layers[0]);
translate(-c.x, -c.y);  // Put the center of the drawing at the origin

2.25 Reference: STL module

Load the module with var stl = require('stl');.

2.25.1 stl.open()

Syntax
stl.open(path)

Reads an STL file. The path is relative to the TPL file. Returns {name, hash, facets}. Each facet is an array of three corner points and a normal, each [x, y, z].

2.25.2 stl.bounds()

Syntax
stl.bounds(stl)

Returns the box around the model: [[minX, minY, minZ], [maxX, maxY, maxZ]].

2.25.3 stl.contour()

Syntax
stl.contour(stl, level, start, end, steps)

Calculates the contours of the model: the closed lines where a horizontal plane cuts the surface.

NameTypeDefaultDescription
stlobjectnoneThe model from stl.open().
levelnumbernoneOne Z height.
start, endnumbernoneThe first and the last Z height of a series.
stepsnumbernoneThe number of heights in the series, at least 2.

With level, it returns an array of contours. Each contour is an array of points {X, Y}. With start, end and steps, it returns an array of {Z, contours}, one for each height.

TPL
var model = stl.open('part.stl');
var contours = stl.contour({stl: model, level: -2});

2.26 Reference: constants

ConstantUse
METRIC, IMPERIALThe units for units().
XY, XZ, YZThe plane for arc(). Also UV, UW, VW.
FEED_UNITS_PER_MIN, FEED_INVERSE_TIME, FEED_UNITS_PER_REVThe feed mode for feed().
CYLINDRICAL, CONICAL, BALLNOSE, SPHEROID, SNUBNOSEThe tool shapes that tool() returns.
JOIN_SQUARE, JOIN_ROUND, JOIN_MITERThe corners for offset().
X_MIN, X_MAX … W_MIN, W_MAX, PROBE, FLOOD, MISTThe ports of the machine, for the port of probe().
dxf.POINT, dxf.LINE, dxf.ARC, dxf.POLYLINE, dxf.SPLINEThe entity types of dxf.open().

2.26.1 Math

JavaScript has a Math object with mathematical functions and constants, for example Math.PI, Math.sin(), Math.cos(), Math.sqrt(), Math.abs(), Math.min() and Math.max(). Angles are in radians.

TPL
var r = 10;
cut(r * Math.cos(Math.PI / 4), r * Math.sin(Math.PI / 4));