10. Computational geometry

10.1. Parametric curves

We work with points

\[{\bf v}=\left [ \begin{array}{c} v_x\\ v_y \end{array} \right]\in {\mathbb R}^2\]

and think them as elements of an Euclidean space \({\mathbb E}^2\) which has a metric \(d({\bf v}_1,{\bf v}_2)=\vert \vert {\bf v}_1-{\bf v}_2 \vert \vert\).

A curve \({\bf C}\) is represented in parametric form when the coordinates of each of its points are expressed separately as a function of a third variable \(u\) called parameter,

\[{\bf C}(u)=(x(u), y(u))\]

where \(u \in [a,b]\). Finally, many of such curves don’t admit a functional representation.

10.1.1. Neile parabola

Described in [Pei75], the Neil parabola \({\bf C}(u)=(u^2, u^3)\), where \(u \in [-2,2]\), has the graphical representation

../_images/RSParametricCurveTest-testLineParametricNeil.svg

produced by the message

"RSTParametricXYLines, protocol lines"
lineParametricNeil

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: -2 to: 2 samples: 100;
               yourself);
        x: [ :t | t raisedTo: 2 ] y: [ :t | t raisedTo: 3 ];
        scale: 10

A little variation to the second component \({\bf C}(u)=(u^2, u^3-u)\), where \(u \in [-2,2]\), has the graphical representation

../_images/RSParametricCurveTest-testLineParametricNeil2.svg

produced by the message

"RSTParametricXYLines, protocol lines"
lineParametricNeil2

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: -2 to: 2 samples: 100;
               yourself);
        x: [ :t | t raisedTo: 2 ] y: [ :t | (t raisedTo: 3) - t ];
        scale: 10

Now consider the curve \({\bf C}(u)=(cos(u), sin(u))\) where \(u \in [0,2\pi]\) has the graphical

../_images/RSParametricCurveTest-testLineParametricUnitCircle.svg

and is coded as

"RSTParametricXYLines, protocol lines"
lineParametricUnitCircle

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: 0 to: Float pi * 2 samples: 100;
               yourself);
        x: [ :t | t cos ] y: [ :t | t sin ];
        scale: 100

Another trigonometric curve \({\bf C}(u)=(cos(3u) cos(u), sin(u) cos(3u))\) where \(\ u \in [0,\pi]\), aka trochoid, has the graphical

../_images/RSParametricCurveTest-testLineParametricTrochoid.svg

and is coded as

"RSTParametricXYLines, protocol lines"
lineParametricTrochoid

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: 0 to: Float pi samples: 100;
               yourself);
        x: [ :t | t cos * (3 * t) cos ] y: [ :t | t sin * (3 * t) cos ];
        scale: 100

Another trigonometric curve \({\bf C}(u)=(cos(3u) cos(u), sin(u) cos(3u))\) where \(\ u \in [0,\pi]\), aka trochoid, has the graphical

../_images/RSParametricCurveTest-testLineParametricLissajous.svg

and is coded as

"RSTParametricXYLines, protocol lines"
lineParametricLissajous

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: 0 to: Float pi * 2 samples: 1000;
               yourself);
        x: [ :t | (3 * t) cos ] y: [ :t | (2 * t) sin ];
        scale: 100

Another trigonometric curve \({\bf C}(u)=(cos(3u) cos(u), sin(u) cos(3u))\) where \(\ u \in [0,\pi]\), aka trochoid, has the graphical

../_images/RSParametricCurveTest-testLineParametricHypotrochoid.svg

and is coded as

"RSTParametricXYLines, protocol lines"
lineParametricHypotrochoid

   | s r d a b |
   s := 5.
   r := 3.
   d := 5.

   a := s - r.
   b := a / r.

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: -10 to: 10 samples: 10000;
               yourself);
        x: [ :t | a * t cos + (d * (b * t) cos) ]
        y: [ :t | a * t sin - (d * (b * t) sin) ];
        scale: 10

10.1.2. Butterfly curve

Introduced in [Fay89], the butterfly curve \({\bf C}(u)\) where \(\ u \in [0, 12\pi]\), has the graphical

../_images/RSParametricCurveTest-testParametricXYLineButterfly.svg

and is coded as

"RSTParametricXYLines, protocol lines"
parametricXYlineButterfly

   ^ RSParametricXYLine new
        parameterization: (RSLinspaceParameterization new
               from: 0 to: Float pi * 12 samples: 10000;
               yourself);
        x: [ :t | 
           t sin
           * (t cos exp - (2 * (4 * t) cos) - ((t / 12) sin raisedTo: 5)) ]
        y: [ :t | 
           t cos
           * (t cos exp - (2 * (4 * t) cos) - ((t / 12) sin raisedTo: 5)) ];
        scale: 30

according to [Wika].

10.2. Bezier curves

10.2.1. Baricentric coordinates and affine transforms

Given two points \({\bf v}_1\) and \({\bf v}_2\), let

\[{\bf v}=w_1 {\bf v}_1+ (1-w_1) {\bf v}_2\]

where \(w_1\in[0,1]\) and \(w_2=1-w_1\) are the baricentric coordinates of \({\bf v}\) with respect to \({\bf v}_1\) and \({\bf v}_2\), respectively. The message

"Point, protocol *Containers-Essentials"
unitAffine: aPoint at: aParam

   | t |
   t := aParam min: 1 max: 0.

   ^ self * t + (1 - t * aPoint)

implements such combination. For the sake of clarity, the shapes

../_images/RSParametricCurveTest-testBaricentricCoordinates.svg

shows the baricentric coordinates \({{1}\over{4}}\) and \({{3}\over{4}}\) of the point \((250, 325)\) with respect to \((100, 100)\) and \((300, 400)\), as the test

"RSParametricCurveTest, protocol systems under tests"
sutBaricentricCoordinates: aBlock

   | aPoint anotherPoint param baricentricPoint |
   aPoint := 100 @ 100.
   anotherPoint := 300 @ 400.
   param := 1 / 4.

   baricentricPoint := aPoint unitAffine: anotherPoint at: param.

   self assert: baricentricPoint equals: 250 @ 325.

   ^ aBlock
        value: { 
              aPoint.
              anotherPoint.
              baricentricPoint }
        value: param

ensures. We can do one more step, given three points \({\bf v}_1\), \({\bf v}_2\) and \({\bf v}_3\), let

\[{\bf v}=w_1 {\bf v}_1+ w_2 {\bf v}_2+(1-w_1-w_2) {\bf v}_3\]

where \(w_1, w_2\in[0,1]\) and \(w_3=1-w_1-w_2\) are the baricentric coordinates of \({\bf v}\) with respect to \({\bf v}_1\), \({\bf v}_2\) and \({\bf v}_3\), respectively. The message

"Point, protocol *Containers-Essentials"
unitAffine: aPoint at: aParam and: anotherPoint at: anotherParam

   | t s |
   t := aParam min: 1 max: 0.
   s := anotherParam min: 1 max: 0.


   ^ self * t + (aPoint * s) + (1 - t - s * anotherPoint)

implements such combination. For the sake of clarity, the shapes

../_images/RSParametricCurveTest-testBaricentricCoordinatesTriangle.svg

shows the baricentric coordinates \({{1}\over{6}}\), \({{1}\over{2}}\) and \({{1}\over{3}}\) of the point \(\left({{400}\over{3}}, 300\right)\) with respect to \((100, 100)\), \((300, 400)\) and \((-100, 250)\), as the test

"RSParametricCurveTest, protocol systems under tests"
sutBaricentricCoordinatesTriangle: aBlock

   | aPoint anotherPoint param baricentricPoint yetAnotherPoint anotherParam |
   aPoint := 100 @ 100.
   anotherPoint := 300 @ 400.
   yetAnotherPoint := -100 @ 250.

   param := 1 / 6.
   anotherParam := 1 / 2.

   baricentricPoint := aPoint
                          unitAffine: anotherPoint
                          at: param
                          and: yetAnotherPoint
                          at: anotherParam.

   self assert: baricentricPoint equals: 400 / 3 @ 300.

   ^ aBlock
        value: { 
              aPoint.
              anotherPoint.
              yetAnotherPoint.
              baricentricPoint }
        value: param
        value: anotherParam

ensures. Finally, a function \(\Phi: {\mathbb E}^2\rightarrow {\mathbb E}^2\) is an affine transformation if it lefts baricentric combinations untouched; for the sake of clarity, given \({\bf v}=\sum_{i=1}^n w_i {\bf v}_i\) and \(\sum_{i=1}^n w_i=1\) then \(\Phi\) is affine if and only if

\[\Phi({\bf v})=\sum_{i=1}^n w_i \Phi({\bf v}_i).\]

10.2.2. Closed control net

../_images/RSParametricCurveTest-testLineDeCasteljauLineClosedControlPoints.svg

and is coded as

"RSBasicShapeExamples, protocol lines"
lineDeCasteljauLineClosedControlPoints

   | points |
   points := { 
                (1 @ 1).
                (3 @ 4).
                (5 @ 6).
                (7 @ 8).
                (10 @ 2).
                (1 @ 1) }.

   ^ RSdeCasteljauLine new
        samplesLinspace: 100;
        controlPoints: points;
        scale: 100

10.2.3. Degree elevation

../_images/RSParametricCurveTest-testLinesDeCasteljauLineDegreeElevation.svg

and is coded as

"RSBasicShapeExamples, protocol lines"
linesDeCasteljauLineDegreeElevation

   | points bspline1 bspline2 bspline3 bspline4 |
   points := { 
                (1 @ 1).
                (3 @ 4).
                (5 @ 6).
                (7 @ (3 / 2)).
                (10 @ 2) }.

   bspline1 := RSdeCasteljauLine new
                  controlPoints: points;
                  scale: 100.

   bspline2 := bspline1 increment.
   bspline3 := bspline2 increment.
   bspline4 := bspline3 increment.

   ^ RSGroup
        with: bspline1
        with: bspline2
        with: bspline3
        with: bspline4

10.2.4. Designing notes

../_images/RSParametricCurveTest-testLineDeCasteljauLineNoteBox.svg

and is coded as

"RSBasicShapeExamples, protocol lines"
lineDeCasteljauLineNoteBox

   ^ RSdeCasteljauLine new
        samplesLinspace: 10;
        controlPoints: { 
              (0 @ 0).
              (8.461 @ 36.411).
              (0.6 @ 129.887).
              (25.3 @ 195.304).
              (-67.3 @ 222.719).
              (16.72 @ 245.576).
              (-55.8 @ 178.406).
              (60 @ 136.3).
              (136 @ 136).
              (142.2 @ 222.332).
              (393.292 @ 192.739).
              (247.8 @ 244.8).
              (179.5 @ 201.105).
              (221.9 @ 163.04).
              (200 @ 125.8).
              (204.4 @ 101.697).
              (210.405 @ 85.124).
              (217.89 @ 18.03).
              (151.73 @ 29.54).
              (244.5 @ -26.58).
              (318.633 @ -42.131).
              (145.27 @ 1.9).
              (52.05 @ 8.718).
              (0 @ 0) };
        yourself
../_images/RSParametricCurveTest-testNoteLoremIpsum.svg

and is coded as

"RSBasicShapeExamples, protocol lines"
noteLoremIpsum

   ^ RSLabel new
        text: (String loremIpsum: 50);
        useDefaultCodeFont;
        padded: Float goldenPlatinumRatio
        withNoteDo: [ :aBox | aBox color: Color yellow translucent ]
../_images/RSParametricCurveTest-testNoteInteger.svg

and is coded as

"RSBasicShapeExamples, protocol lines"
noteInteger

   ^ RSLabel new
        model: 541;
        useDefaultCodeFont;
        notedWithPad: Float goldenPlatinumRatio