Giter Club home page Giter Club logo

Comments (12)

LingDong- avatar LingDong- commented on May 27, 2024

WIP of this feature is now version controlled at wip_features/satin folder of this repo.

Currently it is a standalone Processing sketch, which will be integrated into PEmbroider when it is more complete.

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

@LingDong- ‚  Not sure if this actually matters at all IRL, but is there a way to have all of the diagonals go in the same direction (e.g. all going from southwest to northeast)? Or do even/odd rules make that impossible? There might be some artifacts that arise when different diagonals are mixed together.

Screen Shot 2020-06-23 at 5 07 44 PM

from pembroider.

LingDong- avatar LingDong- commented on May 27, 2024

Hi @golanlevin, the diagonals are in different directions because:

All scan-lines go left to right. But some of them have to go from top to bottom (producing SW diagonals), while some of them have to go from bottom to top (producing NW diagonals).

While it is possible to make scanlines go from right to left for those that goes from bottom to top, I'll need to branch into 2 cases and write checks for each, and I think it can be error prone. There's a lot of nice assertions I'm getting from the preconditions that all scanlines go from left to right.

I'm thinking maybe we can test it first IRL, and if the diagonals are a problem, I can rewrite it to make reversed scanlines.

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

Hi @LingDong- , what's happening on the left edge here — are those off-by-one errors?

Screen Shot 2020-06-23 at 10 27 33 PM

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

There's one row here which is missing dots — not sure if that's a sign of a bug or not:

Screen Shot 2020-06-24 at 3 44 44 AM

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

I tried your second shape. Aliasing caused this shape to break up into two islands, only the first of which (the tiny single pixel in the upper left) got embroidered:

Screen Shot 2020-06-24 at 3 47 51 AM

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

There appears to be a jumping error on that shape too:

Screen Shot 2020-06-24 at 3 49 39 AM

This happens when rot = -0.84.
A similar problem happens when rot = -3.94:

Screen Shot 2020-06-24 at 3 53 23 AM

from pembroider.

LingDong- avatar LingDong- commented on May 27, 2024

Hi @golanlevin , thanks a lot for all the testing!

The Off-by-one Issue

The first off-by-one issue is because when the algorithm finds two branches on lower left and lower right, and decided that it needs to stitch the lower right branch first, and after it's done with that it returns to the next row at the same column where the left branch is found. There are actually two problems:

  • My scanline increments X at start of the loop instead of at the end, so that makes it actually skip the first one when the aforementioned jump happens.
  • The next row might start to the left of the current row instead of at the same column, like this: ▟. Which didn't happen in your screenshot but nevertheless is a possibility!

So the fix is, to scan leftward and find the first black pixel. Now fixed:

image

The Issue of Missing Dots

That seems to be gone ever since I switched to the queue based flood fill. Must've been some subtle error with the previous implementation

Snip20200624_17

The Issue of the Island

Yup I'll write something to preprocess the image first, getting rid of holes, tiny islands, and run the algo on each disjoint shape.

The Issue of the First Jumping

This is actually an unsolvable case. If you look at the row highlighted by green in the first screenshot below, it is the only corridor to go to the regions above it AND the one below it. So if the thread takes the corridor and go to the region above, there's no "road" to go back to the region below! If it uses the corridor to go to the region below, there is no way it can go to the region above! So actually there is a precondition for the raster method to work perfectly: every corridor needs to be at least 2 pixel in height. It doesn't need to be 2 pixel high all the time, just needs to be at unlucky situations like this.

Snip20200624_7

If you look at the higher res version of the same frame, the problem is gone:

Snip20200624_14

The Issue of the Second Jumping

Though this looks like a jumping issue, this is in fact the island issue. Even though the tiny pixel on lower left corner looks "connected" (by Moore neighborhood), the algorithm uses von Neumann neighborhood so it is actually classifies as an island.

Here's a screenshot right before it tries to jump to the island at the last second:

Snip20200624_10

So yeah currently the algorithm assumes no holes, no islands. If there's one, anything could happen: it might just stitch the first island, it might make a jump to stitch all of them, etc. That's why I've been saying all this time I'll write a preprocessing step to handle these situations ;)

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

Fun report :)

from pembroider.

LingDong- avatar LingDong- commented on May 27, 2024

Initial support for islands and holes now added: debe33d

  • 1x1 islands and holes are thrown away since they're most likely aliasing artifacts.
  • larger islands are handled this way: it first try to stitch the image with the original algorithm, then check the result against the input image to see if there're unfilled regions. If so, recursively redo these parts. This has the additional benefit of being a fallback solution for any potential degenerate cases that are causing missing parts.
  • I came up with a rather interesting algorithm to deal with holes:) It's based on flood fill, but uses a cache for efficiency. It makes a bridge (in fact anti-bridge, or maybe canal) between the hole and the nearest side of the shape to its left. It identifies holes and fix them all in one pass.
  • You can now use the mouse to make island or hole in the interactive demo:

Hole:
Snip20200624_24

Island:
Snip20200624_23

Holes instead of island can be created using island mode:

Snip20200624_25

My algorithm is smart in the sense that it knows that it only needs to make a cannel to the closest hole that already has a canal, instead of all the way to the left edge. Currently it is dumb in the sense that it could've just walked upwards for 3 pixels and be done (which I intend to fix soon :P

Snip20200624_26

I thinking about a way to get rid of the canal. So instead there will be two rows of "special" pixels. For the first row, if viewed from above (when scanline goes from top to bottom), it is on, but when viewed from below (when scanline goes from bottom to top), it is off. For the second row, if viewed from below, it is on, but when viewed from above, it is off. Both lines will thus be filled by scanlines going in opposite directions.

This requires to check which direction we're viewing it from for every pixel look up, which can be quite annoying. Wonder if there's an even smarter way.

from pembroider.

LingDong- avatar LingDong- commented on May 27, 2024

Hi @golanlevin

hatchMode(SATIN) now integrated into the library! Works just like other hatch modes: 0dd20b3

Example: b07857e

from pembroider.

golanlevin avatar golanlevin commented on May 27, 2024

Spectacular work Lingdong. @tatyanade , could you please test the new SATIN hatch mode?

from pembroider.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.