#lang scheme
(require "point.ss")
(require "vector.ss")
(require "../utils.ss")
(require (only-in scheme
+ - * /))
(provide (rename-out [+** +]
[-** -]
[*** *]
[/** /]))
(define-syntax define-curried-version
(syntax-rules ()
[(_ name f)
(define name
(case-lambda
[()
(f)]
[(arg)
(lambda args
(apply f arg args))]
[args
(apply f args)]))]))
(define-syntax define-point/vector-version-2*
(lambda (stx)
(syntax-case stx ()
[(_ name f)
#`(define name
(let ([map-point (lambda (p f)
(if (point-3d? p)
(xyz (f (cx p))
(f (cy p))
(f (cz p)))
(xy (f (cx p))
(f (cy p)))))]
[map-vector (lambda (v f)
(if (vector-3d? v)
(vxyz (f (vx v))
(f (vy v))
(f (vz v)))
(vxy (f (vx v))
(f (vy v)))))])
(case-lambda
[()
(f)]
[(arg)
(f arg)]
[(a1 a2)
(let ([error-out (lambda ()
(error #,(syntax->datum #'(quote f))
"Function ~s is not applicable to objects: '~s' and '~s'."
#,(syntax->datum #'(quote f)) a1 a2))])
(cond [(number? a1)
(cond [(number? a2)
(f a1 a2)]
[(point? a2)
(map-point a2 (lambda (x) (f x a2)))]
[(gvector? a2)
(map-vector a2 (lambda (x) (f x a2)))]
[else (error-out)])]
[(point? a1)
(cond [(number? a2)
(map-point a1 (lambda (x) (f x a2)))]
[(point? a2)
(error "Can't apply function " name " to two points.")]
[(gvector? a2)
(when (not (same-dimension? a1 a2))
(error a1 " and " a2 " are not of the same dimension."))
(if (point-3d? a1)
(xyz (f (cx a1) (vx a2))
(f (cy a1) (vy a2))
(f (cz a1) (vz a2)))
(xy (f (cx a1) (vx a2))
(f (cy a1) (vy a2))))]
[else (error-out)])]
[(gvector? a1)
(cond [(number? a2)
(map-vector a1 (lambda (x) (f x a2)))]
[(point? a2)
(when (not (same-dimension? a1 a2))
(error a1 " and " a2 " are not of the same dimension."))
(if (vector-3d? a1)
(vxyz (f (vx a1) (cx a2))
(f (vy a1) (cy a2))
(f (vz a1) (cz a2)))
(vxy (f (vx a1) (cx a2))
(f (vy a1) (cy a2))))]
[(gvector? a2)
(when (not (same-dimension? a1 a2))
(error a1 " and " a2 " are not of the same dimension."))
(if (vector-3d? a1)
(vxyz (f (vx a1) (vx a2))
(f (vy a1) (vy a2))
(f (vz a1) (vz a2)))
(vxy (f (vx a1) (vx a2))
(f (vy a1) (vy a2))))]
[else (error-out)])]
[else (f a1 a2)]))] [args
(apply f args)])))])))
(define-syntax-rule (define-point/vector-version-1 name f)
(define name
(let ([map-point (lambda (p f)
(xyz (f (cx p))
(f (cy p))
(f (cz p))))]
[map-vector (lambda (v f)
(vxyz (f (vx v))
(f (vy v))
(f (vz v))))])
(case-lambda
[()
(f)]
[(arg)
(cond [(point? arg)
(map-point arg f)]
[(gvector? arg)
(map-vector arg f)]
[else (f arg)])]))))
(define-syntax define-point/vector-versions-1
(syntax-rules ()
[(_ new old)
(define-point/vector-version-1 new old)]
[(_ new old more ...)
(begin
(define-point/vector-version-1 new old)
(define-point/vector-versions-1 more ...))]))
(define-point/vector-version-2* +* +)
(define-point/vector-version-2* -* -)
(define-point/vector-version-2* ** *)
(define-point/vector-version-2* /* /)
(define-curried-version +** +*)
(define-curried-version -** -*)
(define-curried-version *** **)
(define-curried-version /** /*)