def removeOverlap(self): bGlyph = BooleanGlyph(self).removeOverlap() # TODO: we're halting removeOverlap for collinear vector diffs (changes # point count, not contour), is this what we want to do? if len(bGlyph.contours) != len(self): self.prepareUndo() self.clearContours() bGlyph.draw(self.getPen()) self.dirty = True
def calculate_pathop(pen1, pen2, operation): if USE_SKIA_PATHOPS: p1 = Path() pen1.replay(p1.getPen()) if operation == BooleanOp.Simplify: # ignore pen2 p1.simplify(fix_winding=True, keep_starting_points=True) d0 = RecordingPen() p1.draw(d0) return d0.value if pen2: p2 = Path() pen2.replay(p2.getPen()) builder = OpBuilder(fix_winding=True, keep_starting_points=True) builder.add(p1, PathOp.UNION) if pen2: builder.add(p2, BooleanOp.Skia(operation)) result = builder.resolve() d0 = RecordingPen() result.draw(d0) return d0.value else: bg2 = BooleanGlyph() if pen2: pen2.replay(bg2.getPen()) bg = BooleanGlyph() pen1.replay(bg.getPen()) bg = bg._booleanMath(BooleanOp.BooleanGlyphMethod(operation), bg2) dp = RecordingPen() bg.draw(dp) return dp.value
def hasOverlap(self): bGlyph = BooleanGlyph() pen = bGlyph.getPointPen() openContours = 0 for contour in self: if not contour.open: contour.drawPoints(pen) else: openContours += 1 bGlyph.removeOverlap() return len(bGlyph.contours) + openContours != len(self)
def removeOverlap(self): # TODO: maybe clear undo stack if no changes self.prepareUndo() bGlyph = BooleanGlyph() pen = bGlyph.getPointPen() for contour in list(self): if not contour.open: contour.drawPoints(pen) self.removeContour(contour) else: contour.selected = False bGlyph = bGlyph.removeOverlap() pen = self.getPointPen() for contour in bGlyph.contours: contour.drawPoints(pen) self.dirty = True
def test_remove_tiny_sub_paths_large_contour(): g = Glyph() p = g.getPen() p.moveTo((100, 100)) p.lineTo((200, 200)) p.lineTo((0, 100)) p.closePath() assert len(g[0]) == 3 assert g.bounds == (0, 100, 200, 200) bg = BooleanGlyph(g) assert remove_tiny_sub_paths(bg, 25, []) == []
def test_remove_tiny_sub_paths_small_contour(): g = Glyph() p = g.getPen() p.moveTo((1, 1)) p.lineTo((2, 2)) p.lineTo((0, 1)) p.closePath() assert len(g[0]) == 3 assert g.bounds == (0, 1, 2, 2) bg = BooleanGlyph(g) assert remove_tiny_sub_paths(bg, 25, []) == \ ['Contour 0 is too small: bounding box is less than minimum area. ' 'Start point: ((1, 1)).']
def mergeContours(glyph): # remember stuff that get's lost when drawing to a fontforge glyph width = glyph.width vwidth = glyph.vwidth anchorPoints = tuple(glyph.anchorPoints) # make a defcon glyph dcGlyph = defcon.Glyph() dcGlyphPen = dcGlyph.getPen() # draw to dcGlyph glyph.draw(dcGlyphPen) # union of dcGlyph result = BooleanGlyph(dcGlyph).removeOverlap() targetPen = glyph.glyphPen() result.draw(targetPen) # restore stuff that a pen should rather not change automagically # in fact, the pen should not reset anything besides outline and components. glyph.width = width glyph.vwidth = vwidth [glyph.addAnchorPoint(*p) for p in anchorPoints]
def filterGroup(glyph, font=None, **overrideGlobalArguments): globalArguments = { self.splitSubfilterArgumentName(argumentName): self.arguments[argumentName] for argumentName in self.arguments } for key in overrideGlobalArguments: _subfilterName_, _overrideArgumentName_, _filterOrder_ = self.splitSubfilterArgumentName( key) if (_subfilterName_, _overrideArgumentName_) != (None, None): globalArguments[( _subfilterName_, _overrideArgumentName_, _filterOrder_)] = overrideGlobalArguments[key] subfilters = [(self.getSubfilter(subfilterName), mode, source) for subfilterName, mode, source in self.subfilters] error = False canvasGlyph = RGlyph() canvasPen = canvasGlyph.getPen() canvasGlyph.width = glyph.width glyph.draw(canvasPen) steps = [] for i, (currentFilter, mode, source) in enumerate(subfilters): if error == True: continue if not source: sourceGlyph = canvasGlyph else: try: sourceGlyph = steps[source - 1] except: layerGlyph = glyph.getLayer(source) if len(layerGlyph) > 0: sourceGlyph = RGlyph() pen = sourceGlyph.getPen() layerGlyph.draw(pen) else: sourceGlyph = canvasGlyph sourceGlyph.name = glyph.name arguments = { argumentName: globalArguments[(subfilterName, argumentName, filterOrder)] for subfilterName, argumentName, filterOrder in globalArguments if subfilterName == currentFilter.name and filterOrder == i } processedGlyph = currentFilter.filterGlyph( sourceGlyph, arguments) if mode in ['union', 'difference', 'intersection', 'xor']: try: # collectedComponents = [component for component in processedGlyph.components] b1 = BooleanGlyph(canvasGlyph) b2 = BooleanGlyph(processedGlyph) operation = getattr(b1, mode) b3 = operation(b2) processedGlyph = RGlyph() processedPen = processedGlyph.getPen() b3.draw(processedPen) # for component in collectedComponents: # processedGlyph.appendComponent(component.baseGlyph, component.offset, component.scale) except: error = True steps.append(processedGlyph) if mode == 'ignore' and len(steps) > 1: processedGlyph = steps[-2] elif mode == 'ignore': processedGlyph = sourceGlyph if mode != 'add': canvasGlyph.clear() processedGlyph.draw(canvasPen) if processedGlyph.width: canvasGlyph.width = processedGlyph.width if error == True: canvasGlyph = ErrorGlyph() elif error == False: cleanPen = FilterPointPen(font) canvasGlyph.drawPoints(cleanPen) canvasGlyph.clearContours() canvasPointPen = canvasGlyph.getPointPen() cleanPen.extract(canvasPointPen) canvasGlyph.name = glyph.name canvasGlyph.unicode = glyph.unicode if canvasGlyph.width is None: canvasGlyph.width = glyph.width return canvasGlyph
def filterGroup(glyph, font=None, **overrideGlobalArguments): globalArguments = { self.splitSubfilterArgumentName(argumentName): self.arguments[argumentName] for argumentName in self.arguments } for key in overrideGlobalArguments: _subfilterName_, _overrideArgumentName_, _filterOrder_ = self.splitSubfilterArgumentName( key) if (_subfilterName_, _overrideArgumentName_) != (None, None): globalArguments[( _subfilterName_, _overrideArgumentName_, _filterOrder_)] = overrideGlobalArguments[key] subfilters = [(self.getSubfilter(subfilterName), mode, source) for subfilterName, mode, source in self.subfilters] error = False canvasGlyph = RGlyph() canvasPen = canvasGlyph.getPen() canvasGlyph.width = glyph.width glyph.draw(canvasPen) steps = [] for i, (currentFilter, mode, source) in enumerate(subfilters): if error == True: continue if source is None: sourceGlyph = canvasGlyph else: try: sourceGlyph = steps[source] except: layerGlyph = glyph.getLayer(source) if len(layerGlyph) > 0: sourceGlyph = RGlyph() pen = sourceGlyph.getPen() layerGlyph.draw(pen) else: sourceGlyph = canvasGlyph sourceGlyph.name = glyph.name arguments = { argumentName: globalArguments[(subfilterName, argumentName, filterOrder)] for subfilterName, argumentName, filterOrder in globalArguments if subfilterName == currentFilter.name and filterOrder == i } processedGlyph = currentFilter.filterGlyph( sourceGlyph, arguments) steps.append(processedGlyph) if mode in ['union', 'difference', 'intersection', 'xor']: try: b1 = BooleanGlyph(canvasGlyph) b2 = BooleanGlyph(processedGlyph) operation = getattr(b1, mode) processedGlyph = operation(b2) except: error = True if mode != 'add': canvasGlyph.clear() processedGlyph.draw(canvasPen) if error == True: canvasGlyph = ErrorGlyph() elif error == False: canvasGlyph.name = glyph.name canvasGlyph.unicode = glyph.unicode if canvasGlyph.width is None: canvasGlyph.width = glyph.width return canvasGlyph
def hasOverlap(self): bGlyph = BooleanGlyph(self).removeOverlap() return len(bGlyph.contours) != len(self)