kurse:efcomputergrafik:kw4

This is an old revision of the document!


Nötige Methode für die Bezier-Klasse

  • x(t): Liefert die Position zum Parameter $t$.
  • v(t): Liefert die Geschwindigkeit zum Parameter $t$ (“exakt”).
  • len(tmin, tmax): Liefert die Länge der Kurve zwischen den Parametern tmin, tmax (angenähert).
  • vnorm(t): Geschwindkeitsvektor mit Länge 1 zum Parameter $t$ (“exakt”).
  • adl(t): Die Ableitung von vnorm nach der Länge der Kurve
  • forward: Interpolation der verbleibenden Länge, wenn über die Kurve hinaus gegangen wird
  • adl(t):
  • a(t,v,g): Effektiver Beschleunigungsvektor beim Punkt $p(t)$, wenn der Geschwindigkeitsbetrag v und Inverse Erdbeschleunigung gegeben ist.
  • koordsyst(t): Orthonormales Koordinatensystem (Liste von 3 Vektoren) mit $x$ parallel zu $v$, $y$ parallel zu $a$ und $z = x \times y$.

Python Code

Python Code

bezier2.py
# -*- coding: utf-8 -*-
 
from vector import Vector
 
class Bezier:
 
    def __init__(self,pts):
        if len(pts)==4:
            self.pts = [p.copy() for p in pts]
        if len(pts)==3:
            self.pts = [pts[0].copy(), 1/3*pts[0]+2/3*pts[1], 1/3*pts[2]*2/3*pts[1], pts[2].copy()]
        if len(pts)==2:
            self.pts = [pts[0].copy(), 2/3*pts[0]+1/3*pts[1], 1/3*pts[0]+2/3*pts[1], pts[1].copy()]
 
    # Punkt für Parameter t (in [0,1])        
    def x(self,t):
        return (1.0-t)**3*self.pts[0]+\
               3*(1.0-t)**2*t*self.pts[1]+\
               3*(1.0-t)*t**2*self.pts[2]+\
               t**3*self.pts[3]
 
    # Geschwindigkeit (dx/dt) in t-Parametrierung
    def v(self,t):
        return -3*(1.0-t)**2*self.pts[0]+\
               3*(1.0-4*t+3*t**2)*self.pts[1]+\
               3*(2*t-3*t**2)*self.pts[2]+\
               3*t**2*self.pts[3]
 
    # Normalisierte Geschwindigkeit
    def vnorm(self,t):
        return self.v(t).normalize()
 
 
    def adl(self,t, dt=0.000001): # Ableitung der normalisierten Geschwindigkeit nach der Länge
        dl = self.v(t).length*dt # (self.x(t+dt)-self.x(t-dt)).length
        return (self.vnorm(t+dt/2)-self.vnorm(t-dt/2))/dl
 
    # Effektive Beschleunigung im Punkt zum Parameter t, mit
    # gegebenem Geschwindigkeitsbetrag und Gravitationsvektor
    def aeff(self, t, v, g):
        return self.adl(t)*v*v-g
 
    # Orthonnormales Bahn-Koordinatensystem im Punkt zum Parameter t, mit
    # gegebenem Geschwindigkeitsbetrag und Gravitationsvektor.
    # Resultat (v,a, v cross a)
    def koordsyst(self, t, v, g):
        x = self.vnorm(t)
        # Effektive Beschleunigung
        aeff = self.aeff(t,v,g)
        # Projektion von aeff auf x (d.h. normalisierte Geschwindigkeit)
        av = x.dot(aeff)/(x.dot(x))*x
        # Effektive Beschleunigung in Normalebene zur Bahn.
        # (ist mathematisch rechtwinklig!)
        aa = (aeff-av).normalize()
        z = x.cross(aa)
        return (x,aa,z)
 
 
 
 
 
    # Laenge der Bezier-Kurve
    def length(self, tmin=0.0, tmax=1.0, steps=1000):
        l = 0.0
        # Zeitschritt
        dt = (tmax-tmin)/steps
        for i in range(steps):
            # Den i-ten Zeitpunkt von steps Zeitpunkten
            ti = (i+0.5)*dt+tmin
            l += self.v(ti).length*dt
        return l
 
    # Input: Startzeitpunkt t, Streckenlaenge l
    # Output: Endzeitpunkt t oder -Restlaenge
    def forward(self, l, startt, dt=0.0001):
        lastl = l
        lastt = startt
        while (startt<1.0 and l>0):
            dl = self.v(startt).length*dt
            lastl = l
            lastt = startt
            l -= dl
            startt += dt
        if startt<1.0:  # Noch auf der Bezierkurve
            return (startt-lastt)*lastl/(lastl+abs(l))+lastt
 
        if l>0: # Es ist noch Laenge uebrig, also auf naechster Kurve
            return -(lastl - (self.x(1)-self.x(lastt)).length)
        return 1.0 # Sonst genau auf dem Ende der Kurve
 
 
    # Zeichnet den Spline
    # Achtung: Funktioniert nur, wenn diese Datei ausgeführt wird...
    def draw(self, steps=1000):
        move(self.pts[0][0], self.pts[0][1]);
        for i in range(1,steps+1):
            p = self.x(1.0*i/steps)
            lineTo((p[0],p[1]))
 
 
if __name__== "__main__":
    from gpanel import *
    makeGPanel(Size(600,600))
    window(0, 599, 0, 599)
    b = Bezier([Vector([100,500,0]), Vector([200,0,0]), Vector([300,300,0]), Vector([500,300,0])])
    b.draw()
    print(b.length(0,1,10000))
    t = 0.0
    while (t>=0.0):
        p = b.x(t)
        a = b.adl(t)
        pa = p+a*10000
        # move(p.x, p.y)
        # circle(5)
        line(p.x,p.y, pa.x, pa.y)
        t = b.forward(10,t)
        print(t)

Bahn-Koordinatensystem

Kreisbewegung mit Geschwindigkeitsbetrag 1:

\begin{align*} x(t) & = r \cdot \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\ v(t) & = x'(t) = \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\ a(t) & = v'(t) = \frac{1}{r} \cdot \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\ \end{align*}

Beträgt jetzt die Geschwindigkeit $\lambda$ anstatt 1, ändern sich die Gleichungen wie folgt:

\begin{align*} x(t) & = r \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\ v(t) & = x'(t) = \lambda \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\ a(t) & = v'(t) = \lambda^2 \cdot \frac{1}{r} \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\ \end{align*}

D.h., wenn die Geschwindigkeit von $1$ auf $\lambda$ erhöht wird, wird die Beschleunigung mit $\lambda^2$ multipliziert.

Sei $\ell(t)$ die Bogenlänge der Bezierkurve, also $\ell(t) = \int_0^t |p'(s)| \textrm{d}s$. Insbesondere gilt dann $\ell'(t) = |p'(t)|$. (Die Länge ändert sich so stark, wie der Punkt in $t$ schnell ist).

Sei $t(\ell)$ die Umkehrfunktion, d.h. der $t$-Parameter für eine bestimmte Länge. Die Ableitung ist dann (nach der Formel $(f^{-1})' = \frac{1}{f'(f^{-1})}$ mit $f^{-1}=t$ und $f=\ell$): $$ \frac{\textrm{d}t(\ell)}{\textrm{d}\ell} = \frac{1}{\ell'(t(\ell))} = \frac{1}{|p'(t(\ell))|}. $$ (D.h. der Parameter $t$ ändert sich mit der Länge indirekt proportional zur $t$-Geschwindigkeit).

Anstatt der “normalen” Parametrierung in $t \in [0,1]$, stellen wir uns eine Parametrierung $p_{\ell}$ vor, so dass die Bogenlänge der Bezierkurve von $p_{\ell}(0)$ bis $p_{\ell}(\ell)$ genau $\ell$ beträgt.

Es gilt $p_{\ell}(\ell) = p(t(\ell))$ und \[ v_n(t(\ell)) := \frac{\textrm{d}p_{\ell}(\ell)}{\textrm{d} \ell} = p'(t(\ell)) \cdot \frac{\textrm{d}t(\ell)}{\textrm{d}\ell} = p'(t(\ell)) \cdot \frac{1}{|p'(t(\ell))|} \] d.h. man erhält den auf den Betrag 1 normalisierten Geschwindgkeitsvektor (was ja genau der Sinn der $p_{\ell}$ Parametrierung ist).

Die zweite Ableitung von $p_{\ell}$ nach $\ell$ ergibt die Beschleunigung $a_n(\ell)$, die rechtwinklich auf $v_n$ steht (sonst würde sich der Betrag von $v_n$ ändern).

Diese zweite Ableitung berechnen wir nummerisch durch Ableiten der ersten: \[ a_n(t(\ell)) := \frac{\textrm{d}v_n(\ell)}{\textrm{d}\ell} \approx \frac{v_n(t(\ell)+\Delta t)-v_n(t(\ell)-\Delta t)}{\ell(t+\Delta t)-\ell(t-\Delta t)} \approx \frac{v_n(t(\ell)+\Delta t)-v_n(t(\ell)-\Delta t)}{|p(t+\Delta t)-p(t-\Delta t)|} \]

  • kurse/efcomputergrafik/kw4.1579721811.txt.gz
  • Last modified: 2020/01/22 20:36
  • by Ivo Blöchliger