Approximate a curve.
(
data: Array,
us: Optional[Array] = None,
knots: int | Array = 50,
order: int = 3,
penalty: int = 4,
lam: float = 0,
tangents: Optional[Tuple[Array, Array]] = None,
)
| 1641 | |
| 1642 | @multidispatch |
| 1643 | def approximate( |
| 1644 | data: Array, |
| 1645 | us: Optional[Array] = None, |
| 1646 | knots: int | Array = 50, |
| 1647 | order: int = 3, |
| 1648 | penalty: int = 4, |
| 1649 | lam: float = 0, |
| 1650 | tangents: Optional[Tuple[Array, Array]] = None, |
| 1651 | ) -> Curve: |
| 1652 | """ |
| 1653 | Approximate a curve. |
| 1654 | """ |
| 1655 | |
| 1656 | npts = data.shape[0] |
| 1657 | |
| 1658 | # parameterize the points if needed |
| 1659 | us = linspace(0, 1, npts) if us is None else us |
| 1660 | |
| 1661 | # construct the knot vector |
| 1662 | if isinstance(knots, int): |
| 1663 | knots_ = np.concatenate( |
| 1664 | (np.repeat(0, order), linspace(0, 1, knots), np.repeat(1, order)) |
| 1665 | ) |
| 1666 | else: |
| 1667 | knots_ = np.array(knots) |
| 1668 | |
| 1669 | # construct the design matrix |
| 1670 | C = designMatrix(us, order, knots_).csc() |
| 1671 | CtC = C.T @ C |
| 1672 | |
| 1673 | # add a penalty term if requested |
| 1674 | if lam: |
| 1675 | up = linspace(0, 1, order * npts) |
| 1676 | |
| 1677 | assert penalty <= order + 2 |
| 1678 | |
| 1679 | # discrete + exact derivatives |
| 1680 | if penalty > order: |
| 1681 | Pexact = derMatrix(up, order, order - 1, knots_)[-1].csc() |
| 1682 | Pdiscrete = discretePenalty(up, penalty - order).csc() |
| 1683 | |
| 1684 | P = Pdiscrete @ Pexact |
| 1685 | |
| 1686 | # only exact derivatives |
| 1687 | else: |
| 1688 | P = derMatrix(up, order, penalty, knots_)[-1].csc() |
| 1689 | |
| 1690 | CtC += lam * P.T @ P |
| 1691 | |
| 1692 | # clamp first and last point |
| 1693 | Cc = C[[0, -1], :] |
| 1694 | bc = data[[0, -1], :] |
| 1695 | nc = 2 # number of constraints |
| 1696 | |
| 1697 | # handle tangent constraints if needed |
| 1698 | if tangents: |
| 1699 | nc += 2 |
| 1700 |