3D effects: merged contours keep their parts, and edge cases are consistent

The boolean's answer went through orient(), which judges each ring's
side from its first point. The boolean often starts a contour where it
touches another, so a triangle whose tip rests on a square's edge was
dropped, and an even-odd hole touching its outline was filled. The
boolean already runs holes against their outlines, so its rings are now
only turned as a whole.

Other fixes:
- A bowtie drawn as one contour has no area of its own. It was dropped
  before the meet check and built nothing, although it fills both lobes.
  Sampling now keeps rings with no area, and orient() drops them after
  the check. Flat rings, every point on one line, fill nothing and are
  still dropped, so a stray flat contour doesn't send separate art
  through the boolean.
- An open subpath was closed along its end handles when the profile went
  through the boolean, but straight otherwise, as the renderer fills it.
  It is now closed straight before the boolean too.
- An empty union was taken as a refusal. Contours that cancel (a square
  drawn twice under even-odd) built a square. They now build nothing.
- Contours meet within twice the boolean's own sweep tolerance,
  computed by its rule from every anchor and handle of the path it is
  given. pathops snaps anchors onto nearby heights before the sweep
  joins edges within that tolerance, so contours up to about 1.4 times
  it apart can come out as one; within twice it, every contour it
  might join goes through it, even far from the origin, and the few it
  leaves apart cost a boolean that builds the same shape.
- A one-anchor subpath draws nothing, so it is skipped, as the renderer
  and the boolean skip it.
- A profile the boolean refuses reuses the rings already sampled.

Tests:
- touching parts and holes;
- an open subpath with handles, alone and beside crossing bars;
- a flat contour beside separate squares;
- contours joined far from the origin, including by handles alone,
  and contours a few millionths apart near it kept apart;
- triangles snapped together and joined at 1.4 times the tolerance,
  the same triangles left apart and kept whole, and the factor pinned
  between 1.9 and 2.2 times, with the worst case just past twice the
  tolerance left apart by pathops;
- a 24-bar grid: too complex for Extrude and Inflate, whole under Rotate;
- the merged rings turned as a whole;
- a one-anchor loop;
- the bowtie and the cancelling squares under all three effects;
- a 3,001-point star that the boolean refuses (TooComplex), built as
  drawn.

Docs: the pathops README's Limits section now says only the try_
functions refuse, lists OpenPath and the caught panic, and describes
unite_all's answers, and which calls take a precision. three-d.md and effects-parity.md (the 3D row, its
history and status line) describe the merge and its limits.
This commit is contained in:
Drew Dibble
2026-11-09 02:24:47 +07:00
committed by bflatastic
parent 62a01689f0
commit bc87fd1b7e
5 changed files with 408 additions and 57 deletions
+7 -4
View File
@@ -19,8 +19,11 @@ another.
Each solid follows its shape as it is filled. Separate and nested contours are built as drawn. Contours that cross,
touch or run along each other or themselves, as type often draws a glyph, are first merged into one outline by
[`vectorcraft-pathops`](../crates/pathops/README.md), keeping contours however narrow. All three effects then share
its [limits](../crates/pathops/README.md#limits): a shape it refuses is built from its contours as drawn, where it can be.
[`vectorcraft-pathops`](../crates/pathops/README.md), keeping every contour but the numerical debris a boolean leaves.
Whether contours meet is judged on the outline as it is followed (see the curve tolerance below), so curves that
overlap by less than that are built as drawn. All three effects share pathops'
[limits](../crates/pathops/README.md#limits): a shape it refuses is built from its contours as drawn, where it can be.
An open subpath is closed by a straight line either way.
## 3D and Materials panel
@@ -234,8 +237,8 @@ out, perspective). No Adobe software, assets, presets or bevel shapes were used.
- Curves are followed within 1/2000 of the shape's size (at least 0.05 pt), so a small curve takes a few points
and a large one up to 32. Extrude & Bevel and Inflate take up to 2,048 outline points (a stroke's outline is
counted on its own), Rotate (which only turns the outline) 65,536. The limit is counted on the shape as drawn and,
when its contours meet, again on the merged outline, which can have more points: bars crossing in a grid trace
every hole between them.
when its contours meet, again on the merged outline, which can have more points (bars crossing in a grid trace
every hole between them); past it, the shape is too complex for the effect.
- **3D (Classic)** (the track cube, surface types, blend steps, map art), Turntable and 3D export are separate,
unbuilt items.