Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine Pixels Into Polygons #98

Merged
merged 8 commits into from
Feb 5, 2023

Conversation

Dheatly23
Copy link
Contributor

This PR fixes #88 by combining pixels into polygons.

@Ciubix8513
Copy link
Contributor

There seems to be an issue with some glyphs:
image
image
While I don't think it will cause any issues with the font rendering, it's still a bug

@Dheatly23
Copy link
Contributor Author

Dheatly23 commented Jan 13, 2023

Yeah, to handle holes, i basically put a tiny cut in the outer polygon, then splice the hole in. There may be better solution though. The hole polygonizer algorithm is still there, just need to rework how to put it back in.

EDIT: Meanwhile i'll fix colinear line in the splicing algorithm.

As it turns out, to add holes, just emit the inner polygon
(RIP colinear remover).
@Dheatly23
Copy link
Contributor Author

Okay i fixed it. Turns out, i just need to emit the inner polygon to be recognized as holes. Fingers crossed that font renderers can handle that.

@Ciubix8513
Copy link
Contributor

Now there's another issue, for some reason the glyphs Ф ф broke:
image
image
I don't think I have enough python knowledge to help fix it

@Dheatly23
Copy link
Contributor Author

Huh, i tested it and it seems like some weird interaction with mutating iterator variable. I'll push the fix soon.

@Ciubix8513
Copy link
Contributor

I think you should add a license notice similar to other files, but otherwise it looks good to me.

@dantaeusb
Copy link
Contributor

dantaeusb commented Feb 3, 2023

My apologies for being a little off-topic, but I am super fascinated by this.
Is there a common name for the algorithm you've used?

  • I see it first creates 1 byte matrix by using flood fill, to create “layers” of rectangles with the lowest bit (later referenced CellFlag.ACTIVE);
  • Then I assume you're writing directions to the upper 4 bits of that matrix in doMove for the whole layer (outer_poly);
  • Then the same applied to all inner “holes”, creating inner vectors (inner_poly), (there was probably the "ф" problem);
  • Those lines then yield to the pen.

My question is how exactly the length is figured out, as the output of doMove is a vector with origin. I can't really wrap my head around where this matrix turns to points because from the first glance, there's no recursive calls or some traversing when those directional flags are set.

I would be super happy to know more about this if you don't mind. You can use email in my profile if you would rather not explain here.

Thanks!

@Dheatly23
Copy link
Contributor Author

Dheatly23 commented Feb 3, 2023

As far as my knowledge goes, there seem to be no one else that do it the same way. I'll explain what the algorithm does:

  1. Split the image into connected parts (the segmentize function). Two pixels are connected if they share an edge or corner.
  2. Now the segmented parts only contains 2 bundaries, outer and possibly inner. So it will make the calculation easier.
  3. To trace the boundary, i use a "turtle" that hugs the boundary from right (right side is filled, left side is empty). The turtle is initally on the top-leftmost pixel facing right.
  4. To make the turtle movement more efficient, in the doMove function i check on neighboring pixels where the turtle at to plan it's movement. There are 9 cases to be considered.
  5. While the turtle is moving, i record every corner that the turtle made.
  6. The turtle is done travelling whenever it goes back to it's original point (this took so long to tweak). Remove the extra path beyond that point.
  7. And for the internal boundary do the same, making sure the turtle is moving opposite of outer loop.
  8. (Optionally) i tried to simplify even further by splicing the inner loop to outer loop, but apparently this may cause issues. Maybe in the future it may be implemented better.

The cell data is a bitflag with values as follows:

  • Bit 0: Cell is filled
  • Bit 4: Cell has wall at top
  • Bit 5: Cell has wall at bottom
  • Bit 6: Cell has wall at left
  • Bit 7: Cell has wall at right

The filled bit is obvious. The wall bits are used to find inner boundaries that has not been found (if it should have wall but isn't set). I don't know what you mean by length, i don't use length in the algorithm, only direction of the turtle is considered.

And that problem with ф is apparently Python does not like mutating iterator variable while it is iterating. I never experienced this issue until now, but currently i restore the inner value every time the inner polygon generation is done. Maybe it's my bug, but so far that fixes it.

@IdreesInc
Copy link
Owner

Apologies for the delay in reviewing this, had the flu, not fun. Thanks @Ciubix8513 for reviewing it in the meantime and discovering those bugs!
But wow this is brilliant. Thank you @Dheatly23 for putting the time and effort into solving this problem, I didn't realize how nontrivial it would turn out to be. I especially appreciate the comments that illustrate how the outlines are being built. Going to merge this into a branch first so that I can update the version number, then will get a release out later today!

@IdreesInc IdreesInc changed the base branch from main to 88-a-small-break-between-pixels February 5, 2023 18:38
@IdreesInc IdreesInc merged commit 78d0a71 into IdreesInc:88-a-small-break-between-pixels Feb 5, 2023
@dantaeusb
Copy link
Contributor

FYI I noticed a detail when installing new version of the font, I believe these margin alignments are (leftMargin from 4403411) are no longer applied.

Screenshot 2023-02-05 at 23 25 08

P.S. I also extended symbols with european-nonlatin set: https://github.com/dantaeusb-mc/Minefont/blob/main/src/characters.json, but it's auto-generated, and I'm still working on it. I want to get non-monospaced version too.

@Dheatly23
Copy link
Contributor Author

Oh yeah, i didn't see that left margin can be non-integer. I just assumed it is and shift the entire image. I think i did the same with descent and diacritic space too. Oh well, that could be fixed later. Thanks anyway for accepting my PR.

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.

A small break between pixels
4 participants