Once we have a VD it is almost trivial to calculate 2D offsets. While the VD for n line-segments takes O(n*log(n)) time to calculate, the offset-generation is a simple "march" that takes O(n) time. In this "A" example it takes 24 milliseconds to calculate the VD and less than 1 millisecond to produce all the shown offsets. Input geometry in yellow, VD in blue. Offset lines in light-green and offset arcs in slightly darker green.
Here is a larger example where VD takes 1.3 seconds, and all offsets shown take 99 milliseconds in total to produce. It would be interesting to benchmark this against libarea or other open-source 2D offset solutions. (here all line/arc offsets in one green color, for simplicity)
Here is a third picture with offsets for a single offset-distance:
The algorithm works by incrementally constructing the diagram while adding the point-generators one by one. This initial configuration is used at the beginning:
The diagram will be correct if new generator points are placed inside the orange circle (this way we avoid edges that extend to infinity). Once about 500 randomly chosen points are added the diagram looks like this:
Because of floating-point errors it gets harder to construct the correct diagram when more and more points are added. My code now crashes at slightly more than 500 generators (due to an assert() that fails, not a segfault - yay!). It boils down to calculating the sign of a 4-by-4 determinant, which due to floating-point error goes wrong at some point. That's why the Sugihara-Iri algorithm is based on strictly preserving the correct topology of the diagram, and in fact they show in their papers that their algorithm doesn't crash when a random error is added to the determinant-calculations, and it even works (in some sense) when the determinant calculation is completely replaced by a random number generator. Their 1992 paper constructs the diagram for one million generators using 32-bit float
numbers, while my naive attempt using double here crashes after 535 points... some work to do still then!
Note how within one voronoi-region the offset is determined by the associated generator (a line, point, or arc). It's very easy to figure out the offset within one region: points and arcs have circular offsets, while lines have line offsets. The complete offset path is a result of connecting the offset from one region with the next region.