Simples Koordinatensystem in Python?

1 Antwort

Ich kann hier einfach mal eine ähnliche Application reinstellen, die wir in dre Uni programmiert hatten. Kann Fehler enthalten und trifft auch nicht ganz das, was du tun möchtest, aber sollte wohl hilfreich sein:

#!/usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons


def de_casteljau_step(P, t):
    """For a given control polygon P of length n, return a control polygon of
    length n-1 by performing a single de Casteljau step with the given
    floating point number t."""
    assert len(P) > 1, 0 <= t <= 1
    oneMinusT = 1-t;
    ret = np.zeros((np.size(P,0)-1, 2));
    for i in range(np.size(P, 0)-1):
        ret[i][0] = oneMinusT*P[i][0] + t*P[i+1][0];
        ret[i][1] = oneMinusT*P[i][1] + t*P[i+1][1];
    return ret;


def de_casteljau(P, t):
    """Evaluate the Bezier curve specified by the control polygon P at a single
    point corresponding to the given t in [0,1]. Returns a one-dimensional
    NumPy array contining the x and y coordinate of the Point,
    respectively."""
    assert len(P) != 0
    while np.size(P, 0) > 1:
        P = de_casteljau_step(P, t);
    return P[0];

def bezier1(P, m):
    """Return a polygon with m points that approximates the Bezier curve
    specified by the control polygon P."""
    assert len(P) > 1, m > 1
    ret = np.zeros((m, 2));
    for i in range(m):
        ret[i] = de_casteljau(P, 0+i/(m-1));
    return ret;


def add_control_point(P):
    """For the given Bezier curve control polygon P of length n, return a new
    control polygon with n+1 points that describes the same curve."""
    assert len(P) > 1
    n = np.size(P, 0);
    ret = np.zeros((n+1, 2));
    ret[0][0] = P[0][0];
    ret[0][1] = P[0][1];
    ret[n][0] = P[n-1][0];
    ret[n][1] = P[n-1][1];
    for i in range(1, n):
        a = i/n;
        ret[i][0] =  a*P[i-1][0] + (1-a)*P[i][0];
        ret[i][1] =  a*P[i-1][1] + (1-a)*P[i][1];
    return ret;


def split_curve(P):
    """Split a Bezier curve, specified by a control polynomial P. Return a
    tuple (L, R), where L and R are control polygons with the same
    length as P, that describe the left and the right half of the original
    curve, respectively."""
    n = np.size(P, 0);
    L = np.zeros((n, 2));
    R = np.zeros((n, 2));
    lastIndex = n-1;
    for i in range(n-1):
        L[i] = P[0];
        R[n-i-1] = P[lastIndex];
        P = de_casteljau_step(P, 1/2);
        lastIndex -= 1;
    L[n-1] = P[0];
    R[0] = P[0];
    return (L, R);

def bezier2(P, depth):
    """Return a polygon that approximates the Bezier curve specified by the
    control polygon P by depth recursive subdivisions."""
    if(depth == 0):
        return P
    else:
        splitted = split_curve(P);
        L = bezier2(splitted[0], depth-1);
        R = bezier2(splitted[1], depth-1);
        ret = np.zeros((2*np.size(L, 0)-1, 2));
        for i in range(np.size(L, 0)):
            ret[i] = L[i];
        for j in range(1,np.size(R, 0)):
            ret[np.size(L, 0)+j-1] = R[j];
        return ret;
            
        


def de_casteljau_plot(P):
    """Draw all polygons in the de Casteljau pyramid of P for varying t."""
    n = len(P)
    t = 0.3
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    lines = ax.plot(P[:,0], P[:,1], 'o-')
    Q = P.copy()
    for i in range(n-1):
        Q = de_casteljau_step(Q,t)
        [line] = ax.plot(Q[:,0], Q[:,1], 'o-')
        lines.append(line)
    plt.grid(True)

    def redraw(t):
        Q = P.copy()
        for i in range(n-1):
            Q = de_casteljau_step(Q,t)
            lines[i+1].set_xdata(Q[:,0])
            lines[i+1].set_ydata(Q[:,1])

    fig.subplots_adjust(left=0.25, bottom=0.25)
    fig.canvas.draw_idle()
    t_slider_ax  = fig.add_axes([0.25, 0.1, 0.5, 0.03])
    t_slider = Slider(t_slider_ax, 't', 0., 1., valinit=t)
    t_slider.on_changed(redraw)
    plt.show()


def bezier_plot(P):
    """Draw different bezier curve approximations for the given P."""
    n = len(P)
    depth = 1
    fig = plt.figure()
    ax = fig.add_subplot(1,1,1)
    B2 = bezier2(P.copy(), depth)
    B1 = bezier1(P.copy(), len(B2))
    [line0] = ax.plot( P[:,0],  P[:,1], 'o-', label="P")
    [line1] = ax.plot(B1[:,0], B1[:,1], 'o-', label="bezier1")
    [line2] = ax.plot(B2[:,0], B2[:,1], 'o-', label="bezier2")
    plt.legend(shadow=True)
    plt.grid(True)

    def redraw(depth):
        depth = int(depth)
        B2 = bezier2(P.copy(), depth)
        line2.set_xdata(B2[:,0])
        line2.set_ydata(B2[:,1])
        B1 = bezier1(P.copy(), len(B2))
        line1.set_xdata(B1[:,0])
        line1.set_ydata(B1[:,1])

    fig.subplots_adjust(left=0.25, bottom=0.25)
    fig.canvas.draw_idle()
    depth_slider_ax  = fig.add_axes([0.25, 0.1, 0.5, 0.03])
    depth_slider = Slider(depth_slider_ax, 'depth', 0, 7, valinit=depth)
    depth_slider.on_changed(redraw)
    plt.show()


def main():
    P = np.array([[3., 2.], [2., 5.], [7., 6.], [8., 1.]])
    #bezier2(P, 2);
    de_casteljau_plot(P)


if __name__ == "__main__": main()