## Bezier curves

When a shape is described using vector graphics, its outline is often described as a sequence of linear, quadratic, and cubic Bezier curves. You can read about [Bézier curves](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) on Wikipedia. 

You don't need to know much about Bezier curves to solve this kata. Just know that the equations of the linear, quadratic, and cubic curves are given by (respectively):

1. `P(t) = (1 - t) * P0 + t * P1`
2. `P(t) = (1 - t)**2 * P0 + 2 * (1 - t) * t * P1 + t**2 * P2`
3. `P(t) = (1 - t)**3 * P0 + 3 * (1 - t)**2 * t * P1 + 3 * (1 - t) * t**2 * P2 + t**3 * P3`

The points `P0`, `P1`, `P2`, `P3` are called the control points of the curve, and `t` is a variable, which, when taking values from `0` to `1`, will cause `P(t)` to trace the curve.

This should suffice to implement the `point_at(t)` method of the classes you are to implement.

To implement the `sub_segment(t)` method, see, in particular, the section on Constructing Bézier Curves of the above referenced Wikipedia article.

This section shows animations of how the Bézier curves grow. The animations are showing longer and longer subsegments, hence showing how subsegments are constructed. If you look closely at the quad curve animation, you can see how the control points move from starting all at P0 and ending up at P0, P1 and P2 respectively. Now look closely at the animation of the cubic curve. See how the control points of the growing subsection start at P0 and end up at P0, P1, P2, and P3. No need to read anything, just look. At the end of the referenced subsection there is a link to de Casteljau's algorithm, which you might find helpful, but I wouldn't go there. Just look carefully at the animations.

In this kata, you are asked to implement a class for each of the linear, quadratic, and cubic Bézier curves. These classes must extend the following abstract base class and implement the abstract methods:

```Python
from abc import ABCMeta, abstractmethod


class Segment(metaclass=ABCMeta):

    @property
    @abstractmethod
    def control_points(self):
        pass

    @abstractmethod
    def point_at(self, t):
        pass

    @abstractmethod
    def sub_segment(self, t):
        pass
```

`control_points` is a property that returns the coordinates of the points that define the curve. Since the linear curve has two control points (the start and end of the segment), `control_points` will hold 4 floats, which are the x- and y-coordinates of the first point followed by the x- and y-coordinates of the second point.  For the quadratic and cubic curves there are 6 and 8 control points respectively.

The method `point_at(t)` should return the point obtained when inserting `t` in the equation for the curve. This method will be tested for values of `t` in the interval `[0, 1]` only (although it's possible to extrapolate the curve). 

The method `sub_segment(t_0)` should return the curve that starts at the first point and ends at the point returned by `point_at(t_0)` and follows the curve of the object that this method is invoked on otherwise. For example, if `quad` is a quadratic curve, then `quad.sub_segment(t_0)` is a quadratic curve that starts at `quad`'s first point and ends at `quad.point_at(t_0)` and follows `quad`'s curve. More precisely, 

```
quad.point_at(t_0 * t) == quad.sub_segment(t_0).point_at(t)
```
for all values of `t` in the interval `[0, 1]`.

Difficulty: MEDIUM
Tags: Fundamentals

Starter code:
def control_points(self):
	

Solutions:
class Segment:

	def __init__(self, *coords):
		self.control_points = coords

	def control_points_at(self, t):
		p = self.control_points
		result = []
		while p:
			result.extend(p[:2])
			p = [v + (p[i + 2] - v) * t for (i, v) in enumerate(p[:-2])]
		return result

	def point_at(self, t):
		return tuple(self.control_points_at(t)[-2:])

	def sub_segment(self, t):
		return self.__class__(*self.control_points_at(t))

class Line(Segment):
	pass

class Quad(Segment):
	pass

class Cubic(Segment):
	pass


class Segment:

	def __init__(self, *coords):
		self._control_points = list(zip(*[iter(coords)] * 2))

	def _flatten(self, points):
		return tuple((coord for point in points for coord in point))

	def _interpolate(self, points, t):
		return [tuple(((1 - t) * x + t * y for (x, y) in zip(p0, p1))) for (p0, p1) in zip(points, points[1:])]

	def _reduce(self, points, t):
		while len(points) > 1:
			yield points[0]
			points = self._interpolate(points, t)
		yield points[0]

	@property
	def control_points(self):
		return self._flatten(self._control_points)

	def point_at(self, t):
		return list(self._reduce(self._control_points, t))[-1]

	def sub_segment(self, t):
		return self.__class__(*self._flatten(self._reduce(self._control_points, t)))

class Line(Segment):
	pass

class Quad(Segment):
	pass

class Cubic(Segment):
	pass


from abc import ABCMeta, abstractmethod

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

class Line(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(x, y) = (self._control_points[::2], self._control_points[1::2])
		(x0, y0, x1, y1) = self._control_points
		eq = lambda p, t: (1 - t) * p[0] + t * p[1]
		return (eq(x, t), eq(y, t))

	def sub_segment(self, t):
		p0 = self._control_points[:2]
		pt = self.point_at(t)
		return self.__class__(*p0, *pt)

class Quad(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(x, y) = (self._control_points[::2], self._control_points[1::2])
		eq = lambda p, t: (1 - t) ** 2 * p[0] + 2 * (1 - t) * t * p[1] + t ** 2 * p[2]
		return (eq(x, t), eq(y, t))

	def sub_segment(self, t):
		p0 = self._control_points[:2]
		q0 = Line(*self._control_points[:4]).point_at(t)
		pt = self.point_at(t)
		return self.__class__(*p0, *q0, *pt)

class Cubic(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(x, y) = (self._control_points[::2], self._control_points[1::2])
		eq = lambda p, t: (1 - t) ** 3 * p[0] + 3 * (1 - t) ** 2 * t * p[1] + 3 * (1 - t) * t ** 2 * p[2] + t ** 3 * p[3]
		return (eq(x, t), eq(y, t))

	def sub_segment(self, t):
		p0 = self._control_points[:2]
		q0 = Line(*self._control_points[:4]).point_at(t)
		q1 = Line(*self._control_points[2:6]).point_at(t)
		r0 = Line(*q0, *q1).point_at(t)
		pt = self.point_at(t)
		return self.__class__(*p0, *q0, *r0, *pt)


from math import factorial

class Coordinate(object):

	def __init__(self, x, y):
		self._x = x
		self._y = y

	@property
	def x(self):
		return self._x

	@property
	def y(self):
		return self._y

	def __mul__(self, num):
		return Coordinate(self.x * num, self.y * num)
	__rmul__ = __mul__

	def __sub__(self, other):
		return Coordinate(self.x - other.x, self.y - other.y)
	__rsub__ = __sub__

	def __add__(self, other):
		try:
			return Coordinate(self.x + other.x, self.y + other.y)
		except AttributeError:
			return Coordinate(self.x + other, self.y + other)
	__radd__ = __add__

	def __repr__(self):
		return 'Coordinate(' + str(self.x) + ', ' + str(self.y) + ')'

	def __str__(self):
		return 'C(' + str(self.x) + ', ' + str(self.y) + ')'

	def __hash__(self):
		return hash((self.x, self.y))

class Segment:

	def __init__(self, *coords):
		if len(coords) % 2 != 0:
			raise ValueError('Incorrect number of argument values.')
		self._control_points = coords
		self._P = [Coordinate(coords[i], coords[i + 1]) for i in range(0, len(coords), 2)]
		self._bezier_curve = self._get_bezier_curve(self._P)

	@property
	def control_points(self):
		return self._control_points

	@staticmethod
	def _comb(n, k):
		return factorial(n) // (factorial(k) * factorial(n - k))

	def _get_bezier_curve(self, points):
		n = len(points) - 1
		return lambda t: sum((self._comb(n, i) * t ** i * (1 - t) ** (n - i) * points[i] for i in range(n + 1)))

	def point_at(self, t):
		pt = self._bezier_curve(t)
		return (pt.x, pt.y)

	def sub_segment(self, t):
		sub_points = [*self._control_points[:2]]
		for i in range(4, len(self._control_points), 2):
			point = Segment(*self._control_points[:i]).point_at(t)
			sub_points.extend(point)
		sub_points.extend(self.point_at(t))
		return Segment(*sub_points)

class Line(Segment):
	pass

class Quad(Segment):
	pass

class Cubic(Segment):
	pass


from abc import ABCMeta, abstractmethod

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

class Coordinate(object):

	def __init__(self, x, y):
		self._x = x
		self._y = y

	@property
	def x(self):
		return self._x

	@property
	def y(self):
		return self._y

	def __mul__(self, num):
		return Coordinate(self.x * num, self.y * num)

	def __rmul__(self, num):
		return Coordinate(self.x * num, self.y * num)

	def __sub__(self, other):
		return Coordinate(self.x - other.x, self.y - other.y)

	def __add__(self, other):
		return Coordinate(self.x + other.x, self.y + other.y)

	def __repr__(self):
		return 'Coordinate(' + str(self.x) + ', ' + str(self.y) + ')'

	def __str__(self):
		return '<' + str(self.x) + ', ' + str(self.y) + '>'

	def __hash__(self):
		return hash((self.x, self.y))

class Line(Segment):

	def __init__(self, *coords):
		self._control_points = coords
		self._P0 = Coordinate(coords[0], coords[1])
		self._P1 = Coordinate(coords[2], coords[3])

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		pt = (1 - t) * self._P0 + t * self._P1
		return (pt.x, pt.y)

	def sub_segment(self, t):
		return Line(self._P0.x, self._P0.y, *self.point_at(t))

class Quad(Segment):

	def __init__(self, *coords):
		self._control_points = coords
		self._P0 = Coordinate(coords[0], coords[1])
		self._P1 = Coordinate(coords[2], coords[3])
		self._P2 = Coordinate(coords[4], coords[5])

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		pt = (1 - t) ** 2 * self._P0 + 2 * (1 - t) * t * self._P1 + t ** 2 * self._P2
		return (pt.x, pt.y)

	def sub_segment(self, t):
		sub_line = Line(self._P0.x, self._P0.y, self._P1.x, self._P1.y)
		return Quad(self._P0.x, self._P0.y, *sub_line.point_at(t), *self.point_at(t))

class Cubic(Segment):

	def __init__(self, *coords):
		self._control_points = coords
		self._P0 = Coordinate(coords[0], coords[1])
		self._P1 = Coordinate(coords[2], coords[3])
		self._P2 = Coordinate(coords[4], coords[5])
		self._P3 = Coordinate(coords[6], coords[7])

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		pt = (1 - t) ** 3 * self._P0 + 3 * (1 - t) ** 2 * t * self._P1 + 3 * (1 - t) * t ** 2 * self._P2 + t ** 3 * self._P3
		return (pt.x, pt.y)

	def sub_segment(self, t):
		sub_line = Line(self._P0.x, self._P0.y, self._P1.x, self._P1.y)
		sub_quad = Quad(self._P0.x, self._P0.y, self._P1.x, self._P1.y, self._P2.x, self._P2.y)
		return Cubic(self._P0.x, self._P0.y, *sub_line.point_at(t), *sub_quad.point_at(t), *self.point_at(t))


from abc import ABCMeta, abstractmethod

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

class Line(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(p_0, p_1, p_2, p_3) = (self.control_points[0], self.control_points[1], self.control_points[2], self.control_points[3])
		x = (1 - t) * p_0 + t * p_2
		y = (1 - t) * p_1 + t * p_3
		return (x, y)

	def sub_segment(self, t):
		t_point = self.point_at(t)
		co_ords = (self.control_points[0], self.control_points[1], t_point[0], t_point[1])
		return Line(*co_ords)

class Quad(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		p_1 = (self.control_points[0], self.control_points[1])
		p_2 = (self.control_points[2], self.control_points[3])
		p_3 = (self.control_points[4], self.control_points[5])
		x = (1 - t) ** 2 * p_1[0] + 2 * (1 - t) * t * p_2[0] + t ** 2 * p_3[0]
		y = (1 - t) ** 2 * p_1[1] + 2 * (1 - t) * t * p_2[1] + t ** 2 * p_3[1]
		return (x, y)

	def sub_segment(self, t):
		lne = Line(self.control_points[0], self.control_points[1], self.control_points[2], self.control_points[3])
		t_p1 = lne.point_at(t)
		t_point = self.point_at(t)
		co_ords = (self.control_points[0], self.control_points[1], t_p1[0], t_p1[1], t_point[0], t_point[1])
		return Quad(*co_ords)

class Cubic(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		p_1 = (self.control_points[0], self.control_points[1])
		p_2 = (self.control_points[2], self.control_points[3])
		p_3 = (self.control_points[4], self.control_points[5])
		p_4 = (self.control_points[6], self.control_points[7])
		x = (1 - t) ** 3 * p_1[0] + 3 * (1 - t) ** 2 * t * p_2[0] + 3 * (1 - t) * t ** 2 * p_3[0] + t ** 3 * p_4[0]
		y = (1 - t) ** 3 * p_1[1] + 3 * (1 - t) ** 2 * t * p_2[1] + 3 * (1 - t) * t ** 2 * p_3[1] + t ** 3 * p_4[1]
		return (x, y)

	def sub_segment(self, t):
		t_point = self.point_at(t)
		lne_1 = Line(self.control_points[0], self.control_points[1], self.control_points[2], self.control_points[3])
		pnt_1 = lne_1.point_at(t)
		lne_2 = Line(self.control_points[2], self.control_points[3], self.control_points[4], self.control_points[5])
		pnt_2 = lne_2.point_at(t)
		lne_3 = Line(self.control_points[4], self.control_points[5], self.control_points[6], self.control_points[7])
		pnt_3 = lne_3.point_at(t)
		lne_g1 = Line(*pnt_1, *pnt_2)
		pnt_g1 = lne_g1.point_at(t)
		lne_g2 = Line(*pnt_2, *pnt_3)
		co_ords = (self.control_points[0], self.control_points[1], pnt_1[0], pnt_1[1], pnt_g1[0], pnt_g1[1], t_point[0], t_point[1])
		return Cubic(*co_ords)


from abc import ABCMeta, abstractmethod
from functools import reduce

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

def mul(a, b):
	return (a[0] * b, a[1] * b)

def add(*args):
	print(args)
	return (sum([args[i][0] + args[i + 1][0] for i in range(len(args) - 1)]), sum([args[i][1] + args[i + 1][1] for i in range(len(args) - 1)]))

class Line(Segment):

	def __init__(self, *c):
		self.c = c
		self.points = [(c[i], c[i + 1]) for i in range(0, len(c) - 1, 2)]

	@property
	def control_points(self):
		return self.c

	def point_at(self, t):
		p = self.points
		return add(mul(p[0], 1 - t), mul(p[1], t))

	def sub_segment(self, t):
		return Line(self.c[0], self.c[1], self.point_at(t)[0], self.point_at(t)[1])

class Quad(Segment):

	def __init__(self, *c):
		self.c = c
		self.points = [(c[i], c[i + 1]) for i in range(0, len(c) - 1, 2)]

	@property
	def control_points(self):
		return self.c

	def point_at(self, t):
		p = self.points
		return reduce(add, [mul(p[0], (1 - t) ** 2), mul(p[1], t * 2 * (1 - t)), mul(p[2], t ** 2)])

	def sub_segment(self, t):
		(a, b) = add(mul(self.points[0], 1 - t), mul(self.points[1], t))
		return Quad(self.c[0], self.c[1], a, b, self.point_at(t)[0], self.point_at(t)[1])

class Cubic(Segment):

	def __init__(self, *c):
		self.c = c
		self.points = [(c[i], c[i + 1]) for i in range(0, len(c) - 1, 2)]

	@property
	def control_points(self):
		return self.c

	def point_at(self, t):
		p = self.points
		return reduce(add, [mul(p[0], (1 - t) ** 3), mul(p[1], 3 * t * (1 - t) ** 2), mul(p[2], 3 * t ** 2 * (1 - t)), mul(p[3], t ** 3)])

	def sub_segment(self, t):
		p = self.points
		(a, b) = add(mul(p[0], 1 - t), mul(p[1], t))
		(c, d) = reduce(add, [mul(p[0], (1 - t) ** 2), mul(p[1], t * 2 * (1 - t)), mul(p[2], t ** 2)])
		return Cubic(self.c[0], self.c[1], a, b, c, d, self.point_at(t)[0], self.point_at(t)[1])


from abc import ABCMeta, abstractmethod

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

class Line(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(x0, y0, x1, y1) = self.control_points
		point = tuple(((1 - t) * p0 + t * p1 for (p0, p1) in [(x0, x1), (y0, y1)]))
		return point

	def sub_segment(self, t):
		return Line(*self.control_points[:2], *self.point_at(t))

class Quad(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(x0, y0, x1, y1, x2, y2) = self.control_points
		point = tuple(((1 - t) ** 2 * p0 + 2 * (1 - t) * t * p1 + t ** 2 * p2 for (p0, p1, p2) in [(x0, x1, x2), (y0, y1, y2)]))
		return point

	def sub_segment(self, t):
		(x0, y0) = self.control_points[:2]
		(x1, y1) = Line(x0, y0, *self.control_points[2:4]).point_at(t)
		(x2, y2) = self.point_at(t)
		return Quad(x0, y0, x1, y1, x2, y2)

class Cubic(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		(x0, y0, x1, y1, x2, y2, x3, y3) = self.control_points
		point = tuple(((1 - t) ** 3 * p0 + 3 * (1 - t) ** 2 * t * p1 + 3 * (1 - t) * t ** 2 * p2 + t ** 3 * p3 for (p0, p1, p2, p3) in [(x0, x1, x2, x3), (y0, y1, y2, y3)]))
		return point

	def sub_segment(self, t):
		(x0, y0) = self.control_points[:2]
		(x1, y1) = Line(x0, y0, *self.control_points[2:4]).point_at(t)
		(x2, y2) = Quad(*self.control_points[:6]).point_at(t)
		(x3, y3) = self.point_at(t)
		return Cubic(x0, y0, x1, y1, x2, y2, x3, y3)


from abc import ABCMeta, abstractmethod
import numpy as np

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

class Line(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		P0 = np.array(self._control_points[0:2])
		P1 = np.array(self._control_points[2:])
		return (1 - t) * P0 + t * P1

	def sub_segment(self, t):
		P0 = np.array(self._control_points[0:2])
		P1 = self.point_at(t)
		return Line(*P0, *P1)

class Quad(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		P0 = np.array(self._control_points[0:2])
		P1 = np.array(self._control_points[2:4])
		P2 = np.array(self._control_points[4:])
		return (1 - t) ** 2 * P0 + 2 * (1 - t) * t * P1 + t ** 2 * P2

	def sub_segment(self, t):
		P0 = np.array(self._control_points[0:2])
		P1 = np.array(self._control_points[2:4])
		l1 = Line(*P0, *P1)
		P1_new = l1.point_at(t)
		P2 = np.array(self._control_points[4:])
		P2_new = self.point_at(t)
		return Quad(*P0, *P1_new, *P2_new)

class Cubic(Segment):

	def __init__(self, *coords):
		self._control_points = coords

	@property
	def control_points(self):
		return self._control_points

	def point_at(self, t):
		P0 = np.array(self._control_points[0:2])
		P1 = np.array(self._control_points[2:4])
		P2 = np.array(self._control_points[4:6])
		P3 = np.array(self._control_points[6:])
		return (1 - t) ** 3 * P0 + 3 * (1 - t) ** 2 * t * P1 + 3 * (1 - t) * t ** 2 * P2 + t ** 3 * P3

	def sub_segment(self, t):
		P0 = np.array(self._control_points[0:2])
		P1 = np.array(self._control_points[2:4])
		P2 = np.array(self._control_points[4:6])
		P3 = np.array(self._control_points[6:])
		l1 = Line(*P0, *P1)
		P1_new = l1.point_at(t)
		l2 = Quad(*P0, *P1, *P2)
		P2_new = l2.point_at(t)
		P3_new = self.point_at(t)
		return Cubic(*P0, *P1_new, *P2_new, *P3_new)


from abc import ABCMeta, abstractmethod

class Segment(metaclass=ABCMeta):

	@property
	@abstractmethod
	def control_points(self):
		pass

	@abstractmethod
	def point_at(self, t):
		pass

	@abstractmethod
	def sub_segment(self, t):
		pass

class Line(Segment):

	def __init__(self, *coords):
		self.cp = coords
		self.P0 = (coords[0], coords[1])
		self.P1 = (coords[2], coords[3])

	@property
	def control_points(self):
		return self.cp

	def point_at(self, t):
		x = (1 - t) * self.P0[0] + t * self.P1[0]
		y = (1 - t) * self.P0[1] + t * self.P1[1]
		return (x, y)

	def sub_segment(self, t):
		return Line(*self.P0, *self.point_at(t))

class Quad(Segment):

	def __init__(self, *coords):
		self.cp = coords
		self.P = [(coords[0], coords[1]), (coords[2], coords[3]), (coords[4], coords[5])]

	@property
	def control_points(self):
		return self.cp

	def get_Q(self, t):
		return (Line(*self.P[0], *self.P[1]).point_at(t), Line(*self.P[1], *self.P[2]).point_at(t))

	def point_at(self, t):
		Q = self.get_Q(t)
		return Line(*Q[0], *Q[1]).point_at(t)

	def sub_segment(self, t):
		Q = self.get_Q(t)[0]
		B = self.point_at(t)
		return Quad(*self.P[0], *Q, *B)

class Cubic(Segment):

	def __init__(self, *coords):
		self.cp = coords
		self.P = [(coords[0], coords[1]), (coords[2], coords[3]), (coords[4], coords[5]), (coords[6], coords[7])]

	@property
	def control_points(self):
		return self.cp

	def get_Q(self, t):
		return (Line(*self.P[0], *self.P[1]).point_at(t), Line(*self.P[1], *self.P[2]).point_at(t), Line(*self.P[2], *self.P[3]).point_at(t))

	def point_at(self, t):
		Q = self.get_Q(t)
		return Quad(*Q[0], *Q[1], *Q[2]).point_at(t)

	def sub_segment(self, t):
		Q = self.get_Q(t)
		R = Line(*Q[0], *Q[1]).point_at(t)
		B = self.point_at(t)
		return Cubic(*self.P[0], *Q[0], *R, *B)