Use Vector in some places where it improves the clarity of the code (#2206)
* Use Vector in some places where it improves the clarity of the code * add __all__ to vector.py * turned some list comprehensions into generator expressions: there's no need for an intermediate list in these cases * Add empty __slots__ to Vector, so we don't waste space on a __dict__. * add some tests for segmentPointAtT
This commit is contained in:
parent
e41c3b8b08
commit
0d3ce2cafc
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
from fontTools.misc.arrayTools import calcBounds, sectRect, rectArea
|
from fontTools.misc.arrayTools import calcBounds, sectRect, rectArea
|
||||||
from fontTools.misc.transform import Offset, Identity
|
from fontTools.misc.transform import Offset, Identity
|
||||||
|
from fontTools.misc.vector import Vector
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
import math
|
import math
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
@ -243,16 +244,15 @@ def calcQuadraticBounds(pt1, pt2, pt3):
|
|||||||
>>> calcQuadraticBounds((0, 0), (100, 0), (100, 100))
|
>>> calcQuadraticBounds((0, 0), (100, 0), (100, 100))
|
||||||
(0.0, 0.0, 100, 100)
|
(0.0, 0.0, 100, 100)
|
||||||
"""
|
"""
|
||||||
(ax, ay), (bx, by), (cx, cy) = calcQuadraticParameters(pt1, pt2, pt3)
|
a, b, c = calcQuadraticParameters(pt1, pt2, pt3)
|
||||||
ax2 = ax * 2.0
|
ax2, ay2 = a * 2
|
||||||
ay2 = ay * 2.0
|
|
||||||
roots = []
|
roots = []
|
||||||
if ax2 != 0:
|
if ax2 != 0:
|
||||||
roots.append(-bx / ax2)
|
roots.append(-b[0] / ax2)
|
||||||
if ay2 != 0:
|
if ay2 != 0:
|
||||||
roots.append(-by / ay2)
|
roots.append(-b[1] / ay2)
|
||||||
points = [
|
points = [
|
||||||
(ax * t * t + bx * t + cx, ay * t * t + by * t + cy)
|
a * (t * t) + b * t + c
|
||||||
for t in roots
|
for t in roots
|
||||||
if 0 <= t < 1
|
if 0 <= t < 1
|
||||||
] + [pt1, pt3]
|
] + [pt1, pt3]
|
||||||
@ -343,21 +343,17 @@ def calcCubicBounds(pt1, pt2, pt3, pt4):
|
|||||||
>>> print("%f %f %f %f" % calcCubicBounds((50, 0), (0, 100), (100, 100), (50, 0)))
|
>>> print("%f %f %f %f" % calcCubicBounds((50, 0), (0, 100), (100, 100), (50, 0)))
|
||||||
35.566243 0.000000 64.433757 75.000000
|
35.566243 0.000000 64.433757 75.000000
|
||||||
"""
|
"""
|
||||||
(ax, ay), (bx, by), (cx, cy), (dx, dy) = calcCubicParameters(pt1, pt2, pt3, pt4)
|
a, b, c, d = calcCubicParameters(pt1, pt2, pt3, pt4)
|
||||||
# calc first derivative
|
# calc first derivative
|
||||||
ax3 = ax * 3.0
|
ax3, ay3 = a * 3.0
|
||||||
ay3 = ay * 3.0
|
bx2, by2 = b * 2.0
|
||||||
bx2 = bx * 2.0
|
cx, cy = c
|
||||||
by2 = by * 2.0
|
|
||||||
xRoots = [t for t in solveQuadratic(ax3, bx2, cx) if 0 <= t < 1]
|
xRoots = [t for t in solveQuadratic(ax3, bx2, cx) if 0 <= t < 1]
|
||||||
yRoots = [t for t in solveQuadratic(ay3, by2, cy) if 0 <= t < 1]
|
yRoots = [t for t in solveQuadratic(ay3, by2, cy) if 0 <= t < 1]
|
||||||
roots = xRoots + yRoots
|
roots = xRoots + yRoots
|
||||||
|
|
||||||
points = [
|
points = [
|
||||||
(
|
a * (t * t * t) + b * (t * t) + c * t + d
|
||||||
ax * t * t * t + bx * t * t + cx * t + dx,
|
|
||||||
ay * t * t * t + by * t * t + cy * t + dy,
|
|
||||||
)
|
|
||||||
for t in roots
|
for t in roots
|
||||||
] + [pt1, pt4]
|
] + [pt1, pt4]
|
||||||
return calcBounds(points)
|
return calcBounds(points)
|
||||||
@ -399,22 +395,17 @@ def splitLine(pt1, pt2, where, isHorizontal):
|
|||||||
((0, 100), (0, 50))
|
((0, 100), (0, 50))
|
||||||
((0, 50), (0, 0))
|
((0, 50), (0, 0))
|
||||||
"""
|
"""
|
||||||
pt1x, pt1y = pt1
|
pt1 = Vector(pt1)
|
||||||
pt2x, pt2y = pt2
|
pt2 = Vector(pt2)
|
||||||
|
|
||||||
ax = pt2x - pt1x
|
a = pt2 - pt1
|
||||||
ay = pt2y - pt1y
|
b = pt1
|
||||||
|
|
||||||
bx = pt1x
|
if a[isHorizontal] == 0:
|
||||||
by = pt1y
|
|
||||||
|
|
||||||
a = (ax, ay)[isHorizontal]
|
|
||||||
|
|
||||||
if a == 0:
|
|
||||||
return [(pt1, pt2)]
|
return [(pt1, pt2)]
|
||||||
t = (where - (bx, by)[isHorizontal]) / a
|
t = (where - b[isHorizontal]) / a[isHorizontal]
|
||||||
if 0 <= t < 1:
|
if 0 <= t < 1:
|
||||||
midPt = ax * t + bx, ay * t + by
|
midPt = a * t + b
|
||||||
return [(pt1, midPt), (midPt, pt2)]
|
return [(pt1, midPt), (midPt, pt2)]
|
||||||
else:
|
else:
|
||||||
return [(pt1, pt2)]
|
return [(pt1, pt2)]
|
||||||
@ -459,7 +450,7 @@ def splitQuadratic(pt1, pt2, pt3, where, isHorizontal):
|
|||||||
solutions = solveQuadratic(
|
solutions = solveQuadratic(
|
||||||
a[isHorizontal], b[isHorizontal], c[isHorizontal] - where
|
a[isHorizontal], b[isHorizontal], c[isHorizontal] - where
|
||||||
)
|
)
|
||||||
solutions = sorted([t for t in solutions if 0 <= t < 1])
|
solutions = sorted(t for t in solutions if 0 <= t < 1)
|
||||||
if not solutions:
|
if not solutions:
|
||||||
return [(pt1, pt2, pt3)]
|
return [(pt1, pt2, pt3)]
|
||||||
return _splitQuadraticAtT(a, b, c, *solutions)
|
return _splitQuadraticAtT(a, b, c, *solutions)
|
||||||
@ -496,7 +487,7 @@ def splitCubic(pt1, pt2, pt3, pt4, where, isHorizontal):
|
|||||||
solutions = solveCubic(
|
solutions = solveCubic(
|
||||||
a[isHorizontal], b[isHorizontal], c[isHorizontal], d[isHorizontal] - where
|
a[isHorizontal], b[isHorizontal], c[isHorizontal], d[isHorizontal] - where
|
||||||
)
|
)
|
||||||
solutions = sorted([t for t in solutions if 0 <= t < 1])
|
solutions = sorted(t for t in solutions if 0 <= t < 1)
|
||||||
if not solutions:
|
if not solutions:
|
||||||
return [(pt1, pt2, pt3, pt4)]
|
return [(pt1, pt2, pt3, pt4)]
|
||||||
return _splitCubicAtT(a, b, c, d, *solutions)
|
return _splitCubicAtT(a, b, c, d, *solutions)
|
||||||
@ -555,24 +546,18 @@ def _splitQuadraticAtT(a, b, c, *ts):
|
|||||||
segments = []
|
segments = []
|
||||||
ts.insert(0, 0.0)
|
ts.insert(0, 0.0)
|
||||||
ts.append(1.0)
|
ts.append(1.0)
|
||||||
ax, ay = a
|
|
||||||
bx, by = b
|
|
||||||
cx, cy = c
|
|
||||||
for i in range(len(ts) - 1):
|
for i in range(len(ts) - 1):
|
||||||
t1 = ts[i]
|
t1 = ts[i]
|
||||||
t2 = ts[i + 1]
|
t2 = ts[i + 1]
|
||||||
delta = t2 - t1
|
delta = t2 - t1
|
||||||
# calc new a, b and c
|
# calc new a, b and c
|
||||||
delta_2 = delta * delta
|
delta_2 = delta * delta
|
||||||
a1x = ax * delta_2
|
a1 = a * delta_2
|
||||||
a1y = ay * delta_2
|
b1 = (2 * a * t1 + b) * delta
|
||||||
b1x = (2 * ax * t1 + bx) * delta
|
|
||||||
b1y = (2 * ay * t1 + by) * delta
|
|
||||||
t1_2 = t1 * t1
|
t1_2 = t1 * t1
|
||||||
c1x = ax * t1_2 + bx * t1 + cx
|
c1 = a * t1_2 + b * t1 + c
|
||||||
c1y = ay * t1_2 + by * t1 + cy
|
|
||||||
|
|
||||||
pt1, pt2, pt3 = calcQuadraticPoints((a1x, a1y), (b1x, b1y), (c1x, c1y))
|
pt1, pt2, pt3 = calcQuadraticPoints(a1, b1, c1)
|
||||||
segments.append((pt1, pt2, pt3))
|
segments.append((pt1, pt2, pt3))
|
||||||
return segments
|
return segments
|
||||||
|
|
||||||
@ -582,10 +567,6 @@ def _splitCubicAtT(a, b, c, d, *ts):
|
|||||||
ts.insert(0, 0.0)
|
ts.insert(0, 0.0)
|
||||||
ts.append(1.0)
|
ts.append(1.0)
|
||||||
segments = []
|
segments = []
|
||||||
ax, ay = a
|
|
||||||
bx, by = b
|
|
||||||
cx, cy = c
|
|
||||||
dx, dy = d
|
|
||||||
for i in range(len(ts) - 1):
|
for i in range(len(ts) - 1):
|
||||||
t1 = ts[i]
|
t1 = ts[i]
|
||||||
t2 = ts[i + 1]
|
t2 = ts[i + 1]
|
||||||
@ -597,17 +578,11 @@ def _splitCubicAtT(a, b, c, d, *ts):
|
|||||||
t1_3 = t1 * t1_2
|
t1_3 = t1 * t1_2
|
||||||
|
|
||||||
# calc new a, b, c and d
|
# calc new a, b, c and d
|
||||||
a1x = ax * delta_3
|
a1 = a * delta_3
|
||||||
a1y = ay * delta_3
|
b1 = (3 * a * t1 + b) * delta_2
|
||||||
b1x = (3 * ax * t1 + bx) * delta_2
|
c1 = (2 * b * t1 + c + 3 * a * t1_2) * delta
|
||||||
b1y = (3 * ay * t1 + by) * delta_2
|
d1 = a * t1_3 + b * t1_2 + c * t1 + d
|
||||||
c1x = (2 * bx * t1 + cx + 3 * ax * t1_2) * delta
|
pt1, pt2, pt3, pt4 = calcCubicPoints(a1, b1, c1, d1)
|
||||||
c1y = (2 * by * t1 + cy + 3 * ay * t1_2) * delta
|
|
||||||
d1x = ax * t1_3 + bx * t1_2 + cx * t1 + dx
|
|
||||||
d1y = ay * t1_3 + by * t1_2 + cy * t1 + dy
|
|
||||||
pt1, pt2, pt3, pt4 = calcCubicPoints(
|
|
||||||
(a1x, a1y), (b1x, b1y), (c1x, c1y), (d1x, d1y)
|
|
||||||
)
|
|
||||||
segments.append((pt1, pt2, pt3, pt4))
|
segments.append((pt1, pt2, pt3, pt4))
|
||||||
return segments
|
return segments
|
||||||
|
|
||||||
@ -750,57 +725,37 @@ def solveCubic(a, b, c, d):
|
|||||||
|
|
||||||
|
|
||||||
def calcQuadraticParameters(pt1, pt2, pt3):
|
def calcQuadraticParameters(pt1, pt2, pt3):
|
||||||
x2, y2 = pt2
|
pt1, pt2, pt3 = (Vector(pt) for pt in (pt1, pt2, pt3))
|
||||||
x3, y3 = pt3
|
c = pt1
|
||||||
cx, cy = pt1
|
b = (pt2 - c) * 2.0
|
||||||
bx = (x2 - cx) * 2.0
|
a = pt3 - c - b
|
||||||
by = (y2 - cy) * 2.0
|
return a, b, c
|
||||||
ax = x3 - cx - bx
|
|
||||||
ay = y3 - cy - by
|
|
||||||
return (ax, ay), (bx, by), (cx, cy)
|
|
||||||
|
|
||||||
|
|
||||||
def calcCubicParameters(pt1, pt2, pt3, pt4):
|
def calcCubicParameters(pt1, pt2, pt3, pt4):
|
||||||
x2, y2 = pt2
|
pt1, pt2, pt3, pt4 = (Vector(pt) for pt in (pt1, pt2, pt3, pt4))
|
||||||
x3, y3 = pt3
|
d = pt1
|
||||||
x4, y4 = pt4
|
c = (pt2 - d) * 3.0
|
||||||
dx, dy = pt1
|
b = (pt3 - pt2) * 3.0 - c
|
||||||
cx = (x2 - dx) * 3.0
|
a = pt4 - d - c - b
|
||||||
cy = (y2 - dy) * 3.0
|
return a, b, c, d
|
||||||
bx = (x3 - x2) * 3.0 - cx
|
|
||||||
by = (y3 - y2) * 3.0 - cy
|
|
||||||
ax = x4 - dx - cx - bx
|
|
||||||
ay = y4 - dy - cy - by
|
|
||||||
return (ax, ay), (bx, by), (cx, cy), (dx, dy)
|
|
||||||
|
|
||||||
|
|
||||||
def calcQuadraticPoints(a, b, c):
|
def calcQuadraticPoints(a, b, c):
|
||||||
ax, ay = a
|
a, b, c = (Vector(coeff) for coeff in (a, b, c))
|
||||||
bx, by = b
|
pt1 = c
|
||||||
cx, cy = c
|
pt2 = (b * 0.5) + c
|
||||||
x1 = cx
|
pt3 = a + b + c
|
||||||
y1 = cy
|
return pt1, pt2, pt3
|
||||||
x2 = (bx * 0.5) + cx
|
|
||||||
y2 = (by * 0.5) + cy
|
|
||||||
x3 = ax + bx + cx
|
|
||||||
y3 = ay + by + cy
|
|
||||||
return (x1, y1), (x2, y2), (x3, y3)
|
|
||||||
|
|
||||||
|
|
||||||
def calcCubicPoints(a, b, c, d):
|
def calcCubicPoints(a, b, c, d):
|
||||||
ax, ay = a
|
a, b, c, d = (Vector(coeff) for coeff in (a, b, c, d))
|
||||||
bx, by = b
|
pt1 = d
|
||||||
cx, cy = c
|
pt2 = (c / 3.0) + d
|
||||||
dx, dy = d
|
pt3 = (b + c) / 3.0 + pt2
|
||||||
x1 = dx
|
pt4 = a + d + c + b
|
||||||
y1 = dy
|
return pt1, pt2, pt3, pt4
|
||||||
x2 = (cx / 3.0) + dx
|
|
||||||
y2 = (cy / 3.0) + dy
|
|
||||||
x3 = (bx + cx) / 3.0 + x2
|
|
||||||
y3 = (by + cy) / 3.0 + y2
|
|
||||||
x4 = ax + dx + cx + bx
|
|
||||||
y4 = ay + dy + cy + by
|
|
||||||
return (x1, y1), (x2, y2), (x3, y3), (x4, y4)
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -818,7 +773,7 @@ def linePointAtT(pt1, pt2, t):
|
|||||||
Returns:
|
Returns:
|
||||||
A 2D tuple with the coordinates of the point.
|
A 2D tuple with the coordinates of the point.
|
||||||
"""
|
"""
|
||||||
return ((pt1[0] * (1 - t) + pt2[0] * t), (pt1[1] * (1 - t) + pt2[1] * t))
|
return (Vector(pt1) * (1 - t) + Vector(pt2) * t)
|
||||||
|
|
||||||
|
|
||||||
def quadraticPointAtT(pt1, pt2, pt3, t):
|
def quadraticPointAtT(pt1, pt2, pt3, t):
|
||||||
@ -831,9 +786,9 @@ def quadraticPointAtT(pt1, pt2, pt3, t):
|
|||||||
Returns:
|
Returns:
|
||||||
A 2D tuple with the coordinates of the point.
|
A 2D tuple with the coordinates of the point.
|
||||||
"""
|
"""
|
||||||
x = (1 - t) * (1 - t) * pt1[0] + 2 * (1 - t) * t * pt2[0] + t * t * pt3[0]
|
pt1, pt2, pt3 = (Vector(pt) for pt in (pt1, pt2, pt3))
|
||||||
y = (1 - t) * (1 - t) * pt1[1] + 2 * (1 - t) * t * pt2[1] + t * t * pt3[1]
|
t1 = 1 - t
|
||||||
return (x, y)
|
return t1 * t1 * pt1 + 2 * t1 * t * pt2 + t * t * pt3
|
||||||
|
|
||||||
|
|
||||||
def cubicPointAtT(pt1, pt2, pt3, pt4, t):
|
def cubicPointAtT(pt1, pt2, pt3, pt4, t):
|
||||||
@ -846,19 +801,14 @@ def cubicPointAtT(pt1, pt2, pt3, pt4, t):
|
|||||||
Returns:
|
Returns:
|
||||||
A 2D tuple with the coordinates of the point.
|
A 2D tuple with the coordinates of the point.
|
||||||
"""
|
"""
|
||||||
x = (
|
pt1, pt2, pt3, pt4 = (Vector(pt) for pt in (pt1, pt2, pt3, pt4))
|
||||||
(1 - t) * (1 - t) * (1 - t) * pt1[0]
|
t1 = 1 - t
|
||||||
+ 3 * (1 - t) * (1 - t) * t * pt2[0]
|
return (
|
||||||
+ 3 * (1 - t) * t * t * pt3[0]
|
t1 * t1 * t1 * pt1
|
||||||
+ t * t * t * pt4[0]
|
+ 3 * t1 * t1 * t * pt2
|
||||||
|
+ 3 * t1 * t * t * pt3
|
||||||
|
+ t * t * t * pt4
|
||||||
)
|
)
|
||||||
y = (
|
|
||||||
(1 - t) * (1 - t) * (1 - t) * pt1[1]
|
|
||||||
+ 3 * (1 - t) * (1 - t) * t * pt2[1]
|
|
||||||
+ 3 * (1 - t) * t * t * pt3[1]
|
|
||||||
+ t * t * t * pt4[1]
|
|
||||||
)
|
|
||||||
return (x, y)
|
|
||||||
|
|
||||||
|
|
||||||
def segmentPointAtT(seg, t):
|
def segmentPointAtT(seg, t):
|
||||||
@ -913,7 +863,7 @@ def lineLineIntersections(s1, e1, s2, e2):
|
|||||||
1
|
1
|
||||||
>>> intersection = a[0]
|
>>> intersection = a[0]
|
||||||
>>> intersection.pt
|
>>> intersection.pt
|
||||||
(374.44882952482897, 313.73458370177315)
|
Vector((374.44882952482897, 313.73458370177315))
|
||||||
>>> (intersection.t1, intersection.t2)
|
>>> (intersection.t1, intersection.t2)
|
||||||
(0.45069111555824454, 0.5408153767394238)
|
(0.45069111555824454, 0.5408153767394238)
|
||||||
"""
|
"""
|
||||||
@ -937,7 +887,7 @@ def lineLineIntersections(s1, e1, s2, e2):
|
|||||||
x = s1x
|
x = s1x
|
||||||
slope34 = (e2y - s2y) / (e2x - s2x)
|
slope34 = (e2y - s2y) / (e2x - s2x)
|
||||||
y = slope34 * (x - s2x) + s2y
|
y = slope34 * (x - s2x) + s2y
|
||||||
pt = (x, y)
|
pt = Vector((x, y))
|
||||||
return [
|
return [
|
||||||
Intersection(
|
Intersection(
|
||||||
pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
|
pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
|
||||||
@ -947,7 +897,7 @@ def lineLineIntersections(s1, e1, s2, e2):
|
|||||||
x = s2x
|
x = s2x
|
||||||
slope12 = (e1y - s1y) / (e1x - s1x)
|
slope12 = (e1y - s1y) / (e1x - s1x)
|
||||||
y = slope12 * (x - s1x) + s1y
|
y = slope12 * (x - s1x) + s1y
|
||||||
pt = (x, y)
|
pt = Vector((x, y))
|
||||||
return [
|
return [
|
||||||
Intersection(
|
Intersection(
|
||||||
pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
|
pt=pt, t1=_line_t_of_pt(s1, e1, pt), t2=_line_t_of_pt(s2, e2, pt)
|
||||||
@ -960,7 +910,7 @@ def lineLineIntersections(s1, e1, s2, e2):
|
|||||||
return []
|
return []
|
||||||
x = (slope12 * s1x - s1y - slope34 * s2x + s2y) / (slope12 - slope34)
|
x = (slope12 * s1x - s1y - slope34 * s2x + s2y) / (slope12 - slope34)
|
||||||
y = slope12 * (x - s1x) + s1y
|
y = slope12 * (x - s1x) + s1y
|
||||||
pt = (x, y)
|
pt = Vector((x, y))
|
||||||
if _both_points_are_on_same_side_of_origin(
|
if _both_points_are_on_same_side_of_origin(
|
||||||
pt, e1, s1
|
pt, e1, s1
|
||||||
) and _both_points_are_on_same_side_of_origin(pt, s2, e2):
|
) and _both_points_are_on_same_side_of_origin(pt, s2, e2):
|
||||||
@ -992,7 +942,7 @@ def _curve_line_intersections_t(curve, line):
|
|||||||
intersections = solveCubic(a[1], b[1], c[1], d[1])
|
intersections = solveCubic(a[1], b[1], c[1], d[1])
|
||||||
else:
|
else:
|
||||||
raise ValueError("Unknown curve degree")
|
raise ValueError("Unknown curve degree")
|
||||||
return sorted([i for i in intersections if 0.0 <= i <= 1])
|
return sorted(i for i in intersections if 0.0 <= i <= 1)
|
||||||
|
|
||||||
|
|
||||||
def curveLineIntersections(curve, line):
|
def curveLineIntersections(curve, line):
|
||||||
@ -1014,7 +964,7 @@ def curveLineIntersections(curve, line):
|
|||||||
>>> len(intersections)
|
>>> len(intersections)
|
||||||
3
|
3
|
||||||
>>> intersections[0].pt
|
>>> intersections[0].pt
|
||||||
(84.90010344084885, 189.87306176459828)
|
Vector((84.90010344084885, 189.87306176459828))
|
||||||
"""
|
"""
|
||||||
if len(curve) == 3:
|
if len(curve) == 3:
|
||||||
pointFinder = quadraticPointAtT
|
pointFinder = quadraticPointAtT
|
||||||
@ -1135,7 +1085,7 @@ def curveCurveIntersections(curve1, curve2):
|
|||||||
>>> len(intersections)
|
>>> len(intersections)
|
||||||
3
|
3
|
||||||
>>> intersections[0].pt
|
>>> intersections[0].pt
|
||||||
(81.7831487395506, 109.88904552375288)
|
Vector((81.7831487395506, 109.88904552375288))
|
||||||
"""
|
"""
|
||||||
intersection_ts = _curve_curve_intersections_t(curve1, curve2)
|
intersection_ts = _curve_curve_intersections_t(curve1, curve2)
|
||||||
return [
|
return [
|
||||||
@ -1163,14 +1113,14 @@ def segmentSegmentIntersections(seg1, seg2):
|
|||||||
>>> len(intersections)
|
>>> len(intersections)
|
||||||
3
|
3
|
||||||
>>> intersections[0].pt
|
>>> intersections[0].pt
|
||||||
(81.7831487395506, 109.88904552375288)
|
Vector((81.7831487395506, 109.88904552375288))
|
||||||
>>> curve3 = [ (100, 240), (30, 60), (210, 230), (160, 30) ]
|
>>> curve3 = [ (100, 240), (30, 60), (210, 230), (160, 30) ]
|
||||||
>>> line = [ (25, 260), (230, 20) ]
|
>>> line = [ (25, 260), (230, 20) ]
|
||||||
>>> intersections = segmentSegmentIntersections(curve3, line)
|
>>> intersections = segmentSegmentIntersections(curve3, line)
|
||||||
>>> len(intersections)
|
>>> len(intersections)
|
||||||
3
|
3
|
||||||
>>> intersections[0].pt
|
>>> intersections[0].pt
|
||||||
(84.90010344084885, 189.87306176459828)
|
Vector((84.90010344084885, 189.87306176459828))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Arrange by degree
|
# Arrange by degree
|
||||||
@ -1202,7 +1152,7 @@ def _segmentrepr(obj):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
return "%g" % obj
|
return "%g" % obj
|
||||||
else:
|
else:
|
||||||
return "(%s)" % ", ".join([_segmentrepr(x) for x in it])
|
return "(%s)" % ", ".join(_segmentrepr(x) for x in it)
|
||||||
|
|
||||||
|
|
||||||
def printSegments(segments):
|
def printSegments(segments):
|
||||||
|
@ -4,6 +4,9 @@ import operator
|
|||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["Vector"]
|
||||||
|
|
||||||
|
|
||||||
class Vector(tuple):
|
class Vector(tuple):
|
||||||
|
|
||||||
"""A math-like vector.
|
"""A math-like vector.
|
||||||
@ -13,6 +16,8 @@ class Vector(tuple):
|
|||||||
negation, rounding, and comparison tests.
|
negation, rounding, and comparison tests.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
def __new__(cls, values, keep=False):
|
def __new__(cls, values, keep=False):
|
||||||
if keep is not False:
|
if keep is not False:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
from fontTools.misc.bezierTools import (
|
from fontTools.misc.bezierTools import (
|
||||||
calcQuadraticBounds, calcCubicBounds, splitLine, splitQuadratic,
|
calcQuadraticBounds, calcCubicBounds, segmentPointAtT, splitLine, splitQuadratic,
|
||||||
splitCubic, splitQuadraticAtT, splitCubicAtT, solveCubic)
|
splitCubic, splitQuadraticAtT, splitCubicAtT, solveCubic)
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -130,3 +130,23 @@ def test_solveCubic():
|
|||||||
assert solveCubic(1.0, -4.5, 6.75, -3.375) == [1.5, 1.5, 1.5]
|
assert solveCubic(1.0, -4.5, 6.75, -3.375) == [1.5, 1.5, 1.5]
|
||||||
assert solveCubic(-12.0, 18.0, -9.0, 1.50023651123) == [0.5, 0.5, 0.5]
|
assert solveCubic(-12.0, 18.0, -9.0, 1.50023651123) == [0.5, 0.5, 0.5]
|
||||||
assert solveCubic(9.0, 0.0, 0.0, -7.62939453125e-05) == [-0.0, -0.0, -0.0]
|
assert solveCubic(9.0, 0.0, 0.0, -7.62939453125e-05) == [-0.0, -0.0, -0.0]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_segmentPointAtT_testData = [
|
||||||
|
([(0, 10), (200, 100)], 0.0, (0, 10)),
|
||||||
|
([(0, 10), (200, 100)], 0.5, (100, 55)),
|
||||||
|
([(0, 10), (200, 100)], 1.0, (200, 100)),
|
||||||
|
([(0, 10), (100, 100), (200, 50)], 0.0, (0, 10)),
|
||||||
|
([(0, 10), (100, 100), (200, 50)], 0.5, (100, 65.0)),
|
||||||
|
([(0, 10), (100, 100), (200, 50)], 1.0, (200, 50.0)),
|
||||||
|
([(0, 10), (100, 100), (200, 100), (300, 0)], 0.0, (0, 10)),
|
||||||
|
([(0, 10), (100, 100), (200, 100), (300, 0)], 0.5, (150, 76.25)),
|
||||||
|
([(0, 10), (100, 100), (200, 100), (300, 0)], 1.0, (300, 0)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("segment, t, expectedPoint", _segmentPointAtT_testData)
|
||||||
|
def test_segmentPointAtT(segment, t, expectedPoint):
|
||||||
|
point = segmentPointAtT(segment, t)
|
||||||
|
assert expectedPoint == point
|
||||||
|
@ -35,6 +35,11 @@ def test_Vector():
|
|||||||
assert v1.dot(v2) == 18
|
assert v1.dot(v2) == 18
|
||||||
v = Vector((2, 4))
|
v = Vector((2, 4))
|
||||||
assert round(v / 3) == (1, 1)
|
assert round(v / 3) == (1, 1)
|
||||||
|
with pytest.raises(
|
||||||
|
AttributeError,
|
||||||
|
match="'Vector' object has no attribute 'newAttr'",
|
||||||
|
):
|
||||||
|
v.newAttr = 12
|
||||||
|
|
||||||
|
|
||||||
def test_deprecated():
|
def test_deprecated():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user