geom.offset
drafting: Q = geom.offset (P, D)
Offset a rectilinear polygon inward or outward.
Q = geom.offset (P, D) slides every edge of the
polygon P a distance D along its own inward normal and returns
the resulting outline Q, with one vertex per vertex of P.
A positive D offsets inward, shrinking the outline; a negative
D offsets outward. D is in the units of P, so millimetres
by package convention. D = 0 returns P unchanged.
The orientation of P, clockwise or counter-clockwise, is preserved in Q, and vertex of Q corresponds to vertex of P.
Rectilinear input only. P must satisfy
geom.isrectilinear; anything else raises an error. This is a
deliberate restriction rather than an oversight. Offsetting a general
polygon is a genuinely hard problem — edges collapse, the outline
self-intersects, and a correct implementation has to detect and resolve both
— while the outlines this is wanted for are rectangular in the great
majority of cases and L-shaped in most of the rest. The interface is general
enough that support for arbitrary polygons can be added later without
disturbing callers.
A general polygon is offset by geom.curveoffset instead,
given its vertices and CLOSED set true. With one point per corner
each normal is the angle bisector, which is the mitred offset exactly. Pass
the vertices and not a dense sampling of the same outline: a corner resolved
by sampling has a vanishing radius of curvature, so the undercut criterion
rejects an offset the polygon itself absorbs without difficulty.
What this function adds over that route is the check below — an exact test that the outline can absorb the offset at all, which a criterion evaluated point by point cannot give.
An offset too large for the outline to absorb raises an error rather than returning a self-intersecting result. This is detected by checking that the orientation survives and that no edge has reversed direction, which is exact for rectilinear outlines.
See also: geom.isrectilinear, geom.largestrect, geom.signedarea
Source Code: geom.offset
Every edge slides along its own inward normal. A positive distance shrinks the outline, a negative one grows it, and the orientation and vertex order are preserved.
P = [0, 0; 60, 0; 60, 20; 30, 20; 30, 45; 0, 45];
D = draw.Drawing ().polyline (P, true);
D.Colour = 'red';
D = D.polyline (geom.offset (P, 5), true);
D.Colour = 'blue';
D = D.polyline (geom.offset (P, -5), true);
plot (D);
title ('an L-shaped outline offset 5 mm in (red) and out (blue)');
An offset too large for the outline to absorb raises rather than returning a self-intersecting result that looks plausible.
try geom.offset ([0, 0; 40, 0; 40, 10; 0, 10], 8); catch err disp (err.message); end_try_catch
geom.offset: D is too large for P; the offset outline would be degenerate.