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
def getExtremaForQuadratic(pt1, pt2, pt3, h=True, v=False): (ax, ay), (bx, by), c = calcQuadraticParameters(pt1, pt2, pt3) ax *= 2.0 ay *= 2.0 points = [] vectors = [] if h: roots = [t for t in solveLinear(ay, by) if 0 < t < 1] points, vectors = get_extrema_points_vectors_quad(roots, pt1, pt2, pt3) if v: roots = [t for t in solveLinear(ax, bx) if 0 < t < 1] v_points, v_vectors = get_extrema_points_vectors_quad(roots, pt1, pt2, pt3) points += v_points vectors += v_vectors return points, vectors
def getExtremaForQuadratic(pt1, pt2, pt3, h=True, v=False): (ax, ay), (bx, by), c = calcQuadraticParameters(pt1, pt2, pt3) ax *= 2.0 ay *= 2.0 points = [] vectors = [] if h: roots = [t for t in solveLinear(ay, by) if 0 < t < 1] points, vectors = get_extrema_points_vectors_quad(roots, pt1, pt2, pt3) if v: roots = [t for t in solveLinear(ax, bx) if 0 < t < 1] v_points, v_vectors = get_extrema_points_vectors_quad( roots, pt1, pt2, pt3) points += v_points vectors += v_vectors return points, vectors
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
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
def getExtremaForQuadratic( pt0: Point, pt1: Point, pt2: Point, h: bool = True, v: bool = False, include_start_end: bool = False, ) -> List[float]: """ Return a list of t values at which the quadratic curve defined by pt0, pt1, pt2 has extrema. :param h: Calculate extrema for horizontal derivative == 0 (= what type designers call vertical extrema!). :type h: bool :param v: Calculate extrema for vertical derivative == 0 (= what type designers call horizontal extrema!). :type v: bool :param include_start_end: Also calculate extrema that lie at the start or end point of the curve. :type include_start_end: bool """ (ax, ay), (bx, by), _c = calcQuadraticParameters(pt0, pt1, pt2) ax *= 2.0 ay *= 2.0 roots = [] if include_start_end: if h: roots = [t for t in solveLinear(ay, by) if 0 <= t <= 1] if v: roots += [t for t in solveLinear(ax, bx) if 0 <= t <= 1] else: if h: roots = [t for t in solveLinear(ay, by) if 0 < t < 1] if v: roots += [t for t in solveLinear(ax, bx) if 0 < t < 1] return roots
pt1 = (100, 100) pt2 = (200, 20) pt3 = (30, 580) pt4 = (153, 654) rect = [20, 20, 100, 100] ## loops c = 10000 print "(loop %s)" % c print "with numpy:" print "calcQuadraticParameters\t\t", n = time.time() for i in range(c): bezierTools.calcQuadraticParameters(pt1, pt2, pt3) print time.time() - n print "calcBounds\t\t\t", n = time.time() for i in range(c): arrayTools.calcBounds( [pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3]) print time.time() - n print "pointsInRect\t\t\t", n = time.time() for i in range(c): arrayTools.pointsInRect( [pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3, pt4], rect)
pt2 = (200, 20) pt3 = (30, 580) pt4 = (153, 654) rect = [20, 20, 100, 100] ## loops c = 10000 print "(loop %s)"%c print "with numpy:" print "calcQuadraticParameters\t\t", n = time.time() for i in range(c): bezierTools.calcQuadraticParameters(pt1, pt2, pt3) print time.time() - n print "calcBounds\t\t\t", n = time.time() for i in range(c): arrayTools.calcBounds([pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3]) print time.time() - n print "pointsInRect\t\t\t", n = time.time() for i in range(c): arrayTools.pointsInRect([pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3, pt1, pt2, pt3, pt4], rect) print time.time() - n print "calcQuadraticBounds\t\t",