Loading editor...

Broadcasting in geometry

Broadcasting is the set of rules by which operations between arrays of different shapes are automatically extended - a concept central to NumPy, JAX, and PyTorch. Adding a (3,1) tensor to a (2,) tensor produces a (3,2) result without any loop; the smaller array is stretched to match the larger one along each axis. If you already reach for reshape or unsqueeze before an operation, this will feel immediately familiar.

The same mental model applies to drawing. When you pass arrays to a geometric function in Geomatic, the output shape follows standard NumPy broadcasting rules - (almost) every function is broadcastable by default. No special syntax, no wrappers.

\circle: from one to many

Pass a single center and a single radius and you get one circle. Pass an array of radii and you get one circle per element:

The center is broadcast to match the shape of radii, producing three concentric circles. The same works in reverse - an array of centers with a single radius draws one circle per center.


Different centers and different radii

What if you want every combination of centers and radii? This is where array dimensions come into play.

  • : xs = \linspace -3 3 3
  • : xs-reshaped = \reshape xs 3 1
  • : centers = \point xs-reshaped 0
  • : radii = \array 1 1.5

The key step: xs-reshaped has shape (3,1) and radii has shape (2,). Broadcasting expands both to (3,2), so every center is paired with every radius:

  • : circles = \circle centers radii

You get 6 circles: 3 positions × 2 sizes. The first axis encodes the center, the second encodes the radius. This is the visual equivalent of a Cartesian product, expressed purely through array shapes.


  • : \clear

Same shape → element-wise pairing

When both arrays have the same shape, there is nothing to expand - broadcasting pairs elements one-to-one. Here, 6 squares each get their own side length and their own rotation angle:

  • : p0 = \point 0 0
  • : n = \scalar 6
  • : angles = \linspace 0 90 n
  • : sides = \linspace 2 3 n
  • : \square p0 sides angles

Both angles and sides have shape (6,). The result is a fan of squares that grow and rotate together - each fully determined by its index.


The pattern is always the same: shape encodes intent. A column vector paired with a row vector gives a grid; two equal-length vectors give a sequence. Designing a visualization becomes an exercise in choosing the right shapes.


Broadcasting extends to user-defined functions

Broadcasting is not limited to built-in functions. Any extension you write gets it for free. To see this, load the test-ext extension from the extensions page using this URL:

https://vinsis.github.io/test-ext/manifest.json

This extension provides a \n-star command whose implementation takes a center point as one of its inputs. Run it once with a single center:

Now pass an array of centers - no changes to the function, no special handling needed:

Two stars, one per element in points. The broadcasting machinery intercepts the call, maps the function over the array dimension, and assembles the results - exactly as it does for every built-in.