booleanOperations icon indicating copy to clipboard operation
booleanOperations copied to clipboard

Glyph distortion after union

Open khaledhosny opened this issue 8 years ago β€’ 19 comments

Using this script on ReemKufi-Regular.ufo.zip:

import sys
from booleanOperations import BooleanOperationManager
from defcon import Font

ufo = Font(sys.argv[1])
manager = BooleanOperationManager()
for glyph in ufo:
    contours = list(glyph)
    glyph.clearContours()
    manager.union(contours, glyph.getPointPen())
ufo.save(sys.argv[1].replace(".ufo", "-new.ufo"))

Results in several distorted glyphs: arMeem.isol, arHeh.fina and arHeh.fina1: 2016-07-08 18-13-20

khaledhosny avatar Jul 08 '16 15:07 khaledhosny

hm.. that's not good. Does re-locating the contours' starting point make any difference?

anthrotype avatar Jul 08 '16 15:07 anthrotype

Changing the start points makes no difference, but moving the horizontal contour so that its first point is not directly above the point in the other contour β€œfixes” the distortion.

khaledhosny avatar Jul 08 '16 17:07 khaledhosny

I dug into this a bit and have a theory on why this is happening. If I'm correct, the code here: https://github.com/typemytype/booleanOperations/blob/ebeaf6ba940dbfeda25b232a065f0cabf8ec9a8f/Lib/booleanOperations/flatten.py#L877

is trying to match an input curve (from the original glyph) with an output curve (from the union-ed polygon) by their first points. It searches for t values in the input curve for the last point on the output curve, and if it doesn't find one, as it might not in the example here, it just drops an entire segment because it assumes at least one would be found: https://github.com/typemytype/booleanOperations/blob/ebeaf6ba940dbfeda25b232a065f0cabf8ec9a8f/Lib/booleanOperations/flatten.py#L924

I'm not sure if I'm right on the mark in diagnosing the actual issue, and I certainly don't know what the solution would be at this point. But maybe this is a start.

jamesgk avatar Aug 10 '16 01:08 jamesgk

cc @typemytype

This is almost certainly a duplicate of https://github.com/typemytype/booleanOperations/issues/27, and of https://github.com/googlei18n/nototools/issues/268#issuecomment-238014664. Basically it's a pretty big issue with BooleanOperations. The code is pretty complex though; I'm hesitant to make any changes for fear of breaking something else.

jamesgk avatar Aug 10 '16 22:08 jamesgk

@jamesgk @anthrotype @typemytype @behdad : I will be at AtypI, jamesgk will be at AtypI. @anthrotype I think you will be there also (and I think you own this code).

Could we meet on Wednesday, 14/Sep evening over some food and beer (water or any non-alcoholic drink of your choice if you don't drink alcohol) and fix it?

@khaledhosny : would be be able to help with testing it (will you be around during AtypI)? I would test for any regressions over the next 24 hours after the fix is checked in (ending on Friday, 16/Sep) using our pipeline (as of today we produce 639 different OTF files including one that causes the problem). If there were any issues most likely they'd appear early, but if there were none I'd know on Friday. If there were any issues we could fix them on Thursday or Friday...

What do you think? I want it fixed soon :-)

marekjez86 avatar Sep 02 '16 15:09 marekjez86

Code is owned by @typemytype . But indeed, all of us (including Khaled and Cosimo) will be at ATypI, so we should get together and tackle this one there. Looks like Wednesday after dinner might work after all. Let's aim for that.

behdad avatar Sep 02 '16 15:09 behdad

Wednesday sounds fine.

khaledhosny avatar Sep 02 '16 22:09 khaledhosny

sounds like a plan! πŸ‘

anthrotype avatar Sep 06 '16 10:09 anthrotype

date set!

gr Frederik www.typemytype.com

On 06 Sep 2016, at 12:42, Cosimo Lupo [email protected] wrote:

sounds like a plan! πŸ‘

β€” You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/typemytype/booleanOperations/issues/32#issuecomment-244913895, or mute the thread https://github.com/notifications/unsubscribe-auth/ABIp1usM5civmLuPBcK8ckU5hf8a_4Frks5qnUN7gaJpZM4JIH_o.

typemytype avatar Sep 07 '16 19:09 typemytype

I managed somehow to fix the issue, by simply using the updated pyclipper extension!

Also see the other screenshots at https://github.com/typemytype/booleanOperations/issues/27#issuecomment-246126715

screenshot 2016-09-10 18 57 32

pyclipper is also available on PyPI https://pypi.org/project/pyclipper/ with pre-compiled wheels for all Mac, Win and Linux!

I'll send a PR soon πŸ’ƒ

anthrotype avatar Sep 10 '16 18:09 anthrotype

Awesome! Now we need something else to do on Wednesday night!

behdad avatar Sep 10 '16 19:09 behdad

Warsaw nightlife ????? with T-shirts showing those tricky unions :)

gr Frederik www.typemytype.com

On 10 Sep 2016, at 21:28, Behdad Esfahbod [email protected] wrote:

Awesome! Now we need something else to do on Wednesday night!

β€” You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/typemytype/booleanOperations/issues/32#issuecomment-246131459, or mute the thread https://github.com/notifications/unsubscribe-auth/ABIp1r2nFxxk0BeZpTbAPgetMqMMoD-bks5qowT6gaJpZM4JIH_o.

typemytype avatar Sep 10 '16 20:09 typemytype

I'm looking into arranging a dinner. Stay tuned.

behdad avatar Sep 10 '16 20:09 behdad

https://github.com/googlei18n/noto-fonts/issues/1206

anthrotype avatar Jun 01 '18 14:06 anthrotype

Could you post the glif xml? Thanks

typemytype avatar Jun 01 '18 14:06 typemytype

here

<?xml version="1.0" encoding="UTF-8"?>
<glyph name="medial_ra_wa.w3" format="2">
  <advance width="229.0"/>
  <note>
    medial_ra_wa.w3
  </note>
  <outline>
    <contour>
      <point x="296.0" y="-467.0" type="curve" smooth="yes"/>
      <point x="1542.0" y="-465.0" type="line"/>
      <point x="1396.0" y="-393.0" type="line"/>
      <point x="292.0" y="-395.0" type="line" smooth="yes"/>
      <point x="214.0" y="-395.0"/>
      <point x="181.0" y="-349.0"/>
      <point x="181.0" y="-269.0" type="curve" smooth="yes"/>
      <point x="181.0" y="806.0" type="line" smooth="yes"/>
      <point x="181.0" y="885.0"/>
      <point x="214.0" y="931.0"/>
      <point x="292.0" y="931.0" type="curve" smooth="yes"/>
      <point x="1531.0" y="931.0" type="line" smooth="yes"/>
      <point x="1607.0" y="931.0"/>
      <point x="1642.0" y="885.0"/>
      <point x="1642.0" y="806.0" type="curve" smooth="yes"/>
      <point x="1642.0" y="760.0" type="line"/>
      <point x="1731.0" y="760.0" type="line"/>
      <point x="1731.0" y="789.0" type="line" smooth="yes"/>
      <point x="1731.0" y="932.0"/>
      <point x="1663.0" y="1003.0"/>
      <point x="1526.0" y="1003.0" type="curve" smooth="yes"/>
      <point x="296.0" y="1003.0" type="line" smooth="yes"/>
      <point x="159.0" y="1003.0"/>
      <point x="91.0" y="932.0"/>
      <point x="91.0" y="789.0" type="curve" smooth="yes"/>
      <point x="91.0" y="-253.0" type="line" smooth="yes"/>
      <point x="91.0" y="-396.0"/>
      <point x="159.0" y="-467.0"/>
    </contour>
    <contour>
      <point x="1542.0" y="-465.0" type="curve" smooth="yes"/>
      <point x="1658.0" y="-465.0"/>
      <point x="1729.0" y="-381.0"/>
      <point x="1729.0" y="-282.0" type="curve" smooth="yes"/>
      <point x="1729.0" y="-177.0"/>
      <point x="1661.0" y="-90.0"/>
      <point x="1545.0" y="-90.0" type="curve" smooth="yes"/>
      <point x="1433.0" y="-90.0"/>
      <point x="1362.0" y="-171.0"/>
      <point x="1362.0" y="-278.0" type="curve" smooth="yes"/>
      <point x="1362.0" y="-385.0"/>
      <point x="1432.0" y="-465.0"/>
    </contour>
    <contour>
      <point x="1546.0" y="-398.0" type="curve" smooth="yes"/>
      <point x="1482.0" y="-398.0"/>
      <point x="1441.0" y="-348.0"/>
      <point x="1441.0" y="-281.0" type="curve" smooth="yes"/>
      <point x="1441.0" y="-208.0"/>
      <point x="1481.0" y="-157.0"/>
      <point x="1546.0" y="-157.0" type="curve" smooth="yes"/>
      <point x="1610.0" y="-157.0"/>
      <point x="1649.0" y="-210.0"/>
      <point x="1649.0" y="-283.0" type="curve" smooth="yes"/>
      <point x="1649.0" y="-350.0"/>
      <point x="1606.0" y="-398.0"/>
    </contour>
  </outline>
  <lib>
    <dict>
      <key>com.schriftgestaltung.Glyphs.glyph.leftMetricsKey</key>
      <string>medial_ra</string>
      <key>com.schriftgestaltung.Glyphs.glyph.widthMetricsKey</key>
      <string>medial_ra</string>
      <key>com.schriftgestaltung.Glyphs.lastChange</key>
      <string>2017/10/10 16:27:16</string>
    </dict>
  </lib>
</glyph>

anthrotype avatar Jun 01 '18 14:06 anthrotype

it does not happen to this glyph, which is very similar in shape:

<?xml version="1.0" encoding="UTF-8"?>
<glyph name="medial_ra_wa.w2" format="2">
  <advance width="229.0"/>
  <note>
    medial_ra_wa.w2
  </note>
  <outline>
    <contour>
      <point x="296.0" y="-467.0" type="curve" smooth="yes"/>
      <point x="1089.0" y="-467.0" type="line"/>
      <point x="959.0" y="-395.0" type="line"/>
      <point x="292.0" y="-395.0" type="line" smooth="yes"/>
      <point x="214.0" y="-395.0"/>
      <point x="181.0" y="-349.0"/>
      <point x="181.0" y="-269.0" type="curve" smooth="yes"/>
      <point x="181.0" y="806.0" type="line" smooth="yes"/>
      <point x="181.0" y="885.0"/>
      <point x="214.0" y="931.0"/>
      <point x="292.0" y="931.0" type="curve" smooth="yes"/>
      <point x="1077.0" y="931.0" type="line" smooth="yes"/>
      <point x="1153.0" y="931.0"/>
      <point x="1188.0" y="885.0"/>
      <point x="1188.0" y="806.0" type="curve" smooth="yes"/>
      <point x="1188.0" y="760.0" type="line"/>
      <point x="1277.0" y="760.0" type="line"/>
      <point x="1277.0" y="789.0" type="line" smooth="yes"/>
      <point x="1277.0" y="932.0"/>
      <point x="1209.0" y="1003.0"/>
      <point x="1072.0" y="1003.0" type="curve" smooth="yes"/>
      <point x="296.0" y="1003.0" type="line" smooth="yes"/>
      <point x="159.0" y="1003.0"/>
      <point x="91.0" y="932.0"/>
      <point x="91.0" y="789.0" type="curve" smooth="yes"/>
      <point x="91.0" y="-253.0" type="line" smooth="yes"/>
      <point x="91.0" y="-396.0"/>
      <point x="159.0" y="-467.0"/>
    </contour>
    <contour>
      <point x="1089.0" y="-467.0" type="curve" smooth="yes"/>
      <point x="1204.0" y="-467.0"/>
      <point x="1275.0" y="-384.0"/>
      <point x="1275.0" y="-283.0" type="curve" smooth="yes"/>
      <point x="1275.0" y="-180.0"/>
      <point x="1206.0" y="-91.0"/>
      <point x="1091.0" y="-91.0" type="curve" smooth="yes"/>
      <point x="976.0" y="-91.0"/>
      <point x="908.0" y="-180.0"/>
      <point x="908.0" y="-283.0" type="curve" smooth="yes"/>
      <point x="908.0" y="-384.0"/>
      <point x="978.0" y="-467.0"/>
    </contour>
    <contour>
      <point x="1092.0" y="-400.0" type="curve" smooth="yes"/>
      <point x="1028.0" y="-400.0"/>
      <point x="988.0" y="-349.0"/>
      <point x="988.0" y="-281.0" type="curve" smooth="yes"/>
      <point x="988.0" y="-210.0"/>
      <point x="1026.0" y="-158.0"/>
      <point x="1092.0" y="-158.0" type="curve" smooth="yes"/>
      <point x="1156.0" y="-158.0"/>
      <point x="1195.0" y="-213.0"/>
      <point x="1195.0" y="-285.0" type="curve" smooth="yes"/>
      <point x="1195.0" y="-350.0"/>
      <point x="1153.0" y="-400.0"/>
    </contour>
  </outline>
  <lib>
    <dict>
      <key>com.schriftgestaltung.Glyphs.glyph.leftMetricsKey</key>
      <string>medial_ra</string>
      <key>com.schriftgestaltung.Glyphs.glyph.widthMetricsKey</key>
      <string>medial_ra</string>
      <key>com.schriftgestaltung.Glyphs.lastChange</key>
      <string>2017/10/10 16:27:16</string>
    </dict>
  </lib>
</glyph>

anthrotype avatar Jun 01 '18 14:06 anthrotype

it definitely has something to do with two points from different contours being on top of each other, and one being a tangent point between line/curve, the other being a sharp corner. something like https://github.com/typemytype/booleanOperations/issues/27 -- which we thought was fixed, but apparently not.

anthrotype avatar Jun 01 '18 14:06 anthrotype

the problem is that the bottom part is not straight, its 2 units of, likely a design mistake...

however it should not happen: but it happens when flatting out that extremely shallow line and points got lost, even when the numbers are bigger.

typemytype avatar Jun 10 '18 21:06 typemytype