def test_roundTrip1(self): spen = _TestSegmentPen() pen = SegmentToPointPen(PointToSegmentPen(spen)) pen.moveTo((10, 10)) pen.lineTo((10, 20)) pen.lineTo((20, 20)) pen.closePath() self.assertEqual("10 10 moveto 10 20 lineto 20 20 lineto closepath", repr(spen))
def test_roundTrip2(self): spen = _TestSegmentPen() pen = SegmentToPointPen(PointToSegmentPen(spen)) pen.qCurveTo((10, 20), (20, 20), (20, 10), (10, 10), None) pen.closePath() pen.addComponent('base', [1, 0, 0, 1, 0, 0]) self.assertEqual( "10 20 20 20 20 10 10 10 None qcurveto closepath " "'base' [1, 0, 0, 1, 0, 0] addcomponent", repr(spen))
def test_cubic(self): tpen = _TestPointPen() pen = SegmentToPointPen(tpen) pen.moveTo((10, 10)) pen.curveTo((10, 20), (20, 20), (20, 10)) pen.closePath() self.assertEqual("beginPath() addPoint((10, 10), segmentType='line') " "addPoint((10, 20)) addPoint((20, 20)) addPoint((20, 10), " "segmentType='curve') endPath()", repr(tpen))
def test_roundTrip1(self): tpen = _TestPointPen() ppen = PointToSegmentPen(SegmentToPointPen(tpen)) ppen.beginPath() ppen.addPoint((10, 10), "line") ppen.addPoint((10, 20)) ppen.addPoint((20, 20)) ppen.addPoint((20, 40), "curve") ppen.endPath() self.assertEqual("beginPath() addPoint((10, 10), segmentType='line') addPoint((10, 20)) " "addPoint((20, 20)) addPoint((20, 40), segmentType='curve') endPath()", repr(tpen))
def test_move(self): tpen = _TestPointPen() pen = SegmentToPointPen(tpen) pen.moveTo((10, 10)) pen.endPath() self.assertEqual("beginPath() addPoint((10, 10), segmentType='move') endPath()", repr(tpen))
def test_quad2(self): tpen = _TestPointPen() pen = SegmentToPointPen(tpen) pen.qCurveTo((10, 20), (20, 20), (20, 10), (10, 10), None) pen.closePath() self.assertEqual( "beginPath() addPoint((10, 20)) addPoint((20, 20)) " "addPoint((20, 10)) addPoint((10, 10)) endPath()", repr(tpen))
def test_roundTrip2(self): tpen = _TestPointPen() ppen = PointToSegmentPen(SegmentToPointPen(tpen)) ppen.beginPath() ppen.addPoint((0, 651), segmentType="line") ppen.addPoint((0, 101), segmentType="line") ppen.addPoint((0, 101), segmentType="line") ppen.addPoint((0, 651), segmentType="line") ppen.endPath() self.assertEqual( "beginPath() " "addPoint((0, 651), segmentType='line') " "addPoint((0, 101), segmentType='line') " "addPoint((0, 101), segmentType='line') " "addPoint((0, 651), segmentType='line') " "endPath()", repr(tpen))
def getReversePen(self): adapterPen = PointToSegmentPen(self.otherPen) reversePen = ReverseContourPointPen(adapterPen) return SegmentToPointPen(reversePen)
def getPen(self) -> AbstractPen: """Returns a pen for others to draw into self.""" pen = SegmentToPointPen(self.getPointPen()) return pen
def test(glyphsets, glyphs=None, names=None): if names is None: names = glyphsets if glyphs is None: glyphs = glyphsets[0].keys() hist = [] problems = OrderedDict() def add_problem(glyphname, problem): problems.setdefault(glyphname, []).append(problem) for glyph_name in glyphs: # print() # print(glyph_name) try: allVectors = [] allNodeTypes = [] allContourIsomorphisms = [] for glyphset, name in zip(glyphsets, names): # print('.', end='') if glyph_name not in glyphset: add_problem(glyph_name, { "type": "missing", "master": name }) continue glyph = glyphset[glyph_name] perContourPen = PerContourOrComponentPen(RecordingPen, glyphset=glyphset) try: glyph.draw(perContourPen, outputImpliedClosingLine=True) except TypeError: glyph.draw(perContourPen) contourPens = perContourPen.value del perContourPen contourVectors = [] contourIsomorphisms = [] nodeTypes = [] allNodeTypes.append(nodeTypes) allVectors.append(contourVectors) allContourIsomorphisms.append(contourIsomorphisms) for ix, contour in enumerate(contourPens): nodeVecs = tuple(instruction[0] for instruction in contour.value) nodeTypes.append(nodeVecs) stats = StatisticsPen(glyphset=glyphset) try: contour.replay(stats) except OpenContourError as e: add_problem( glyph_name, { "master": name, "contour": ix, "type": "open_path" }, ) continue size = abs(stats.area)**0.5 * 0.5 vector = ( int(size), int(stats.meanX), int(stats.meanY), int(stats.stddevX * 2), int(stats.stddevY * 2), int(stats.correlation * size), ) contourVectors.append(vector) # print(vector) # Check starting point if nodeVecs[0] == 'addComponent': continue assert nodeVecs[0] == 'moveTo' assert nodeVecs[-1] in ('closePath', 'endPath') points = RecordingPointPen() converter = SegmentToPointPen(points, False) contour.replay(converter) # points.value is a list of pt,bool where bool is true if on-curve and false if off-curve; # now check all rotations and mirror-rotations of the contour and build list of isomorphic # possible starting points. bits = 0 for pt, b in points.value: bits = (bits << 1) | b n = len(points.value) mask = (1 << n) - 1 isomorphisms = [] contourIsomorphisms.append(isomorphisms) for i in range(n): b = ((bits << i) & mask) | ((bits >> (n - i))) if b == bits: isomorphisms.append( _rot_list( [complex(*pt) for pt, bl in points.value], i)) # Add mirrored rotations mirrored = list(reversed(points.value)) reversed_bits = 0 for pt, b in mirrored: reversed_bits = (reversed_bits << 1) | b for i in range(n): b = ((reversed_bits << i) & mask) | ((reversed_bits >> (n - i))) if b == bits: isomorphisms.append( _rot_list( [complex(*pt) for pt, bl in mirrored], i)) # Check each master against the next one in the list. for i, (m0, m1) in enumerate(zip(allNodeTypes[:-1], allNodeTypes[1:])): if len(m0) != len(m1): add_problem( glyph_name, { "type": "path_count", "master_1": names[i], "master_2": names[i + 1], "value_1": len(m0), "value_2": len(m1), }, ) if m0 == m1: continue for pathIx, (nodes1, nodes2) in enumerate(zip(m0, m1)): if nodes1 == nodes2: continue if len(nodes1) != len(nodes2): add_problem( glyph_name, { "type": "node_count", "path": pathIx, "master_1": names[i], "master_2": names[i + 1], "value_1": len(nodes1), "value_2": len(nodes2), }, ) continue for nodeIx, (n1, n2) in enumerate(zip(nodes1, nodes2)): if n1 != n2: add_problem( glyph_name, { "type": "node_incompatibility", "path": pathIx, "node": nodeIx, "master_1": names[i], "master_2": names[i + 1], "value_1": n1, "value_2": n2, }, ) continue for i, (m0, m1) in enumerate(zip(allVectors[:-1], allVectors[1:])): if len(m0) != len(m1): # We already reported this continue if not m0: continue costs = [[_vlen(_vdiff(v0, v1)) for v1 in m1] for v0 in m0] matching, matching_cost = min_cost_perfect_bipartite_matching( costs) identity_matching = list(range(len(m0))) identity_cost = sum(costs[i][i] for i in range(len(m0))) if matching != identity_matching and matching_cost < identity_cost * .95: add_problem( glyph_name, { "type": "contour_order", "master_1": names[i], "master_2": names[i + 1], "value_1": list(range(len(m0))), "value_2": matching, }, ) break for i, (m0, m1) in enumerate( zip(allContourIsomorphisms[:-1], allContourIsomorphisms[1:])): if len(m0) != len(m1): # We already reported this continue if not m0: continue for contour0, contour1 in zip(m0, m1): c0 = contour0[0] costs = [ v for v in (_complex_vlen(_vdiff(c0, c1)) for c1 in contour1) ] min_cost = min(costs) first_cost = costs[0] if min_cost < first_cost * .95: add_problem( glyph_name, { "type": "wrong_start_point", "master_1": names[i], "master_2": names[i + 1], }, ) except ValueError as e: add_problem( glyph_name, { "type": "math_error", "master": name, "error": e }, ) return problems
def drawPoints(pointPen): pen = SegmentToPointPen(pointPen) outline.draw(pen)
def drawToPointPen(self, pen): self.drawToPen(SegmentToPointPen(pen))
def getPen(self): pen = SegmentToPointPen(self.getPointPen()) return pen
def getPen(self): from fontTools.pens.pointPen import SegmentToPointPen return SegmentToPointPen(self.getPointPen())
def drawPoints(self, pointPen): """Use another PointPen to replay the glyph's outline commands, indirectly through an adapter. """ pen = SegmentToPointPen(pointPen) self.draw(pen)
def getPen(self): return SegmentToPointPen(self.getPointPen())
def getPen(self): """Return a SegmentPen adapter that can 'draw' on this glyph.""" return SegmentToPointPen(self._pen)
def getPen(self): return SegmentToPointPen(self.outline)