From 5fc57c13db4e985a24e62c629e00bef8284cc9e8 Mon Sep 17 00:00:00 2001 From: Fabrice Salvaire Date: Sun, 27 Jan 2019 14:39:22 +0100 Subject: [PATCH] Splitted geometry doc --- Patro/GeometryEngine/Bezier.py | 251 +---------------- Patro/GeometryEngine/Spline.py | 239 +--------------- Patro/GeometryEngine/Transformation.py | 59 +--- doc/sphinx/source/index.rst | 1 + .../source/resources/geometry/bezier.rst | 258 ++++++++++++++++++ .../source/resources/geometry/index.rst | 18 ++ .../source/resources/geometry/spline.rst | 246 +++++++++++++++++ .../resources/geometry/transformations.rst | 66 +++++ doc/sphinx/source/resources/index.rst | 16 ++ 9 files changed, 608 insertions(+), 546 deletions(-) create mode 100644 doc/sphinx/source/resources/geometry/bezier.rst create mode 100644 doc/sphinx/source/resources/geometry/index.rst create mode 100644 doc/sphinx/source/resources/geometry/spline.rst create mode 100644 doc/sphinx/source/resources/geometry/transformations.rst create mode 100644 doc/sphinx/source/resources/index.rst diff --git a/Patro/GeometryEngine/Bezier.py b/Patro/GeometryEngine/Bezier.py index 38f54aa..95d9edf 100644 --- a/Patro/GeometryEngine/Bezier.py +++ b/Patro/GeometryEngine/Bezier.py @@ -20,256 +20,7 @@ r"""Module to implement Bézier curve. -Definitions ------------ - -A Bézier curve is defined by a set of control points :math:`\mathbf{P}_0` through -:math:`\mathbf{P}_n`, where :math:`n` is called its order (:math:`n = 1` for linear, 2 for -quadratic, 3 for cubic etc.). The first and last control points are always the end points of the -curve; - -In the following :math:`0 \le t \le 1`. - -Linear Bézier Curves ---------------------- - -Given distinct points :math:`\mathbf{P}_0` and :math:`\mathbf{P}_1`, a linear Bézier curve is simply -a straight line between those two points. The curve is given by - -.. math:: - \begin{align} - \mathbf{B}(t) &= \mathbf{P}_0 + t (\mathbf{P}_1 - \mathbf{P}_0) \\ - &= (1-t) \mathbf{P}_0 + t \mathbf{P}_1 - \end{align} - -and is equivalent to linear interpolation. - -Quadratic Bézier Curves ------------------------ - -A quadratic Bézier curve is the path traced by the function :math:`\mathbf{B}(t)`, given points -:math:`\mathbf{P}_0`, :math:`\mathbf{P}_1`, and :math:`\mathbf{P}_2`, - -.. math:: - \mathbf{B}(t) = (1 - t)[(1 - t) \mathbf{P}_0 + t \mathbf{P}_1] + t [(1 - t) \mathbf{P}_1 + t \mathbf{P}_2] - -which can be interpreted as the linear interpolant of corresponding points on the linear Bézier -curves from :math:`\mathbf{P}_0` to :math:`\mathbf{P}_1` and from :math:`\mathbf{P}_1` to -:math:`\mathbf{P}_2` respectively. - -Rearranging the preceding equation yields: - -.. math:: - \begin{align} - \mathbf{B}(t) &= (1 - t)^{2} \mathbf{P}_0 + 2(1 - t)t \mathbf{P}_1 + t^{2} \mathbf{P}_2 \\ - &= (\mathbf{P}_0 - 2\mathbf{P}_1 + \mathbf{P}_2) t^2 + - (-2\mathbf{P}_0 + 2\mathbf{P}_1) t + - \mathbf{P}_0 - \end{align} - -This can be written in a way that highlights the symmetry with respect to :math:`\mathbf{P}_1`: - -.. math:: - \mathbf{B}(t) = \mathbf{P}_1 + (1 - t)^{2} ( \mathbf{P}_0 - \mathbf{P}_1) + t^{2} (\mathbf{P}_2 - \mathbf{P}_1) - -Which immediately gives the derivative of the Bézier curve with respect to `t`: - -.. math:: - \mathbf{B}'(t) = 2(1 - t) (\mathbf{P}_1 - \mathbf{P}_0) + 2t (\mathbf{P}_2 - \mathbf{P}_1) - -from which it can be concluded that the tangents to the curve at :math:`\mathbf{P}_0` and -:math:`\mathbf{P}_2` intersect at :math:`\mathbf{P}_1`. As :math:`t` increases from 0 to 1, the -curve departs from :math:`\mathbf{P}_0` in the direction of :math:`\mathbf{P}_1`, then bends to -arrive at :math:`\mathbf{P}_2` from the direction of :math:`\mathbf{P}_1`. - -The second derivative of the Bézier curve with respect to :math:`t` is - -.. math:: - \mathbf{B}''(t) = 2 (\mathbf{P}_2 - 2 \mathbf{P}_1 + \mathbf{P}_0) - -Cubic Bézier Curves -------------------- - -Four points :math:`\mathbf{P}_0`, :math:`\mathbf{P}_1`, :math:`\mathbf{P}_2` and -:math:`\mathbf{P}_3` in the plane or in higher-dimensional space define a cubic Bézier curve. The -curve starts at :math:`\mathbf{P}_0` going toward :math:`\mathbf{P}_1` and arrives at -:math:`\mathbf{P}_3` coming from the direction of :math:`\mathbf{P}_2`. Usually, it will not pass -through :math:`\mathbf{P}_1` or :math:`\mathbf{P}_2`; these points are only there to provide -directional information. The distance between :math:`\mathbf{P}_1` and :math:`\mathbf{P}_2` -determines "how far" and "how fast" the curve moves towards :math:`\mathbf{P}_1` before turning -towards :math:`\mathbf{P}_2`. - -Writing :math:`\mathbf{B}_{\mathbf P_i,\mathbf P_j,\mathbf P_k}(t)` for the quadratic Bézier curve -defined by points :math:`\mathbf{P}_i`, :math:`\mathbf{P}_j`, and :math:`\mathbf{P}_k`, the cubic -Bézier curve can be defined as an affine combination of two quadratic Bézier curves: - -.. math:: - \mathbf{B}(t) = (1-t) \mathbf{B}_{\mathbf P_0,\mathbf P_1,\mathbf P_2}(t) + - t \mathbf{B}_{\mathbf P_1,\mathbf P_2,\mathbf P_3}(t) - -The explicit form of the curve is: - -.. math:: - \begin{align} - \mathbf{B}(t) &= (1-t)^3 \mathbf{P}_0 + 3(1-t)^2t \mathbf{P}_1 + 3(1-t)t^2 \mathbf{P}_2 + t^3\mathbf{P}_3 \\ - &= (\mathbf{P}_3 - 3\mathbf{P}_2 + 3\mathbf{P}_1 - \mathbf{P}_0) t^3 + - 3(\mathbf{P}_2 - 2\mathbf{P}_1 + \mathbf{P}_0) t^2 + - 3(\mathbf{P}_1 - \mathbf{P}_0) t + - \mathbf{P}_0 - \end{align} - -For some choices of :math:`\mathbf{P}_1` and :math:`\mathbf{P}_2` the curve may intersect itself, or -contain a cusp. - -The derivative of the cubic Bézier curve with respect to :math:`t` is - -.. math:: - \mathbf{B}'(t) = 3(1-t)^2 (\mathbf{P}_1 - \mathbf{P}_0) + 6(1-t)t (\mathbf{P}_2 - \mathbf{P}_1) + 3t^2 (\mathbf{P}_3 - \mathbf{P}_2) - -The second derivative of the Bézier curve with respect to :math:`t` is - -.. math:: - \mathbf{B}''(t) = 6(1-t) (\mathbf{P}_2 - 2 \mathbf{P}_1 + \mathbf{P}_0) + 6t (\mathbf{P}_3 - 2 \mathbf{P}_2 + \mathbf{P}_1) - -Recursive definition --------------------- - -A recursive definition for the Bézier curve of degree :math:`n` expresses it as a point-to-point -linear combination of a pair of corresponding points in two Bézier curves of degree :math:`n-1`. - -Let :math:`\mathbf{B}_{\mathbf{P}_0\mathbf{P}_1\ldots\mathbf{P}_n}` denote the Bézier curve -determined by any selection of points :math:`\mathbf{P}_0`, :math:`\mathbf{P}_1`, :math:`\ldots`, -:math:`\mathbf{P}_{n-1}`. - -The recursive definition is - -.. math:: - \begin{align} - \mathbf{B}_{\mathbf{P}_0}(t) &= \mathbf{P}_0 \\[1em] - \mathbf{B}(t) &= \mathbf{B}_{\mathbf{P}_0\mathbf{P}_1\ldots\mathbf{P}_n}(t) \\ - &= (1-t) \mathbf{B}_{\mathbf{P}_0\mathbf{P}_1\ldots\mathbf{P}_{n-1}}(t) + - t \mathbf{B}_{\mathbf{P}_1\mathbf{P}_2\ldots\mathbf{P}_n}(t) - \end{align} - -The formula can be expressed explicitly as follows: - -.. math:: - \begin{align} - \mathbf{B}(t) &= \sum_{i=0}^n b_{i,n}(t) \mathbf{P}_i \\ - &= \sum_{i=0}^n {n\choose i}(1 - t)^{n - i}t^i \mathbf{P}_i \\ - &= (1 - t)^n \mathbf{P}_0 + - {n\choose 1}(1 - t)^{n - 1}t \mathbf{P}_1 + - \cdots + - {n\choose n - 1}(1 - t)t^{n - 1} \mathbf{P}_{n - 1} + - t^n \mathbf{P}_n - \end{align} - -where :math:`b_{i,n}(t)` are the Bernstein basis polynomials of degree :math:`n` and :math:`n -\choose i` are the binomial coefficients. - -Degree elevation ----------------- - -A Bézier curve of degree :math:`n` can be converted into a Bézier curve of degree :math:`n + 1` with -the same shape. - -To do degree elevation, we use the equality - -.. math:: - \mathbf{B}(t) = (1-t) \mathbf{B}(t) + t \mathbf{B}(t) - -Each component :math:`\mathbf{b}_{i,n}(t) \mathbf{P}_i` is multiplied by :math:`(1-t)` and -:math:`t`, thus increasing a degree by one, without changing the value. - -For arbitrary :math:`n`, we have - -.. math:: - \begin{align} - \mathbf{B}(t) &= (1 - t) \sum_{i=0}^n \mathbf{b}_{i,n}(t) \mathbf{P}_i + - t \sum_{i=0}^n \mathbf{b}_{i,n}(t) \mathbf{P}_i \\ - &= \sum_{i=0}^n \frac{n + 1 - i}{n + 1} \mathbf{b}_{i, n + 1}(t) \mathbf{P}_i + - \sum_{i=0}^n \frac{i + 1}{n + 1} \mathbf{b}_{i + 1, n + 1}(t) \mathbf{P}_i \\ - &= \sum_{i=0}^{n + 1} \mathbf{b}_{i, n + 1}(t) - \left(\frac{i}{n + 1} \mathbf{P}_{i - 1} + - \frac{n + 1 - i}{n + 1} \mathbf{P}_i\right) \\ - &= \sum_{i=0}^{n + 1} \mathbf{b}_{i, n + 1}(t) \mathbf{P'}_i - \end{align} - -Therefore the new control points are - -.. math:: - \mathbf{P'}_i = \frac{i}{n + 1} \mathbf{P}_{i - 1} + \frac{n + 1 - i}{n + 1} \mathbf{P}_i - -It introduces two arbitrary points :math:`\mathbf{P}_{-1}` and :math:`\mathbf{P}_{n+1}` which are -cancelled in :math:`\mathbf{P'}_i`. - -Matrix Forms ------------- - -.. math:: - \mathbf{B}(t) = \mathbf{Transformation} \; \mathbf{Control} \; \mathbf{Basis} \; \mathbf{T}(t) - -.. math:: - \begin{align} - \mathbf{B^2}(t) &= \mathbf{Tr} - \begin{pmatrix} - P_{1x} & P_{2x} & P_{3x} \\ - P_{1y} & P_{2x} & P_{3x} \\ - 1 & 1 & 1 - \end{pmatrix} - \begin{pmatrix} - 1 & -2 & 1 \\ - 0 & 2 & -2 \\ - 0 & 0 & 1 - \end{pmatrix} - \begin{pmatrix} - 1 \\ - t \\ - t^2 - \end{pmatrix} \\[1em] - \mathbf{B^3}(t) &= \mathbf{Tr} - \begin{pmatrix} - P_{1x} & P_{2x} & P_{3x} & P_{4x} \\ - P_{1y} & P_{2x} & P_{3x} & P_{4x} \\ - 0 & 0 & 0 & 0 \\ - 1 & 1 & 1 & 1 - \end{pmatrix} - \begin{pmatrix} - 1 & -3 & 3 & -1 \\ - 0 & 3 & -6 & 3 \\ - 0 & 0 & 3 & -3 \\ - 0 & 0 & 0 & 1 - \end{pmatrix} - \begin{pmatrix} - 1 \\ - t \\ - t^2 \\ - t^3 - \end{pmatrix} - \end{align} - -.. B(t) = P0 (1 - 2t + t^2) + - P1 ( 2t - t^2) + - P2 t^2 - -Symbolic Calculation --------------------- - -.. code-block:: py3 - - >>> from sympy import * - - >>> P0, P1, P2, P3, P, t = symbols('P0 P1 P2 P3 P t') - - >>> B2 = (1-t)*((1-t)*P0 + t*P1) + t*((1-t)*P1 + t*P2) - >>> collect(expand(B2), t) - P0 + t**2*(P0 - 2*P1 + P2) + t*(-2*P0 + 2*P1) - - >>> B2_012 = (1-t)*((1-t)*P0 + t*P1) + t*((1-t)*P1 + t*P2) - >>> B2_123 = (1-t)*((1-t)*P1 + t*P2) + t*((1-t)*P2 + t*P3) - >>> B3 = (1-t)*B2_012 + t*B2_123 - >>> collect(expand(B2), t) - P0 + t**3*(-P0 + 3*P1 - 3*P2 + P3) + t**2*(3*P0 - 6*P1 + 3*P2) + t*(-3*P0 + 3*P1) +For resources on Bézier curve see :ref:`this section `. """ diff --git a/Patro/GeometryEngine/Spline.py b/Patro/GeometryEngine/Spline.py index f2bc8a6..aa9f06f 100644 --- a/Patro/GeometryEngine/Spline.py +++ b/Patro/GeometryEngine/Spline.py @@ -20,244 +20,7 @@ r"""Module to implement Spline curve. -B-spline Basis --------------- - -A nonuniform, nonrational B-spline of order `k` is a piecewise polynomial function of degree -:math:`k - 1` in a variable `t`. - -.. check: k+1 knots ??? - -.. It is defined over :math:`k + 1` locations :math:`t_i`, called knots, which must be in - non-descending order :math:`t_i \leq t_{i+1}`. This series defines a knot vector :math:`T = (t_0, - \ldots, t_{k})`. - -A set of non-descending breaking points, called knot, :math:`t_0 \le t_1 \le \ldots \le t_m` defines -a knot vector :math:`T = (t_0, \ldots, t_{m})`. - -If each knot is separated by the same distance `h` (where :math:`h = t_{i+1} - t_i`) from its -predecessor, the knot vector and the corresponding B-splines are called "uniform". - -Given a knot vector `T`, the associated B-spline basis functions, :math:`B_i^k(t)` are defined as: - -.. t \in [t_i, t_{i+1}[ - -.. math:: - B_i^1(t) = - \left\lbrace - \begin{array}{l} - 1 \;\textrm{if}\; t_i \le t < t_{i+1} \\ - 0 \;\textrm{otherwise} - \end{array} - \right. - -.. math:: - \begin{split} - B_i^k(t) &= \frac{t - t_i}{t_{i+k-1} - t_i} B_i^{k-1}(t) - + \frac{t_{i+k} - t}{t_{i+k} - t_{i+1}} B_{i+1}^{k-1}(t) \\ - &= w_i^{k-1}(t) B_i^{k-1}(t) + [1 - w_{i+1}^{k-1}(t)] B_{i+1}^{k-1}(t) - \end{split} - -where - -.. math:: - w_i^k(t) = - \left\lbrace - \begin{array}{l} - \frac{t - t_i}{t_{i+k} - t_i} \;\textrm{if}\; t_i < t_{i+k} \\ - 0 \;\textrm{otherwise} - \end{array} - \right. - -These equations have the following properties, for :math:`k > 1` and :math:`i = 0, 1, \ldots, n` : - -* Positivity: :math:`B_i^k(t) > 0`, for :math:`t_i < t < t_{i+k}` -* Local Support: :math:`B_i^k(t) = 0`, for :math:`t_0 \le t \le t_i` and :math:`t_{i+k} \le t \le t_{n+k}` -* Partition of unity: :math:`\sum_{i=0}^n B_i^k(t)= 1`, for :math:`t \in [t_0, t_m]` -* Continuity: :math:`B_i^k(t)` as :math:`C^{k-2}` continuity at each simple knot - -.. The B-spline contributes only in the range between the first and last of these knots and is zero - elsewhere. - -B-spline Curve --------------- - -A B-spline curve of order `k` is defined as a linear combination of control points :math:`p_i` and -B-spline basis functions :math:`B_i^k(t)` given by - -.. math:: - S^k(t) = \sum_{i=0}^{n} p_i\; B_i^k(t) ,\quad n \ge k - 1,\; t \in [t_{k-1}, t_{n+1}] - -In this context the control points are called De Boor points. The basis functions :math:`B_i^k(t)` -is defined on a knot vector - -.. math:: - T = (t_0, t_1, \ldots, t_{k-1}, t_k, t_{k+1}, \ldots, t_{n-1}, t_n, t_{n+1}, \ldots, t_{n+k}) - -where there are :math:`n+k+1` elements, i.e. the number of control points :math:`n+1` plus the order -of the curve `k`. Each knot span :math:`t_i \le t \le t_{i+1}` is mapped onto a polynomial curve -between two successive joints :math:`S(t_i)` and :math:`S(t_{i+1})`. - -Unlike Bézier curves, B-spline curves do not in general pass through the two end control points. -Increasing the multiplicity of a knot reduces the continuity of the curve at that knot. -Specifically, the curve is :math:`(k-p-1)` times continuously differentiable at a knot with -multiplicity :math:`p (\le k)`, and thus has :math:`C^{k-p-1}` continuity. Therefore, the control -polygon will coincide with the curve at a knot of multiplicity :math:`k-1`, and a knot with -multiplicity `k` indicates :math:`C^{-1}` continuity, or a discontinuous curve. Repeating the knots -at the end `k` times will force the endpoints to coincide with the control polygon. Thus the first -and the last control points of a curve with a knot vector described by - -.. math:: - \begin{eqnarray} - T = ( - \underbrace{t_0, t_1, \ldots, t_{k-1},}_{\mbox{$k$ equal knots}} - \quad - \underbrace{t_k, t_{k+1}, \ldots, t_{n-1}, t_n,}_{\mbox{$n$-$k$+1 internal knots}} - \quad - \underbrace{t_{n+1}, \ldots, t_{n+k}}_{\mbox{$k$ equal knots}}) - \end{eqnarray} - -coincide with the endpoints of the curve. Such knot vectors and curves are known as *clamped*. In -other words, *clamped/unclamped* refers to whether both ends of the knot vector have multiplicity -equal to `k` or not. - -**Local support property**: A single span of a B-spline curve is controlled only by `k` control -points, and any control point affects `k` spans. Specifically, changing :math:`p_i` affects the -curve in the parameter range :math:`t_i < t < t_{i+k}` and the curve at a point where :math:`t_r < t -< t_{r+1}` is determined completely by the control points :math:`p_{r-(k-1)}, \ldots, p_r`. - -**B-spline to Bézier property**: From the discussion of end points geometric property, it can be -seen that a Bézier curve of order `k` (degree :math:`k-1`) is a B-spline curve with no internal -knots and the end knots repeated `k` times. The knot vector is thus - -.. math:: - \begin{eqnarray} - T = ( - \underbrace{t_0, t_1, \ldots, t_{k-1}}_{\mbox{$k$ equal knots}} - ,\quad - \underbrace{t_{n+1}, \ldots, t_{n+k}}_{\mbox{$k$ equal knots}} - ) - \end{eqnarray} - -where :math:`n+k+1 = 2k` or :math:`n = k-1`. - -Algorithms for B-spline curves ------------------------------- - -Evaluation and subdivision algorithm -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A B-spline curve can be evaluated at a specific parameter value `t` using the de Boor algorithm, -which is a generalization of the de Casteljau algorithm. The repeated substitution of the recursive -definition of the B-spline basis function into the previous definition and re-indexing leads to the -following de Boor algorithm: - -.. math:: - S(t) = \sum_{i=0}^{n+j} p_i^j B_i^{k-j}(t) ,\quad j = 0, 1, \ldots, k-1 - -where - -.. math:: - p_i^j = \Big[1 - w_i^j\Big] p_{i-1}^{j-1} + w_i^j p_i^{j-1}, \; j > 0 - -with - -.. math:: - - w_i^j = \frac{t - t_i}{t_{i+k-j} - t_i} \quad \textrm{and} \; p_j^0 = p_j - -For :math:`j = k-1`, the B-spline basis function reduces to :math:`B_l^1` for :math:`t \in [t_l, -t_{l+1}]`, and :math:`p_l^{k-1}` coincides with the curve :math:`S(t) = p_l^{k-1}`. - -The de Boor algorithm is a generalization of the de Casteljau algorithm. The de Boor algorithm also -permits the subdivision of the B-spline curve into two segments of the same order. - -De Boor Algorithm -~~~~~~~~~~~~~~~~~ - -Let the index `l` define the knot interval that contains the position, :math:`t \in [t_l , -t_{l+1}]`. We can see in the recursion formula that only B-splines with :math:`i = l-K, \dots, l` -are non-zero for this knot interval, where :math:`K = k - 1` is the degree. Thus, the sum is -reduced to: - -.. math:: - S^k(t) = \sum _{i=l-K}^{l} p_{i} B_i^k(t) - -The algorithm does not compute the B-spline functions :math:`B_i^k(t)` directly. Instead it -evaluates :math:`S(t)` through an equivalent recursion formula. - -Let :math:`d _i^r` be new control points with :math:`d_i^1 = p_i` for :math:`i = l-K, \dots, l`. - -For :math:`r = 2, \dots, k` the following recursion is applied: - -.. math:: - d_i^r = (1 - w_i^r) d_{i-1}^{r-1} + w_i^r d_i^{r-1} \quad i = l-K+r, \dots, l - - w_i^r = \frac{t - t_i}{t_{i+1+l-r} - t_{i}} - -Once the iterations are complete, we have :math:`S^k(t) = d_l^k`. - -.. , meaning that :math:`d_l^k` is the desired result. - -De Boor's algorithm is more efficient than an explicit calculation of B-splines :math:`B_i^k(t)` -with the Cox-de Boor recursion formula, because it does not compute terms which are guaranteed to be -multiplied by zero. - -.. - :math:`S(t) = p_j^k` for :math:`t \in [t_j , t_{j+1}[` for :math:`k \le j \le n` with the following relation: - .. math:: - \begin{split} - p_i^{r+1} &= \frac{t - t_i}{t_{i+k-r} - t} p_i^r + \frac{t_{i+k-r} - t_i}{t_{i+k-r} - t_i} p_{i-1}^r \\ - &= w_i^{k-r}(t) p_i^r + (1 - w_i^{k-r}(t)) p_{i-1}^r - \end{split} - -Knot insertion -~~~~~~~~~~~~~~ - -A knot can be inserted into a B-spline curve without changing the -geometry of the curve. The new curve is identical to - -.. math:: - \begin{array}{lcl} - \sum_{i=0}^n p_i B_i^k(t) & \textrm{becomes} & \sum_{i=0}^{n+1} \bar{p}_i \bar B_i^k(t) \\ - \mbox{over}\; T = (t_0, t_1, \ldots, t_l, t_{l+1}, \ldots) & & - \mbox{over}\; T = (t_0, t_1, \ldots, t_l, \bar t, t_{l+1}, \ldots) & & - \end{array} - -when a new knot :math:`\bar t` is inserted between knots :math:`t_l` and :math:`t_{l+1}`. The new -de Boor points are given by - -.. math:: - \bar{p}_i = (1 - w_i) p_{i-1} + w_i p_i - -where - -.. math:: - w_i = - \left\{ \begin{array}{ll} - 1 & i \le l-k+1 \\ - 0 & i \ge l+1 \\ - \frac{\bar{t} - t_i}{t_{l+k-1} - t_i} & l-k+2 \le i \leq l - \end{array} - \right. - -The above algorithm is also known as **Boehm's algorithm**. A more general (but also more complex) -insertion algorithm permitting insertion of several (possibly multiple) knots into a B-spline knot -vector, known as the Oslo algorithm, was developed by Cohen et al. - -A B-spline curve is :math:`C^{\infty}` continuous in the interior of a span. Within exact -arithmetic, inserting a knot does not change the curve, so it does not change the continuity. -However, if any of the control points are moved after knot insertion, the continuity at the knot -will become :math:`C^{k-p-1}`, where `p` is the multiplicity of the knot. - -The B-spline curve can be subdivided into Bézier segments by knot insertion at each internal knot -until the multiplicity of each internal knot is equal to `k`. - -References ----------- - -* Computer Graphics, Principle and Practice, Foley et al., Adison Wesley -* http://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node15.html +For resources on Spline curve see :ref:`this section `. """ diff --git a/Patro/GeometryEngine/Transformation.py b/Patro/GeometryEngine/Transformation.py index 3126e35..ac77881 100644 --- a/Patro/GeometryEngine/Transformation.py +++ b/Patro/GeometryEngine/Transformation.py @@ -20,64 +20,7 @@ r"""Module to implement transformations like scale, rotation and translation. -Transformation matrices ------------------------ - -To transform a vector, we multiply the vector with a transformation matrix - -.. math:: - \begin{pmatrix} x' \\ y' \end{pmatrix} = \mathbf{T} \begin{pmatrix} x \\ y \end{pmatrix} - -Usual transformation matrices in 2D are - -.. math:: - \begin{align} - \mathbf{Id} &= \begin{bmatrix} - 1 & 0 \\ - 0 & 1 - \end{bmatrix} \\[1em] - \mathbf{Scale}(s_x, s_y) &= \begin{bmatrix} - s_x & 0 \\ - 0 & s_y - \end{bmatrix} \\[1em] - \mathbf{Rotation}(\theta) &= \begin{bmatrix} - \cos\theta & \sin\theta \\ - -\sin\theta & \cos\theta - \end{bmatrix} \\[1em] - \end{align} - -For translation and affine transformation, we must introduce the concept of homogeneous coordinate -which add a virtual third dimension: - -.. math:: - \mathbf{V} = \begin{bmatrix} - x \\ - y \\ - 1 - \end{bmatrix} - -Then the translation and affine transformation matrix are expressed as: - -.. math:: - \begin{align} - \mathbf{Translation}(t_x, t_y) &= \begin{bmatrix} - 1 & 0 & t_x \\ - 0 & 1 & t_y \\ - 0 & 0 & 1 - \end{bmatrix} \\[1em] - \mathbf{Generic} &= \begin{bmatrix} - r_{11} & r_{12} & t_x \\ - r_{12} & r_{22} & t_y \\ - 0 & 0 & 1 - \end{bmatrix} - \end{align} - -To compose transformations, we must multiply the transformations in this order: - -.. math:: - \mathbf{T} = \mathbf{T_n} \ldots \mathbf{T_2} \mathbf{T_1} - -Note the matrix multiplication is not commutative. +For resources on transformations see :ref:`this section `. """ diff --git a/doc/sphinx/source/index.rst b/doc/sphinx/source/index.rst index 72f05c4..c4133e1 100644 --- a/doc/sphinx/source/index.rst +++ b/doc/sphinx/source/index.rst @@ -149,6 +149,7 @@ If you want to donate to the project or need a more professional support. examples.rst faq.rst design-notes.rst + resources/index.rst reference-manual.rst development.rst how-to-refer.rst diff --git a/doc/sphinx/source/resources/geometry/bezier.rst b/doc/sphinx/source/resources/geometry/bezier.rst new file mode 100644 index 0000000..f242215 --- /dev/null +++ b/doc/sphinx/source/resources/geometry/bezier.rst @@ -0,0 +1,258 @@ +.. include:: ../../abbreviation.txt + +.. _bezier-geometry-ressources-page: + +=============== + Bézier Curves +=============== + +Definitions +----------- + +A Bézier curve is defined by a set of control points :math:`\mathbf{P}_0` through +:math:`\mathbf{P}_n`, where :math:`n` is called its order (:math:`n = 1` for linear, 2 for +quadratic, 3 for cubic etc.). The first and last control points are always the end points of the +curve; + +In the following :math:`0 \le t \le 1`. + +Linear Bézier Curves +--------------------- + +Given distinct points :math:`\mathbf{P}_0` and :math:`\mathbf{P}_1`, a linear Bézier curve is simply +a straight line between those two points. The curve is given by + +.. math:: + \begin{align} + \mathbf{B}(t) &= \mathbf{P}_0 + t (\mathbf{P}_1 - \mathbf{P}_0) \\ + &= (1-t) \mathbf{P}_0 + t \mathbf{P}_1 + \end{align} + +and is equivalent to linear interpolation. + +Quadratic Bézier Curves +----------------------- + +A quadratic Bézier curve is the path traced by the function :math:`\mathbf{B}(t)`, given points +:math:`\mathbf{P}_0`, :math:`\mathbf{P}_1`, and :math:`\mathbf{P}_2`, + +.. math:: + \mathbf{B}(t) = (1 - t)[(1 - t) \mathbf{P}_0 + t \mathbf{P}_1] + t [(1 - t) \mathbf{P}_1 + t \mathbf{P}_2] + +which can be interpreted as the linear interpolant of corresponding points on the linear Bézier +curves from :math:`\mathbf{P}_0` to :math:`\mathbf{P}_1` and from :math:`\mathbf{P}_1` to +:math:`\mathbf{P}_2` respectively. + +Rearranging the preceding equation yields: + +.. math:: + \begin{align} + \mathbf{B}(t) &= (1 - t)^{2} \mathbf{P}_0 + 2(1 - t)t \mathbf{P}_1 + t^{2} \mathbf{P}_2 \\ + &= (\mathbf{P}_0 - 2\mathbf{P}_1 + \mathbf{P}_2) t^2 + + (-2\mathbf{P}_0 + 2\mathbf{P}_1) t + + \mathbf{P}_0 + \end{align} + +This can be written in a way that highlights the symmetry with respect to :math:`\mathbf{P}_1`: + +.. math:: + \mathbf{B}(t) = \mathbf{P}_1 + (1 - t)^{2} ( \mathbf{P}_0 - \mathbf{P}_1) + t^{2} (\mathbf{P}_2 - \mathbf{P}_1) + +Which immediately gives the derivative of the Bézier curve with respect to `t`: + +.. math:: + \mathbf{B}'(t) = 2(1 - t) (\mathbf{P}_1 - \mathbf{P}_0) + 2t (\mathbf{P}_2 - \mathbf{P}_1) + +from which it can be concluded that the tangents to the curve at :math:`\mathbf{P}_0` and +:math:`\mathbf{P}_2` intersect at :math:`\mathbf{P}_1`. As :math:`t` increases from 0 to 1, the +curve departs from :math:`\mathbf{P}_0` in the direction of :math:`\mathbf{P}_1`, then bends to +arrive at :math:`\mathbf{P}_2` from the direction of :math:`\mathbf{P}_1`. + +The second derivative of the Bézier curve with respect to :math:`t` is + +.. math:: + \mathbf{B}''(t) = 2 (\mathbf{P}_2 - 2 \mathbf{P}_1 + \mathbf{P}_0) + +Cubic Bézier Curves +------------------- + +Four points :math:`\mathbf{P}_0`, :math:`\mathbf{P}_1`, :math:`\mathbf{P}_2` and +:math:`\mathbf{P}_3` in the plane or in higher-dimensional space define a cubic Bézier curve. The +curve starts at :math:`\mathbf{P}_0` going toward :math:`\mathbf{P}_1` and arrives at +:math:`\mathbf{P}_3` coming from the direction of :math:`\mathbf{P}_2`. Usually, it will not pass +through :math:`\mathbf{P}_1` or :math:`\mathbf{P}_2`; these points are only there to provide +directional information. The distance between :math:`\mathbf{P}_1` and :math:`\mathbf{P}_2` +determines "how far" and "how fast" the curve moves towards :math:`\mathbf{P}_1` before turning +towards :math:`\mathbf{P}_2`. + +Writing :math:`\mathbf{B}_{\mathbf P_i,\mathbf P_j,\mathbf P_k}(t)` for the quadratic Bézier curve +defined by points :math:`\mathbf{P}_i`, :math:`\mathbf{P}_j`, and :math:`\mathbf{P}_k`, the cubic +Bézier curve can be defined as an affine combination of two quadratic Bézier curves: + +.. math:: + \mathbf{B}(t) = (1-t) \mathbf{B}_{\mathbf P_0,\mathbf P_1,\mathbf P_2}(t) + + t \mathbf{B}_{\mathbf P_1,\mathbf P_2,\mathbf P_3}(t) + +The explicit form of the curve is: + +.. math:: + \begin{align} + \mathbf{B}(t) &= (1-t)^3 \mathbf{P}_0 + 3(1-t)^2t \mathbf{P}_1 + 3(1-t)t^2 \mathbf{P}_2 + t^3\mathbf{P}_3 \\ + &= (\mathbf{P}_3 - 3\mathbf{P}_2 + 3\mathbf{P}_1 - \mathbf{P}_0) t^3 + + 3(\mathbf{P}_2 - 2\mathbf{P}_1 + \mathbf{P}_0) t^2 + + 3(\mathbf{P}_1 - \mathbf{P}_0) t + + \mathbf{P}_0 + \end{align} + +For some choices of :math:`\mathbf{P}_1` and :math:`\mathbf{P}_2` the curve may intersect itself, or +contain a cusp. + +The derivative of the cubic Bézier curve with respect to :math:`t` is + +.. math:: + \mathbf{B}'(t) = 3(1-t)^2 (\mathbf{P}_1 - \mathbf{P}_0) + 6(1-t)t (\mathbf{P}_2 - \mathbf{P}_1) + 3t^2 (\mathbf{P}_3 - \mathbf{P}_2) + +The second derivative of the Bézier curve with respect to :math:`t` is + +.. math:: + \mathbf{B}''(t) = 6(1-t) (\mathbf{P}_2 - 2 \mathbf{P}_1 + \mathbf{P}_0) + 6t (\mathbf{P}_3 - 2 \mathbf{P}_2 + \mathbf{P}_1) + +Recursive definition +-------------------- + +A recursive definition for the Bézier curve of degree :math:`n` expresses it as a point-to-point +linear combination of a pair of corresponding points in two Bézier curves of degree :math:`n-1`. + +Let :math:`\mathbf{B}_{\mathbf{P}_0\mathbf{P}_1\ldots\mathbf{P}_n}` denote the Bézier curve +determined by any selection of points :math:`\mathbf{P}_0`, :math:`\mathbf{P}_1`, :math:`\ldots`, +:math:`\mathbf{P}_{n-1}`. + +The recursive definition is + +.. math:: + \begin{align} + \mathbf{B}_{\mathbf{P}_0}(t) &= \mathbf{P}_0 \\[1em] + \mathbf{B}(t) &= \mathbf{B}_{\mathbf{P}_0\mathbf{P}_1\ldots\mathbf{P}_n}(t) \\ + &= (1-t) \mathbf{B}_{\mathbf{P}_0\mathbf{P}_1\ldots\mathbf{P}_{n-1}}(t) + + t \mathbf{B}_{\mathbf{P}_1\mathbf{P}_2\ldots\mathbf{P}_n}(t) + \end{align} + +The formula can be expressed explicitly as follows: + +.. math:: + \begin{align} + \mathbf{B}(t) &= \sum_{i=0}^n b_{i,n}(t) \mathbf{P}_i \\ + &= \sum_{i=0}^n {n\choose i}(1 - t)^{n - i}t^i \mathbf{P}_i \\ + &= (1 - t)^n \mathbf{P}_0 + + {n\choose 1}(1 - t)^{n - 1}t \mathbf{P}_1 + + \cdots + + {n\choose n - 1}(1 - t)t^{n - 1} \mathbf{P}_{n - 1} + + t^n \mathbf{P}_n + \end{align} + +where :math:`b_{i,n}(t)` are the Bernstein basis polynomials of degree :math:`n` and :math:`n +\choose i` are the binomial coefficients. + +Degree elevation +---------------- + +A Bézier curve of degree :math:`n` can be converted into a Bézier curve of degree :math:`n + 1` with +the same shape. + +To do degree elevation, we use the equality + +.. math:: + \mathbf{B}(t) = (1-t) \mathbf{B}(t) + t \mathbf{B}(t) + +Each component :math:`\mathbf{b}_{i,n}(t) \mathbf{P}_i` is multiplied by :math:`(1-t)` and +:math:`t`, thus increasing a degree by one, without changing the value. + +For arbitrary :math:`n`, we have + +.. math:: + \begin{align} + \mathbf{B}(t) &= (1 - t) \sum_{i=0}^n \mathbf{b}_{i,n}(t) \mathbf{P}_i + + t \sum_{i=0}^n \mathbf{b}_{i,n}(t) \mathbf{P}_i \\ + &= \sum_{i=0}^n \frac{n + 1 - i}{n + 1} \mathbf{b}_{i, n + 1}(t) \mathbf{P}_i + + \sum_{i=0}^n \frac{i + 1}{n + 1} \mathbf{b}_{i + 1, n + 1}(t) \mathbf{P}_i \\ + &= \sum_{i=0}^{n + 1} \mathbf{b}_{i, n + 1}(t) + \left(\frac{i}{n + 1} \mathbf{P}_{i - 1} + + \frac{n + 1 - i}{n + 1} \mathbf{P}_i\right) \\ + &= \sum_{i=0}^{n + 1} \mathbf{b}_{i, n + 1}(t) \mathbf{P'}_i + \end{align} + +Therefore the new control points are + +.. math:: + \mathbf{P'}_i = \frac{i}{n + 1} \mathbf{P}_{i - 1} + \frac{n + 1 - i}{n + 1} \mathbf{P}_i + +It introduces two arbitrary points :math:`\mathbf{P}_{-1}` and :math:`\mathbf{P}_{n+1}` which are +cancelled in :math:`\mathbf{P'}_i`. + +Matrix Forms +------------ + +.. math:: + \mathbf{B}(t) = \mathbf{Transformation} \; \mathbf{Control} \; \mathbf{Basis} \; \mathbf{T}(t) + +.. math:: + \begin{align} + \mathbf{B^2}(t) &= \mathbf{Tr} + \begin{pmatrix} + P_{1x} & P_{2x} & P_{3x} \\ + P_{1y} & P_{2x} & P_{3x} \\ + 1 & 1 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 & -2 & 1 \\ + 0 & 2 & -2 \\ + 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 \\ + t \\ + t^2 + \end{pmatrix} \\[1em] + \mathbf{B^3}(t) &= \mathbf{Tr} + \begin{pmatrix} + P_{1x} & P_{2x} & P_{3x} & P_{4x} \\ + P_{1y} & P_{2x} & P_{3x} & P_{4x} \\ + 0 & 0 & 0 & 0 \\ + 1 & 1 & 1 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 & -3 & 3 & -1 \\ + 0 & 3 & -6 & 3 \\ + 0 & 0 & 3 & -3 \\ + 0 & 0 & 0 & 1 + \end{pmatrix} + \begin{pmatrix} + 1 \\ + t \\ + t^2 \\ + t^3 + \end{pmatrix} + \end{align} + +.. B(t) = P0 (1 - 2t + t^2) + + P1 ( 2t - t^2) + + P2 t^2 + +Symbolic Calculation +-------------------- + +.. code-block:: py3 + + >>> from sympy import * + + >>> P0, P1, P2, P3, P, t = symbols('P0 P1 P2 P3 P t') + + >>> B2 = (1-t)*((1-t)*P0 + t*P1) + t*((1-t)*P1 + t*P2) + >>> collect(expand(B2), t) + P0 + t**2*(P0 - 2*P1 + P2) + t*(-2*P0 + 2*P1) + + >>> B2_012 = (1-t)*((1-t)*P0 + t*P1) + t*((1-t)*P1 + t*P2) + >>> B2_123 = (1-t)*((1-t)*P1 + t*P2) + t*((1-t)*P2 + t*P3) + >>> B3 = (1-t)*B2_012 + t*B2_123 + >>> collect(expand(B2), t) + P0 + t**3*(-P0 + 3*P1 - 3*P2 + P3) + t**2*(3*P0 - 6*P1 + 3*P2) + t*(-3*P0 + 3*P1) diff --git a/doc/sphinx/source/resources/geometry/index.rst b/doc/sphinx/source/resources/geometry/index.rst new file mode 100644 index 0000000..36b4e65 --- /dev/null +++ b/doc/sphinx/source/resources/geometry/index.rst @@ -0,0 +1,18 @@ +.. include:: ../../abbreviation.txt + +.. _geometry-ressources-page: + +==================== + Geometry Resources +==================== + +This section contains resource on geometry. + +Contents: + +.. toctree:: + :maxdepth: 2 + + bezier.rst + spline.rst + transformations.rst diff --git a/doc/sphinx/source/resources/geometry/spline.rst b/doc/sphinx/source/resources/geometry/spline.rst new file mode 100644 index 0000000..b173b70 --- /dev/null +++ b/doc/sphinx/source/resources/geometry/spline.rst @@ -0,0 +1,246 @@ +.. include:: ../../abbreviation.txt + +.. _spline-geometry-ressources-page: + +=============== + Spline Curves +=============== + +B-spline Basis +-------------- + +A nonuniform, nonrational B-spline of order `k` is a piecewise polynomial function of degree +:math:`k - 1` in a variable `t`. + +.. check: k+1 knots ??? + +.. It is defined over :math:`k + 1` locations :math:`t_i`, called knots, which must be in + non-descending order :math:`t_i \leq t_{i+1}`. This series defines a knot vector :math:`T = (t_0, + \ldots, t_{k})`. + +A set of non-descending breaking points, called knot, :math:`t_0 \le t_1 \le \ldots \le t_m` defines +a knot vector :math:`T = (t_0, \ldots, t_{m})`. + +If each knot is separated by the same distance `h` (where :math:`h = t_{i+1} - t_i`) from its +predecessor, the knot vector and the corresponding B-splines are called "uniform". + +Given a knot vector `T`, the associated B-spline basis functions, :math:`B_i^k(t)` are defined as: + +.. t \in [t_i, t_{i+1}[ + +.. math:: + B_i^1(t) = + \left\lbrace + \begin{array}{l} + 1 \;\textrm{if}\; t_i \le t < t_{i+1} \\ + 0 \;\textrm{otherwise} + \end{array} + \right. + +.. math:: + \begin{split} + B_i^k(t) &= \frac{t - t_i}{t_{i+k-1} - t_i} B_i^{k-1}(t) + + \frac{t_{i+k} - t}{t_{i+k} - t_{i+1}} B_{i+1}^{k-1}(t) \\ + &= w_i^{k-1}(t) B_i^{k-1}(t) + [1 - w_{i+1}^{k-1}(t)] B_{i+1}^{k-1}(t) + \end{split} + +where + +.. math:: + w_i^k(t) = + \left\lbrace + \begin{array}{l} + \frac{t - t_i}{t_{i+k} - t_i} \;\textrm{if}\; t_i < t_{i+k} \\ + 0 \;\textrm{otherwise} + \end{array} + \right. + +These equations have the following properties, for :math:`k > 1` and :math:`i = 0, 1, \ldots, n` : + +* Positivity: :math:`B_i^k(t) > 0`, for :math:`t_i < t < t_{i+k}` +* Local Support: :math:`B_i^k(t) = 0`, for :math:`t_0 \le t \le t_i` and :math:`t_{i+k} \le t \le t_{n+k}` +* Partition of unity: :math:`\sum_{i=0}^n B_i^k(t)= 1`, for :math:`t \in [t_0, t_m]` +* Continuity: :math:`B_i^k(t)` as :math:`C^{k-2}` continuity at each simple knot + +.. The B-spline contributes only in the range between the first and last of these knots and is zero + elsewhere. + +B-spline Curve +-------------- + +A B-spline curve of order `k` is defined as a linear combination of control points :math:`p_i` and +B-spline basis functions :math:`B_i^k(t)` given by + +.. math:: + S^k(t) = \sum_{i=0}^{n} p_i\; B_i^k(t) ,\quad n \ge k - 1,\; t \in [t_{k-1}, t_{n+1}] + +In this context the control points are called De Boor points. The basis functions :math:`B_i^k(t)` +is defined on a knot vector + +.. math:: + T = (t_0, t_1, \ldots, t_{k-1}, t_k, t_{k+1}, \ldots, t_{n-1}, t_n, t_{n+1}, \ldots, t_{n+k}) + +where there are :math:`n+k+1` elements, i.e. the number of control points :math:`n+1` plus the order +of the curve `k`. Each knot span :math:`t_i \le t \le t_{i+1}` is mapped onto a polynomial curve +between two successive joints :math:`S(t_i)` and :math:`S(t_{i+1})`. + +Unlike Bézier curves, B-spline curves do not in general pass through the two end control points. +Increasing the multiplicity of a knot reduces the continuity of the curve at that knot. +Specifically, the curve is :math:`(k-p-1)` times continuously differentiable at a knot with +multiplicity :math:`p (\le k)`, and thus has :math:`C^{k-p-1}` continuity. Therefore, the control +polygon will coincide with the curve at a knot of multiplicity :math:`k-1`, and a knot with +multiplicity `k` indicates :math:`C^{-1}` continuity, or a discontinuous curve. Repeating the knots +at the end `k` times will force the endpoints to coincide with the control polygon. Thus the first +and the last control points of a curve with a knot vector described by + +.. math:: + \begin{eqnarray} + T = ( + \underbrace{t_0, t_1, \ldots, t_{k-1},}_{\mbox{$k$ equal knots}} + \quad + \underbrace{t_k, t_{k+1}, \ldots, t_{n-1}, t_n,}_{\mbox{$n$-$k$+1 internal knots}} + \quad + \underbrace{t_{n+1}, \ldots, t_{n+k}}_{\mbox{$k$ equal knots}}) + \end{eqnarray} + +coincide with the endpoints of the curve. Such knot vectors and curves are known as *clamped*. In +other words, *clamped/unclamped* refers to whether both ends of the knot vector have multiplicity +equal to `k` or not. + +**Local support property**: A single span of a B-spline curve is controlled only by `k` control +points, and any control point affects `k` spans. Specifically, changing :math:`p_i` affects the +curve in the parameter range :math:`t_i < t < t_{i+k}` and the curve at a point where :math:`t_r < t +< t_{r+1}` is determined completely by the control points :math:`p_{r-(k-1)}, \ldots, p_r`. + +**B-spline to Bézier property**: From the discussion of end points geometric property, it can be +seen that a Bézier curve of order `k` (degree :math:`k-1`) is a B-spline curve with no internal +knots and the end knots repeated `k` times. The knot vector is thus + +.. math:: + \begin{eqnarray} + T = ( + \underbrace{t_0, t_1, \ldots, t_{k-1}}_{\mbox{$k$ equal knots}} + ,\quad + \underbrace{t_{n+1}, \ldots, t_{n+k}}_{\mbox{$k$ equal knots}} + ) + \end{eqnarray} + +where :math:`n+k+1 = 2k` or :math:`n = k-1`. + +Algorithms for B-spline curves +------------------------------ + +Evaluation and subdivision algorithm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A B-spline curve can be evaluated at a specific parameter value `t` using the de Boor algorithm, +which is a generalization of the de Casteljau algorithm. The repeated substitution of the recursive +definition of the B-spline basis function into the previous definition and re-indexing leads to the +following de Boor algorithm: + +.. math:: + S(t) = \sum_{i=0}^{n+j} p_i^j B_i^{k-j}(t) ,\quad j = 0, 1, \ldots, k-1 + +where + +.. math:: + p_i^j = \Big[1 - w_i^j\Big] p_{i-1}^{j-1} + w_i^j p_i^{j-1}, \; j > 0 + +with + +.. math:: + + w_i^j = \frac{t - t_i}{t_{i+k-j} - t_i} \quad \textrm{and} \; p_j^0 = p_j + +For :math:`j = k-1`, the B-spline basis function reduces to :math:`B_l^1` for :math:`t \in [t_l, +t_{l+1}]`, and :math:`p_l^{k-1}` coincides with the curve :math:`S(t) = p_l^{k-1}`. + +The de Boor algorithm is a generalization of the de Casteljau algorithm. The de Boor algorithm also +permits the subdivision of the B-spline curve into two segments of the same order. + +De Boor Algorithm +~~~~~~~~~~~~~~~~~ + +Let the index `l` define the knot interval that contains the position, :math:`t \in [t_l , +t_{l+1}]`. We can see in the recursion formula that only B-splines with :math:`i = l-K, \dots, l` +are non-zero for this knot interval, where :math:`K = k - 1` is the degree. Thus, the sum is +reduced to: + +.. math:: + S^k(t) = \sum _{i=l-K}^{l} p_{i} B_i^k(t) + +The algorithm does not compute the B-spline functions :math:`B_i^k(t)` directly. Instead it +evaluates :math:`S(t)` through an equivalent recursion formula. + +Let :math:`d _i^r` be new control points with :math:`d_i^1 = p_i` for :math:`i = l-K, \dots, l`. + +For :math:`r = 2, \dots, k` the following recursion is applied: + +.. math:: + d_i^r = (1 - w_i^r) d_{i-1}^{r-1} + w_i^r d_i^{r-1} \quad i = l-K+r, \dots, l + + w_i^r = \frac{t - t_i}{t_{i+1+l-r} - t_{i}} + +Once the iterations are complete, we have :math:`S^k(t) = d_l^k`. + +.. , meaning that :math:`d_l^k` is the desired result. + +De Boor's algorithm is more efficient than an explicit calculation of B-splines :math:`B_i^k(t)` +with the Cox-de Boor recursion formula, because it does not compute terms which are guaranteed to be +multiplied by zero. + +.. + :math:`S(t) = p_j^k` for :math:`t \in [t_j , t_{j+1}[` for :math:`k \le j \le n` with the following relation: + .. math:: + \begin{split} + p_i^{r+1} &= \frac{t - t_i}{t_{i+k-r} - t} p_i^r + \frac{t_{i+k-r} - t_i}{t_{i+k-r} - t_i} p_{i-1}^r \\ + &= w_i^{k-r}(t) p_i^r + (1 - w_i^{k-r}(t)) p_{i-1}^r + \end{split} + +Knot insertion +~~~~~~~~~~~~~~ + +A knot can be inserted into a B-spline curve without changing the +geometry of the curve. The new curve is identical to + +.. math:: + \begin{array}{lcl} + \sum_{i=0}^n p_i B_i^k(t) & \textrm{becomes} & \sum_{i=0}^{n+1} \bar{p}_i \bar B_i^k(t) \\ + \mbox{over}\; T = (t_0, t_1, \ldots, t_l, t_{l+1}, \ldots) & & + \mbox{over}\; T = (t_0, t_1, \ldots, t_l, \bar t, t_{l+1}, \ldots) & & + \end{array} + +when a new knot :math:`\bar t` is inserted between knots :math:`t_l` and :math:`t_{l+1}`. The new +de Boor points are given by + +.. math:: + \bar{p}_i = (1 - w_i) p_{i-1} + w_i p_i + +where + +.. math:: + w_i = + \left\{ \begin{array}{ll} + 1 & i \le l-k+1 \\ + 0 & i \ge l+1 \\ + \frac{\bar{t} - t_i}{t_{l+k-1} - t_i} & l-k+2 \le i \leq l + \end{array} + \right. + +The above algorithm is also known as **Boehm's algorithm**. A more general (but also more complex) +insertion algorithm permitting insertion of several (possibly multiple) knots into a B-spline knot +vector, known as the Oslo algorithm, was developed by Cohen et al. + +A B-spline curve is :math:`C^{\infty}` continuous in the interior of a span. Within exact +arithmetic, inserting a knot does not change the curve, so it does not change the continuity. +However, if any of the control points are moved after knot insertion, the continuity at the knot +will become :math:`C^{k-p-1}`, where `p` is the multiplicity of the knot. + +The B-spline curve can be subdivided into Bézier segments by knot insertion at each internal knot +until the multiplicity of each internal knot is equal to `k`. + +References +---------- + +* Computer Graphics, Principle and Practice, Foley et al., Adison Wesley +* http://web.mit.edu/hyperbook/Patrikalakis-Maekawa-Cho/node15.html diff --git a/doc/sphinx/source/resources/geometry/transformations.rst b/doc/sphinx/source/resources/geometry/transformations.rst new file mode 100644 index 0000000..6da86c3 --- /dev/null +++ b/doc/sphinx/source/resources/geometry/transformations.rst @@ -0,0 +1,66 @@ +.. include:: ../../abbreviation.txt + +.. _transformation-geometry-ressources-page: + +================= + Transformations +================= + +Transformation matrices +----------------------- + +To transform a vector, we multiply the vector with a transformation matrix + +.. math:: + \begin{pmatrix} x' \\ y' \end{pmatrix} = \mathbf{T} \begin{pmatrix} x \\ y \end{pmatrix} + +Usual transformation matrices in 2D are + +.. math:: + \begin{align} + \mathbf{Id} &= \begin{bmatrix} + 1 & 0 \\ + 0 & 1 + \end{bmatrix} \\[1em] + \mathbf{Scale}(s_x, s_y) &= \begin{bmatrix} + s_x & 0 \\ + 0 & s_y + \end{bmatrix} \\[1em] + \mathbf{Rotation}(\theta) &= \begin{bmatrix} + \cos\theta & \sin\theta \\ + -\sin\theta & \cos\theta + \end{bmatrix} \\[1em] + \end{align} + +For translation and affine transformation, we must introduce the concept of homogeneous coordinate +which add a virtual third dimension: + +.. math:: + \mathbf{V} = \begin{bmatrix} + x \\ + y \\ + 1 + \end{bmatrix} + +Then the translation and affine transformation matrix are expressed as: + +.. math:: + \begin{align} + \mathbf{Translation}(t_x, t_y) &= \begin{bmatrix} + 1 & 0 & t_x \\ + 0 & 1 & t_y \\ + 0 & 0 & 1 + \end{bmatrix} \\[1em] + \mathbf{Generic} &= \begin{bmatrix} + r_{11} & r_{12} & t_x \\ + r_{12} & r_{22} & t_y \\ + 0 & 0 & 1 + \end{bmatrix} + \end{align} + +To compose transformations, we must multiply the transformations in this order: + +.. math:: + \mathbf{T} = \mathbf{T_n} \ldots \mathbf{T_2} \mathbf{T_1} + +Note the matrix multiplication is not commutative. diff --git a/doc/sphinx/source/resources/index.rst b/doc/sphinx/source/resources/index.rst new file mode 100644 index 0000000..745d85b --- /dev/null +++ b/doc/sphinx/source/resources/index.rst @@ -0,0 +1,16 @@ +.. include:: ../abbreviation.txt + +.. _ressources-page: + +=========== + Resources +=========== + +This section contains resource documentation. + +Contents: + +.. toctree:: + :maxdepth: 2 + + geometry/index.rst -- GitLab