Macros recipes

Object creation

 * [[Image:Macro_makeCube.png|16px]] Macro_makeCube : creates a cube from 4 points

Draw 2D function
Use it to draw a function described by a "equation" [z=F(x)] (Z-X plane) The example done here generate a parabol. Need to be defined : F=variable used in the fonction, X=initial value of x, Nb= Number of step, Z=function express with x ZZ=function express with xx

import FreeCAD, FreeCADGui, Part import math F=800 X=-500 Nb=10 Step=1000/Nb Y=0 for I in range(Nb): XX=X+Step Z=X*X/(4*F) ZZ=XX*XX/(4*F) if I==0: print "Le test est vrai !" nomme=Part.makeLine((X,Y,Z),(XX,Y,ZZ)) WWire=Part.Wire([nomme]) else : print "Le test est 2 !" nomme=Part.makeLine((X,Y,Z),(XX,Y,ZZ)) WWire=Part.Wire([WWire,nomme]) X=XX Part.show(WWire)

Array copy
This macro copies the selected object several times, on an array grid. You can define the number of rows and columns and the distance between them. You need pyqt installed.

import FreeCAD, FreeCADGui, Part from PyQt4 import QtGui,QtCore def proceed: try: u = (int(l1.text),float(l2.text)) v = (int(l3.text),float(l4.text)) except: FreeCAD.Console.PrintError("Wrong input! Only numbers allowed...\n") sel = FreeCADGui.Selection.getSelection if sel: sel = sel[0] name = sel.Name shape = sel.Shape for column in range(u[0]): for row in range(v[0]): if (column != 0) or (row != 0): delta = FreeCAD.Vector(column*u[1],row*v[1],0) newshape = sel.Shape.copy newshape.translate(delta) newobject = FreeCAD.ActiveDocument.addObject("Part::Feature",name) newobject.Shape = newshape else: FreeCAD.Console.PrintError("Error: One object must be selected") hide def hide: dialog.hide dialog = QtGui.QDialog dialog.resize(200,300) dialog.setWindowTitle("Array") la = QtGui.QVBoxLayout(dialog) t1 = QtGui.QLabel("number of columns") la.addWidget(t1) l1 = QtGui.QLineEdit la.addWidget(l1) t2 = QtGui.QLabel("distance between columns") la.addWidget(t2) l2 = QtGui.QLineEdit la.addWidget(l2) t3 = QtGui.QLabel("number of rows") la.addWidget(t3) l3 = QtGui.QLineEdit la.addWidget(l3) t4 = QtGui.QLabel("distance between rows") la.addWidget(t4) l4 = QtGui.QLineEdit la.addWidget(l4) okbox = QtGui.QDialogButtonBox(dialog) okbox.setOrientation(QtCore.Qt.Horizontal) okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) la.addWidget(okbox) QtCore.QObject.connect(okbox, QtCore.SIGNAL("accepted"), proceed) QtCore.QObject.connect(okbox, QtCore.SIGNAL("rejected"), hide) QtCore.QMetaObject.connectSlotsByName(dialog) dialog.show

Flatten wire
This macro flattens draft wires that are not plane to their median Z coordinate.

import FreeCAD obj = FreeCAD.ActiveDocument.ActiveObject z = 0 for p in obj.Points: z += p.z z = z/len(obj.Points) newpoints = [] for p in obj.Points: newppoints.append(FreeCAD.Vector(p.x,p.y,z)) obj.Points = newppoints

Convert Meshes to Parts
This macro converts selected meshes to parts. It has a broad tolerance, so use it only with objects that have no curves otherwise you'll get weird results.

import FreeCAD,FreeCADGui,Mesh,Part,MeshPart for obj in FreeCADGui.Selection.getSelection: if "Mesh" in obj.PropertiesList: faces = [] mesh = obj.Mesh segments = mesh.getPlanes(0.01) # use rather strict tolerance here for i in segments: if len(i) > 0: # a segment can have inner holes wires = MeshPart.wireFromSegment(mesh, i) 		    # we assume that the exterior boundary is that one with the biggest bounding box if len(wires) > 0: ext = None max_length = 0 for i in wires: if i.BoundBox.DiagonalLength > max_length: max_length = i.BoundBox.DiagonalLength ext = i 	       	wires.remove(ext) # all interior wires mark a hole and must reverse their orientation, otherwise Part.Face fails for i in wires: i.reverse # make sure that the exterior wires comes as first in the lsit wires.insert(0, ext) faces.append(Part.Face(wires)) shell=Part.Compound(faces) solid = Part.Solid(Part.Shell(faces)) name = obj.Name FreeCAD.ActiveDocument.removeObject(name) FreeCAD.ActiveDocument.addObject("Part::Feature",name).Shape = solid

Joint wire
This macro allow to find and joint all non connected edge to the closest non connected one using a line. It take a shape matrix in entry ( [shape1,shape2,...]).

def findWires(edges): def verts(shape): return [shape.Vertexes[0].Point,shape.Vertexes[-1].Point] def group(shapes): shapesIn = shapes[:] pointTst = [] pointOut =[] for s in shapesIn : pointTst=pointTst+[s.Vertexes[0].Point] pointTst=pointTst+[s.Vertexes[-1].Point] print pointTst changed = False for s in shapesIn: if len(s.Vertexes) < 2: print "one vertex, its a circle, just add" else: for v in verts(s): twoDot=0 for vv in pointTst: if v == vv: twoDot=twoDot+1 if v==vv and twoDot==2 : changed = True print "found matching vert" break if twoDot<2: print "didn't find any matching vert..." pointOut.append(v) print "Dots non connected", pointOut return(changed,pointOut) def joint(point): for p in range(len(point)/2) : print point deltI=Part.Vertex(100,100,100).Point pos=1 for pp in range(len(point)-1) : print "position:",pp+1 if len(point)-1>1: deltN=(point[0]-point[pp+1]) if deltN.Length<deltI.Length: deltI=deltN pos=pp+1 print "changement",pos else: pos=1 print "points a joindre",point[0],point[pos] if point[0]!=point[pos]: Part.show(Part.makePolygon([point[0],point[pos]])) else: print "WARNING les points ont la meme valeurs " point.pop(0) point.pop(pos-1) point=0 #to have a return normally void return(point) working = True edgeSet = edges result = group(edgeSet) working = result[0] edgeSet = result[1] joint(result[1]) return result[1]

Remove parametric history from a shape
This will remove all parametric associativity from an object, leaving it as a "dumb" shape.

newShape = originalObject.Shape.copy newName = FreeCAD.ActiveDocument.ActiveObject.Name FreeCAD.ActiveDocument.removeObject(newName) newObject = FreeCAD.ActiveDocument.addObject("Part::Feature",newName) newObject.Shape = newShape

3D View operations

 * Macro Rotate View This macro rotates the current view by 90° to the left. Only works if you are in Top view.

Automatic Drawing
This code allow the user to get the view of his object in a drawing with 4 different position(front,top,iso,right). Need some modification to be perfecly effective.

import FreeCAD, Part, Drawing if len(Gui.Selection.getSelectionEx)>1: App.Console.PrintError("Warning: Only the first item is generate") if len(Gui.Selection.getSelectionEx)==0: App.Console.PrintError("Warning: Need to select one item") Piece=Gui.Selection.getSelectionEx[0] App.activeDocument.addObject('Drawing::FeaturePage','AutoDrawing') App.activeDocument.AutoDrawing.Template = App.getResourceDir+'Mod/Drawing/Templates/A3_Landscape.svg' DH=20 DL=30 L=Piece.Object.Shape.BoundBox.XMax H=Piece.Object.Shape.BoundBox.ZMax P=Piece.Object.Shape.BoundBox.YMax Sc=(400-3*DL)/(L+H) Sc2=(250-3*DH)/(P+H) if Sc>Sc2 : Sc=Sc2 TopX=DL+Sc*L FrontX=DL+Sc*L RightX=2*DL+Sc*L IsoX=2*DL+Sc*(L) TopY=DH+Sc*P RightY=DH+P*Sc FrontY=2*DH+Sc*(P+H) IsoY=2*DH+Sc*P print TopX,RightX,TopY,FrontY App.activeDocument.addObject('Drawing::FeatureViewPart','topView') App.activeDocument.topView.Source =Piece.Object App.activeDocument.topView.Direction = (0,0,1) App.activeDocument.topView.Rotation=180 App.activeDocument.topView.X = TopX App.activeDocument.topView.Y = TopY App.activeDocument.topView.ShowHiddenLines=True App.activeDocument.AutoDrawing.addObject(App.activeDocument.topView) App.activeDocument.topView.Scale = Sc App.activeDocument.addObject('Drawing::FeatureViewPart','FrontView') App.activeDocument.FrontView.Source =Piece.Object App.activeDocument.FrontView.Direction = (0,-1,0) App.activeDocument.FrontView.Rotation=90 App.activeDocument.FrontView.Scale = Sc App.activeDocument.FrontView.X = FrontX App.activeDocument.FrontView.Y = FrontY App.activeDocument.FrontView.ShowHiddenLines=True App.activeDocument.AutoDrawing.addObject(App.activeDocument.FrontView) App.activeDocument.addObject('Drawing::FeatureViewPart','RightView') App.activeDocument.RightView.Source =Piece.Object App.activeDocument.RightView.Direction = (1,0,0) App.activeDocument.RightView.Scale = Sc App.activeDocument.RightView.X = RightX App.activeDocument.RightView.Y = RightY App.activeDocument.RightView.ShowHiddenLines=True App.activeDocument.AutoDrawing.addObject(App.activeDocument.RightView) App.activeDocument.addObject('Drawing::FeatureViewPart','IsoView') App.activeDocument.IsoView.Source =Piece.Object App.activeDocument.IsoView.Direction = (1,1,1) App.activeDocument.IsoView.Rotation=60 App.activeDocument.IsoView.Scale = Sc*.6 App.activeDocument.IsoView.X = IsoX App.activeDocument.IsoView.Y = IsoY App.activeDocument.IsoView.ShowHiddenLines=True App.activeDocument.AutoDrawing.addObject(App.activeDocument.IsoView)
 * 1) Create topView
 * 1) Create FrontView
 * 1) Create RightView
 * 1) Create IsotView

Creating and printing corner shapes
This macro is a complete application, it pops up a dialog asking for the dimensions of your corner piece, then creates the object in the document and creates a page view with top, front and lateral views of the piece.

# -*- coding:utf-8 -*- #####################################   # Importation de fonctions externes : #from os import * import FreeCAD, FreeCADGui, Part, Draft, math, MeshPart, Mesh, Drawing from PyQt4 import QtGui,QtCore from FreeCAD import Base App=FreeCAD Gui=FreeCADGui ##################################   # Défnition Class : class Corniere: def __init__(self, obj): obj.addProperty("App::PropertyLength","L1","Corniere","Largeur 1").L1=20.0 obj.addProperty("App::PropertyLength","L2","Corniere","Largeur 2").L2=20.0 obj.addProperty("App::PropertyLength","e1","Corniere","Epaisseur 1").e1=2.0 #obj.addProperty("App::PropertyLength","e2","Corniere","Epaisseur 2").e2=2.0 obj.addProperty("App::PropertyLength","Longueur","Corniere","Longueur").Longueur=200.0 obj.Proxy = self def execute(self, fp): P1=Base.Vector(fp.e1,fp.e1,0) S1=Part.makeBox(fp.L1,fp.L2,fp.Longueur) S2=Part.makeBox(fp.L1-fp.e1,fp.L2-fp.e1,fp.Longueur,P1) fp.Shape=S1.cut(S2) ##################################   # Défnition locale de fonctions : def proceed: QtGui.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) if FreeCAD.ActiveDocument==None: FreeCAD.newDocument("Corniere") oldDocumentObjects=App.ActiveDocument.Objects try: QL1 = float(l1.text) QL2 = float(l2.text) Qe = float(l3.text) QLongueur = float(l4.text) except: FreeCAD.Console.PrintError("Wrong input! Only numbers allowed...\n") Cor=FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Corniere") Corniere(Cor) Cor.ViewObject.Proxy=0 Cor.L1=QL1 Cor.L2=QL2 Cor.e1=Qe Cor.Longueur=QLongueur App.ActiveDocument.recompute Gui.SendMsgToActiveView("ViewFit") QtGui.qApp.restoreOverrideCursor Plan(Cor) dialog.hide def hide: dialog.hide def Plan(obj): ObjetProjete=obj.Shape TailleX=ObjetProjete.BoundBox.XLength TailleY=ObjetProjete.BoundBox.YLength TailleZ=ObjetProjete.BoundBox.ZLength page = App.activeDocument.addObject('Drawing::FeaturePage','Page') page.Template = App.getResourceDir+'Mod/Drawing/Templates/A3_Landscape.svg' vueprofil = App.activeDocument.addObject('Drawing::FeatureViewPart','VueProfil') vueprofil.Source = obj vueprofil.Direction = (0.0,0.0,1.0) vueprofil.Scale = 1.0 vueprofil.X = 50.0 vueprofil.Y = 50.0 page.addObject(vueprofil) vuegauche = App.activeDocument.addObject('Drawing::FeatureViewPart','Vuegauche') vuegauche.Source = obj vuegauche.Direction = (-1.0,0.0,0.0) vuegauche.ShowHiddenLines = True vuegauche.Scale = 1.0 vuegauche.Rotation = 180.0 vuegauche.X = 50.0+TailleX/2+TailleX vuegauche.Y = 50.0 page.addObject(vuegauche) vuedessus = App.activeDocument.addObject('Drawing::FeatureViewPart','Vuedessus') vuedessus.Source = obj vuedessus.Direction = (0.0,-1.0,0.0) vuedessus.ShowHiddenLines = True vuedessus.Scale = 1.0 vuedessus.Rotation = 180.0 vuedessus.X = 50.0+TailleX/2+TailleX vuedessus.Y = 50.0+TailleX/2+TailleY+TailleX page.addObject(vuedessus) vueiso = App.activeDocument.addObject('Drawing::FeatureViewPart','VueIso') vueiso.Source = obj vueiso.Direction = (-1.0,-1.0,0.5) vueiso.Scale = 1.0 vueiso.ShowSmoothLines = True vueiso.X = TailleZ+TailleX/2 vueiso.Y = 7*TailleZ+3*TailleY page.addObject(vueiso) App.activeDocument.recompute PageFile = open(page.PageResult,'r') OutFile = open('temp.svg','w') OutFile.write(PageFile.read) del OutFile,PageFile dialog = QtGui.QDialog dialog.resize(200,200) dialog.setWindowTitle("Corniere") la = QtGui.QVBoxLayout(dialog) e1 = QtGui.QLabel("Dimensions de la corniere") commentFont=QtGui.QFont("Arial",10,True) e1.setFont(commentFont) la.addWidget(e1) t1 = QtGui.QLabel("L1") la.addWidget(t1) l1 = QtGui.QLineEdit l1.setText("20") la.addWidget(l1) t2 = QtGui.QLabel("L2") la.addWidget(t2) l2 = QtGui.QLineEdit l2.setText("20") la.addWidget(l2) t3 = QtGui.QLabel("e") la.addWidget(t3) l3 = QtGui.QLineEdit l3.setText("2") la.addWidget(l3) t4 = QtGui.QLabel("Longueur") la.addWidget(t4) l4 = QtGui.QLineEdit l4.setText("300") la.addWidget(l4) okbox = QtGui.QDialogButtonBox(dialog) okbox.setOrientation(QtCore.Qt.Horizontal) okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) la.addWidget(okbox) QtCore.QObject.connect(okbox, QtCore.SIGNAL("accepted"), proceed) QtCore.QObject.connect(okbox, QtCore.SIGNAL("rejected"), hide) QtCore.QMetaObject.connectSlotsByName(dialog) dialog.show