def getWeightValue(t, curviness, axMin, axMax):

    curve = ((0,0), (0, H*curviness), (W,H-(H*curviness)), (W,H)) # slow to fast to slow (bell curve)
    split = splitCubicAtT(*curve, t)
    x, y = split[0][-1]
    # if t <= 0.75:
    if t <= 0.5:
        # Scale the y value to the range of 0 and 1, assuming it was in a range of 0 to 1000
        f = x / W * 2
        
        # f *= 2
        value = interpolate(axMin, 800, f)
        
    else:
        # curve = ((W/2,H), (W/2,H-(H*curviness)), (W, H*curviness),(W,0)) # slow to fast to slow (bell curve)
        # curve = ((0,0), (0, H*curviness), (W/2,H-(H*curviness)), (W/2,H)) # slow to fast to slow (bell curve)
        split = splitCubicAtT(*curve, t)
        x, y = split[0][-1]
        # Scale the y value to the range of 0 and 1, assuming it was in a range of 0 to 1000
        f = x / W
        # f = 1 - (f - 0.5) * 2 # reversed
        f = (f - 0.5) * 2 

        value = interpolate(800, axMax, f)

    return value, x, y
Пример #2
0
def test_splitCubicAtT():
    assert splitCubicAtT(
        (0, 0), (25, 100), (75, 100), (100, 0),
        0.5) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)),
                 ((50, 75), (68.75, 75), (87.5, 50), (100, 0))]
    assert splitCubicAtT(
        (0, 0), (25, 100), (75, 100), (100, 0), 0.5,
        0.75) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)),
                  ((50, 75), (59.375, 75), (68.75, 68.75), (77.34375, 56.25)),
                  ((77.34375, 56.25), (85.9375, 43.75), (93.75, 25), (100, 0))]
Пример #3
0
def test_splitCubicAtT():
    assert splitCubicAtT(
        (0, 0), (25, 100), (75, 100), (100, 0), 0.5
    ) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)),
          ((50, 75), (68.75, 75), (87.5, 50), (100, 0))]
    assert splitCubicAtT(
        (0, 0), (25, 100), (75, 100), (100, 0), 0.5, 0.75
    ) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)),
          ((50, 75), (59.375, 75), (68.75, 68.75), (77.34375, 56.25)),
          ((77.34375, 56.25), (85.9375, 43.75), (93.75, 25), (100, 0))]
Пример #4
0
def get_extrema_points_vectors(roots, pt1, pt2, pt3, pt4):
    split_segments = [
        p for p in splitCubicAtT(pt1, pt2, pt3, pt4, *roots)[:-1]
    ]
    points = [p[3] for p in split_segments]
    vectors = [get_vector(p[2], p[3]) for p in split_segments]
    return points, vectors
Пример #5
0
def append_point_rate(contour, rpoints, rate):
    """ Appends RPoint object to curve(RSegment object) by rate.

    Args:
        contour:: RContour
            The RContour object that you want to add RPoint object.
        rpoints:: list
            A list of RPoint objects. It should be containing 4 RPoint objects like
            [startpoint, bcp(of startpoint), bcp(of endpoint), endpoint].
            The order of start and end follows a index of contour.points.
        rate:: float
            A rate of location. It must be in [0, 1].

    Raises:
        arguments value error:: ValueError
            If not found target segment in contour, raises this error.
            This can be occured when the rpoints(RPoint objects) are not in the contour.points.
        splitting error:: AssertionError
            If function of splitting is not done properly, raises this error.
            For example, if it split one line(or curve) but result is also one line(or curve).
    """
    points = _r2t(rpoints)
    new_curve = splitCubicAtT(points[0], points[1], points[2], points[3], rate)
    print("new_curve")
    assert (len(new_curve) > 1)
    _append_point_curve(contour, rpoints, new_curve)
Пример #6
0
 def split(self, tValues):
     """
     Split the segment according the t values
     """
     if self.segmentType == "curve":
         on1 = self.previousOnCurve
         off1 = self.points[0].coordinates
         off2 = self.points[1].coordinates
         on2 = self.points[2].coordinates
         return bezierTools.splitCubicAtT(on1, off1, off2, on2, *tValues)
     elif self.segmentType == "line":
         segments = []
         x1, y1 = self.previousOnCurve
         x2, y2 = self.points[0].coordinates
         dx = x2 - x1
         dy = y2 - y1
         pp = x1, y1
         for t in tValues:
             np = (x1+dx*t, y1+dy*t)
             segments.append([pp, np])
             pp = np
         segments.append([pp, (x2, y2)])
         return segments
     elif self.segmentType == "qcurve":
         raise NotImplementedError
     else:
         raise NotImplementedError
Пример #7
0
 def split(self, tValues):
     """
     Split the segment according the t values
     """
     if self.segmentType == "curve":
         on1 = self.previousOnCurve
         off1 = self.points[0].coordinates
         off2 = self.points[1].coordinates
         on2 = self.points[2].coordinates
         return bezierTools.splitCubicAtT(on1, off1, off2, on2, *tValues)
     elif self.segmentType == "line":
         segments = []
         x1, y1 = self.previousOnCurve
         x2, y2 = self.points[0].coordinates
         dx = x2 - x1
         dy = y2 - y1
         pp = x1, y1
         for t in tValues:
             np = (x1 + dx * t, y1 + dy * t)
             segments.append([pp, np])
             pp = np
         segments.append([pp, x2, y2])
         return segments
     elif self.segmentType == "qcurve":
         raise NotImplementedError
     else:
         raise NotImplementedError
    def drawCurveWurst(self, p0, p1, p2, p3, radius, margin):
        if distance(p0, p3) < radius:
            return
        if p0 == p1 or p2 == p3:
            return

        s1 = splitCubicAtLength(p0, p1, p2, p3, radius+margin)
        s2 = 1-splitCubicAtLength(p3, p2, p1, p0, radius)

        curves = splitCubicAtT(p0, p1, p2, p3, s1, s2)
        p0, p1, p2, p3 = curves[1]

        dx1, dy1 = slope(p1, p0)
        dx2, dy2 = slope(p2, p3)
        n1 = normalise(dx1, dy1)
        n2 = normalise(dx2, dy2)
        m1 = n1[1], -n1[0]
        m2 = n2[1], -n2[0]

        cdistance = distance(p0, p3)

        path = self.getPath()

        newPath()

        start = offsetPoint(p0, m1, -radius)
        path.moveTo(start)
        self.drawWurstCap(path, p0, n1, m1, radius)
        self.drawWurstCurveSide(path, p0, p1, p2, p3, m1, m2, cdistance, radius)
        self.drawWurstCap(path, p3, n2, m2, radius)
        self.drawWurstCurveSide(path, p3, p2, p1, p0, m2, m1, cdistance, radius)
        path.closePath()

        drawPath()
Пример #9
0
 def _testCurve(self, pts, flatPts, f0, f1, inRange=False):
     # Normalize and scale the BCPs
     scaled0 = (pts[1] - pts[0]) * f0
     pts[1] = pts[1] + scaled0
     dist1 = abs(self.pointClass(pts[3]).distance(pts[2]))
     scaled1 = (pts[3] - pts[2]) * f1
     pts[2] = pts[2] + scaled1
     # Split at a few locations
     splitFactors = [0.25, 0.5, 0.75]
     newSplit = splitCubicAtT(pts[0], pts[1], pts[2], pts[3], *splitFactors)
     newSplitLocs = [self.pointClass(pts[-1]) for pts in newSplit]
     newSplitLocs = newSplitLocs[:-1]
     # Measure these splits back to the flattened original segment
     # Prepare chunks of the flatPts, if we should be testing inRange
     #   ...a factor of 0.25 should only be compared against 0.2-0.3, 0.5 should be 0.45-0.55, 0.75 should be 0.7-0.8
     totalFlats = len(flatPts)
     flatRanges = [(int(totalFlats * 0.2), int(totalFlats * 0.3)),
                   (int(totalFlats * 0.45), int(totalFlats * 0.55)),
                   (int(totalFlats * 0.7), int(totalFlats * 0.8))
                   ]  # These relate directly to the factors in splitFactors
     totalDiff = 0
     for i, loc in enumerate(newSplitLocs):
         if inRange:
             # If it should only check a smaller range of flat points
             # (experimental)
             flatPtChunk = flatPts[flatRanges[i][0]:flatRanges[i][1]]
         else:
             flatPtChunk = flatPts
         closestLoc, closestDist = self.findClosest(loc, flatPtChunk)
         angle = loc.angle(self.pointClass(closestLoc))
         expectedDistance = self.getThickness(angle)
         diff = expectedDistance - closestDist
         totalDiff += diff
     return pts, totalDiff
Пример #10
0
def easeCurve(f):
    curve = [(0, 0), (1000, 0), (0, 1000), (1000, 1000)]  # ease in-out
    #curve = [(0, 0), (0, 900), (1000, 100), (1000, 1000)] # jump jump
    #curve = [(0, 0), (1000, 0), (1000, 0), (1000, 1000)] # ease in
    split = splitCubicAtT(curve[0], curve[1], curve[2], curve[3], f)
    split = split[0][-1][1]
    return split / 1000
 def _curveToOne(self, pt1, pt2, pt3):
     if self.optimizeCurve:
         curves = splitCubicAtT(self.prevPoint, pt1, pt2, pt3, .5)
     else:
         curves = [(self.prevPoint, pt1, pt2, pt3)]
     for curve in curves:
         p1, h1, h2, p2 = curve
         self._processCurveToOne(h1, h2, p2)
Пример #12
0
 def _addCubic(self, p0, p1, p2, p3):
     arch = distance(p0, p3)
     box = distance(p0, p1) + distance(p1, p2) + distance(p2, p3)
     if arch * self._mult >= box:
         self.value += (arch + box) * .5
     else:
         for c in splitCubicAtT(p0, p1, p2, p3, .5):
             self._addCubic(*c)
Пример #13
0
	def _addCubic(self, p0, p1, p2, p3):
		arch = _distance(p0, p3)
		box = _distance(p0, p1) + _distance(p1, p2) + _distance(p2, p3)
		if arch * self._mult >= box:
			self.value += (arch + box) * .5
		else:
			for c in splitCubicAtT(p0,p1,p2,p3,.2,.4,.6,.8):
				self._addCubic(*c)
Пример #14
0
def splitCubicAtT_cached(a, b, c, d, t):
    global __split_cache
    abcdt = (a, b, c, d, t)
    sc = __split_cache.get(abcdt)
    if sc:
        return sc
    else:
        s = splitCubicAtT(a, b, c, d, t)
        __split_cache[abcdt] = s
        return s
def getAxisValue(t, curviness, axMin, axMax):
    curve = ((0, 0), (W * curviness, 0), (W - (W * curviness), H), (W, H))
    # curve = ((0, 20), (-2689.98, 30), (-2000,H), (W,H))
    split = splitCubicAtT(*curve, t)
    x, y = split[0][-1]
    # Scale the y value to the range of 0 and 1, assuming it was in a range of 0 to 1000
    f = y / H
    # Use this value to interpolate between the start and end values on your axis
    value = interpolate(axMin, axMax, f)
    return value, x, y
Пример #16
0
def _getUnevenHandleShape(pt0, pt1, pt2, pt3, intersection, start, end, off):
    splitSegments = ftBezierTools.splitCubicAtT(pt0, pt1, pt2, pt3, *intersection.t)
    curves = []
    for segment in splitSegments:
        if _roundPoint(segment[0]) != _roundPoint(start) and not curves:
            continue
        curves.append(segment[1:])
        if _roundPoint(segment[-1]) == _roundPoint(end):
            break
    return curves + [off, start]
Пример #17
0
 def split_curve(pts):
     p0, p1, p2, p3 = pts
     length_arc = calcCubicArcLength(p0, p1, p2, p3)
     if length_arc <= self.length:
         nc.append(["curveTo", pts[1:]])
     else:
         d = self.length / length_arc
         b = (p0, p1, p2, p3)
         a, b = splitCubicAtT(*b, d)
         nc.append(["curveTo", a[1:]])
         split_curve(b)
Пример #18
0
def _getUnevenHandleShape(pt0, pt1, pt2, pt3, intersection, start, end, off):
    # TODO: Here we use fontTools bezierTools
    splitSegments = rfBezierTools.splitCubicAtT(pt0, pt1, pt2, pt3, *intersection.t)
    curves = []
    for segment in splitSegments:
        if _roundPoint(segment[0]) != _roundPoint(start) and not curves:
            continue
        curves.append(segment[1:])
        if _roundPoint(segment[-1]) == _roundPoint(end):
            break
    return curves + [off, start]
Пример #19
0
 def splitAtAngledExtremas(self, pt0, pt1, pt2, pt3):
     frontAngle = self.frontAngle
     segments = []
     for i in range(101):
         t = i / 100
         nx, ny = firstDerivative(pt0, pt1, pt2, pt3, t)
         tanAngle = atan2(ny, nx)
         if tan(frontAngle - _ANGLE_EPSILON) < tan(tanAngle) < tan(frontAngle + _ANGLE_EPSILON):
             newSegments = splitCubicAtT(pt0, pt1, pt2, pt3, t)
             if len(newSegments) > 1:
                 segments = newSegments
                 break
     return segments
Пример #20
0
 def splitAtAngledExtremas(self, pt0, pt1, pt2, pt3):
     frontAngle = self.frontAngle
     segments = []
     for i in range(101):
         t = i / 100
         nx, ny = firstDerivative(pt0, pt1, pt2, pt3, t)
         tanAngle = atan2(ny, nx)
         if tan(frontAngle - _ANGLE_EPSILON) < tan(tanAngle) < tan(frontAngle + _ANGLE_EPSILON):
             newSegments = splitCubicAtT(pt0, pt1, pt2, pt3, t)
             if len(newSegments) > 1:
                 segments = newSegments
                 break
     return segments
Пример #21
0
 def drawComplexCurves(self, contours, scale):
     impliedSCurveColor.set()
     for contourIndex, segments in contours.items():
         for segment in segments:
             pt0, pt1, pt2, pt3 = segment
             path = NSBezierPath.bezierPath()
             path.moveToPoint_(pt0)
             path.curveToPoint_controlPoint1_controlPoint2_(pt3, pt1, pt2)
             path.setLineWidth_(3 * scale)
             path.setLineCapStyle_(NSRoundLineCapStyle)
             path.stroke()
             mid = splitCubicAtT(pt0, pt1, pt2, pt3, 0.5)[0][-1]
             drawString(mid, "Complex Path", 10, scale, impliedSCurveColor, backgroundColor=NSColor.whiteColor())
Пример #22
0
 def split(self, tValues):
     """
     Split the segment according the t values
     """
     if self.segmentType == "curve":
         on1 = self.previousOnCurve
         off1 = self.points[0].coordinates
         off2 = self.points[1].coordinates
         on2 = self.points[2].coordinates
         return bezierTools.splitCubicAtT(on1, off1, off2, on2, *tValues)
     elif self.segmentType == "qcurve":
         raise NotImplementedError
     else:
         raise NotImplementedError
Пример #23
0
def getExtremaForCubic(pt1, pt2, pt3, pt4, h=True, v=False):
	(ax, ay), (bx, by), c, d = calcCubicParameters(pt1, pt2, pt3, pt4)
	ax *= 3.0
	ay *= 3.0
	bx *= 2.0
	by *= 2.0
	h_roots = []
	v_roots = []
	if h:
		h_roots = [t for t in solveQuadratic(ay, by, c[1]) if 0 < t < 1]
	if v:
		v_roots  = [t for t in solveQuadratic(ax, bx, c[0]) if 0 < t < 1]
	roots = h_roots + v_roots
	return [p[3] for p in splitCubicAtT(pt1, pt2, pt3, pt4, *roots)[:-1]]
Пример #24
0
def getExtremaForCubic(pt1, pt2, pt3, pt4, h=True, v=False):
    (ax, ay), (bx, by), c, d = calcCubicParameters(pt1, pt2, pt3, pt4)
    ax *= 3.0
    ay *= 3.0
    bx *= 2.0
    by *= 2.0
    h_roots = []
    v_roots = []
    if h:
        h_roots = [t for t in solveQuadratic(ay, by, c[1]) if 0 < t < 1]
    if v:
        v_roots = [t for t in solveQuadratic(ax, bx, c[0]) if 0 < t < 1]
    roots = h_roots + v_roots
    return [p[3] for p in splitCubicAtT(pt1, pt2, pt3, pt4, *roots)[:-1]]
Пример #25
0
def flattenCurve(curvePoints, steps=100):
    pts = []
    for pt in curvePoints:
        pts += str(pt.x), str(pt.y)
    curvePointsName = "-".join(pts)
    if curvePointsName in flattenCache:
        return flattenCache[curvePointsName]
    else:
        flatPoints = []
        for i in range(steps + 1):
            t = i / steps
            split = splitCubicAtT(*curvePoints, t)
            flatPoints.append(split[0][-1])
        flattenCache[curvePointsName] = flatPoints
        return flatPoints
Пример #26
0
def visualizeWarp(initial_cubics,
                  warp_cubic_fn,
                  warp_pt_fn,
                  num_seg=10,
                  draw_ctls=False):
    warped_cubics = []
    for cubic in initial_cubics:
        split_cubics = splitCubicAtT(
            *cubic, *(t / num_seg for t in range(0, num_seg + 1)))
        for split_cubic in split_cubics:
            split_cubic = tuple(Point(*t) for t in split_cubic)
            # naive; just move according to shift
            # in the end expecting control point movement to differ from start/end point
            warped_cubic = warp_cubic_fn(split_cubic)
            warped_cubics.append(warped_cubic)
    warped_cubics = tuple(warped_cubics)

    fill(None)
    stroke(0.5, 0.5, 0.5)
    strokeWidth(0.25)
    for cubic in initial_cubics:
        drawPath(bezOfCubics((cubic, )))

    for warp_cubic in warped_cubics:
        fill(None)
        stroke(0.3, 0.3, 0.75)
        strokeWidth(0.5)
        drawPath(bezOfCubics((warp_cubic, )))
        if draw_ctls:
            fill(None)
            stroke(0.6, 0.6, 0.6)
            strokeWidth(1)
            line(*warp_cubic[0:2])
            line(*warp_cubic[2:4])

            fill(0, 0, 0)
            stroke(None)
            dot(warp_cubic[0])

    fill(None)
    stroke(0.75, 0.5, 0.75)
    strokeWidth(0.25)
    for cubic in initial_cubics:
        pts = tuple(warp_pt_fn(p) for p in points(cubic, 100))
        for i in range(1, len(pts)):
            line(pts[i - 1], pts[i])
        for pt in pts:
            dot(pt, radius=1)
Пример #27
0
 def getSplits(self) -> list:
     # gets points that need to be added on selected curves
     collector: list = []
     for cIndex, segIndexes in self.selectedCS.items():
         for segIndex in segIndexes[::-1]:
             if self.g[cIndex][segIndex].type != "curve":
                 continue
             segCoos = self.coos[cIndex][segIndex]
             segRotated = map(lambda x: self.rotatePoint(x), segCoos)
             extremes = self.getExtremes(segRotated)
             if len(extremes) == 1 and sum(extremes) in [0, 1]:
                 # make more sofisticated conditions. Check if the splits themselves are of at least some length
                 continue
             splits = splitCubicAtT(*segCoos, *extremes)
             splits = list(map(list, splits))
             collector.append((cIndex, segIndex, splits))
     return collector
Пример #28
0
 def _splitAndInsertAtSegmentAndT(self, segmentIndex, t, insert):
     segments = self.segments
     segment = segments[segmentIndex]
     segment.insert(0, segments[segmentIndex - 1][-1])
     firstPoint = segment[0]
     lastPoint = segment[-1]
     segmentType = lastPoint.segmentType
     segment = [(point.x, point.y) for point in segment]
     if segmentType == "line":
         (x1, y1), (x2, y2) = segment
         x = x1 + (x2 - x1) * t
         y = y1 + (y2 - y1) * t
         pointsToInsert = [((x, y), "line", False)]
         insertionPoint = (x, y)
         pointWillBeSmooth = False
     elif segmentType == "curve":
         pt1, pt2, pt3, pt4 = segment
         (pt1, pt2, pt3,
          pt4), (pt5, pt6, pt7,
                 pt8) = bezierTools.splitCubicAtT(pt1, pt2, pt3, pt4, t)
         pointsToInsert = [(pt2, None, False), (pt3, None, False),
                           (pt4, "curve", True), (pt6, None, False),
                           (pt7, None, False)]
         insertionPoint = tuple(pt4)
         pointWillBeSmooth = True
     else:
         # XXX could be a quad. in that case, we could handle it.
         raise NotImplementedError("unknown segment type: %s" % segmentType)
     if insert:
         firstPointIndex = self._points.index(firstPoint)
         lastPointIndex = self._points.index(lastPoint)
         firstPoints = self._points[:firstPointIndex + 1]
         if firstPointIndex == len(self._points) - 1:
             firstPoints = firstPoints[lastPointIndex:]
             lastPoints = []
         elif lastPointIndex == 0:
             lastPoints = []
         else:
             lastPoints = self._points[lastPointIndex:]
         newPoints = [
             self._pointClass(pos, segmentType=segmentType, smooth=smooth)
             for pos, segmentType, smooth in pointsToInsert
         ]
         self._points = firstPoints + newPoints + lastPoints
         self.dirty = True
     return insertionPoint, pointWillBeSmooth
Пример #29
0
 def drawComplexCurves(self, contours, scale):
     impliedSCurveColor.set()
     for contourIndex, segments in contours.items():
         for segment in segments:
             pt0, pt1, pt2, pt3 = segment
             path = NSBezierPath.bezierPath()
             path.moveToPoint_(pt0)
             path.curveToPoint_controlPoint1_controlPoint2_(pt3, pt1, pt2)
             path.setLineWidth_(3 * scale)
             path.setLineCapStyle_(NSRoundLineCapStyle)
             path.stroke()
             mid = splitCubicAtT(pt0, pt1, pt2, pt3, 0.5)[0][-1]
             drawString(mid,
                        "Complex Path",
                        10,
                        scale,
                        impliedSCurveColor,
                        backgroundColor=NSColor.whiteColor())
Пример #30
0
    def getValues(self,sender):

        glyph = CurrentGlyph()

        if glyph is not None:

            t = self.w.sliderVal.get()
            segmentPoints = self.returnSelectedPointsInSegment(glyph)

            if segmentPoints != None:

                self.w.sliderVal.enable(True)
                self.w.button.enable(True)

                r = bT.splitCubicAtT(segmentPoints[0],segmentPoints[1],segmentPoints[2],segmentPoints[3],t)

                UpdateCurrentGlyphView()

                return r
Пример #31
0
 def splitSegment(self, index, t):
     segments = self._segments
     segment = segments[index]
     pts = segment.points
     pts_len = len(pts)
     if pts_len == 2:
         p1, p2 = pts
         p = Point(p1.x + (p2.x - p1.x) * t, p1.y + (p2.y - p1.y) * t,
                   "line")
         self._points.insert(segment._start, p)
         newSegment = copy(segment)
         segments.insert(index, newSegment)
         for seg in segments[index + 1:]:
             seg._start += 1
             seg._end += 1
     elif pts_len == 4:
         # inline
         p1, p2, p3, p4 = [(p.x, p.y) for p in pts]
         (p1, p2, p3,
          p4), (p5, p6, p7,
                p8) = bezierTools.splitCubicAtT(p1, p2, p3, p4, t)
         points = self._points
         start = segment._start
         p = points[start]
         p.x, p.y = p6
         p = points[start + 1]
         p.x, p.y = p7
         p = points[start + 2]
         p.x, p.y = p8
         points[start:start] = [
             Point(*p2),
             Point(*p3),
             Point(*p4, "curve", smooth=True)
         ]
         newSegment = copy(segment)
         segments.insert(index, newSegment)
         for seg in segments[index + 1:]:
             seg._start += 3
             seg._end += 3
     else:
         raise ValueError("unattended len %d" % pts_len)
     return newSegment
Пример #32
0
def convertToQuadratic(p0, p1, p2, p3):
    # TODO: test for accuracy and subdivide further if needed
    p = [(i.x, i.y) for i in [p0, p1, p2, p3]]
    # if p[0][0] == p[1][0] and p[0][0] == p[2][0] and p[0][0] == p[2][0] and p[0][0] == p[3][0]:
    #     return (p[0],p[1],p[2],p[3])
    # if p[0][1] == p[1][1] and p[0][1] == p[2][1] and p[0][1] == p[2][1] and p[0][1] == p[3][1]:
    #     return (p[0],p[1],p[2],p[3])
    seg1, seg2 = bezierTools.splitCubicAtT(p[0], p[1], p[2], p[3], .5)
    pts1 = [array([i[0], i[1]]) for i in seg1]
    pts2 = [array([i[0], i[1]]) for i in seg2]
    on1 = seg1[0]
    on2 = seg2[3]
    try:
        off1 = calcIntersect(pts1[0], pts1[1], pts1[2], pts1[3])
        off2 = calcIntersect(pts2[0], pts2[1], pts2[2], pts2[3])
    except:
        return (p[0], p[1], p[2], p[3])
    off1 = (on1 - off1) * OFFCURVE_VECTOR_CORRECTION + off1
    off2 = (on2 - off2) * OFFCURVE_VECTOR_CORRECTION + off2
    return (on1, off1, off2, on2)
Пример #33
0
def convertToQuadratic(p0,p1,p2,p3):
    # TODO: test for accuracy and subdivide further if needed
    p = [(i.x,i.y) for i in [p0,p1,p2,p3]]
    # if p[0][0] == p[1][0] and p[0][0] == p[2][0] and p[0][0] == p[2][0] and p[0][0] == p[3][0]:
    #     return (p[0],p[1],p[2],p[3]) 
    # if p[0][1] == p[1][1] and p[0][1] == p[2][1] and p[0][1] == p[2][1] and p[0][1] == p[3][1]:
    #     return (p[0],p[1],p[2],p[3])     
    seg1,seg2 = bezierTools.splitCubicAtT(p[0], p[1], p[2], p[3], .5)
    pts1 = [array([i[0], i[1]]) for i in seg1]
    pts2 = [array([i[0], i[1]]) for i in seg2]
    on1 = seg1[0]
    on2 = seg2[3]
    try:
        off1 = calcIntersect(pts1[0], pts1[1], pts1[2], pts1[3])
        off2 = calcIntersect(pts2[0], pts2[1], pts2[2], pts2[3])
    except:
        return (p[0],p[1],p[2],p[3])
    off1 = (on1 - off1) * OFFCURVE_VECTOR_CORRECTION + off1
    off2 = (on2 - off2) * OFFCURVE_VECTOR_CORRECTION + off2
    return (on1,off1,off2,on2)
def getCurveValue(t, curviness, axMin, axMax, loop="loop"):
    # curve = ((0,0), (W*curviness, 0), (W-(W*curviness),H), (W,H)) # fast to slow to fast (not sure?)
    curve = ((0,0), (0, H*curviness), (W,H-(H*curviness)), (W,H)) # slow to fast to slow, based on x over time (bell curve)
    # curve = ((0, 20), (-2689.98, 30), (-2000,H), (W,H))
    split = splitCubicAtT(*curve, t)
    x, y = split[0][-1]
    # Scale the y value to the range of 0 and 1, assuming it was in a range of 0 to 1000
    # f = y / H # for some reason, y isn't working as well for me as x to attain different curves...
    f = x / W
    
    # go up with curve for first half, then back down
    if loop is "loop":
        if t <= 0.5:
            f *= 2
        else:
            f = 1 - (f - 0.5) * 2
            
    value = interpolate(axMin, axMax, f)
            
    return value, x, y
Пример #35
0
def get_extrema_points_vectors(roots, pt1, pt2, pt3, pt4):
    split_segments = [p for p in splitCubicAtT(pt1, pt2, pt3, pt4, *roots)[:-1]]
    points = [p[3] for p in split_segments]
    vectors = [get_vector(p[2], p[3]) for p in split_segments]
    for s in split_segments:
        print "    Split:", s
        save()
        stroke(None)
        fill(1, 0.6, 0, 0.8)
        for p in s:
            oval(p[0] - 1, p[1] - 1, 2, 2)
            fontSize(4)
            text("%i|%i" % p, p)
        #oval(s[-1][0] - 2, s[-1][1] - 2, 4, 4)
        fill(None)
        strokeWidth(0.5)
        stroke(1, 0.6, 0, 0.8)
        line(s[0], s[1])
        line(s[2], s[3])
        restore()
    return points, vectors
Пример #36
0
def getCurveValue(t, curviness, axMin, axMax, loop="loop"):
    from fontTools.misc.bezierTools import splitCubicAtT

    curve = ((0, 0), (0, H * curviness), (W, H - (H * curviness)), (W, H)
             )  # slow to fast to slow, based on x over time (bell curve)
    split = splitCubicAtT(*curve, t)
    x, y = split[0][-1]
    # Scale the y value to the range of 0 and 1, assuming it was in a range of 0 to 1000
    f = x / W

    # go up with curve for first half, then back down
    if loop is "loop":
        if t <= 0.5:
            f *= 2
        else:
            f = 1 - (f - 0.5) * 2

    value = interpolate(axMin, axMax, f)

    # return value, x, y
    return value
Пример #37
0
def cubic_approx_spline(p, n):
    """Approximate a cubic bezier curve with a spline of n quadratics.

    Returns None if n is 1 and the cubic's control vectors are parallel, since
    no quadratic exists with this cubic's tangents.
    """

    if n == 1:
        try:
            p1 = calc_intersect(p)
        except ValueError:
            return None
        return [p[0], p1, p[3]]

    spline = [p[0]]
    ts = [i / n for i in range(1, n)]
    segments = bezierTools.splitCubicAtT(p[0], p[1], p[2], p[3], *ts)
    for i in range(len(segments)):
        segment = cubic_approx(segments[i], i / (n - 1))
        spline.append(segment[1])
    spline.append(p[3])
    return spline
Пример #38
0
def cubic_approx_spline(p, n):
    """Approximate a cubic bezier curve with a spline of n quadratics.

    Returns None if n is 1 and the cubic's control vectors are parallel, since
    no quadratic exists with this cubic's tangents.
    """

    if n == 1:
        try:
            p1 = calc_intersect(p)
        except ValueError:
            return None
        return [p[0], p1, p[3]]

    spline = [p[0]]
    ts = [i / n for i in range(1, n)]
    segments = bezierTools.splitCubicAtT(p[0], p[1], p[2], p[3], *ts)
    for i in range(len(segments)):
        segment = cubic_approx(segments[i], i / (n - 1))
        spline.append(segment[1])
    spline.append(p[3])
    return spline
Пример #39
0
 def _splitAndInsertAtSegmentAndT(self, segmentIndex, t, insert):
     segments = self.segments
     segment = segments[segmentIndex]
     segment.insert(0, segments[segmentIndex-1][-1])
     firstPoint = segment[0]
     lastPoint = segment[-1]
     segmentType = lastPoint.segmentType
     segment = [(point.x, point.y) for point in segment]
     if segmentType == "line":
         (x1, y1), (x2, y2) = segment
         x = x1 + (x2 - x1) * t
         y = y1 + (y2 - y1) * t
         pointsToInsert = [((x, y), "line", False)]
         insertionPoint =  (x, y)
         pointWillBeSmooth = False
     elif segmentType == "curve":
         pt1, pt2, pt3, pt4 = segment
         (pt1, pt2, pt3, pt4), (pt5, pt6, pt7, pt8) = bezierTools.splitCubicAtT(pt1, pt2, pt3, pt4, t)
         pointsToInsert = [(pt2, None, False), (pt3, None, False), (pt4, "curve", True), (pt6, None, False), (pt7, None, False)]
         insertionPoint = tuple(pt4)
         pointWillBeSmooth = True
     else:
         # XXX could be a quad. in that case, we could handle it.
         raise NotImplementedError("unknown segment type: %s" % segmentType)
     if insert:
         firstPointIndex = self._points.index(firstPoint)
         lastPointIndex = self._points.index(lastPoint)
         firstPoints = self._points[:firstPointIndex + 1]
         if firstPointIndex == len(self._points) - 1:
             firstPoints = firstPoints[lastPointIndex:]
             lastPoints = []
         elif lastPointIndex == 0:
             lastPoints = []
         else:
             lastPoints = self._points[lastPointIndex:]
         newPoints = [self._pointClass(pos, segmentType=segmentType, smooth=smooth) for pos, segmentType, smooth in pointsToInsert]
         self._points = firstPoints + newPoints + lastPoints
         self.dirty = True
     return insertionPoint, pointWillBeSmooth
Пример #40
0
def split_at_extrema(pt1, pt2, pt3, pt4, transform=Transform()):
    """
    Add extrema to a cubic curve, after applying a transformation.
    Example ::

        >>> # A segment in which no extrema will be added.
        >>> split_at_extrema((297, 52), (406, 52), (496, 142), (496, 251))
        [((297, 52), (406, 52), (496, 142), (496, 251))]
        >>> from fontTools.misc.transform import Transform
        >>> split_at_extrema((297, 52), (406, 52), (496, 142), (496, 251), Transform().rotate(-27))
        [((297.0, 52.0), (84.48072108963274, -212.56513799170233), (15.572491694678519, -361.3686192413668), (15.572491694678547, -445.87035970621713)), ((15.572491694678547, -445.8703597062171), (15.572491694678554, -506.84825401175414), (51.4551516055374, -534.3422304091257), (95.14950889754756, -547.6893014808263))]
    """
    # Transform the points for extrema calculation;
    # transform is expected to rotate the points by - nib angle.
    t2, t3, t4 = transform.transformPoints([pt2, pt3, pt4])
    # When pt1 is the current point of the path,  it is already transformed, so
    # we keep it like it is.
    t1 = pt1

    (ax, ay), (bx, by), c, d = calcCubicParameters(t1, t2, t3, t4)
    ax *= 3.0
    ay *= 3.0
    bx *= 2.0
    by *= 2.0

    # vertical
    roots = [t for t in solveQuadratic(ay, by, c[1]) if 0 < t < 1]

    # horizontal
    roots += [t for t in solveQuadratic(ax, bx, c[0]) if 0 < t < 1]

    # Use only unique roots and sort them
    # They should be unique before, or can a root be duplicated (in h and v?)
    roots = sorted(set(roots))

    if not roots:
        return [(t1, t2, t3, t4)]

    return splitCubicAtT(t1, t2, t3, t4, *roots)
Пример #41
0
def get_extrema_points_vectors(roots, pt1, pt2, pt3, pt4):
    split_segments = [
        p for p in splitCubicAtT(pt1, pt2, pt3, pt4, *roots)[:-1]
    ]
    points = [p[3] for p in split_segments]
    vectors = [get_vector(p[2], p[3]) for p in split_segments]
    for s in split_segments:
        print "    Split:", s
        save()
        stroke(None)
        fill(1, 0.6, 0, 0.8)
        for p in s:
            oval(p[0] - 1, p[1] - 1, 2, 2)
            fontSize(4)
            text("%i|%i" % p, p)
        #oval(s[-1][0] - 2, s[-1][1] - 2, 4, 4)
        fill(None)
        strokeWidth(0.5)
        stroke(1, 0.6, 0, 0.8)
        line(s[0], s[1])
        line(s[2], s[3])
        restore()
    return points, vectors
            self.buildConnection()

        self.innerCurrentPoint = currentPoint - self.pointClass(cos(self.currentAngle), sin(self.currentAngle)) * thickness
        self.innerPen.lineTo(self.innerCurrentPoint)
        self.innerPrevPoint = self.innerCurrentPoint

        self.outerCurrentPoint = currentPoint + self.pointClass(cos(self.currentAngle), sin(self.currentAngle)) * thickness
        self.outerPen.lineTo(self.outerCurrentPoint)
        self.outerPrevPoint = self.outerCurrentPoint

        self.prevPoint = currentPoint
        self.prevAngle = self.currentAngle

    def _curveToOne(self, (x1, y1), (x2, y2), (x3, y3)):
        if self.optimizeCurve:
            curves = splitCubicAtT(self.prevPoint, (x1, y1), (x2, y2), (x3, y3), .5)
        else:
            curves = [(self.prevPoint, (x1, y1), (x2, y2), (x3, y3))]
        for curve in curves:
            p1, h1, h2, p2 = curve
            self._processCurveToOne(h1, h2, p2)

    def _processCurveToOne(self, (x1, y1), (x2, y2), (x3, y3)):
        if self.offset == 0:
            self.outerPen.curveTo((x1, y1), (x2, y2), (x3, y3))
            self.innerPen.curveTo((x1, y1), (x2, y2), (x3, y3))
            return
        self.originalPen.curveTo((x1, y1), (x2, y2), (x3, y3))

        p1 = self.pointClass(x1, y1)
        p2 = self.pointClass(x2, y2)
Пример #43
0
def warpGlyph(g, angle=-40, floatingDist=120, axis=1):
    # axis = axis to warp along, 1 = use "y" axis for measurement

    if len(g.contours):

        # Get the bounds of the glyph drawing for the warp curve
        boundMax = g.bounds[axis + 2]
        boundMin = g.bounds[axis]
        """
        # Optionally increase the bounds to include the BCP locations
        for c in g.contours:
            for pt in c.points:
                ptLoc = (pt.x, pt.y)
                if ptLoc[axis] > boundMax:
                    boundMax = ptLoc[axis]
                if ptLoc[axis] < boundMin:
                    boundMin = ptLoc[axis]
        """

        # Find handle locations at 33.3 / 66.7 between these bounds
        p0 = [0, boundMax]
        p3 = [0, boundMin]
        p1y = interpolate(0.3333, boundMax, boundMin)
        p1x = getOpposite(angle, boundMax - p1y)
        p1 = [p1x, p1y]
        p2y = interpolate(0.6667, boundMax, boundMin)
        p2x = getOpposite(angle, p2y - boundMin)
        p2 = [p2x, p2y]
        if axis == 0:
            p0.reverse()
            p1.reverse()
            p2.reverse()
            p3.reverse()

        if False:  # Draw the curve
            pen = g.getPen()
            pen.moveTo(p0)
            pen.curveTo(p1, p2, p3)
            pen.endPath()
            g.changed()

        # Shift this curve so that it's balanced at the floatingDist
        midPt = splitCubicAtT(p0, p1, p2, p3, 0.5)[0][-1][not axis]
        floatShift = int(round((-midPt * 0.5) + floatingDist))
        p0[not axis] += floatShift
        p1[not axis] += floatShift
        p2[not axis] += floatShift
        p3[not axis] += floatShift
        warpCurve = [p0, p1, p2, p3]

        # Extrapolate the warp curve a little bit to account for any BCPs that are outside the glyph bounds
        pct = 0.2  # extrapolation percentage
        s = splitCubicAtT(*warpCurve, 1 + pct)  # extrap a little on one end
        warpCurve = s[0]
        s = splitCubicAtT(*warpCurve,
                          0 - pct)  # extrap a little on the other end
        warpCurve = s[1]

        # For each bpoint in the contour, find where it would it the curve
        # Move bPoint anchors to match the angle of that point on the curve.
        # Keep the "y" location of all points (including handles) as they move

        libData = {}

        for c in g.contours:

            # Take care of the first moveTo
            pt = c.points[0]
            ptLoc = (pt.x, pt.y)
            splitLoc, angle = splitWithAngle(warpCurve, ptLoc[axis], axis)
            anchorZ = splitLoc[not axis]
            if pt.name == None:
                pt.name = makeUniqueName()
            libData[pt.name] = int(round(anchorZ))
            prevOnCurve = pt
            prevOnCurveLoc = [pt.x, pt.y]

            for s in c.segments:
                if len(s.points) == 3:
                    # Split at the prevOnCurve to move this bcpOut
                    bcpOut = absoluteBCP(prevOnCurve, s.points[0])
                    splitLoc, angle = splitWithAngle(warpCurve,
                                                     prevOnCurveLoc[axis],
                                                     axis)
                    bcpOutZ = getOpposite(
                        angle, bcpOut[axis]) + libData[prevOnCurve.name]
                    # Split at the new on curve and move the bcpIn
                    bcpIn = absoluteBCP(s.points[-1], s.points[1])
                    endAnchorLoc = (s.points[-1].x, s.points[-1].y)
                    splitLoc, angle = splitWithAngle(warpCurve,
                                                     endAnchorLoc[axis], axis)
                    anchorZ = splitLoc[not axis]
                    bcpInZ = getOpposite(angle, bcpIn[axis]) + anchorZ

                    # Three points now have three "z" values
                    # bcpOutZ, bcpInZ, anchorZ
                    zLocs = [bcpOutZ, bcpInZ, anchorZ]
                    for ptIdx, pt in enumerate(s.points):
                        if pt.name == None:
                            pt.name = makeUniqueName()
                        libData[pt.name] = int(round(zLocs[ptIdx]))
                else:
                    pt = s.points[0]
                    ptLoc = (pt.x, pt.y)
                    splitLoc, angle = splitWithAngle(warpCurve, ptLoc[axis],
                                                     axis)
                    anchorZ = splitLoc[not axis]
                    if pt.name == None:
                        pt.name = makeUniqueName()
                    libData[pt.name] = int(round(anchorZ))
                # Hold the previous onCurve for the next segment
                prevOnCurve = s.points[-1]
                prevOnCurveLoc = (prevOnCurve.x, prevOnCurve.y)

        if LIBKEY in g.lib.keys():
            g.lib[LIBKEY].clear()
        g.lib[LIBKEY] = copy.deepcopy(libData)

        g.changed()
Пример #44
0
def get_extrema_points_vectors(roots, pt1, pt2, pt3, pt4):
	split_segments = [p for p in splitCubicAtT(pt1, pt2, pt3, pt4, *roots)[:-1]]
	points = [p[3] for p in split_segments]
	vectors = [get_vector(p[2], p[3]) for p in split_segments]
	return points, vectors