Headless FreeCAD/de

Einleitung

FreeCAD kann ohne seine grafische Benutzerschnittstelle (Graphical User Interface, kurz GUI) ausgeführt werden, in einem Modu, der als 'headless' (kopflos) bezeichnet wird. Dieser stellt mehrere leistungsfähige Methoden zum Skripten, Automatisieren und Einbetten seiner Fähigkeiten in andere Anwendungen bereit. Diese Seite dokumentiert die verschiedenen Möglichkeiten, FreeCAD im Headless-Modus auszuführen.

In FreeCADs Python-Konsole

Dies ist ein interaktiver Modus, in dem FreeCAD direkt in einer Python-Konsole startet. Diese Konsole ist eine voll funktionsfähige Python-Umgebung mit allen Python-Modulen von FreeCAD, wie Part, BIM und Draft, die über ihre öffentliche API zugänglich sind. Das Kernmodul FreeCAD ist integriert, sodass es während der Konsolensitzung nicht explizit importiert werden muss. Andere Module können während der Sitzung nach Bedarf importiert werden (z. B. import Part).

Dieser Modus kann über die Befehlszeile mit FreeCAD -c oder FreeCADCmd gestartet werden. Er bietet dieselben Funktionen wie die Python-Konsole in der vollständigen FreeCAD-Anwendung.

Es eignet sich am besten zum schnellen Testen von Python-Code, der auf die FreeCAD-API zugreift, oder zum Debuggen kleiner Skripte, die einfach in die Konsole eingefügt werden können.

Mit einem Python-Skript

In diesem Modus wird FreeCAD als Standard-Python-Bibliothek verwendet. Dadurch können Sie die gesamte Python-API in jedes externe Python-Skript oder jede externe Python-Anwendung importieren und sie wie ein natives Modul behandeln.

Um dies zu ermöglichen, muss der Python-Interpreter die FreeCAD-Bibliotheksdatei finden können, die unter Linux und macOS den Namen FreeCAD.so und auf anderen Plattformen den Namen FreeCAD.pyd trägt. Fügen dazu ganz am Anfang des Skripts das Verzeichnis dieser Datei an die Suchpfade von Python an. Sobald der Pfad festgelegt ist, kann der Rest des Skripts wie jedes andere Python-Modul auf die FreeCAD-API zugreifen.

Nachfolgend befindet sich ein einfaches Beispiel, das einen Quader erstellt und dessen Volumen und Oberfläche ausgibt:

# Set the path to your FreeCAD installation
# Example for Linux:
# FREECADPATH = '/usr/lib/freecad/lib'
# Example for macOS:
# FREECADPATH = '/Applications/FreeCAD.app/Contents/Resources/lib'
# Example for Windows:
FREECADPATH = 'C:\\Program Files\\FreeCAD\\bin'
import sys
sys.path.append(FREECADPATH)

# The rest of the script can now import and use the FreeCAD API
import FreeCAD
import Part

# Create a simple geometric shape
my_box = Part.makeBox(10, 20, 30)

# Access its properties
print(f"The volume of the box is: {my_box.Volume}")
print(f"The area of the box is: {my_box.Area}")

Um das Beispielskript auszuführen, speichert man den Code in einer Datei (z.B. run_box.py) und führt ihn über das Terminal des Systems mit dem Python-Interpreter aus:

$ python run_box.py
The volume of the box is: 6000.0
The area of the box is: 2200.0

Dies ist eine sehr leistungsstarke Funktion, die das gesamte Potenzial von FreeCAD für Automatisierungs- und Integrationsaufgaben freisetzt. Man könnte beispielsweise ein Skript schreiben, das sowohl die FreeCAD- als auch die Blender-API nutzt, um Objekte aus einer .FCStd-Datei programmgesteuert direkt in eine Blender-Szene zu importieren.

Beachte, dass dieser Modus für die Verwendung der FreeCAD-API ohne GUI vorgesehen ist. Zwar können einige GUI-bezogene Module importiert werden, doch ist die API-Nutzung, die direkt auf GUI-Komponenten zugreift oder diese manipuliert, sehr eingeschränkt und wird in einem headless-Kontext im Allgemeinen nicht unterstützt.

Zusätzliche Überlegungen zu Arbeitsbereichs-Modulen im Headless-Modus

Wenn FreeCAD als Python-Bibliothek in einem headless-Kontext verwendet wird (beispielsweise über einen Standard-Python-Interpreter oder FreeCADCmd), stehen nicht alle Arbeitsbereich-Module automatisch zur Verfügung, selbst wenn die FreeCAD-Kernmodule erfolgreich importiert werden können.

Insbesondere Module, die sich im Verzeichnis Mod/ befinden (wie z. B. PartDesign oder Untermodule von Part), werden von Python möglicherweise nicht erkannt, sofern ihre Pfade nicht explizit zu sys.path hinzugefügt werden. Dies kann dazu führen, dass Dokumentobjekte als generische Typen (z. B. GeoFeature) anstelle ihrer spezifischen Typen (z. B. PartDesign::Body) geladen werden oder dass der Import von Arbeitsbereichs-bezogenen Modulen fehlschlägt.

Um die volle Funktionalität zu gewährleisten, kann es erforderlich sein, den Python-Suchpfad manuell um das FreeCAD-Verzeichnis Mod/ und in manchen Fällen um bestimmte Unterverzeichnisse zu erweitern:

import sys

# Example paths (adjust to your installation)
sys.path.append("/usr/lib/freecad/Mod")
sys.path.append("/usr/lib/freecad/Mod/Part")

# Workbench modules can now be imported
import PartDesign
from BOPTools import BOPFeatures

Die genauen Pfade hängen von der Plattform und der Installationsmethode ab.

Diese manuelle Konfiguration stellt sicher, dass Arbeitsbereichs-Module importiert werden können, Dokumentobjekte mit den richtigen Typen rekonstruiert werden und zusätzliche Python-Dienstprogramme, die mit den Arbeitsbereichen gebündelt sind, zur Verfügung stehen.

Es muss beachtet werden, dass die FreeCAD-GUI-Umgebung diese Initialisierung automatisch durchführt. Bei der Verwendung ohne grafische Benutzeroberfläche muss dieser Schritt jedoch explizit vom Benutzer durchgeführt werden.

Siehe FreeCAD einbinden.

Mit einem Shell-Skript

FreeCAD kann auch ohne Kopf (engl. headless) aus einem Shell-Skript heraus ausgeführt werden, indem FreeCAD -c oder FreeCADCmd gefolgt von den erforderlichen Argumenten aufrufen wird.

Eine vollständige Liste der verfügbaren Befehlszeilenargumente kann mit dem Flag --help angezeigt werden. Hier ist ein Beispiel für die Hilfeausgabe für FreeCAD 1.0.2:

Command-line arguments for FreeCAD 1.0.2 (Click to expand)
$ FreeCAD -c --help
FreeCAD

For a detailed description see https://wiki.freecad.org/Start_up_and_Configuration

Usage: FreeCAD [options] File1 File2 ...

Allowed options:

Generic options:
  -v [ --version ]          Prints version string
  --verbose                 Prints verbose version string
  -h [ --help ]             Prints help message
  -c [ --console ]          Starts in console mode
  --response-file arg       Can be specified with '@name', too
  --dump-config             Dumps configuration
  --get-config arg          Prints the value of the requested configuration key
  --set-config arg          Sets the value of a configuration key
  --keep-deprecated-paths   If set then config files are kept on the old 
                            location

Configuration:
  -l [ --write-log ]        Writes FreeCAD.log to the user directory.
  --log-file arg            Unlike --write-log this allows logging to an 
                            arbitrary file
  -u [ --user-cfg ] arg     User config file to load/save user settings
  -s [ --system-cfg ] arg   System config file to load/save system settings
  -t [ --run-test ] arg     Run a given test case (use 0 (zero) to run all 
                            tests). If no argument is provided then return list
                            of all available tests.
  -r [ --run-open ] arg     Run a given test case (use 0 (zero) to run all 
                            tests). If no argument is provided then return list
                            of all available tests.  Keeps UI open after 
                            test(s) complete.
  -M [ --module-path ] arg  Additional module paths
  -E [ --macro-path ] arg   Additional macro paths
  -P [ --python-path ] arg  Additional python paths
  --disable-addon arg       Disable a given addon.
  --single-instance         Allow to run a single instance of the application
  --safe-mode               Force enable safe mode
  --pass arg                Ignores the following arguments and pass them 
                            through to be used by a script

Diese Methode eignet sich ideal für automatisierte Aufgaben und Skripte zur kontinuierlichen Integration (CI). Häufige Anwendungsfälle sind die Ausführung der gesamten Testsuite mit FreeCADCmd -t 0 oder die Ausführung von Tests für ein bestimmtes Modul, wie z. B. FreeCADCmd -t TestArch (alle Arbeitsbereich BIM-Tests) oder FreeCADCmd -t TestArch.TestWall (nur die Wandtests des Arbeitsbereichs BIM).

Python-Code direkt ausführen

Die ausführbaren Befehlszeilenprogramme von FreeCAD können auch als spezialisierte Python-Interpreter fungieren, wodurch Python-Code direkt ausgeführt werden kann. Dies bietet eine bequeme und leistungsstarke Alternative zur Einbettung von FreeCAD in ein externes Python-Skript.

Ausführen eines Inline-Skripts

Eine Zeichenfolge mit Python-Code kann direkt als einzelnes Argument übergeben werden. Dies ist nützlich für sehr kurze Befehle mit einem einzigen Zweck. Beachte, dass das Befehlszeilenargument kein Pfad zu einer vorhandenen Datei sein darf, damit dies funktioniert.

$ FreeCADCmd "import Part; print(Part.makeBox(10,5,15).Volume)"
$ FreeCAD -c "import Part; my_box = Part.makeBox(10,5,15)"

Ausführen einer Skriptdatei

Eine leistungsfähigere Methode ist die Verwendung von FreeCAD zur direkten Ausführung einer Python-Skriptdatei. Dies ist der empfohlene Ansatz für alle nicht trivialen kopflosen-Modus-Aufgaben (engl. headless mode).

$ FreeCADCmd /path/to/my_script.py

Wenn ein Skript auf diese Weise ausgeführt wird, ist die FreeCAD-Umgebung bereits konfiguriert. Der entscheidende Vorteil besteht darin, dass das Skript den Standardcode sys.path.append() nicht benötigt. Die FreeCAD-Module stehen sofort zum Import bereit.

Zum Beispiel, eine Datei mit Namen create_box.py könnte enthalten:

import Part
# The FreeCAD module is already available, but it can be imported explicitly
import FreeCAD

# Create a new document and add a box to it
doc = FreeCAD.newDocument()
box_obj = doc.addObject("Part::Box", "MyBox")
doc.recompute()

# Export the part to a STEP file
Part.export([box_obj], "my_box_model.step")

print("Box created and exported successfully to my_box_model.step")

So einfach wird das Skript aus dem Terminal heraus ausgeführt:

$ FreeCADCmd create_box.py
Box created and exported successfully to my_box_model.step

Über die vollständige GUI-Anwendung auf einem virtuellen Bildschirm

Mit den oben genannten Methoden (FreeCADCmd, FreeCAD -c und die Verwendung von FreeCAD als eingebettete Python-Bibliothek) lassen sich keine Viewprovider erstellen. Wenn das Skript Zugriff auf ViewObject benötigt (beispielsweise auf Eigenschaften wie Textstil oder Schriftgröße), funktioniert keine der oben genannten Methoden.

Um eine vollständig initialisierte GUI-Sitzung (einschließlich funktionierender View-Provider) ohne physischen Monitor zu erhalten, kann unter Linux die eigentliche FreeCAD-GUI-Ausführungsdatei unter einem virtuellen X-Server wie Xvfb ausgeführt werden. Im Gegensatz zu den Konsolenmodi führt die GUI-Ausführungsdatei ihren normalen Startvorgang durch (Erstellen eines MainWindow und echter View-Providers).

Unter Linux lässt sich dies mit xvfb-run erreichen, das die Zuweisung eines virtuellen Bildschirms und die Bereinigung automatisch übernimmt:

$ xvfb-run -a FreeCAD my_script.py

Wie beim Aufruf der Skriptdatei, der unter Programmstart und Konfiguration beschrieben ist, kann die über die Befehlszeile übergebene Datei entweder die Erweiterung .py oder .FCMacro haben; beide werden auf die gleiche Weise ausgeführt.

Die Anwendung wird nach Abschluss des Skripts nicht automatisch beendet. Im Gegensatz zu FreeCADCmd tritt die GUI-Ausführungsdatei immer in die normale Qt-Ereignisschleife ein und bleibt geöffnet, unabhängig davon, ob für den Benutzer eine Anzeige sichtbar ist oder nicht. Das Skript selbst muss den Beendigungsbefehl auslösen.

Der alleinige Aufruf von FreeCADGui.getMainWindow().close() ist hierfür nicht zuverlässig: Er durchläuft die normale interaktive Schließsequenz, zu der auch die FreeCAD-Abfrage „Änderungen speichern?“ für jedes Dokument mit ungespeicherten Änderungen gehört. Dies führt unter einer virtuellen Anzeige zu einem unbefristeten Hängenbleiben des Prozesses, da eine menschliche Interaktion erforderlich ist, um die Abfrage zu schließen. Daher muss zunächst das Änderungsflag jedes Dokuments zurück gesetzt werden, damit keine Abfrage mehr erscheint:

import FreeCAD as App
import FreeCADGui as Gui

# ... script code ...

for doc in App.listDocuments().values():
    Gui.getDocument(doc.Name).Modified = False
Gui.getMainWindow().close()

Sollte der Prozess trotz allem noch durch etwas anderes am Laufen gehalten werden (beispielsweise durch einen anderen modalen Dialog, der nichts mit ungespeicherten Änderungen zu tun hat), kann ein Skript auf einen „Hard Exit“ zurückgreifen, der die Qt-Ereignisschleife vollständig umgeht:

import os
# ... script code ...
os._exit(0)

Diese Option nur als letzten Ausweg verwenden: Sie umgeht den normalen Beendigungs- und Aufräumvorgang von Qt und FreeCAD, sodass alles, was bei einer normalen Beendigung entfernt würde (z.B. Sperrdateien), zurückbleibt. Nach Möglichkeit lieber das Änderungsflag löschen und das Programm wie gewohnt schließen.

Beispiele

FreeCAD-Module suchen

  1. Das Terminal öffnen und Folgendes eingeben:
    $ /path/to/FreeCAD -c
    oder
    $ /path/to/FreeCADCmd
  2. Eine Python-Shell wird mit einer Eingabeaufforderung gestartet. Folgendes eingeben: help().
  3. Ein Hilfetext wird angezeigt.
  4. Tippe modules freecad.

Szenengraph-Darstellung

Es ist nicht möglich, die Viewprovider im kopflosen Modus zu erzeugen oder zu erreichen. Es ist möglich, FreeCADGui im kopflosen Modus zu laden, aber es gibt keine Möglichkeit, auf das GUI-Dokument zuzugreifen, da es nicht erstellt wird und folglich keine Viewprovider vorhanden sind.

Was jedoch möglich ist, ist die Erstellung einesSzenengraph-Darstellung eines Objekts:

import FreeCADGui as Gui
from pivy import coin

Gui.setupWithoutGUI()
doc = App.newDocument()
obj = doc.addObject("Part::Box","Box")
doc.recompute()
view = Gui.subgraphFromObject(obj)

Siehe Forenbeitrag: forum thread.

Verwandt