3. Verbinden und herausschneiden

Bereits bekannte Befehle:

color("#800000")
  translate([20,20,0])
    cube([10,20,1]);

Verbinden und herausschneiden:

Diese Operationen werden auch "Boolesche Operationen" (Boolean operations) genannt.

Wikipedia:
Ein boolescher Operator ist ein logischer Operator, also ein Operator, der auf Wahrheitswerten operiert. Er ist benannt nach George Boole. Der wichtigste Anwendungsbereich der booleschen Operatoren ist die Programmierung.

Im Verlauf des Kurses werden wir den Begriff Boolean in einem anderen Zusammenhang nochmals kennenlernen. Bei 2D- und 3D-Objekten geht es um das Verschmelzen oder Ausschneiden von Objekten.

Verbinden = Objekt + Objekt

Ausschneiden = Objekt – Objekt

3.1 Funktion - union()

In diesem Beispiel erstellen wir zwei cube()-Objekte unterschiedlicher Größe und Farbe. Der Befehl union() — umgeben von geschweiften Klammern, die die beiden cube()-Objekte einschließen — verbindet oder verschmilzt diese beiden Körper: also erster cube() + zweiter cube().

union() {
  color("green")
    cube([10,10,10]); // erster Würfel

  color("yellow")
    cube([3,3,20]); // zweiter Würfel
}

geschrieben ist, wird beim verarbeiten des Codes nicht beachtet. Auf diese Art können hilfreiche Kommentare geschrieben werden.

Nach einem F5 zeigt sich folgendes Bild.

druckansicht

Dreht die Darstellung (mit gedrückter linker Maustaste) und beobachtet die Verfärbung an den überschneidenden Flächen. Warum tritt dieses Phänomen auf? Müssen wir es beachten?

Diese beiden Fragen können wir im nächsten Beispiel — mit difference() — noch besser erklären.

3.2 Funktion - difference()

Das Gegenstück zu union() ist difference(). Das Wort beschreibt bereits, was dabei geschieht. Im Beispiel wird aus dem grünen cube() der gelbe cube() „abgezogen“ oder „herausgeschnitten“. Das Ergebnis ist die Differenz der beiden cube()-Objekte: also erster cube() minus dem zweiten cube().

difference() {
  color("green")
    cube([10,10,10]); // erster Würfel

  color("yellow")
    cube([3,3,20]); // zweiter Würfel
}

Beim Resultat sehen wir wieder das seltsame Phänomen bei den parallelen Flächen der beiden cube(). Wird die Ansicht noch ein wenig gedreht, erkennen wir schnell, dass da etwas nicht stimmen kann.

druckansicht

Was ist das für ein Phänomen?

Ein Teil der Flächen der beiden cube()-Objekte ist deckungsgleich — sie liegen mathematisch genau auf derselben Ebene. Beim Drehen der Ansicht wird die Darstellung dieser Flächen bei jeder Position neu berechnet. Welche der beiden Flächen wird nun sichtbar sein? Wer gewinnt? Intern hängt das von den Zahlenwerten hinter dem Komma ab — also von winzigen Rundungsfehlern, die jeweils einen Sieger bestimmen.

Bei der Funktion union() ist das kein Problem, da beide Flächen Teil desselben Körpers sind. Bei difference() jedoch kann dies zu unerwartetem Verhalten führen — besonders bei der 3D-Druckvorbereitung, wo solche Flächen oft als „schwach“ oder „nicht solid“ gelten.

Was tun?

3.3 difference() aber besser

Der zweite cube() sollte nicht — wie der erste — bei x=0, y=0 beginnen. Wenn wir ihn um –0.1 mm in x, y und z verschieben, beginnt er vor dem ersten cube(). Auf diese Weise entstehen keine deckungsgleichen Flächen mehr.

Aber Vorsicht!Der zweite cube() muss auch in x und y 0.1 mm größer sein — sonst stimmt die Tiefe des Ausschnitts nicht mehr. Diese soll ja 3 mm betragen, nicht 2.9 mm.

difference() {
  color("green")
    cube([10,10,10]); // erster Würfel

  translate([-0.1,-0.1,-0.1])
  color("yellow")
    cube([3.1,3.1,10.2]); // zweiter Würfel
}

Ein weiterer wichtiger Punkt ist die Höhe des zweiten cube().Im union()-Beispiel war die Höhe 20 mm — bei difference() ist das nicht nötig, da der erste cube() nur 10 mm hoch ist.Aber Achtung: 10,1 mm wäre immer noch zu wenig — denn der zweite cube() beginnt bei z = -0.1, und sollte oben 0,1 mm über den ersten cube() hinausragen. Daher muss die Höhe 10,2 mm betragen.

druckansicht

Auf diese Weise haben wir eine Kerbe mit einer Tiefe von 3 mm in x- und y-Richtung in den ersten cube() geschnitten.

3.4 Varianten von union() oder difference()

Das Beispiel zeigt eine eckige Schale mit einer Kantenlänge von 20 mm, einer Randhöhe von 5 mm und einer Wanddicke von 2 mm. Auch der Boden der Schale ist 2 mm dick.

druckansicht

Es gibt tatsächlich zwei gängige Varianten, wie man eine solche Schale in OpenSCAD erstellen kann:

3.4.1 Variante mit union()

Bei der zweiten Variante bauen wir die Schale aus einzelnen cube()-Objekten zusammen:

Beachte z. B. translate([0, 18, 0]) — die y-Verschiebung ist 18, nicht 20, da die Wand 2 mm dick ist. Andernfalls würde die Schale eine Grundfläche von 22 mm haben — was nicht gewünscht ist.

union() {
  color("green")
    cube([20,20,2]); // Bodenplatte
  
  color("red")
    cube([20,2,5]); // Wand vorne

  color("yellow")
    translate([0,18,0])
      cube([20,2,5]); // Wand hinten
  
  color("blue")
    cube([2,20,5]); // Wand links

  color("lime")
    translate([18,0,0])
      cube([2,20,5]); // Wand rechts
}

druckansicht

3.4.2 Variante mit difference()

Die genau gleiche Schale kann aber auch mit difference() gemacht werden. Das ergibt auch einfacheren Code. Dabei muss bei der Vertiefung das translate([2,2,2]) beachtet werden. Alle drei Achsen werden mit 2mm verschoben.

difference() {
  color("green")
    cube([20,20,5]); // Bodenplatte
  
  color("red")
    translate([2,2,2])
    cube([16,16,5]); // Vertiefung
}

druckansicht

Wass wenn du den difference()-Befehl und die geschweiften Klammern entfernst?

color("green")
  cube([20,20,5]); // Bodenplatte

color("red")
  translate([2,2,2])
  cube([16,16,5]); // Vertiefung

Nun sehen wir die beiden cube() ineinander geschachtelt. Und ja: z=5 beim cube([16,16,5]) müsste 3,1 sein.

druckansicht

3.5 Übungen zum Kaptiel

3.5.1 Rahmenwürfel

Wie kann dieser „Rahmenwürfel“ (links im Bild) erstellt werden?

Der Basiswürfel hat im Beispiel eine Kantenlänge von 20 mm. Im rechten Bild sieht man die Vorbereitung für den „Rahmenwürfel“. Die Farbflächen haben jeweils eine Kantenlänge von 14 mm und sind im Beispiel in rot, gelb und blau eingefärbt.

Wie in diesem Kapitel bereits gesehen, muss bei der Funktion difference() der „Aushöhl“-cube jeweils 0,1 mm oder mehr vor dem Basiskörper beginnen und auch 0,1 mm über dessen Ende hinausgehen.

druckansicht

Der Weg zum Ziel geht über folgende Schritte:

druckansicht

3.5.2 Weiterer Würfel aber mit Vertiefungen

Bei diesem Beispiel können wir den Rahmenwürfel gleich als Basis verwenden. Die Masse bleiben die gleichen, aber mit dem Unterschied, dass die gelbe und blaue Fläche eine Vertiefung von nur 1 mm in den Würfel machen dürfen.

Wie im nach oben gekippten Würfel rechts zu sehen ist, soll auch auf der gegenüberliegenden Seite des Würfels eine Vertiefung sein. Nur die rote Achse geht durch den Würfel.

Wichtig: die Vertiefung muss genau 1 mm sein.

druckansicht

Hier eine kleine Hilfe: Die beiden gelben Vertiefungen werden wie im Beispiel-Code erstellt. Dabei wurde color() mit einer Klammer über beide Vertiefungen geschrieben.

  color("yellow") {
    translate([3,3,-0.1])
      cube([14,14,1.1]); // z Achse
    translate([3,3,19])
      color("yellow")
        cube([14,14,2]); // z Achse
  }