Skip to content

Conversation

@armano2
Copy link
Contributor

@armano2 armano2 commented Mar 15, 2025

Fixes #89
unblocks nfroidure/svgicons2svgfont#60 nfroidure/svgicons2svgfont#113

this is still an early draft that need a lot of cleanup, i have been working on this for quite some time and optimization and other changes are required, but outline itself is producing now correct results for most path's (~99%)

i'm also not keen on using bezier in here, but in this first draft that was easiest way to verify if this is feasible

this is a revised and improved version of outline generation that i did in nfroidure/svgicons2svgfont#178

Proposed changes

  • implement outline generation

Code quality

  • I made some tests for my changes

License

To get your contribution merged, you must check the following.

  • I read the project license in the LICENSE file
  • I agree with publishing under this project license

@armano2 armano2 changed the title feat; outline generation for given path feat: outline generation for given path Mar 15, 2025
@armano2
Copy link
Contributor Author

armano2 commented Mar 15, 2025

draft review and some feedback would be appreciated

],
} satisfies Record<string, Partial<OffsetOptions>[]>;

const TEST_SHAPES = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No arcs?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see generateOutlinePath handles that by doing .aToC, but it's not being validated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes current implementation supports only lines and beziers, this def should/could be extended but as POC, i didn't bother

): boolean {
if (!p1 || !p2) return false;

return Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2) <= tolerance;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Often this is implemented as (...) <= tolerance ** 2 to avoid the sqrt. Just an aside.

...TEST_SHAPES.withCorners,
...TEST_SHAPES.special,
};

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest writing a custom function which generate a baseline/snapshot in the form of a viewable SVG. Eg a big table with rows = test_shapes and columns = TEST_CONFIGS (or at least a subset). That way anyone can easily verify that the results make sense. Currently I can't really validate the snapshots without additional effort

Copy link
Contributor Author

@armano2 armano2 Mar 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a web demo that just let me input paths to test all functionalities but I will push just a generator than, unless you prefer web version, example is is ticket

Image

Copy link
Contributor Author

@armano2 armano2 Mar 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i pushed my testing file that you can add in generateOutlinePath, thats a reason why i have been making those functions :)

writeSvg(createOutlineSvg(path, pathData, options, {
  showControlPoints: true,
  showHandleLines: true,
  showSegmentPoints: true,
  showDirectionArrows: false,
  showBounds: true,
}));

if you think its a good idea, i can push instead of that my website, tho i used vite to serve it locally into something like docs or play folder as separate PR

@NaridaL
Copy link
Collaborator

NaridaL commented Mar 16, 2025

draft review and some feedback would be appreciated

Looks good to me, you have comments and tests. Added a couple of comments.

Wrt bezier.js, I'm fine to depend on it. I think you're mainly using it for the bezier/bezier and bezier/line intersections. Been a while, but iirc those are fairly easy to reimplement.

@armano2
Copy link
Contributor Author

armano2 commented Mar 16, 2025

bezier rn is used for

offsetting:

  • offset.ts
  • this one is surprisingly hardest to re-implement
    • you have to calculate extremas, normals, roots, ...
    • split/simplify beziers to not have weird shapes (reduce)
    • create new points

splitting (slice):

  • eg in trimming

intersection:

  • this also use projection and bbox (we have implementation for that that could be extracted)
  • l to c
  • c to c
  • l to l - is handled manually

derivative

  let v1 = prevSegment.derivative(1);
  const v1Mag = Math.sqrt(v1.x * v1.x + v1.y * v1.y);

    if (v1Mag < POINT_TOLERANCE) {
      v1 = createVector(
        prevSegment.points[0],
        prevSegment.points[prevSegment.points.length - 1],
      );
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

outline generation for set path,

2 participants