pointsandfaces – ein weniger einfaches Beispiel

Wenn man beide Mutationen des Konzeptes Rohr kombinieren möchte, um ein gebogenes Rohr das sich in der Mitte verjüngt zu erhalten, muss man die Taktik ändern, und hier kann pointsandfaces seine Vorteile demonstrieren, indem die Funktionen in pnf_pointsforge.scad Verwendung finden.

Wie man sehen kann, ist das Listing etwas komplizierter als das vorherige Beispiel, aber werfen wir einen näheren Blick darauf, um ihm die Mystik zu rauben.

use <inc/pnf/pnf_cylinder.scad>
use <inc/pnf/pnf_littlehelpers.scad>
use <inc/pnf/pnf_pointsforge.scad>
fn = 128;
outer_radius = 30;
wall_thickness = 4;
narrowing = 10;
bending_radius=40;
height = pnf_pi()*bending_radius/2;
v = pnf_tube_pnf_v(r = outer_radius, h = height, wt = wall_thickness, nz = 180, fn = fn);
v_n = [ for(p = v[0]) 
    let (
        x = p[0],
        y = p[1],
        z = p[2],
        n = cos((z - height / 2) / height * 180) * narrowing,
        r = sqrt(x * x + y * y),
        w = atan2(y, x),
        r_n = r - n
        )
    [
        r_n * cos(w),
        r_n * sin(w),
        z 
    ]
];
v_nb = pnf_bend_points_v(P = v_n, brx = bending_radius);
polyhedron(v_nb, v[1], 4);

Der erste Unterschied, der auffällt, wenn man das Listing von oben nach unten liest, ist das Inkludieren von pnf_pointsforge.scad und pnf_littlehelpers.scad. Die Include Datei pnf_pointsforge.scad enthält Funktionen mit denen die Positionen von Punkten abhängig von ihrer Position verändert werden können, was uns in die Lage versetzt, Objekte zu “schmieden”. Das Eisen sind die Punkte und wir wollen das Eisen stauchen, biegen und drehen, um die gewünschte Form zu erhalten. Und wir benutzen keinen Hammer, sondern Funktionen. Wie ein Schmied haben wir fertige Werkzeuge in unserer Schmiede, und Werkzeuge, die wir uns für ein oder wenige Stücke anfertigen.

In diesem beispiel benutzen wir beide Arten, ein Werkzeug in unserer Schmiede, das pnf_bend_points_v() genannt wird, um die Punkte zu biegen, und wir machen unser eigenes Werkzeug, um das Rohr in der Mitte zu verjüngen. Das Verjüngen wird zuerst angewendet. Der Grad der Verjüngung ist von der Höhe abhängig, und um ein glattes Verjüngen zu erreichen, benutzen wir die sin()-Funktion, um es zu berechnen. Die errechnete Verjüngung anzuwenden, ist nicht so leicht, wie das Kreieren des Polygons für pnf_rotate_extrude(). Wir haben nicht einen einfachen Eingabe-Parameter, sondern eine Kombination aus dreien, nämlich die x, y, und z Positionen für jeden Punkt. Daher bedarf es ein wenig Geometrie, um die neuen Positionen zu berechnen. Wenn es etwas komplizierter wird, teile ich ein Problem gerne in kleine Teile, was in diesem Fall die Verwendung von Zwischenvariablen im let()-statement bedeutet. Um den Code lesbarer zu gestalten, holen wir uns erst die Positionen aus dem Punkt:

        x = p[0],
        y = p[1],
        z = p[2],

Dann wollen wir die Entfernung des Punktes zur Mitte des Rohrs wissen, welche in diesem Fall 30 für doe äußeren und 26 für die inneren Punkte sein wird. Aber die Entfernung steht nicht im gegebenen Feld, also errechnen wir sie mittels Pythagoras:

        r = sqrt(x * x + y * y),

Wir brauchen außerdem den Winkel des Punktes in Relation zur Mitte, wobei uns die Funktion atan2() hilft, besondere Fälle, die mit Division durch null zu tun haben, zu vermeiden:

        w = atan2(y, x),

Nun haben wir eine Entfernung und einen Winkel. Alles, was wir jetzt noch tun müssen, ist die entsprechende Verjüngung anhand der z-Position zu berechnen, und diese Verjüngung von der Entfernung abzuziehen,

        n = cos((z - height / 2) / height * 180) * narrowing,
        r_n = r - n

und die Position mit sin() und cos() neu zu berechnen, was so einfach ist, dass wir es außerhalb des let()-Statements und innerhalb der Definition des Ergebniswertes machen:

    [
        r_n * cos(w),
        r_n * sin(w),
        z
    ]

Aber wir sind noch nicht fertig. Das Feld ist noch nicht gebogen. Das ist einfach, denn wir können dafür ein Werkzeug aus unserer Schmiede benutzen, nämlich die Funktion pnf_bend_points_v(), die macht, was ihr Name sagt. Es würde über den Rahmen der Erläuterung dieses Beispiels hinausgehen, in die Interna von pnf_bend_points_v() zu gehen, also werfen wir nur einen schnellen Blick darauf, bevor wir weiter in die Tiefe gehen:

function pnf_bend_points_v(P, brx = 0, bry = 0) = 
[
    for (p=P)
        let
        (
            x = p[0],
            y = p[1],
            z = p[2],
            wx = brx ? (z / (brx * 2 * pnf_pi()) * 360) : 0,
            wy = bry ? (z / (bry * 2 * pnf_pi()) * 360) : 0,
            x2 = x * cos(wx),
            y2 = y * cos(wy),
            z2 = x * sin(wx) + y * sin(wy)
        )
        [
            brx ? (-brx + (cos(wx) * brx) + x2) : x,
            bry ? (-bry + (cos(wy) * bry) + y2) : y,
            sin(wx) * brx + sin(wy) * bry + z2
        ]
];

Eigentlich ist es einfach. Wir haben zwei Richtungen, in die gebogen werden kann, x und y. Schauen wir auf eine davon, sagen wir x. Das Biegen wird durch die Rotation jedes Punktes um die Mittelachse der Biegung in einem Winkel, der von der Höhe (z-Wert) abhängt, bewerkstelligt. Die neue Position wird mit Trigonometrie berechnet.

Aber wie arbeitet die Function pnf_tube_pnf_v() Und warum wollen wir das wissen?
Werfen wir einen Blick auf einige Interna.