System Functions Reference
System functions are pre-defined arrow functions for common CAM outline shapes. They are automatically loaded into every FSL program.
Usage
Call a system function like any other arrow function:
gear = 96
Round() // Uses defaults: angle=43, sym=8
Round(45, 6) // Override parameters
Oval(45, 1.5) // Override length-width ratio (angle defaults to 45)
Available Functions
| Function | Parameters | Description |
|---|---|---|
Round | angle=43, sym=8 | Simple round preform |
Oval | angle=45, lwr=1.2, segmentsPerQuad=5 | Elliptical outline |
Rect | lwr=1.5, angle=45 | Rectangular outline |
RectTr | lwr=1.5, angle=45, truncation=0.3, offset=0 | Rectangle with truncated corners |
RectDblTr | lwr=1.5, angle=45, first_truncation=0.3, second_truncation=0.2, offset=0 | Double-truncated rectangle for octagons |
SquareTr | angle=42, truncation=0.3 | Square with truncated corners |
SquareCushTr | cushion=1, angle=45, truncation=0.4 | Cushion square with truncation |
PentCushTr | offset=1, angle=45, truncation=0.3 | Pentagon cushion with truncation |
Shield | angle=45 | Shield outline (threefold symmetry) |
TriTr | truncation=0.25, angle=42 | Triangle with truncated corners |
TriCushTr | truncation=0.25, angle=42, cushion=1 | Cushion triangle |
TriCurved | angle=45, c1=2, c2=4 | Curved trilliant |
Source Code
The system functions are defined using FSL. Here is the complete source:
// System library - lambda syntax with defaults
Round = (angle = 43, sym = 8) => {
assert(gear%sym == 0, "Gear must be divisible by symmetry count")
G1 0 @ 90 : size x sym
P1 0 @ angle : cp() x sym
}
Rect = (lwr = 1.5, angle = 45) => {
assert(gear%4 == 0, "Gear must be divisible by 4 for Rect")
beta = Math.toDegrees(Math.atan(Math.tan(Math.toRadians(angle)) / lwr))
corner_index = gear / 4
PF1 corner_index @ beta : cp() xx2
PF2 0 @ angle : cp() xx2
G1 corner_index @ 90 : 0.5 xx2
G2 0 @ 90 : mp(G1, PF1, PF2) xx2
}
RectTr = (lwr = 1.5, angle = 45, truncation = 0.3, offset = 0) => {
assert(gear%8 == 0, "Gear must be divisible by 8 for RectTr")
beta = Math.toDegrees(Math.atan(Math.tan(Math.toRadians(angle)) / lwr))
corner_index = gear / 4
PF1 corner_index @ beta : cp() xx2
PF2 0 @ angle : cp() xx2
G1 corner_index @ 90 : 0.5 xx2
G2 0 @ 90 : mp(G1, PF1, PF2) xx2
tr_index = gear / 8 + offset
PF3 tr_index : cp() : ep(edge(PF1 : corner_index, G1 : corner_index), 1 - truncation / 2) xx2
G3 tr_index @ 90 : mp(G2, PF3, PF2) xx2
}
RectDblTr = (lwr = 1.5, angle = 45, first_truncation = 0.3, second_truncation = 0.2, offset = 0) => {
// Double-truncated rectangle for octagons.
assert(lwr > 0, "Length-to-width ratio must be positive.")
assert(gear%4 == 0, "Gear index should be a multiple of 4.")
assert(first_truncation >= 0, "First truncation must be non-negative.")
assert(first_truncation <= 1, "First truncation should stay within 0-1.")
assert(second_truncation >= 0, "Second truncation must be non-negative.")
assert(second_truncation <= 2, "Second truncation should stay within 0-2.")
corner_index = gear / 4
split_index = Math.floor(gear / 8) + offset
outer_ratio = first_truncation / 2
inner_ratio = second_truncation / 2
yo = corner_index + offset
PF1 yo @ Math.toDegrees(Math.atan(
Math.tan(Math.toRadians(angle)) / lwr)) : cp() x 2
PF2 offset @ angle : cp() x 2
G1 yo @ 90 : size x 2
G2 offset @ 90 : mp(G1, PF1, PF2) x 2
PF3 split_index
: cp()
: ep(edge(PF1 : (corner_index + offset), G1 : (corner_index + offset)), 1 - outer_ratio) xx2
G3 split_index @ 90 : mp(G2, PF3, PF2)
yoyo = (Math.floor(3 * gear / 16) + offset)
PF4 yoyo
: cp()
: ep(edge(PF3 : split_index, G3 : split_index), inner_ratio) xx2
yoyo7 = (Math.floor(gear / 16) + offset)
PF5 yoyo7
: cp()
: ep(edge(PF3 : split_index, G3 : split_index), 1 - inner_ratio) xx2
yo2 = (Math.floor(gear / 16) + offset)
G4 yo2 @ 90 : mp(G3, PF5, PF3) xx2
yo3 = (Math.floor(3 * gear / 16) + offset)
G5 yo3 @ 90 : mp(G3, PF4, PF3) xx2
}
SquareTr = (angle = 42, truncation = 0.3) => {
assert(gear%8 == 0, "Gear must be divisible by 8 for SquareTr")
corner_index = gear / 8
PF1 0 @ angle : cp() x4
G1 0 @ 90 : size x4
PF2 corner_index : cp() : ep(edge(PF1 : 0, G1 : 0), 1 - truncation / 2) x4
G2 corner_index @ 90 : mp(G1, PF1, PF2) x4
}
Shield = (angle = 45) => {
assert(gear == 96, "Shield macro requires 96 index gear")
PF1 6 @ angle : cp() xx3
G1 6 @ 90 : size xx3
}
TriTr = (truncation = 0.25, angle = 42) => {
assert(gear%6 == 0, "Gear must be divisible by 6 for TriTr")
PF1 0 @ angle : cp() x3
G1 0 @ 90 : 0.7 x3
PF2 gear / 6 : cp() : ep(edge(PF1 : 0, G1 : 0), 1 - truncation / 2) x3
G2 gear / 6 @ 90 : mp(G1, PF1, PF2) x3
}
Oval = (angle = 45, lwr = 1.2, segmentsPerQuad = 5) => {
assert(lwr > 0, "Length-to-width ratio must be positive")
assert(segmentsPerQuad >= 2, "segmentsPerQuad must be at least 2")
assert(gear%4 == 0, "Gear index should be a multiple of 4")
width = 1
length = lwr
rx = length / 2
ry = width / 2
quarter = gear / 4
steps = segmentsPerQuad
stepSize = quarter / steps
h = Math.cos(angle * Math.PI / 90)
Math.range(1, steps + 1).forEach(k => {
idx = Math.round(k * stepSize)%gear
ang = (idx / gear) * 2 * Math.PI
c = Math.cos(ang)
s = Math.sin(ang)
d = Math.sqrt(rx * rx * c * c + ry * ry * s * s)
prevK = k - 1
prevIdx = Math.round(prevK * stepSize)%gear
prevAng = (prevIdx / gear) * 2 * Math.PI
prevC = Math.cos(prevAng)
prevS = Math.sin(prevAng)
prevD = Math.sqrt(rx * rx * prevC * prevC + ry * ry * prevS * prevS)
det = prevC * s - prevS * c
x = (prevD * s - d * prevS) / det
y = (d * prevC - prevD * c) / det
concat(O, k) prevIdx : Point(x, y, - h) : cp() xx2
k == steps ? {
concat(O, k + 1) quarter : Point(x, y, - h) : cp() xx2
}
: 0
}
)
G1 0 @ 90 : size
Math.range(2, steps + 1).forEach(k => {
idx = Math.round((k - 1) * stepSize)%gear
concat(G, k) idx @ 90 : mp(concat(G, k - 1), concat(O, k - 1))
}
)
concat(G, steps + 1) quarter @ 90 : mp(concat(G, steps), concat(O, steps))
}
SquareCushTr = (cushion = 1, angle = 45, truncation = 0.4) => {
assert(cushion >= 1, "Index offset must be 1 or more")
assert(gear%4 == 0, "Gear must be multiple of 4")
side_index = cushion
corner_index = gear / 8
G1 side_index @ 90 : size xx4
PF1 side_index @ angle : cp() xx4
PF2 corner_index : cp() : ep(edge(PF1 : side_index, G1 : side_index), truncation / 2) x4
G2 corner_index @ 90 : mp(G1, PF2, PF1) x4
}
PentCushTr = (offset = 1, angle = 45, truncation = 0.3) => {
assert(offset >= 1, "Offset >= 1")
assert(truncation >= 0)
assert(truncation <= 1)
assert(gear%10 == 0)
side_index = offset
corner_index = gear / 10
G1 side_index @ 90 : size xx5
PF1 side_index @ angle : cp() xx5
PF2 corner_index : cp() : ep(edge(PF1 : side_index, G1 : side_index), truncation) xx5
G2 corner_index @ 90 : mp(G1, PF1, PF2) xx5
}
TriCushTr = (truncation = 0.25, angle = 42, cushion = 1) => {
assert(truncation >= 0)
assert(truncation < 2)
assert(cushion >= 0)
assert(gear%6 == 0)
PF1 cushion @ angle : cp() xx3
G1 cushion @ 90 : 0.7 xx3
PF2 gear / 6 : cp() : ep(edge(PF1 : cushion, G1 : cushion), truncation) x3
G2 gear / 6 @ 90 : mp(G1, PF1, PF2) x3
}
TriCurved = (angle = 45, c1 = 2, c2 = 4) => {
cube = 3.4
assert(c1 < c2)
assert(gear%c1 == 0)
assert(gear%c2 == 0)
PF1 c1 @ angle : cp() xx3
G1 c1 @ 90 : size
PF2 c2 : cp() : ep(edge(PF1 : c1, G1 : c1), 0.5) xx3
G2 c2 @ 90 : mp(PF1, PF2, G1) xx3
}