Code snippets/it

Modelli di codici
Questa pagina contiene deli esempi di codice Python utilizzabili in FreeCAD, raccolti dalle esperienze degli utenti e dalle discussioni nel forum. Dopo averli letti, è possibile usarli per iniziare a creare degli script personali ...

__

Un tipico file InitGui.py
Ogni modulo deve contenere, oltre al file del modulo principale, un file InitGui.py che ha il compito di inserire il modulo nella finestra grafica principale (GUI).

Questo è un esempio semplice di un file InitGui.py:

class ScriptWorkbench (Workbench): MenuText = "Scripts" def Initialize(self): import Scripts # assumendo che Scripts.py sia il proprio modulo list = ["Script_Cmd"] # Questo elenco deve contenere i nomi dei comandi che possono essere definiti in Scripts.py        self.appendToolbar("My Scripts",list) Gui.addWorkbench(ScriptWorkbench)

Un tipico file del modulo
Il seguente è un esempio di un file del modulo principale. Esso contiene tutto ciò che il modulo deve seguire. È il file Scripts.py richiamato dall'esempio precedente. In esso è possibile inserire tutti i comandi personalizzati.

import FreeCAD, FreeCADGui class ScriptCmd: def Activated(self): # Qui si scrive tutto quello che il proprio ScriptCmd esegue... FreeCAD.Console.PrintMessage('Hello, World!') def GetResources(self): return {'Pixmap' : 'path_to_an_icon/myicon.png', 'MenuText': 'Short text', 'ToolTip': 'More detailed text'} FreeCADGui.addCommand('Script_Cmd', ScriptCmd)

Importare un nuovo tipo di file
In FreeCAD, è facile creare un importatore per un nuovo tipo di file. FreeCAD non considera che si importano dati in un documento aperto, ma piuttosto che si può semplicemente aprire direttamente il nuovo tipo di file. Quindi, quello che si deve fare è aggiungere la nuova estensione di file alla lista delle estensioni conosciute di FreeCAD, scrivere il codice che legge il file e creare gli oggetti di FreeCAD che si desidera:

Per aggiungere la nuova estensione di file all'elenco si deve aggiungere questa riga al file InitGui.py :

FreeCAD.addImportType("Your new File Type (*.ext)","Import_Ext")
 * 1) Si assume che Import_Ext.py sia il file che contiene il codice per aprire e leggere i file .ext

Poi nel file Import_Ext.py:

def open(filename): doc=App.newDocument # qui si fa tutto ciò che serve fare con filename, leggere, classificare i dati, creare i corrispondenti oggetti FreeCAD doc.recompute

L'esportazione di un proprio documento in un nuovo tipo di file funziona allo stesso modo, ma si utilizza:

FreeCAD.addExportType("Your new File Type (*.ext)","Export_Ext")

Aggiungere una linea
Una linea ha semplicemente 2 punti.

import Part,PartGui doc=App.activeDocument l=Part.Line l.StartPoint=(0.0,0.0,0.0) l.EndPoint=(1.0,1.0,1.0) doc.addObject("Part::Feature","Line").Shape=l.toShape doc.recompute
 * 1) aggiungere un elemento linea al documento e impostare i suoi punti

Aggiungere un poligono
Un poligono è semplicemente un insieme di segmenti di linea collegati tra di loro (una polilinea in AutoCAD). Non è necessario che sia chiusa.

import Part,PartGui doc=App.activeDocument n=list v=App.Vector(0,0,0) n.append(v) v=App.Vector(10,0,0) n.append(v) p=doc.addObject("Part::Polygon","Polygon") p.Nodes=n doc.recompute
 * 1) creare un vettore 3D, impostare le sue coordinate e aggiungerlo alla lista
 * 1) ... ripetere per tutti i nodi
 * 2) Creare un oggetto poligono e impostate i suoi nodi

Aggiungere e rimuovere un oggetto in un gruppo
doc=App.activeDocument grp=doc.addObject("App::DocumentObjectGroup", "Group") lin=doc.addObject("Part::Feature", "Line") grp.addObject(lin) # aggiunge l'oggetto lin al gruppo grp grp.removeObject(lin) # rimuove l'oggetto lin dal gruppo grp

Nota: È anche possibile annidare dei gruppi in altri gruppi e creare dei sottogruppi...

Aggiungere un Mesh
import Mesh doc=App.activeDocument m = Mesh.Mesh m.addFacet(0.0,0.0,0.0, 0.0,0.0,1.0, 0.0,1.0,1.0) m.addFacet(0.0,0.0,0.0, 0.0,1.0,1.0, 0.0,1.0,0.0) m.addFacet(0.0,0.0,0.0, 1.0,0.0,0.0, 1.0,0.0,1.0) m.addFacet(0.0,0.0,0.0, 1.0,0.0,1.0, 0.0,0.0,1.0) m.addFacet(0.0,0.0,0.0, 0.0,1.0,0.0, 1.0,1.0,0.0) m.addFacet(0.0,0.0,0.0, 1.0,1.0,0.0, 1.0,0.0,0.0) m.addFacet(0.0,1.0,0.0, 0.0,1.0,1.0, 1.0,1.0,1.0) m.addFacet(0.0,1.0,0.0, 1.0,1.0,1.0, 1.0,1.0,0.0) m.addFacet(0.0,1.0,1.0, 0.0,0.0,1.0, 1.0,0.0,1.0) m.addFacet(0.0,1.0,1.0, 1.0,0.0,1.0, 1.0,1.0,1.0) m.addFacet(1.0,1.0,0.0, 1.0,1.0,1.0, 1.0,0.0,1.0) m.addFacet(1.0,1.0,0.0, 1.0,0.0,1.0, 1.0,0.0,0.0) m.scale(100.0) me=doc.addObject("Mesh::Feature","Cube") me.Mesh=m
 * 1) create a new empty mesh
 * 1) build up box out of 12 facets
 * 1) scale to a edge langth of 100
 * 1) add the mesh to the active document

Aggiungere un arco o un cerchio
import Part doc = App.activeDocument c = Part.Circle c.Radius=10.0 f = doc.addObject("Part::Feature", "Circle") # create a document with a circle feature f.Shape = c.toShape # Assign the circle shape to the shape property doc.recompute

Accedere alla rappresentazione di un oggetto e modificarla
A ogni oggetto di un documento di FreeCAD è associato un oggetto di rappresentazione della sua vista in cui sono memorizzati tutti i parametri che definiscono il modo in cui l'oggetto deve apparire, come il colore, la larghezza di linea, ecc ..

gad=Gui.activeDocument  # access the active document containing all # view representations of the features in the # corresponding App document v=gad.getObject("Cube")   # access the view representation to the Mesh feature 'Cube' v.ShapeColor              # prints the color to the console v.ShapeColor=(1.0,1.0,1.0) # sets the shape color to white

Controllare gli eventi del mouse nel visualizzatore 3D tramite Python
La struttura di Inventor permette di aggiungere uno o più nodi di richiamo (callback) al grafo di scena (Scenegraph) della vista. In FreeCAD è installato di default un nodo callback per la vista che permette di aggiungere funzioni C++ globali o statiche. In appropriate associazioni Python vengono forniti alcuni metodi per utilizzare questa tecnica all'interno del codice Python.

App.newDocument v=Gui.activeDocument.activeView class ViewObserver: def logPosition(self, info): down = (info["State"] == "DOWN") pos = info["Position"] if (down): FreeCAD.Console.PrintMessage("Clicked on position: ("+str(pos[0])+", "+str(pos[1])+")\n") o = ViewObserver c = v.addEventCallback("SoMouseButtonEvent",o.logPosition)
 * 1) This class logs any mouse button events. As the registered callback function fires twice for 'down' and
 * 2) 'up' events we need a boolean flag to handle this.

Ora, cliccate in qualche parte nella zona nella vista 3D e osservate i messaggi nella finestra di output. Per terminare l'osservazione basta chiamare:

v.removeEventCallback("SoMouseButtonEvent",c)

Sono supportati i seguenti tipi di eventi:


 * SoEvent -- Tutti i tipi di eventi
 * SoButtonEvent -- Tutti gli eventi del mouse e della tastiera
 * SoLocation2Event -- Eventi di movimento 2D (normalmente i movimenti del mouse)
 * SoMotion3Event -- Eventi di movimento 3D (normalmente di spaceball)
 * SoKeyboardEvent -- Eventi dei tasti alto e basso
 * SoMouseButtonEvent -- Eventi dei pulsanti del mouse verso il basso e verso l'alto
 * SoSpaceballButtonEvent -- Eventi di SpaceBall in basso e in alto

La funzione di Python che può essere registrata con addEventCallback si aspetta una difinizione. Secondo l'evento controllato la definizione può contenere chiavi differenti.

Per tutti gli eventi esistono le seguenti chiavi:


 * Type -- Il nome del tipo di evento, ad esempio SoMouseEvent, SoLocation2Event, ...
 * Time -- L'ora corrente come stringa
 * Position -- Una tupla di due interi, dipendenti dalla posizione del mouse
 * ShiftDown -- un valore booleano, vero (true) se Shift è stato premuto altrimenti false
 * CtrlDown -- un valore booleano, true se è stato premuto Ctrl altrimenti false
 * AltDown -- un valore booleano, true se è stato premuto Alt altrimenti false

Per tutti gli eventi dei pulsanti, ad esempio eventi di tastiera, mouse o spaceball:

Per gli eventi da tastiera:
 * State -- Una stringa 'UP' se il pulsante è verso l'alto, 'DOWN' se è verso il basso o 'UNKNOWN' per tutti gli altri casi

Per gli eventi del pulsante del mouse
 * Key -- Un carattere del tasto premuto

Per gli eventi di Spaceball:
 * Button -- Il pulsante premuto, potrebbe essere BUTTON1, ..., BUTTON5 o ANY

E infine eventi di movimento:
 * Button -- Il pulsante premuto, potrebbe essere BUTTON1, ..., BUTTON7 o ANY


 * Translation -- Una tupla di tre numeri in virgola mobile
 * Rotation -- Un quaternione per la rotazione, cioè una tupla di quattro numeri in virgola mobile

Manipolare il grafo della scena in Python
È anche possibile ottenere il Scenegraph (grafo della scena) in Python e modificarlo, con il modulo 'Pivy '- una associazione di Python per Coin.

from pivy.coin import *               # load the pivy module view = Gui.ActiveDocument.ActiveView  # get the active viewer root = view.getSceneGraph           # the root is an SoSeparator node root.addChild(SoCube) view.fitAll

L'API in Python di Pivy viene creato utilizzando lo strumento SWIG. In FreeCAD si usano alcuni nodi auto-scritti che non è possibile creare direttamente in Python. Tuttavia, è possibile creare un nodo dal suo nome interno.

Si può creare una istanza di tipo 'SoFCSelection' con:

type = SoType.fromName("SoFCSelection") node = type.createInstance

Aggiungere e rimuovere oggetti nel grafo della scena
Questo è un modo per aggiungere dei nuovi nodi al Scenegraph. Accertarsi di aggiungere sempre un SoSeparator per contenere la geometria, le coordinate e le informazioni sui materiale di uno stesso oggetto.

L'esempio seguente aggiunge una linea rossa da (0,0,0) a (10,0,0):

from pivy import coin sg = Gui.ActiveDocument.ActiveView.getSceneGraph co = coin.SoCoordinate3 pts = 0,0,0],[10,0,0 co.point.setValues(0,len(pts),pts) ma = coin.SoBaseColor ma.rgb = (1,0,0) li = coin.SoLineSet li.numVertices.setValue(2) no = coin.SoSeparator no.addChild(co) no.addChild(ma) no.addChild(li) sg.addChild(no)

Per rimuoverla, è sufficiente scrivere:

sg.removeChild(no)

Aggiungere dei widget personalizzati all'interfaccia
È possibile creare widget personalizzati con Qt designer, trasformarli in uno script Python e poi caricarli nell'interfaccia di FreeCAD con PyQt4.

Il codice Python prodotto dal compilatore Ui di Python (lo strumento che converte i file .ui di Qt-designer nel codice Python) appare in genere come questo (è semplice, si può anche codificare direttamente in Python):

class myWidget_Ui(object): def setupUi(self, myWidget): myWidget.setObjectName("my Nice New Widget") myWidget.resize(QtCore.QSize(QtCore.QRect(0,0,300,100).size).expandedTo(myWidget.minimumSizeHint)) # sets size of the widget self.label = QtGui.QLabel(myWidget) # creates a label self.label.setGeometry(QtCore.QRect(50,50,200,24)) # sets its size self.label.setObjectName("label") # sets its name, so it can be found by name def retranslateUi(self, draftToolbar): # built-in QT function that manages translations of widgets myWidget.setWindowTitle(QtGui.QApplication.translate("myWidget", "My Widget", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("myWidget", "Welcome to my new widget!", None, QtGui.QApplication.UnicodeUTF8))

Dopo, basta creare un riferimento alla finestra Qt di FreeCAD, inserire un widget personalizzato in essa, e "trasformare" questo widget nel proprio con il codice Ui che abbiamo appena creato:

app = QtGui.qApp FCmw = app.activeWindow # the active qt window, = the freecad window since we are inside it myNewFreeCADWidget = QtGui.QDockWidget # create a new dckwidget myNewFreeCADWidget.ui = myWidget_Ui # load the Ui script myNewFreeCADWidget.ui.setupUi(myNewFreeCADWidget) # setup the ui FCmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,myNewFreeCADWidget) # add the widget to the main window

Aggiungere una scheda alla Combo View
Il seguente codice consente di aggiungere una nuova scheda nel pannello ComboView (vista combinata) di FreeCAD, oltre le schede standard "Progetto" e "Attività". Questo codice utilizza anche il modulo UIC per caricare un file ui direttamente nella nuova scheda.

from PyQt4 import QtGui,QtCore from PyQt4 import uic def getMainWindow: "returns the main window" # using QtGui.qApp.activeWindow isn't very reliable because if another # widget than the mainwindow is active (e.g. a dialog) the wrong widget is   # returned toplevel = QtGui.qApp.topLevelWidgets for i in toplevel: if i.metaObject.className == "Gui::MainWindow": return i   raise Exception("No main window found") def getComboView(mw): dw=mw.findChildren(QtGui.QDockWidget) for i in dw: if str(i.objectName) == "Combo View": return i.findChild(QtGui.QTabWidget) raise Exception("No tab widget found") mw = getMainWindow tab = getComboView(getMainWindow) tab2=QtGui.QDialog tab.addTab(tab2,"A Special Tab") uic.loadUi("/myTaskPanelforTabs.ui",tab2) tab2.show
 * 1) from PySide import QtGui,QtCore
 * 1) tab.removeTab(2)

Aprire una specifica pagina Web
import WebGui WebGui.openBrowser("http://www.example.com")

Ottenere il contenuto HTML di una pagina web aperta
from PyQt4 import QtGui,QtWebKit a = QtGui.qApp mw = a.activeWindow v = mw.findChild(QtWebKit.QWebFrame) html = unicode(v.toHtml) print html

Reperire e utilizzare le coordinate di 3 punti o oggetti selezionati
import Part, FreeCAD, math, PartGui, FreeCADGui from FreeCAD import Base, Console sel = FreeCADGui.Selection.getSelection # " sel " contiene gli elementi selezionati if len(sel)!=3 : # Se non sono selezionati 3 oggetti, viene visualizzato un errore nel report # il \r é \n in fine della linea significa ritorno a capo e la nuova riga CR + LF. Console.PrintError("Selezionare esattamente 3 punti\r\n") else : points=[] for obj in sel: points.append(obj.Shape.BoundBox.Center)
 * 1) -*- coding: utf-8 -*-
 * 2) la riga precedente permette di scrivere caratteri accentati nelle osservazioni
 * 3) Se questa riga non è presente, viene restituito un errore
 * 4) reperire e utilizzare le coordinate dei 3 punti selezionati

for pt in points: # visualizzare le coordinate nel report Console.PrintMessage(str(pt.x)+"\r\n") Console.PrintMessage(str(pt.y)+"\r\n") Console.PrintMessage(str(pt.z)+"\r\n")

Console.PrintMessage(str(pt[1]) + "\r\n")

Lista di oggetti
App.ActiveDocument=App.getDocument("Unnamed") doc = FreeCAD.ActiveDocument objs = FreeCAD.ActiveDocument.Objects for obj in objs: name = obj.Name       # lista il nome degli oggetti print name            # mostra il nome degli oggetti
 * 1) -*- coding: utf-8 -*-
 * 2) Elenca gli oggetti
 * 1) print objs
 * 2) print len(FreeCAD.ActiveDocument.Objects)
 * 1) doc.removeObject("Ortho") # Cancella l'oggetto

Funzione residente per una azione con un clic del mouse
class SelObserver: def addSelection(self,doc,obj,sub,pnt): # Selezione print "addSelection" print doc                           # Nome del documento print obj                           # Nome dell'oggetto print sub                           # Nome della parte dell'oggetto print pnt                           # Coordinate dell'oggetto
 * 1) -*- coding: utf-8 -*-
 * 2) provoca un'azione con un clic del mouse su un oggetto
 * 3) Questa funzione rimane residente (in memoria) grazie a "addObserver(s)"
 * 4) "removeObserver(s) # Disinstalla la funzione residente

def removeSelection(self,doc,obj,sub):  # Eliminare l'oggetto selezionato print "removeSelection" def setSelection(self,doc):             # Selezione in ComboView print "setSelection" def clearSelection(self,doc):           # Se fai clic sullo schermo, annulla la selezione print "clearSelection"              # Se fai clic su un altro oggetto, cancella la precedente selezione

s=SelObserver FreeCADGui.Selection.addObserver(s)   # installa la funzione modalità residente
 * 1) FreeCADGui.Selection.removeObserver(s) # Disinstalla la funzione residente

Elencare i componenti di un oggetto
Questa funzione elenca i componenti ed estrae le coordinate XYZ di un oggetto, i bordi (edge) e le loro lunghezze, le sue facce e la loro superficie.


 * 1) -*- coding: utf-8 -*-
 * 2) This function list the components of an object
 * 3) and extract this object its XYZ coordinates,
 * 4) its edges and their lengths center of mass and coordinates
 * 5) its faces and their center of mass
 * 6) its faces and their surfaces and coordinates
 * 7) 8/05/2014

import Draft,Part def detail: sel = FreeCADGui.Selection.getSelection  # Select an object if len(sel) != 0:                          # If there is a selection then Vertx=[] Edges=[] Faces=[] compt_V=0 compt_E=0 compt_F=0 pas   =0 perimetre = 0.0 EdgesLong = []

# Displays the "Name" and the "Label" of the selection App.Console.PrintMessage("Selection > " + str(sel[0].Name) + " " + str(sel[0].Label) +"\n"+"\n")

for j in enumerate(sel[0].Shape.Edges):                                    # Search the "Edges" and their lengths compt_E+=1 Edges.append("Edge%d" % (j[0]+1)) EdgesLong.append(str(sel[0].Shape.Edges[compt_E-1].Length)) perimetre += (sel[0].Shape.Edges[compt_E-1].Length)                    # calculates the perimeter

# Displays the "Edge" and its length App.Console.PrintMessage("Edge"+str(compt_E)+" Length > "+str(sel[0].Shape.Edges[compt_E-1].Length)+"\n")

# Displays the "Edge" and its center mass App.Console.PrintMessage("Edge"+str(compt_E)+" Center > "+str(sel[0].Shape.Edges[compt_E-1].CenterOfMass)+"\n")

num = sel[0].Shape.Edges[compt_E-1].Vertexes[0] Vertx.append("X1: "+str(num.Point.x)) Vertx.append("Y1: "+str(num.Point.y)) Vertx.append("Z1: "+str(num.Point.z)) # Displays the coordinates 1 App.Console.PrintMessage("X1: "+str(num.Point[0])+" Y1: "+str(num.Point[1])+" Z1: "+str(num.Point[2])+"\n")

try: num = sel[0].Shape.Edges[compt_E-1].Vertexes[1] Vertx.append("X2: "+str(num.Point.x)) Vertx.append("Y2: "+str(num.Point.y)) Vertx.append("Z2: "+str(num.Point.z)) except: Vertx.append("-") Vertx.append("-") Vertx.append("-") # Displays the coordinates 2 App.Console.PrintMessage("X2: "+str(num.Point[0])+" Y2: "+str(num.Point[1])+" Z2: "+str(num.Point[2])+"\n")

App.Console.PrintMessage("\n") App.Console.PrintMessage("Perimeter of the form : "+str(perimetre)+"\n")

App.Console.PrintMessage("\n") FacesSurf = [] for j in enumerate(sel[0].Shape.Faces):                                     # Search the "Faces" and their surface compt_F+=1 Faces.append("Face%d" % (j[0]+1)) FacesSurf.append(str(sel[0].Shape.Faces[compt_F-1].Area))

# Displays 'Face' and its surface App.Console.PrintMessage("Face"+str(compt_F)+" > Surface "+str(sel[0].Shape.Faces[compt_F-1].Area)+"\n")

# Displays 'Face' and its CenterOfMass App.Console.PrintMessage("Face"+str(compt_F)+" > Center  "+str(sel[0].Shape.Faces[compt_F-1].CenterOfMass)+"\n")

# Displays 'Face' and its Coordinates FacesCoor = [] fco = 0 for f0 in sel[0].Shape.Faces[compt_F-1].Vertexes:                       # Search the Vertexes of the face fco += 1 FacesCoor.append("X"+str(fco)+": "+str(f0.Point.x)) FacesCoor.append("Y"+str(fco)+": "+str(f0.Point.y)) FacesCoor.append("Z"+str(fco)+": "+str(f0.Point.z))

# Displays 'Face' and its Coordinates App.Console.PrintMessage("Face"+str(compt_F)+" > Coordinate"+str(FacesCoor)+"\n")

# Displays 'Face' and its Volume App.Console.PrintMessage("Face"+str(compt_F)+" > Volume  "+str(sel[0].Shape.Faces[compt_F-1].Volume)+"\n") App.Console.PrintMessage("\n")

# Displays the total surface of the form App.Console.PrintMessage("Surface of the form   : "+str(sel[0].Shape.Area)+"\n")

# Displays the total Volume of the form App.Console.PrintMessage("Volume of the form    : "+str(sel[0].Shape.Volume)+"\n")

detail