# Outline of a Shape

The algorithm for drawing the Outline of a Shape is as follows:

1) The Destination starts filled with whatever background we need to draw on top of. The distance buffer is assumed to be initially filled with 'infinite' (in practice, any sufficiently large value will do).

2) The algorithm continues by following the Trajectory specified by the outline. This is done in discrete steps or jumps. At each step, the pen is moved to a new point in the trajectory, jumping by a fraction of a pixel. A step of about 1/4 of a pixel is small enough. This is done using float (or fixed point) arithmetic.

3) For each step, the pen is at some (float) point. The possibly affected pixels are in the circle defined by the pen outer diameter (w+r). For each of these pixels, the Euclidean Distance from the pixel center to the pen center is computed. This distance is stored in the distance buffer if it is less that the value already there.

4) When the pen has finished following the prescribed trajectory, the distance buffer contains, for each pixel, the minimum distance d to the trajectory. The opacity value is obtained by evaluating the opacity function of the filtering pen at distance d. This opacity value is used to alpha-blend the shape color over the destination frame buffer. Afterwards, the distance buffer is filled with infinite, to be ready for the next call.

[…] Figure 5. Each pixel is painted with the opacity obtained by taking its distance to the path, and using it as the argument to the prefiltering pen function. To illustrate, for some pixels, the small black arrows show this distance to the path. As a further example, for the two arrows closest to the bottom of the figure, the distance is projected (dashed lines) over the filtering pen function, to show how to obtain the opacity values used to paint the pixels. The same procedure is used for all pixels.

chat.openai

Here's a possible implementation of the algorithm in JavaScript:

function drawOutline(destination, trajectory, penOuterDiameter, filteringPen) { const width = destination.width; const height = destination.height; const distanceBuffer = []; for (let i = 0; i < width * height; i++) { distanceBuffer[i] = Number.POSITIVE_INFINITY; } for (let i = 0; i < trajectory.length - 1; i++) { const start = trajectory[i]; const end = trajectory[i + 1]; const step = (end - start) / 4; let current = start; while (current <= end) { const x = Math.round(current.x); const y = Math.round(current.y); const r = penOuterDiameter / 2; for (let i = Math.max(0, x - r); i <= Math.min(width - 1, x + r); i++) { for (let j = Math.max(0, y - r); j <= Math.min(height - 1, y + r); j++) { const distance = Math.sqrt((i - x) ** 2 + (j - y) ** 2); if (distance < distanceBuffer[i + j * width]) { distanceBuffer[i + j * width] = distance; } } } current = current.add(step); } for (let i = 0; i < width * height; i++) { const x = i % width; const y = Math.floor(i / width); const opacity = filteringPen(distanceBuffer[i]); const index = (x + y * width) * 4; destination.data[index + 3] = opacity * 255; } }

~

The graphics engines commonly used to draw vector graphics apply the antialiasing technique known as Pixel Coverage.

pages/outline-of-a-shape

//wiki.ralfbarkow.ch/assets/pages/outline-of-a-shape/outline.html HEIGHT 333