Beispiel #1
0
def _pointWithinThreshold(x, y, curve, eps):
    """
    See whether *(x, y)* is within *eps* of *curve*.
    """
    path = QPainterPath()
    path.addEllipse(x - eps, y - eps, 2 * eps, 2 * eps)
    curvePath = QPainterPath()
    if curve[-1].segmentType == "curve":
        p1, p2, p3, p4 = curve
        curvePath.moveTo(p1.x, p1.y)
        curvePath.cubicTo(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y)
        curvePath.cubicTo(p3.x, p3.y, p2.x, p2.y, p1.x, p1.y)
    else:
        first = curve[0]
        curvePath.moveTo(first.x, first.y)
        # PACK for fontTools
        pts = []
        for pt in curve:
            pts.append((pt.x, pt.y))
        # draw
        for pt1, pt2 in decomposeQuadraticSegment(pts[1:]):
            curvePath.quadTo(*pt1 + pt2)
        for pt1, pt2 in decomposeQuadraticSegment(list(reversed(pts[:-1]))):
            curvePath.quadTo(*pt1 + pt2)
    return path.intersects(curvePath)
Beispiel #2
0
def _pointWithinThreshold(x, y, curve, eps):
    """
    See whether *(x, y)* is within *eps* of *curve*.
    """
    path = QPainterPath()
    path.addEllipse(x - eps, y - eps, 2 * eps, 2 * eps)
    curvePath = QPainterPath()
    if curve[-1].segmentType == "curve":
        p1, p2, p3, p4 = curve
        curvePath.moveTo(p1.x, p1.y)
        curvePath.cubicTo(p2.x, p2.y, p3.x, p3.y, p4.x, p4.y)
        curvePath.cubicTo(p3.x, p3.y, p2.x, p2.y, p1.x, p1.y)
    else:
        first = curve[0]
        curvePath.moveTo(first.x, first.y)
        # PACK for fontTools
        pts = []
        for pt in curve:
            pts.append((pt.x, pt.y))
        # draw
        for pt1, pt2 in decomposeQuadraticSegment(pts[1:]):
            curvePath.quadTo(*pt1+pt2)
        for pt1, pt2 in decomposeQuadraticSegment(list(reversed(pts[:-1]))):
            curvePath.quadTo(*pt1+pt2)
    return path.intersects(curvePath)
Beispiel #3
0
def _tValueForPointOnQuadCurve(point, pts, isHorizontal=0):
    quadSegments = decomposeQuadraticSegment(pts[1:])
    previousOnCurve = pts[0]
    solutionsDict = dict()
    for index, (pt1, pt2) in enumerate(quadSegments):
        a, b, c = bezierTools.calcQuadraticParameters(previousOnCurve, pt1,
                                                      pt2)
        subSolutions = bezierTools.solveQuadratic(
            a[isHorizontal], b[isHorizontal],
            c[isHorizontal] - point[isHorizontal])
        subSolutions = [t for t in subSolutions if 0 <= t < 1]
        for t in subSolutions:
            solutionsDict[(t, index)] = _getQuadPoint(t, previousOnCurve, pt1,
                                                      pt2)
        previousOnCurve = pt2
    solutions = solutionsDict.keys()
    if not solutions and not isHorizontal:
        return _tValueForPointOnQuadCurve(point, pts, isHorizontal=1)
    if len(solutions) > 1:
        intersectionLenghts = {}
        for t in solutions:
            tp = solutionsDict[t]
            dist = _distance(tp, point)
            intersectionLenghts[dist] = t
        minDist = min(intersectionLenghts.keys())
        solutions = [intersectionLenghts[minDist]]
    return solutions
Beispiel #4
0
 def qCurveTo(self, *points):
     decomp = decomposeQuadraticSegment(points)
     for pair in decomp:
         if pair[1] is None:
             pair = (pair[0],decomp[0][0])
         shifted = self.shiftList(pair)
         print(self.indent+"path.quadTo(%gf,%gf,%gf,%gf);" % tuple(shifted[0]+shifted[1]))
Beispiel #5
0
 def qCurveTo(self, *points):
     if points and points[-1] is None:
         print("// this shouldn't happen but it does")
         print(self.indent +
               "path.moveTo(%gf,%gf);" % self.shift(points[0]))
         points = points[:-1]
     decomp = decomposeQuadraticSegment(points)
     for pair in decomp:
         shifted = self.shiftList(pair)
         if shifted[0] and shifted[1]:
             print(self.indent + "path.quadTo(%gf,%gf,%gf,%gf);" %
                   tuple(shifted[0] + shifted[1]))
Beispiel #6
0
 def __init__(self, points=None, previousOnCurve=None, willBeReversed=False):
     if points is None:
         points = []
     self.points = points
     self.previousOnCurve = previousOnCurve
     self.scaledPreviousOnCurve = _scaleSinglePoint(previousOnCurve, scale=clipperScale)
     self.used = False
     self.flat = []
     # if the bcps are equal to the oncurves convert the segment to a line segment.
     # otherwise this causes an error when flattening.
     if self.segmentType == "curve":
         if previousOnCurve == points[0].coordinates and points[1].coordinates == points[-1].coordinates:
             oncurve = points[-1]
             oncurve.segmentType = "line"
             self.points = points = [oncurve]
     # its a reversed segment the flat points will be set later on in the InputContour
     if willBeReversed:
         return
     pointsToFlatten = []
     if self.segmentType == "qcurve":
         assert len(points) >= 0
         flat = []
         currentOnCurve = previousOnCurve
         pointCoordinates = [point.coordinates for point in points]
         for pt1, pt2 in decomposeQuadraticSegment(pointCoordinates[1:]):
             pt0x, pt0y = currentOnCurve
             pt1x, pt1y = pt1
             pt2x, pt2y = pt2
             mid1x = pt0x + 0.66666666666666667 * (pt1x - pt0x)
             mid1y = pt0y + 0.66666666666666667 * (pt1y - pt0y)
             mid2x = pt2x + 0.66666666666666667 * (pt1x - pt2x)
             mid2y = pt2y + 0.66666666666666667 * (pt1y - pt2y)
             
             convertedQuadPointToFlatten = [currentOnCurve, (mid1x, mid1y), (mid2x, mid2y), pt2]
             flat.extend(_flattenSegment(convertedQuadPointToFlatten))
             currentOnCurve = pt2
         self.flat = flat
     elif self.segmentType == "curve":
         pointsToFlatten = [previousOnCurve] + [point.coordinates for point in points]
     else:
         assert len(points) == 1
         self.flat = [point.coordinates for point in points]
     if pointsToFlatten:
         self.flat = _flattenSegment(pointsToFlatten)
     self.flat = _scalePoints(self.flat, scale=clipperScale)
     self.used = False
Beispiel #7
0
def qcurveIntersections(x1, y1, x2, y2, *pts):
    """
    Computes intersection between a cubic spline and a line segment.
    Adapted from: https://www.particleincell.com/2013/cubic-line-intersection/

    Takes four defcon points describing curve and four scalars describing line
    parameters.
    """

    sol = []

    # PACK for fontTools
    points = []
    for pt in pts:
        points.append((pt.x, pt.y))

    p1 = (pts[0].x, pts[0].y)
    for p2, p3 in decomposeQuadraticSegment(points[1:]):
        bx, by = (y1 - y2), (x2 - x1)
        m = x1 * y2 - x2 * y1
        a, b, c = bezierTools.calcQuadraticParameters(p1, p2, p3)

        # prepare for next turn
        p1 = p3

        pc0 = bx * a[0] - by * a[1]
        pc1 = (bx * b[0] + by * b[1]) / pc0
        pc2 = (bx * c[0] + by * c[1] + m) / pc0
        r = bezierTools.solveQuadratic(pc0, pc1, pc2)

        for t in r:
            if t < 0 or t > 1:
                continue
            s0 = a[0] * (1 - t) ** 2 + b[0] * 2 * t * (1 - t) + c[0] * t ** 2
            s1 = a[1] * (1 - t) ** 2 + b[1] * 2 * t * (1 - t) + c[1] * t ** 2
            if (x2 - x1) != 0:
                s = (s0 - x1) / (x2 - x1)
            else:
                s = (s1 - y1) / (y2 - y1)
            if s < 0 or s > 1:
                continue
            sol.append((s0, s1, t))
    return sol
Beispiel #8
0
def _tValueForPointOnQuadCurve(point, pts, isHorizontal=0):
    quadSegments = decomposeQuadraticSegment(pts[1:])
    previousOnCurve = pts[0]
    solutionsDict = dict()
    for index, (pt1, pt2) in enumerate(quadSegments):
        a, b, c = bezierTools.calcQuadraticParameters(previousOnCurve, pt1, pt2)
        subSolutions = bezierTools.solveQuadratic(a[isHorizontal], b[isHorizontal], c[isHorizontal] - point[isHorizontal])
        subSolutions = [t for t in subSolutions if 0 <= t < 1]
        for t in subSolutions:
            solutionsDict[(t, index)] = _getQuadPoint(t, previousOnCurve, pt1, pt2)
        previousOnCurve = pt2
    solutions = list(solutionsDict.keys())
    if not solutions and not isHorizontal:
        return _tValueForPointOnQuadCurve(point, pts, isHorizontal=1)
    if len(solutions) > 1:
        intersectionLenghts = {}
        for t in solutions:
            tp = solutionsDict[t]
            dist = _distance(tp, point)
            intersectionLenghts[dist] = t
        minDist = min(intersectionLenghts.keys())
        solutions = [intersectionLenghts[minDist]]
    return solutions
Beispiel #9
0
 def qCurveTo(self, *points):
     decomp = decomposeQuadraticSegment(points)
     for pair in decomp:
         self.update(pair[1])
Beispiel #10
0
 def qCurveTo(self, *points):
     _qCurveToOne = self._qCurveToOne
     for pt1, pt2 in decomposeQuadraticSegment(points):
         _qCurveToOne(pt1, pt2)
         self.__currentPoint = pt2