예제 #1
0
def curve_pos_and_speed(curve, x):
    x1000 = x * 1000
    for idx, (action, pts) in enumerate(curve.value):
        if action in ["moveTo", "endPath", "closePath"]:
            continue
        last_action, last_pts = curve.value[idx - 1]
        if action == "curveTo":
            o = -1
            a = last_pts[-1]
            b, c, d = pts
            if x1000 == a[0]:
                o = a[1] / 1000
                eb = a
                ec = b
            elif x1000 == d[0]:
                o = d[1] / 1000
                eb = c
                ec = d
            elif x1000 > a[0] and x1000 < d[0]:
                e, f = splitCubic(a, b, c, d, x1000, isHorizontal=False)
                ez, ea, eb, ec = e
                o = ec[1] / 1000
            else:
                continue
            tangent = math.degrees(
                math.atan2(ec[1] - eb[1], ec[0] - eb[0]) + math.pi * .5)
            #print(o, tangent)
            if tangent >= 90:
                t = (tangent - 90) / 90
            else:
                t = tangent / 90
            if o != -1:
                return o, t
    raise Exception("No curve value found!")
예제 #2
0
def intersect(glyph, where, isHorizontal):
    """
    Intersection of a glyph with a horizontal or vertical line.
    Intersects each segment of a glyph using fontTools bezierTools.splitCubic and splitLine methods.
    """
    pen = CollectSegmentsPen()
    glyph.draw(pen)
    nakedGlyph = pen.getSegments()
    glyphIntersections = []

    for i, contour in enumerate(nakedGlyph):

        for segment in contour:

            length = len(segment)

            if length == 2:
                pt1, pt2 = segment
                returnedSegments = splitLine(pt1, pt2, where, int(isHorizontal))
            elif length == 4:
                pt1, pt2, pt3, pt4 = segment
                returnedSegments = bezierTools.splitCubic(pt1, pt2, pt3, pt4, where, int(isHorizontal))

            if len(returnedSegments) > 1:
                intersectionPoints = findDuplicatePoints(returnedSegments)
                if len(intersectionPoints):
                    box = calcBounds(segment)
                    intersectionPoints = [point for point in intersectionPoints if arrayTools.pointInRect(point, box)]
                    glyphIntersections.extend(intersectionPoints)

    return glyphIntersections
예제 #3
0
def intersect(glyph, where, isHorizontal):
    """
    Intersect a glyph with a horizontal or vertical line.
    Intersect each segment of a glyph using fontTools bezierTools.splitCubic and splitLine methods.
    """
    pen = CollectSegmentsPen(glyph.layer)
    glyph.draw(pen)
    nakedGlyph = pen.getSegments()
    glyphIntersections = []

    for i, contour in enumerate(nakedGlyph):

        for segment in contour:

            length = len(segment)

            if length == 2:
                pt1, pt2 = segment
                returnedSegments = splitLine(pt1, pt2, where, int(isHorizontal))
            elif length == 4:
                pt1, pt2, pt3, pt4 = segment
                returnedSegments = bezierTools.splitCubic(pt1, pt2, pt3, pt4, where, int(isHorizontal))

            if len(returnedSegments) > 1:
                intersectionPoints = findDuplicatePoints(returnedSegments)
                if len(intersectionPoints):
                    box = calcBounds(segment)
                    intersectionPoints = [point for point in intersectionPoints if arrayTools.pointInRect(point, box)]
                    glyphIntersections.extend(intersectionPoints)

    return glyphIntersections
예제 #4
0
def append_point_coordinate(contour, rpoints, where, is_horizontal):
    """ Appends RPoint object to curve(RSegment object) by horizontal or vertical line.

    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.
        where:: int or float
            The coordinate value of line(x value if uses vertical line otherwise y value).
        is_horizontal:: bool
            If this is True, uses horizontal line(coordinate value of y).
            Otherwise uses vertical line(coordinate value of x).

    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 = splitCubic(points[0], points[1], points[2], points[3], where,
                           is_horizontal)
    assert (len(new_curve) > 1)
    _append_point_curve(contour, rpoints, new_curve)
예제 #5
0
def test_splitCubic():
    assert splitCubic(
        (0, 0), (25, 100), (75, 100), (100, 0), where=150,
        isHorizontal=False) == [((0, 0), (25, 100), (75, 100), (100, 0))]
    assert splitCubic(
        (0, 0), (25, 100), (75, 100), (100, 0), where=50,
        isHorizontal=False) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)),
                                ((50, 75), (68.75, 75), (87.5, 50), (100, 0))]
    assert_curves_approx_equal(
        splitCubic((0, 0), (25, 100), (75, 100), (100, 0),
                   where=25,
                   isHorizontal=True),
        [((0, 0), (2.293792, 9.17517), (4.798045, 17.5085), (7.47414, 25)),
         ((7.47414, 25), (31.2886, 91.6667), (68.7114, 91.6667),
          (92.5259, 25)),
         ((92.5259, 25), (95.202, 17.5085), (97.7062, 9.17517),
          (100, 1.77636e-15))])
예제 #6
0
def test_splitCubic():
    assert splitCubic(
        (0, 0), (25, 100), (75, 100), (100, 0), where=150, isHorizontal=False
    ) == [((0, 0), (25, 100), (75, 100), (100, 0))]
    assert splitCubic(
        (0, 0), (25, 100), (75, 100), (100, 0), where=50, isHorizontal=False
    ) == [((0, 0), (12.5, 50), (31.25, 75), (50, 75)),
          ((50, 75), (68.75, 75), (87.5, 50), (100, 0))]
    assert_curves_approx_equal(
        splitCubic(
            (0, 0), (25, 100), (75, 100), (100, 0), where=25,
            isHorizontal=True),
        [((0, 0), (2.293792, 9.17517), (4.798045, 17.5085), (7.47414, 25)),
         ((7.47414, 25), (31.2886, 91.6667), (68.7114, 91.6667),
          (92.5259, 25)),
         ((92.5259, 25), (95.202, 17.5085), (97.7062, 9.17517),
          (100, 1.77636e-15))])
예제 #7
0
파일: naive_warp.py 프로젝트: rsheeter/warp
    def _seg_ending_at(self, x):
        x = clamp(self.minx, self.maxx, x)

        # Draw a line at pt.x through the warp; the pt on the warp is be the desired offset
        segments = splitCubic(*self.warp, x, False)

        # no kinks/overlaps; there should be <=2 curves when split
        # we are really just interested in there being only one unique start/end at pt.x
        assert len(segments) <= 2, f"Too many segments: {segments}"

        return segments[0]
예제 #8
0
def flagWarpVec(pt, accuracy=0.001):
    # only active between warp[0].x and warp[-1].x
    if pt.x < warp[0].x or pt.x > warp[-1].x:
        print("Out of bounds:", pt)
        return pt, Point(0, 0)
    # Draw a line at pt.x through the warp; the pt on the warp is be the desired offset
    segments = splitCubic(*warp, pt.x, False)
    # no kinks/overlaps; there should be <=2 curves when split
    # we are really just interested in there being only one unique start/end at pt.x
    assert len(segments) <= 2, f"Too many segments: {segments}"
    wpt = Point(*(segments[0][-1]))
    deriv_pt = cubic_deriv_pos(1, *(Point(*s) for s in segments[0]))
    return Point(0, wpt.y), deriv_pt
예제 #9
0
def splitWithAngle(curve, loc, axis):
    # Split a curve at location y and return the location and angle
    r = splitCubic(*curve, loc, isHorizontal=axis)
    if len(r) == 2:
        splitLoc = r[0][-1]
        a = getAngle(r[0][-1], r[1][1])  # handle to handle
    else:
        # The location is either exatly on the end of the curve, or off the curve
        # Return the angle and location either at the top or bottom
        if loc >= curve[0][axis]:
            splitLoc = curve[0]
            a = getAngle(curve[0], curve[1])
        else:
            splitLoc = curve[-1]
            a = getAngle(curve[-2], curve[-1])
    if axis == 0:
        a = 90 - a
    return splitLoc, a
예제 #10
0
 def _curveToOne(self, pt1, pt2, pt3):
     hits = splitCubic(self.currentPt, pt1, pt2, pt3, self.value, self.isHorizontal)
     for i in range(len(hits) - 1):
         # a number of intersections is possible. Just take the
         # last point of each segment.
         if self.contourIndex not in self.hits:
             self.hits[self.contourIndex] = []
         if self.isHorizontal:
             self.hits[self.contourIndex].append(round(hits[i][-1][0], 4))
         else:
             self.hits[self.contourIndex].append(round(hits[i][-1][1], 4))
     if self.isHorizontal and pt3[1] == self.value:
         # it could happen
         if self.contourIndex not in self.hits:
             self.hits[self.contourIndex] = []
         self.hits[self.contourIndex].append(pt3[0])
     if (not self.isHorizontal) and (pt3[0] == self.value):
         # it could happen
         if self.contourIndex not in self.hits:
             self.hits[self.contourIndex] = []
         self.hits[self.contourIndex].append(pt3[1])
     self.currentPt = pt3
예제 #11
0
 def _curveToOne(self, pt1, pt2, pt3):
     hits = splitCubic(self.currentPt, pt1, pt2, pt3, self.value,
                       self.isHorizontal)
     for i in range(len(hits) - 1):
         # a number of intersections is possible. Just take the
         # last point of each segment.
         if self.contourIndex not in self.hits:
             self.hits[self.contourIndex] = []
         if self.isHorizontal:
             self.hits[self.contourIndex].append(round(hits[i][-1][0], 4))
         else:
             self.hits[self.contourIndex].append(round(hits[i][-1][1], 4))
     if self.isHorizontal and pt3[1] == self.value:
         # it could happen
         if self.contourIndex not in self.hits:
             self.hits[self.contourIndex] = []
         self.hits[self.contourIndex].append(pt3[0])
     if (not self.isHorizontal) and (pt3[0] == self.value):
         # it could happen
         if self.contourIndex not in self.hits:
             self.hits[self.contourIndex] = []
         self.hits[self.contourIndex].append(pt3[1])
     self.currentPt = pt3