Code snippets/es

Esta página contiene ejemplos, pedazos, trozos de código de Python en FreeCAD recogidos de experiencias de los usuarios y las discusiones en los foros. Lee y utilízala como punto de partida para tus propios archivos de guión ...

Un típico archivo InitGui.py
Cada módulo debe contener, además de tu archivo del módulo principal, un archivo InitGui.py, responsable de insertar el módulo en la interfaz GUI principal. Este es un ejemplo de uno sencillo:

class ScriptWorkbench (Workbench): MenuText = "Scripts" def Initialize(self): import Scripts # assuming Scripts.py is your module list = ["Script_Cmd"] # That list must contain command names, that can be defined in Scripts.py        self.appendToolbar("My Scripts",list) Gui.addWorkbench(ScriptWorkbench)

Un típico archivo de módulo
Este es un ejemplo de un archivo de módulo principal, que contiene todo lo que tu módulo hace. Es el archivo Scripts.py invocado por el ejemplo anterior. Puedes tener en él todos tus comandos personalizados.

import FreeCAD, FreeCADGui class ScriptCmd: def Activated(self): # Here your write what your ScriptCmd does... 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)

Importar un nuevo tipo de archivo
Hacer un importador para un nuevo tipo de archivo en FreeCAD es fácil. FreeCAD no considera que importes datos de un documento abierto, sino que simplemente puede abrir directamente el nuevo tipo de archivo. Así que, lo qué tienes que hacer es añadir la nueva extensión de archivo a la lista de las extensiones conocidas de FreeCAD, y escribir el código que leerá el archivo, y crear los objetos de FreeCAD que desees.

Esta línea debe añadirse al archivo InitGui.py para agregar la nueva extensión de archivo a la lista:

FreeCAD.addImportType("Your new File Type (*.ext)","Import_Ext")
 * 1) Assumes Import_Ext.py is the file that has the code for opening and reading .ext files

Y despues en el archivo Import_Ext.py :

def open(filename): doc=App.newDocument # here you do all what is needed with filename, read, classify data, create corresponding FreeCAD objects doc.recompute

Para exportar tu documentno a algún nuevo tipo de archivo, se haría del mismo modo, salvo que usarías:

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

Añadir una linea
Una línea simplemente tiene 2 puntos.

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) add a line element to the document and set its points

Añadir un polígono
Un polígono es simplemente un conjunto de segmentos de línea concetados (una polilínea en AutoCAD). No tiene que ser necesariamente cerrado.

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) create a 3D vector, set its coordinates and add it to the list
 * 1) ... repeat for all nodes
 * 2) Create a polygon object and set its nodes

Añadiendo y quitando un objeto en un grupo
doc=App.activeDocument grp=doc.addObject("App::DocumentObjectGroup", "Group") lin=doc.addObject("Part::Feature", "Line") grp.addObject(lin) # adds the lin object to the group grp grp.removeObject(lin) # removes the lin object from the group grp

Nota: También puedes añadir grupos a otros grupos...

Añadir una malla
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

Añadiendo un arco o un círculo
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

Accediendo y cambiando la representación de un objeto
Cada objeto en un documento de FreeCAD tiene asociado un objeto de representación de la vista, que almacena todos los parámetros que definen la forma en que el objeto aparece, tales como el color, ancho de línea, etc ..

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

Observación de Eventos del ratón en el visor 3D a través de Python
La estructura de Inventor permite añadir uno o más nodos de devolución de llamada al escenario gráfico del visor. De forma predeterminada en FreeCAD se instala un nodo de devolución de llamada por cada visor lo que permite añadir funciones C++ globales o estáticas. En el caso de la pasarela Python se han incluido algunos métodos para hacer uso de esta técnica dentro del código 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.

Ahora, pulsa en algún lugar en la zona del visor 3D y observa los mensajes en la ventana de resultados. Para finalizar la observación sólo llama

v.removeEventCallback("SoMouseButtonEvent",c)

Se soportan los siguientes tipos de eventos:


 * SoEvent -- Todo tipo de eventos
 * SoButtonEvent -- Todos los eventos de los botones del ratón y del teclado
 * SoLocation2Event -- Eventos de movimiento 2D (normalmente movimientos del ratón)
 * SoMotion3Event -- Eventos de movimiento 3D (normalmente del spaceball)
 * SoKeyboardEvent -- Eventos de pulsar y soltar teclas
 * SoMouseButtonEvent -- Eventos de presionar y soltar los botones del ratón
 * SoSpaceballButtonEvent -- Eventos de presionar y soltar los botones del spaceball

La función de Python que se puede registrar con addEventCallback espera un diccionario. Dependiendo del evento observado, el diccionario puede contener diferentes claves.

En todos los eventos existen las siguientes claves:


 * Type -- El nombre del tipo de evento i.e. SoMouseEvent, SoLocation2Event, ...
 * Time -- La hora actual como una cadena de texto
 * Position -- Una dupla de dos enteros, con la posición del ratón
 * ShiftDown -- Un booleano, true si la tecla Shift estaba presionada y false en caso contrario
 * CtrlDown -- Un booleano, true si la tecla Ctrl estaba presionada y false en caso contrario
 * AltDown -- Un booleano, true si la tecla Alt estaba presionada y false en caso contrario

Para los eventos de botones, (tanto del teclado, como del ratón o de un spaceball): Para eventos de teclado: Para eventos de botón de ratón Para eventos de spaceball: Y por último, eventos de movimiento:
 * State -- Una cadena de texto 'UP' si el botón no estaba presionado, 'DOWN' si estaba presionado o 'UNKNOWN' para cualquier otro caso
 * Key -- Un carácter de la tecla presionada
 * Button -- El botón presionado, podría ser BUTTON1, ..., BUTTON5 o ANY
 * Button -- El botón presionado, podría ser BUTTON1, ..., BUTTON7 o ANY
 * Translation -- Una tripla de tres números de coma flotante
 * Rotation -- Una cuádrupla para la rotación, i.e. a tupla de cuatro números de coma flotante

Manipular escenario gráfico en Python
También es posible obtener y cambiar el escenario gráfico en Python, con el módulo 'Pivy' - una pasarela de Python para 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

La API en Python de Pivy está creada utilizando la herramienta de SWIG. En FreeCAD se usan algunos nodos auto-escritos, que no pueden crearse directamente en Python. Sin embargo, es posible crear un nodo por su nombre interno. Se puede crear una instancia del tipo "SoFCSelection" con

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

Añadir y eliminar objetos al/del escenario gráfico
La adición de nuevos nodos al escenario gráfico se puede hacer de esta manera. Ten cuidado de añadir siempre un SoSeparator para contener la geometría, las coordenadas y la información de materiales de un mismo objeto. En el ejemplo siguiente se agrega una línea roja desde (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)

Para quitarlo, simplemente escribe:

sg.removeChild(no)

Añadiendo widgets o complementos personalizados a la interfaz
Puedes crear widgets personalizados con Qt designer, transformarlos es archivos de guión en Python, y luego cargarlos en la interfaz de FreeCAD con PyQt4.

El código de Python producido por el compilador-UI de python (la herramienta que convierte archivos .UI de Qt-designer en código de Python) tiene, en general, este aspecto (es simple, también puedes escribir el código directamente en 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))

Despues, todo lo que necesitas hacer es crear una referencia a la ventana Qt de FreeCAD, insertar un widget personalizado en ella, y "transformar" ese widget en el tuyo con el código UI que acabas de hacer:

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

Añadiendo una pestaña al Combo View
El siguiente código te permite añadir una pestaña al ComboView de FreeCAD, además de las pestañas "Proyecto" y "Tareas". Utiliza también el módulo UIC para cargar un archivo UI directamente en esa pestaña.

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)

Abrir una página web personalizada
import WebGui WebGui.openBrowser("http://www.example.com")

Obtener el contenido HTML de una página web abierta
from PyQt4 import QtGui,QtWebKit a = QtGui.qApp mw = a.activeWindow v = mw.findChild(QtWebKit.QWebFrame) html = unicode(v.toHtml) print html

Lista de componentes de un objeto

 * 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
 * 5) its faces and their surfaces

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

for num in sel[0].Shape.Vertexes:      # Search the XYZ coordinates and displays compt_V+=1 if pas == 0: Vertx.append("X1: "+str(num.Point[0])) Vertx.append("Y1: "+str(num.Point[1])) Vertx.append("Z1: "+str(num.Point[2])) print "X1: "+str(num.Point[0])," Y1: "+str(num.Point[1])," Z1: "+str(num.Point[2]), pas=1 else: Vertx.append("X2: "+str(num.Point[0])) Vertx.append("Y2: "+str(num.Point[1])) Vertx.append("Z2: "+str(num.Point[2])) print " X2: "+str(num.Point[0])," Y2: "+str(num.Point[1])," Z2: "+str(num.Point[2]) pas=0 print "Number of Vertex      : ", compt_V perimetre = 0.0 EdgesLong = []

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 print "Edge",str(compt_E)," > ",str(sel[0].Shape.Edges[compt_E-1].Length)# Displays the "Edge" and its length print "Perimeter of the form : ",perimetre

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)) print "Face",str(compt_F)," > ",sel[0].Shape.Faces[compt_F-1].Area      # Displays 'Face' and its surface print "Surface of the form   : ",sel[0].Shape.Area                          # Displays the total surface of the form

detail