Guionización de datos topológicos
Introducción
Aquí le explicaremos cómo controlar el Entorno de Trabajo de Pieza directamente desde el intérprete de Python de FreeCAD o desde cualquier script externo. Asegúrese de consultar la sección Guionizado y las páginas Conceptos básicos de programación en FreeCAD, si necesita más información sobre cómo funciona la programación en Python en FreeCAD. Si es nuevo en el uso de Python, le recomendamos leer primero la Introducción a Python.
Ver también
Diagrama de clase
Esta es una descripción general de las clases más importantes del módulo Pieza (Part): Unified Modeling Language (UML) (Lenguaje Unificado de Modelado, UML): Clases de Python del módulo Part
Geometría
Los objetos geométricos son los bloques de construcción de todos los objetos topológicos:
- Geom Clase base de los objetos geométricos.
- Línea Una línea recta en 3D, definida por un punto inicial y un punto final.
- Círculo Círculo o segmento de círculo definido por un punto central y un punto inicial y final.
- Etc.
Topología
Los siguientes tipos de datos topológicos están disponibles:
- Compuesto Un grupo de cualquier tipo de objetos topológicos.
- Sólido compuesto Un sólido compuesto es un conjunto de sólidos conectados por sus caras. Amplía las nociones de ALAMBRE y CASCO a los sólidos.
- Sólido Una parte del espacio limitada por cáscaras. Es tridimensional.
- Cáscara Conjunto de caras conectadas por sus aristas. Una cáscara puede ser abierta o cerrada.
- En 2D es parte de un plano; en 3D es parte de una superficie. Su geometría está limitada (recortada) por los contornos. Es bidimensional.
- Alambre Conjunto de aristas conectadas por sus vértices. Puede ser un contorno abierto o cerrado dependiendo de si las aristas están unidas o no.
- Arista Elemento topológico que corresponde a una curva restringida. Una arista está generalmente limitada por los vértices. Tiene una dimensión.
- Vértice Elemento topológico que corresponde a un punto. Tiene una dimensión cero.
- Forma Término genérico que abarca todo lo anterior.
Ejemplo: Crear una topología simple
Ahora crearemos una topología construyéndola a partir de una geometría más sencilla. Como caso de estudio utilizaremos una pieza como la que se ve en la imagen que consta de cuatro vértices, dos arcos y dos líneas.
Crear geometría
Primero creamos las distintas partes geométricas de este cable. Asegurándonos de que las partes que tienen que ser conectadas más tarde comparten los mismos vértices.
Así que primero creamos los puntos:
import FreeCAD as App
import Part
V1 = App.Vector(0, 10, 0)
V2 = App.Vector(30, 10, 0)
V3 = App.Vector(30, -10, 0)
V4 = App.Vector(0, -10, 0)
Arco
Para cada arco necesitamos un punto de ayuda:
VC1 = App.Vector(-10, 0, 0)
C1 = Part.Arc(V1, VC1, V4)
VC2 = App.Vector(40, 0, 0)
C2 = Part.Arc(V2, VC2, V3)
Línea
Los segmentos de línea se pueden crear a partir de dos puntos:
L1 = Part.LineSegment(V1, V2)
L2 = Part.LineSegment(V3, V4)
Poniendo todo junto
El último paso es poner los elementos base de la geometría juntos y formar una forma topológica:
S1 = Part.Shape([C1, L1, C2, L2])
Crear un prisma
Ahora extruir el hilo en una dirección y crear una forma 3D real:
W = Part.Wire(S1.Edges)
P = W.extrude(App.Vector(0, 0, 10))
Mostrar todo
Part.show(P)
Crear formas básicas
Puede crear fácilmente objetos topológicos básicos con los métodos make...() del módulo Pieza:
b = Part.makeBox(100, 100, 100)
Part.show(b)
Algunos métodos disponibles make...():
makeBox(l, w, h, [p, d]): Hace una caja situada en p y apuntando a la dirección d con las dimensiones (l,w,h).makeCircle(radius): Hace un círculo con un radio determinado.makeCone(radius1, radius2, height)Hace un cono con los radios y la altura dados.makeCylinder(radius, height): Hace un cilindro con un radio y altura dados.makeLine((x1, y1, z1), (x2, y2, z2))Hace una línea desde dos puntos.makePlane(length, width): Hace un plano con longitud y anchura.makePolygon(list): Hace un polígono a partir de una lista de puntos.makeSphere(radius): Hace una esfera con un radio determinado.makeTorus(radius1, radius2): Hace un toroide con los radios dados.
Consulte la página Part API o esta otra: autogenerated Python Part API documentation, para obtener una lista completa de los métodos disponibles del módulo Part.
Módulos de importación
Primero necesitamos importar los módulos FreeCAD y Part para poder usar su contenido en Python:
import FreeCAD as App
import Part
Crear un vector
Los Vectores son una de las piezas de información más importantes cuando se van a construir formas. Suelen contener tres números (pero no necesariamente siempre): las coordenadas cartesianas X, Y y Z. Se crea un vector así:
myVector = App.Vector(3, 2, 0)
Hemos creado un vector en las coordenadas X = 3, Y = 2, Z = 0. En el módulo de la pieza, los vectores se utilizan en todas partes. Las formas de la pieza también utilizan otro tipo de representación de puntos llamada Vértice que es simplemente un contenedor para un vector. Se accede al vector de un vértice así:
myVertex = myShape.Vertexes[0]
print(myVertex.Point)
> Vector (3, 2, 0)
Crear un borde
Un borde no es más que una línea con dos vértices:
edge = Part.makeLine((0, 0, 0), (10, 0, 0))
edge.Vertexes
> [<Vertex object at 01877430>, <Vertex object at 014888E0>]
Nota: También se puede crear un borde pasando dos vectores:
vec1 = App.Vector(0, 0, 0)
vec2 = App.Vector(10, 0, 0)
line = Part.LineSegment(vec1, vec2)
edge = line.toShape()
Puedes encontrar la longitud y el centro de un borde así:
edge.Length
> 10.0
edge.CenterOfMass
> Vector (5, 0, 0)
Poniendo la forma en la pantalla
Hasta ahora hemos creado un objeto de borde, pero no aparece en ninguna parte de la pantalla. Esto se debe a que la escena 3D de FreeCAD sólo muestra lo que tú le dices que muestre. Para ello, utilizamos este sencillo método:
Part.show(edge)
La función mostrar crea un objeto en nuestro documento de FreeCAD y le asigna nuestra forma "borde". Utilízala siempre que sea el momento de mostrar tu creación en pantalla.
Crear un hilo
Un hilo es una línea de varias aristas y puede crearse a partir de una lista de aristas o incluso de una lista de hilos:
edge1 = Part.makeLine((0, 0, 0), (10, 0, 0))
edge2 = Part.makeLine((10, 0, 0), (10, 10, 0))
wire1 = Part.Wire([edge1, edge2])
edge3 = Part.makeLine((10, 10, 0), (0, 10, 0))
edge4 = Part.makeLine((0, 10, 0), (0, 0, 0))
wire2 = Part.Wire([edge3, edge4])
wire3 = Part.Wire([wire1, wire2])
wire3.Edges
> [<Edge object at 016695F8>, <Edge object at 0197AED8>, <Edge object at 01828B20>, <Edge object at 0190A788>]
Part.show(wire3)
Part.show(wire3) mostrará los 4 bordes que componen nuestro cable. Otra información útil se puede recuperar fácilmente:
wire3.Length
> 40.0
wire3.CenterOfMass
> Vector (5, 5, 0)
wire3.isClosed()
> True
wire2.isClosed()
> False
Crear una cara
Solo serán válidas las caras creadas a partir de cables cerrados. En este ejemplo, wire3 es un cable cerrado, pero wire2 no lo es (ver más arriba):
face = Part.Face(wire3)
face.Area
> 99.99999999999999
face.CenterOfMass
> Vector (5, 5, 0)
face.Length
> 40.0
face.isValid()
> True
sface = Part.Face(wire2)
sface.isValid()
> False
Solo las caras tendrán un área definida; los cables y los bordes no.
Crear un círculo
Se puede crear un círculo así:
circle = Part.makeCircle(10)
circle.Curve
> Circle (Radius : 10, Position : (0, 0, 0), Direction : (0, 0, 1))
Si quieres crearlo en una cierta posición y con una cierta dirección:
ccircle = Part.makeCircle(10, App.Vector(10, 0, 0), App.Vector(1, 0, 0))
ccircle.Curve
> Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
ccircle se creará a una distancia de 10 del origen X y estará orientado hacia afuera a lo largo del eje X. Nota: makeCircle() solo acepta App.Vector() para los parámetros de posición y normal, no tuplas. También puede crear parte del círculo especificando un ángulo inicial y un ángulo final:
from math import pi
arc1 = Part.makeCircle(10, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 0, 180)
arc2 = Part.makeCircle(10, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 180, 360)
Los ángulos deben proporcionarse en grados. Si tiene radianes, simplemente conviértalos usando la fórmula: grados = radians * 180/pi o usando el módulo math de Python:
import math
degrees = math.degrees(radians)
Crear un arco a lo largo de los puntos
Lamentablemente, no existe la función makeArc(), pero sí la función Part.Arc() para crear un arco que pase por tres puntos. Esta función crea un objeto arco que une el punto inicial con el punto final a través del punto medio. Para obtener un objeto de borde, se debe llamar a la función toShape() del objeto arco, al igual que cuando se usa Part.LineSegment en lugar de Part.makeLine.
arc = Part.Arc(App.Vector(0, 0, 0), App.Vector(0, 5, 0), App.Vector(5, 5, 0))
arc
> <Arc object>
arc_edge = arc.toShape()
Part.show(arc_edge)
Arc() solo acepta App.Vector() para puntos y no para tuplas. También puede obtener un arco usando una porción de un círculo:
from math import pi
circle = Part.Circle(App.Vector(0, 0, 0), App.Vector(0, 0, 1), 10)
arc = Part.Arc(circle,0,pi)
Los arcos son bordes válidos, al igual que las líneas, por lo que también se pueden utilizar en cables.
Crear un polígono
Un polígono es simplemente un cable con múltiples aristas rectas. La función makePolygon() toma una lista de puntos y crea un cable a través de esos puntos:
lshape_wire = Part.makePolygon([App.Vector(0, 5, 0), App.Vector(0, 0, 0), App.Vector(5, 0, 0)])
Crear una curva de Bézier
Las curvas de Bézier se utilizan para modelar curvas suaves mediante una serie de polos (puntos) y ponderaciones opcionales. La siguiente función crea una Part.BezierCurve() a partir de una serie de puntos FreeCAD.Vector(). Nota: al obtener y establecer un polo o ponderación, los índices comienzan en 1, no en 0.
def makeBCurveEdge(Points):
geomCurve = Part.BezierCurve()
geomCurve.setPoles(Points)
edge = Part.Edge(geomCurve)
return(edge)
Crear un plano
Un plano es una superficie rectangular plana. El método utilizado para crearlo es makePlane(length, width, [start_pnt, dir_normal]). Por defecto, start_pnt = Vector(0, 0, 0) y dir_normal = Vector(0, 0, 1). Si se utiliza: dir_normal = Vector(0, 0, 1), el plano se creará orientado en la dirección positiva del eje Z, mientras que si se utiliza: dir_normal = Vector(1, 0, 0), el plano se creará orientado en la dirección positiva del eje X.
plane = Part.makePlane(2, 2)
plane
> <Face object at 028AF990>
plane = Part.makePlane(2, 2, App.Vector(3, 0, 0), App.Vector(0, 1, 0))
plane.BoundBox
> BoundBox (3, 0, 0, 5, 0, 2)
BoundBox es un cuboide que encierra el plano con una diagonal que comienza en (3, 0, 0) y termina en (5, 0, 2). Aquí, el grosor de BoundBox a lo largo del eje Y es cero, ya que nuestra figura es totalmente plana.
Nota: makePlane() solo acepta App.Vector() para start_pnt y dir_normal y no tuplas.
Crear una elipse
Existen varias formas de crear una elipse:
Part.Ellipse()
Crea una elipse con radio mayor de 2 y radio menor de 1 con centro en (0, 0, 0).
Part.Ellipse(Ellipse)
Crea una copia de la elipse dada
Part.Ellipse(S1, S2, Center)
Crea una elipse centrada en el punto Centro, donde el plano de la elipse está definido por Centro, S1 y S2, su eje mayor está definido por Centro y S1, su radio mayor es la distancia entre el Centro y S1, y su radio menor es la distancia entre S2 y el eje mayor.
Part.Ellipse(Center, MajorRadius, MinorRadius)
Crea una elipse con radios mayor y menor MajorRadius y MinorRadius, respectivamente, ubicada en el plano definido por el punto Center y la normal (0,0,1)
eli = Part.Ellipse(App.Vector(10, 0, 0), App.Vector(0, 5, 0), App.Vector(0, 0, 0))
Part.show(eli.toShape())
En el código anterior hemos pasado S1, S2 y Center. De forma similar a Arc, Ellipse crea un objeto elíptico, no un borde, por lo que necesitamos convertirlo en un borde usando toShape() para su visualización.
Nota: Ellipse() solo acepta App.Vector() para puntos y no para tuplas.
eli = Part.Ellipse(App.Vector(0, 0, 0), 10, 5)
Part.show(eli.toShape())
Para el constructor de la elipse anterior, hemos pasado centro, radio mayor y radio menor.
Crear un toroide
Usando makeTorus(radius1, radius2, [pnt, dir, angle1, angle2, angle]). Por defecto, pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1), angle1 = 0, angle2 = 360 y angle = 360. Consideremos un toroide como un círculo pequeño cuyo centro se desplaza a lo largo de un círculo grande de tal forma que el plano del círculo siempre es perpendicular a la trayectoria del círculo grande. Radius1 es el radio del círculo grande, radius2 es el radio del círculo pequeño, pnt es el centro del toroide y dir es la dirección normal. angle1 y angle2 son ángulos en grados para el círculo pequeño; el último parámetro angle es para hacer una sección del toro:
torus = Part.makeTorus(10, 2)
El código de arriba creará un toroide con diámetro de 20 (radio de 10) y espesor de 4 (radio del círculo pequeño de 2).
tor=Part.makeTorus(10, 5, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 0, 180)
El código anterior creará una porción del toroide.
tor=Part.makeTorus(10, 5, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 0, 360, 180)
El código anterior creará un semitoroide; solo se modifica el último parámetro, es decir, los ángulos restantes conservan sus valores predeterminados. Al introducir el ángulo 180, se creará un toroide de 0 a 180 grados, o sea, medio toroide.
Crear una caja o cuboide
Usando makeBox(length, width, height, [pnt, dir]). Por defecto, pnt = Vector(0, 0, 0) y dir = Vector(0, 0, 1).
box = Part.makeBox(10, 10, 10)
len(box.Vertexes)
> 8
Crear una esfera
Usando makeSphere(radius, [pnt, dir, angle1, angle2, angle3]). Por defecto, pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1), angle1 = -90, angle2 = 90 y angle3 = 360. Angle1 y angle2 son el mínimo y máximo vertical de la esfera, angle3 es el diámetro de la esfera.
sphere = Part.makeSphere(10)
hemisphere = Part.makeSphere(10, App.Vector(0, 0, 0), App.Vector(0, 0, 1), -90, 90, 180)
Crear un cilindro
Usando makeCylinder(radius, height, [pnt, dir, angle]). Por defecto pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1) y angle = 360.
cylinder = Part.makeCylinder(5, 20)
partCylinder = Part.makeCylinder(5, 20, App.Vector(20, 0, 0), App.Vector(0, 0, 1), 180)
Crear un cono
Using makeCone(radius1, radius2, height, [pnt, dir, angle]). By default pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1) and angle = 360.
cone = Part.makeCone(10, 0, 20)
semicone = Part.makeCone(10, 0, 20, App.Vector(20, 0, 0), App.Vector(0, 0, 1), 180)
Modificar formas
Hay varias formas de modificar figuras. Algunas son operaciones de transformación sencillas, como mover o rotar figuras; otras son más complejas, como unir o restar una figura de otra.
Operaciones de transformación
Traslación de una forma
Trasladar es el acto de mover una figura de un lugar a otro. Cualquier figura (arista, cara, cubo, etc.) se puede trasladar de la misma manera:
myShape = Part.makeBox(2, 2, 2)
myShape.translate(App.Vector(2, 0, 0))
Esto moverá nuestra figura "myShape" 2 unidades en la dirección X.
Rotación de una forma
Para rotar una figura, es necesario especificar el centro de rotación, el eje y el ángulo de rotación:
myShape.rotate(App.Vector(0, 0, 0),App.Vector(0, 0, 1), 180)
El código de arriba rotará la forma 180 grados alrededor del eje Z.
Transformaciones matriciales
Una matriz es una forma muy práctica de almacenar transformaciones en el mundo 3D. En una sola matriz, se pueden establecer valores de traslación, rotación y escala que se aplicarán a un objeto. Por ejemplo:
myMat = App.Matrix()
myMat.move(App.Vector(2, 0, 0))
myMat.rotateZ(math.pi/2)
Nota: Las matrices de FreeCAD funcionan en radianes. Además, casi todas las operaciones matriciales que aceptan un vector también pueden aceptar tres números, por lo que estas dos líneas hacen lo mismo:
myMat.move(2, 0, 0)
myMat.move(App.Vector(2, 0, 0))
Una vez definida nuestra matriz, podemos aplicarla a nuestra forma. FreeCAD ofrece dos métodos para hacerlo: transformShape() y transformGeometry(). La diferencia radica en que, con el primero, se garantiza que no se producirán deformaciones (véase Escalado de una forma más abajo). Podemos aplicar nuestra transformación de la siguiente manera:
myShape.transformShape(myMat)
o
myShape.transformGeometry(myMat)
Escalar una forma
Escalar una forma es una operación más peligrosa porque, a diferencia de la traslación o la rotación, escalar de forma no uniforme (con diferentes valores para X, Y y Z) puede modificar la estructura de la figura. Por ejemplo, escalar un círculo con un valor mayor horizontalmente que verticalmente lo transformará en una elipse, que se comporta matemáticamente de forma muy diferente. Para escalar, no podemos usar transformShape(), debemos usar transformGeometry():
myMat = App.Matrix()
myMat.scale(2, 1, 1)
myShape=myShape.transformGeometry(myMat)
Operaciones Booleanas
Diferencia
En FreeCAD, restar una forma de otra se llama "cortar" y se hace de la siguiente manera:
cylinder = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
sphere = Part.makeSphere(5, App.Vector(5, 0, 0))
diff = cylinder.cut(sphere)
Intersección
The same way, the intersection between two shapes is called "common" and is done this way:
cylinder1 = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cylinder2 = Part.makeCylinder(3, 10, App.Vector(5, 0, -5), App.Vector(0, 0, 1))
common = cylinder1.common(cylinder2)
Unión
La unión se llama "fusionar" y funciona de la misma manera:
cylinder1 = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cylinder2 = Part.makeCylinder(3, 10, App.Vector(5, 0, -5), App.Vector(0, 0, 1))
fuse = cylinder1.fuse(cylinder2)
Sección
Una "sección" es la intersección entre una figura sólida y una figura plana. Devuelve una curva de intersección, una curva compuesta formada por aristas.
cylinder1 = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cylinder2 = Part.makeCylinder(3, 10, App.Vector(5, 0, -5), App.Vector(0, 0, 1))
section = cylinder1.section(cylinder2)
section.Wires
> []
section.Edges
> [<Edge object at 0D87CFE8>, <Edge object at 019564F8>, <Edge object at 0D998458>,
<Edge object at 0D86DE18>, <Edge object at 0D9B8E80>, <Edge object at 012A3640>,
<Edge object at 0D8F4BB0>]
Extrusión
La extrusión es el acto de "empujar" una forma plana en una dirección determinada, dando como resultado un cuerpo sólido. Piense en un círculo que se convierte en un tubo al "empujarlo hacia afuera":
circle = Part.makeCircle(10)
tube = circle.extrude(App.Vector(0, 0, 2))
Si tu círculo está hueco, obtendrás un tubo hueco. Si tu círculo es en realidad un disco con una cara rellena, obtendrás un cilindro sólido.
wire = Part.Wire(circle)
disc = Part.Face(wire)
cylinder = disc.extrude(App.Vector(0, 0, 2))
Explorar formas
Puede explorar fácilmente la estructura de datos topológica:
import Part
b = Part.makeBox(100, 100, 100)
b.Wires
w = b.Wires[0]
w
w.Wires
w.Vertexes
Part.show(w)
w.Edges
e = w.Edges[0]
e.Vertexes
v = e.Vertexes[0]
v.Point
Al escribir las líneas anteriores en el intérprete de Python, adquirirá la comprensión de la estructura de los objetos Part. Aquí, nuestro comando makeBox() creó una forma sólida. Este sólido, como todos los sólidos Part, contiene caras. Las caras siempre contienen cables, que son listas de aristas que las delimitan. Cada cara tiene al menos un cable cerrado (puede tener más si la cara tiene un agujero). En el cable, podemos ver cada arista por separado, y dentro de cada arista, podemos ver los vértices. Las aristas rectas tienen solo dos vértices, obviamente.
Análisis de aristas
En el caso de una arista, que es una curva arbitraria, lo más probable es que desee realizar una discretización. En FreeCAD, las aristas se parametrizan por su longitud. Esto significa que puede recorrer una arista/curva a lo largo de su longitud:
import Part
box = Part.makeBox(100, 100, 100)
anEdge = box.Edges[0]
print(anEdge.Length)
Ahora puede acceder a muchas propiedades de la arista utilizando su longitud como posición. Esto significa que si esta mide 100 mm, la posición inicial es 0 y la posición final es 100.
anEdge.tangentAt(0.0) # tangent direction at the beginning
anEdge.valueAt(0.0) # Point at the beginning
anEdge.valueAt(100.0) # Point at the end of the edge
anEdge.derivative1At(50.0) # first derivative of the curve in the middle
anEdge.derivative2At(50.0) # second derivative of the curve in the middle
anEdge.derivative3At(50.0) # third derivative of the curve in the middle
anEdge.centerOfCurvatureAt(50) # center of the curvature for that position
anEdge.curvatureAt(50.0) # the curvature
anEdge.normalAt(50) # normal vector at that position (if defined)
Usando la selección
A continuación, veremos cómo podemos utilizar una selección realizada por el usuario en el visor. En primer lugar, creamos un cuadro y lo mostramos en el visor.
import Part
Part.show(Part.makeBox(100, 100, 100))
Gui.SendMsgToActiveView("ViewFit")
Ahora seleccione algunas caras o aristas. Con este script puede iterar sobre todos los objetos seleccionados y sus subelementos:
for o in Gui.Selection.getSelectionEx():
print(o.ObjectName)
for s in o.SubElementNames:
print("name: ", s)
for s in o.SubObjects:
print("object: ", s)
Selecciona algunas aristas y este archivo de guión calculará la longitud:
length = 0.0
for o in Gui.Selection.getSelectionEx():
for s in o.SubObjects:
length += s.Length
print("Length of the selected edges: ", length)
Ejemplo: La botella OCC
Un ejemplo típico, que se encuentra en la página web de tecnología OpenCasCade [1], es cómo construir una botella. Este también es un buen ejercicio para FreeCAD. De hecho, si sigue nuestro ejemplo a continuación y la página de OCC simultáneamente, verá lo bien que se implementan las estructuras de OCC en FreeCAD. El script está incluido en la instalación de FreeCAD (dentro de la carpeta Mod/Part) y se puede llamar desde el intérprete de Python escribiendo:
import Part
import MakeBottle
bottle = MakeBottle.makeBottle()
Part.show(bottle)
El guión
Para este tutorial, utilizaremos una versión reducida del script. En esta versión, la botella no estará ahuecada y el cuello no tendrá rosca.
import FreeCAD as App
import Part, math
def makeBottleTut(myWidth = 50.0, myHeight = 70.0, myThickness = 30.0):
aPnt1=App.Vector(-myWidth / 2., 0, 0)
aPnt2=App.Vector(-myWidth / 2., -myThickness / 4., 0)
aPnt3=App.Vector(0, -myThickness / 2., 0)
aPnt4=App.Vector(myWidth / 2., -myThickness / 4., 0)
aPnt5=App.Vector(myWidth / 2., 0, 0)
aArcOfCircle = Part.Arc(aPnt2, aPnt3, aPnt4)
aSegment1=Part.LineSegment(aPnt1, aPnt2)
aSegment2=Part.LineSegment(aPnt4, aPnt5)
aEdge1=aSegment1.toShape()
aEdge2=aArcOfCircle.toShape()
aEdge3=aSegment2.toShape()
aWire=Part.Wire([aEdge1, aEdge2, aEdge3])
aTrsf=App.Matrix()
aTrsf.rotateZ(math.pi) # rotate around the z-axis
aMirroredWire=aWire.copy()
aMirroredWire.transformShape(aTrsf)
myWireProfile=Part.Wire([aWire, aMirroredWire])
myFaceProfile=Part.Face(myWireProfile)
aPrismVec=App.Vector(0, 0, myHeight)
myBody=myFaceProfile.extrude(aPrismVec)
myBody=myBody.makeFillet(myThickness / 12.0, myBody.Edges)
neckLocation=App.Vector(0, 0, myHeight)
neckNormal=App.Vector(0, 0, 1)
myNeckRadius = myThickness / 4.
myNeckHeight = myHeight / 10.
myNeck = Part.makeCylinder(myNeckRadius, myNeckHeight, neckLocation, neckNormal)
myBody = myBody.fuse(myNeck)
return myBody
el = makeBottleTut()
Part.show(el)
Explicación detallada
import FreeCAD as App
import Part, math
Por supuesto, necesitaremos los módulos FreeCAD e Part.
def makeBottleTut(myWidth = 50.0, myHeight = 70.0, myThickness = 30.0):
aPnt1=App.Vector(-myWidth / 2., 0, 0)
aPnt2=App.Vector(-myWidth / 2., -myThickness / 4., 0)
aPnt3=App.Vector(0, -myThickness / 2., 0)
aPnt4=App.Vector(myWidth / 2., -myThickness / 4., 0)
aPnt5=App.Vector(myWidth / 2., 0, 0)
Aquí definimos nuestra función makeBottleTut. Esta función puede llamarse sin argumentos, como hicimos anteriormente, en cuyo caso se usarán los valores predeterminados para el ancho, la altura y el grosor. A continuación, definimos un par de puntos que se usarán para construir nuestro perfil base.
...
aArcOfCircle = Part.Arc(aPnt2, aPnt3, aPnt4)
aSegment1=Part.LineSegment(aPnt1, aPnt2)
aSegment2=Part.LineSegment(aPnt4, aPnt5)
Aquí definimos la geometría: un arco, formado por tres puntos, y dos segmentos de línea, formados por dos puntos.
...
aEdge1=aSegment1.toShape()
aEdge2=aArcOfCircle.toShape()
aEdge3=aSegment2.toShape()
aWire=Part.Wire([aEdge1, aEdge2, aEdge3])
¿Recuerda la diferencia entre geometría y figuras? Aquí construimos figuras a partir de nuestra geometría básica. Tres aristas (rectas o curvas), y luego un alambre formado por esas tres aristas.
...
aTrsf=App.Matrix()
aTrsf.rotateZ(math.pi) # rotate around the z-axis
aMirroredWire=aWire.copy()
aMirroredWire.transformShape(aTrsf)
myWireProfile=Part.Wire([aWire, aMirroredWire])
Hasta ahora solo hemos construido la mitad del perfil. En lugar de construir el perfil completo de la misma manera, podemos simplemente reflejar lo que hicimos y unir ambas mitades. Primero creamos una matriz. Una matriz es una forma muy común de aplicar transformaciones a objetos en el mundo 3D, ya que puede contener en una sola estructura todas las transformaciones básicas que pueden experimentar los objetos 3D (mover, rotar y escalar). Después de crear la matriz, la reflejamos, luego creamos una copia de nuestro alambre y le aplicamos la matriz de transformación. Ahora tenemos dos alambres, y podemos crear un tercer alambre a partir de ellos, ya que los alambres son en realidad listas de aristas.
...
myFaceProfile=Part.Face(myWireProfile)
aPrismVec=App.Vector(0, 0, myHeight)
myBody=myFaceProfile.extrude(aPrismVec)
myBody=myBody.makeFillet(myThickness / 12.0, myBody.Edges)
Ahora que tenemos un alambre cerrado, podemos convertirlo en una cara. Una vez que tenemos una cara, podemos extruirla. Al hacerlo, creamos un sólido. Luego, le aplicamos un pequeño redondeo a nuestro objeto porque nos importa el buen diseño, ¿verdad?
...
neckLocation=App.Vector(0, 0, myHeight)
neckNormal=App.Vector(0, 0, 1)
myNeckRadius = myThickness / 4.
myNeckHeight = myHeight / 10.
myNeck = Part.makeCylinder(myNeckRadius, myNeckHeight, neckLocation, neckNormal)
En este punto, el cuerpo de nuestra botella está hecho, pero aún necesitamos crear el cuello. Así que creamos un nuevo sólido, con forma de cilindro.
...
myBody = myBody.fuse(myNeck)
El mecanismo de fusión es muy potente. Se encargará de pegar lo que sea necesario y de retirar las piezas que deban retirarse.
...
return myBody
Luego, devolvemos nuestra parte sólida como resultado de nuestra función.
el = makeBottleTut()
Part.show(el)
Finalmente, llamamos a la función para crear la pieza y luego hacerla visible.
Ejemplo: Caja perforada
Aquí tiene un ejemplo completo de cómo construir una caja perforada.
La construcción se realiza lado por lado. Una vez terminado el cubo, se ahueca cortando un cilindro a través de él.
import FreeCAD as App
import Part, math
size = 10
poly = Part.makePolygon([(0, 0, 0), (size, 0, 0), (size, 0, size), (0, 0, size), (0, 0, 0)])
face1 = Part.Face(poly)
face2 = Part.Face(poly)
face3 = Part.Face(poly)
face4 = Part.Face(poly)
face5 = Part.Face(poly)
face6 = Part.Face(poly)
myMat = App.Matrix()
myMat.rotateZ(math.pi / 2)
face2.transformShape(myMat)
face2.translate(App.Vector(size, 0, 0))
myMat.rotateZ(math.pi / 2)
face3.transformShape(myMat)
face3.translate(App.Vector(size, size, 0))
myMat.rotateZ(math.pi / 2)
face4.transformShape(myMat)
face4.translate(App.Vector(0, size, 0))
myMat = App.Matrix()
myMat.rotateX(-math.pi / 2)
face5.transformShape(myMat)
face6.transformShape(myMat)
face6.translate(App.Vector(0, 0, size))
myShell = Part.makeShell([face1, face2, face3, face4, face5, face6])
mySolid = Part.makeSolid(myShell)
myCyl = Part.makeCylinder(2, 20)
myCyl.translate(App.Vector(size / 2, size / 2, 0))
cut_part = mySolid.cut(myCyl)
Part.show(cut_part)
Cargando y guardando
Hay varias maneras de guardar su trabajo. Puede guarda su documento de FreeCAD, por supuesto, pero también puede guardar objetos Part directamente en formatos CAD comunes, como BREP, IGS, STEP y STL.
Guardar una forma en un archivo es fácil. Hay dos métodos: exportBrep(), exportIges(), exportStep() e exportStl(), disponibles para todos los objetos de forma. Entonces, haciendo:
import Part
s = Part.makeBox(10, 10, 10)
s.exportStep("test.stp")
Guardará nuestra caja en un archivo STEP. Para cargar un archivo BREP, IGES o STEP:
import Part
s = Part.Shape()
s.read("test.stp")
Para convertir un archivo STEP a un archivo IGS:
import Part
s = Part.Shape()
s.read("file.stp") # incoming file igs, stp, stl, brep
s.exportIges("file.igs") # outbound file igs
- FreeCAD scripting: Python, Introduction to Python, Python scripting tutorial, FreeCAD Scripting Basics
- Modules: Builtin modules, Units, Quantity
- Workbenches: Workbench creation, Gui Commands, Commands, Installing more workbenches
- Meshes and Parts: Mesh Scripting, Topological data scripting, Mesh to Part, PythonOCC
- Parametric objects: Scripted objects, Viewproviders (Custom icon in tree view)
- Scenegraph: Coin (Inventor) scenegraph, Pivy
- Graphical interface: Interface creation, Interface creation completely in Python (1, 2, 3, 4, 5), PySide, PySide examples beginner, intermediate, advanced
- Macros: Macros, How to install macros
- Embedding: Embedding FreeCAD, Embedding FreeCADGui
- Other: Expressions, Code snippets, Line drawing function, FreeCAD vector math library (deprecated)
- Hubs: User hub, Power users hub, Developer hub


