Zentralprojektion

Eine Zentralprojektion wird festgelegt durch einen dreidimensionalen Augpunkt S und eine Ebene E. Die Projektion bildet einen dreidimensionalen Punkt P auf einen Punkt T(P) in der Ebene E so ab, dass S, T(P) und P auf einer Geraden liegen.

Wenn die Ebene E durch zwei orthogonale Einheitsvektoren u und v und einen Punkt w festgelegt wird, führt die obige Definition auf

  T(P) = x u + y v + w und
  T(P) = S + a (P - S),

wobei P, S, u, v und w gegeben sind und man T(P), x, y und a sucht. Das führt auf ein Gleichungssystem:

  u1 x + v1 y + (S1 - P1) a = S1 - w1
  u2 x + v2 y + (S2 - P2) a = S2 - w2
  u3 x + v3 y + (S3 - P3) a = S3 - w3

Da u und v orthogonale Einheitsvektoren sind, kann man die Lösungen des Gleichungssystems in x und y zu einem Punkt (x y) kombinieren und diesen als Ergebnis der Projektion von P ins Zweidimensionale auffassen.

Die Realisierung verwendet die Funktion create-projection-matrix, um aus den Vektoren u und v und den Punkten s und p die Matrix des linearen Gleichungssystems aufzustellen.

(defproc create-projection-matrix (u v s p)
  (new matrix 3 3
    (list
      (list (first u) (first v) (- (first s) (first p)))
      (list (second u) (second v) (- (second s) (second p)))
      (list (third u) (third v) (- (third s) (third p))))))

Der Spaltenvektor des linearen Gleichungssystems wird von der Funktion create-projection-column-vector in Abhängigkeit von w und s berechnet.

(defproc create-projection-column-vector (w s)
  (new column-vector 3
    (list
      (- (first s) (first w))
      (- (second s) (second w))
      (- (third s) (third w)))))

Die Funktion project-point projiziert einen Punkt indem, wie oben beschrieben, das lineare Gleichungssystem gelöst wird (siehe Lineare Gleichungssysteme lösen). Die Lösung hat drei Elemente (x, y und a), von denen man das letzte nicht verwendet.

(defproc project-point (u v w s point)
  (map-with
    first
    (butlast
      (.
        (solve-linear-equations
          (create-projection-matrix u v s point)
          (create-projection-column-vector w s))
        elements))))

Die Funktion project-polylines wendet project-point auf die Punkte in einer Liste von Listen an.

(defproc project-polylines (u v w s polylines)
  (map-with
    (lambda (polyline)
      (map-with
        (curry (project-point u v w s _))
        polyline))
    polylines))

Die Funktion get-bounds bestimmt den rechteckigen Bereich, in dem sich die Punkte in einer Liste von Listen befinden.

(defproc get-bounds (polylines)
  (let
    ((min-x nil) (min-y nil) (max-x nil) (max-y nil))
    (dolist (polyline polylines (list min-x min-y (- max-x min-x) (- max-y min-y)))
      (dolist (point polyline)
        (when (or (null? min-x) (< (first point) min-x))
          (setq min-x (first point)))
        (when (or (null? min-y) (< (second point) min-y))
          (setq min-y (second point)))
        (when (or (null? max-x) (> (first point) max-x))
          (setq max-x (first point)))
        (when (or (null? max-y) (> (second point) max-y))
          (setq max-y (second point)))))))

Die Funktion adjust-polylines verschiebt die Punkte aus einer Liste von Listen. Die Verschiebung wird anhand der Resultate von get-bounds so gewählt, dass keine Koordinate einen negativen Wert hat.
 
(defproc adjust-polylines (polylines min-x min-y)
  (map-with
    (lambda (polyline)
      (map-with
        (lambda (point)
          (list
            (- (first point) min-x)
            (- (second point) min-y)))
      polyline))
    polylines))

Schließlich benutzt die Funktion draw-projected-polylines das Primitiv grid, um aus einer Liste von Listen von dreidimensionalen Punkten polylines-3d und den Parametern u, v, w und s eine Zeichnung zu erzeugen.

(defproc draw-projected-polylines (u v w s polylines-3d)
  (let
    ((polylines-2d (project-polylines u v w s polylines-3d)))
    (let
      ((bounds (get-bounds polylines-2d)))
      (grid
        (third bounds)
        (fourth bounds)
        (adjust-polylines polylines-2d (first bounds) (second bounds))))))


Anlage

Projektion des Linienzugs mit den Ecken (0 0 0), (1 0 0), (1 1 0), (0 1 0), (0 0 0), (0 0 1), (1 0 1), (1 1 1), (0 1 1) und (0 1/5 1) mit u = (1 0 0), v = (0 1 0) und S = (-4 2 -20)

perspective-projection.sheet.xml