Recently I found that it is possible to use OOP in LilyPond Scheme by using the `oop goops` module so I would like to reconstruct some of my code in my `lily-score` project. However I encountered a problem with the following example: I would like to design a class system for some parametric curves, so I have a class `<parametric-curve>` with one slot named `fn` to provide parameterize function for the curve.

After that I defined a sub-class `<bezier>` representing Bezier curves, I want the Bezier curve cunstructor to receive a set of control points (stored in slot `cpts`) and generate the parameterize function automatically. i.e. the `fn` slot should be automatically filled.

I want all these classes to be immutable so they remain stable during the program. There are some ways I came up with but they failed to meet my standard for immutable classes. The first way is to set `#:allocation #:virtual` for the slot `fn`, but virtual slots must be tied to a `#:slot-get` and `#:slot-set!` property, and `#:slot-set` means the value will be changed, which fails the "immutable" requirement. The second way is to use `define-method` and define a `curve-fn` method for the `<bezier>` class. But this will force the class to generate a new function object every time the parameterize function is requested from the `<bezier>` object, which is inefficient.

I don't know whether there is a way to satisfy all my needs described above. Currently I have all the functions required to create the bezier curve. Another small problem is how to make the control point lists and their internal points immutable once after they are created.

The OOP related code is as follows:

```ly
#(use-modules (oop goops))

#(define-class <parametric-curve> ()
  (fn #:init-keyword #:fn #:getter curve-fn))
#(define-class <bezier> (<parametric-curve>)
  (cpts #:init-keyword #:cpts #:getter bezier-cpts))

#(define-method (curve-point-at (curve <parametric-curve>) (t <real>))
  ((curve-fn curve) t))

#(define-method (bezier-degree (curve <bezier>))
  (- (length (bezier-cpts curve)) 1))

```

And the Bezier-related code:

```ly
#(define (binom n k)
  ;; binomial coefficient $\binom{n}{k} = \frac{n!}{k!(n - k)!}$
  (if (> k (/ n 2)) (set! k (- n k)))
  (let*
    ((result 1))
    (for-each
      (lambda (i)
        (let* ((p (- n i))
               (q (- k i)))
          (set! result (* result (/ p q)))))
      (iota k))
    result))

#(define ((bernstein-poly n k) t)
  (* (binom n k) (expt (- 1 t) (- n k)) (expt t k)))

#(define ((bezier cpts) t)
  ;; parameterization for bezier curves
  (let* ((x 0) (y 0)
         (n (- (length cpts) 1))(k 0))
    (for-each (lambda (cpt)
        (let* ((x_k (car cpt))
               (y_k (cdr cpt))
               (coef ((bernstein-poly n k) t)))
          (set! x (+ x (* x_k coef)))
          (set! y (+ y (* y_k coef))))
        (set! k (+ k 1)))
      cpts)
    (cons x y)))
```

Reply via email to