Skip to content
New issue

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

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

Already on GitHub? # to your account

FilterRedundantPointPen and start points #276

Closed
arialcrime opened this issue Mar 2, 2022 · 1 comment · Fixed by #277
Closed

FilterRedundantPointPen and start points #276

arialcrime opened this issue Mar 2, 2022 · 1 comment · Fixed by #277

Comments

@arialcrime
Copy link

I came across a situation where depending on the start point, FilterRedundantPointPen is not able to catch redundant offcurve points.

In a glyph like the one here, the offcurve points stay in place after running the pen.

<?xml version='1.0' encoding='UTF-8'?>
<glyph name="C" format="2">
  <advance width="500"/>
  <outline>
    <contour>
      <point x="298" y="132"/>
      <point x="298" y="80"/>
      <point x="298" y="80" type="curve"/>
      <point x="600" y="80" type="line"/>
      <point x="600" y="132" type="line"/>
      <point x="298" y="132" type="line"/>
    </contour>
  </outline>
</glyph>

In the case below, FilterRedundantPointPen works as expected by getting rid of the 2 points without a type.

<?xml version='1.0' encoding='UTF-8'?>
<glyph name="C" format="2">
  <advance width="500"/>
  <outline>
    <contour>
      <point x="298" y="80" type="curve"/>
      <point x="600" y="80" type="line"/>
      <point x="600" y="132" type="line"/>
      <point x="298" y="132" type="line"/>
      <point x="298" y="132"/>
      <point x="298" y="80"/>
    </contour>
  </outline>
</glyph>

@typemytype
Copy link
Member

will make a PR

from fontTools.pens.pointPen import AbstractPointPen

class FilterRedundantPointPen(AbstractPointPen):

    def __init__(self, anotherPointPen):
        self._pen = anotherPointPen
        self._points = []

    def _flushContour(self):
        # convert to a list of mutable dicts
        # keep the point order
        # keep a flag if the point will be removed
        points = [
            dict(
                pt=pt, 
                segmentType=segmentType, 
                smooth=smooth, 
                name=name, 
                identifier=identifier, 
                removed=False
                ) 
                    for pt, segmentType, smooth, name, identifier in self._points
            ]

        for index, data in enumerate(points):
            if data["segmentType"] == "curve":
                prevOnCurve = points[index - 3]
                prevOffCurve1 = points[index -2]
                prevOffCurve2 = points[index - 1]
                
                if prevOnCurve["pt"] == prevOffCurve1["pt"] and prevOffCurve2["pt"] == data["pt"]:
                    # the off curves are on top of the on curve point
                    # change the segmentType
                    data["segmentType"] = "line"
                    # flag the off curves to be removed
                    prevOffCurve1["removed"] = True
                    prevOffCurve2["removed"] = True
                                                    
        for data in points:
            if not data["removed"]:
                self._pen.addPoint(
                    data["pt"], 
                    data["segmentType"], 
                    smooth=data["smooth"], 
                    name=data["name"], 
                    identifier=data["identifier"]
                )

    def beginPath(self, identifier=None, **kwargs):
        self._points = []
        self._pen.beginPath(identifier=identifier)

    def addPoint(self, pt, segmentType=None, smooth=False, name=None, identifier=None, **kwargs):
        self._points.append((pt, segmentType, smooth, name, identifier))

    def endPath(self):
        self._flushContour()
        self._pen.endPath()

    def addComponent(self, baseGlyph, transformation, identifier=None, **kwargs):
        self._pen.addComponent(baseGlyph, transformation, identifier)


from fontPens.printPointPen import PrintPointPen

pen = FilterRedundantPointPen(PrintPointPen())

pen.beginPath()
pen.addPoint((298, 132))
pen.addPoint((298, 80))
pen.addPoint((298, 80), segmentType="curve")
pen.addPoint((600, 80), segmentType="line")
pen.addPoint((600, 132), segmentType="line")
pen.addPoint((298, 132), segmentType="line")
pen.endPath()


pen.beginPath()
pen.addPoint((298, 80), segmentType="curve")
pen.addPoint((600, 80), segmentType="line")
pen.addPoint((600, 132), segmentType="line")
pen.addPoint((298, 132), segmentType="line")
pen.addPoint((298, 132))
pen.addPoint((298, 80))
pen.endPath()

pen.beginPath()
pen.addPoint((298, 80))
pen.addPoint((298, 80), segmentType="curve")
pen.addPoint((600, 80), segmentType="line")
pen.addPoint((600, 132), segmentType="line")
pen.addPoint((298, 132), segmentType="line")
pen.addPoint((298, 132))

pen.endPath()

pen.beginPath()
pen.addPoint((298, 132))
pen.addPoint((298, 81))
pen.addPoint((298, 80), segmentType="curve")
pen.addPoint((600, 80), segmentType="line")
pen.addPoint((600, 132), segmentType="line")
pen.addPoint((298, 132), segmentType="line")
pen.endPath()


pen.beginPath()
pen.addPoint((298, 80), segmentType="curve")
pen.addPoint((600, 80), segmentType="line")
pen.addPoint((600, 132), segmentType="line")
pen.addPoint((298, 132), segmentType="line")
pen.addPoint((298, 132))
pen.addPoint((298, 81))
pen.endPath()

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants