Macros recipes: Difference between revisions
No edit summary |
|||
Line 1: | Line 1: | ||
This page contains macros to add functionality to your freecad installation |
|||
== Macros == |
|||
=== Object creation === |
=== Object creation === |
||
Line 6: | Line 10: | ||
=== Object transformation === |
=== Object transformation === |
||
* [[Macro ArrayCopy]]: copies the selected object several times, on an array grid |
|||
==== Array copy ==== |
|||
* [[Macro FlattenWire]]: flattens draft wires that are not plane to their median Z coordinate |
|||
* [[Macro MeshToPart]]: converts selected meshes to parts |
|||
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 [http://en.wikipedia.org/wiki/PyQt pyqt] installed. |
|||
* [[Macro JointWire]]: allows to find and joint all non connected edge to the closest non connected one using a line |
|||
* [[Macro Remove parametric history]]: removes all parametric associativity from an object, leaving it as a "dumb" shape |
|||
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 === |
=== 3D View operations === |
||
Line 202: | Line 22: | ||
=== Wizards === |
=== Wizards === |
||
* [[Macro Automatic drawing]]: allows 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 |
|||
==== Automatic Drawing ==== |
|||
* [[Macro Corner shapes wizard]]: 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 |
|||
== How to use? == |
|||
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. |
|||
The above macros can easily be plugged on any FreeCAD installation |
|||
import FreeCAD, Part, Drawing |
|||
* Copy the macro python code from the corresponding macro page |
|||
if len(Gui.Selection.getSelectionEx())>1: |
|||
* Paste it in a blank text document (for example using notepad on windows or gedit on ubuntu) |
|||
App.Console.PrintError("Warning: Only the first item is generate") |
|||
* Save the text file with a .FCMacro extension |
|||
if len(Gui.Selection.getSelectionEx())==0: |
|||
* move the .FCMacro file to the FreeCAD user folder (/home/yourUser/.FreeCAD on unixes, C:\Users\yourUser\Application Data\FreeCAD on windows) |
|||
App.Console.PrintError("Warning: Need to select one item") |
|||
* restart FreeCAD |
|||
Piece=Gui.Selection.getSelectionEx()[0] |
|||
* Open the Macro manager, select your new macro and click "execute" |
|||
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 |
|||
#Create topView |
|||
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 |
|||
#Create FrontView |
|||
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) |
|||
#Create RightView |
|||
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) |
|||
#Create IsotView |
|||
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) |
|||
Additionally, you can also add your new macro to a custom toolbar |
|||
==== Creating and printing corner shapes ==== |
|||
* In FreeCAD, go to Tools -> Customize |
|||
* In the Macros tab, add a new macro, and, if you like, define an icon and a keyboard shortcut |
|||
* In the Toolbars tab, create a new toolbar, and add your macro, taking it from the "Macros" category. |
|||
== Adding new macros to this repository == |
|||
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. |
|||
* Create a new page, beginning its name with "Macro", for example "Macro_My_Excellent_Macro" |
|||
# -*- coding:utf-8 -*- |
|||
* In that page, paste the following text: |
|||
<nowiki>{{Macro|Name=My Excellent Macro|Description=What my excellent macro does|Author=your username}}</nowiki> |
|||
##################################### |
|||
* If you like, upload a .png icon with the exact same name as your macro page (ex. Macro_My_Excellent_Macro.png) |
|||
# Importation de fonctions externes : |
|||
* Add it to the above categories, create a new category if needed |
|||
#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() |
|||
Line 452: | Line 52: | ||
[[Category:Repository]] |
[[Category:Repository]] |
||
[[Category:Macros]] |
[[Category:Macros]] |
||
[[Category:Python Code]] |
Revision as of 18:21, 1 August 2011
This page contains macros to add functionality to your freecad installation
Macros
Object creation
- Macro_makeCube : creates a cube from 4 points
- Macro draw2DFunction: draws a function described by an equation z=F(x)
Object transformation
- Macro ArrayCopy: copies the selected object several times, on an array grid
- Macro FlattenWire: flattens draft wires that are not plane to their median Z coordinate
- Macro MeshToPart: converts selected meshes to parts
- Macro JointWire: allows to find and joint all non connected edge to the closest non connected one using a line
- Macro Remove parametric history: removes all parametric associativity from an object, leaving it as a "dumb" shape
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.
Wizards
- Macro Automatic drawing: allows 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
- Macro Corner shapes wizard: 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
How to use?
The above macros can easily be plugged on any FreeCAD installation
- Copy the macro python code from the corresponding macro page
- Paste it in a blank text document (for example using notepad on windows or gedit on ubuntu)
- Save the text file with a .FCMacro extension
- move the .FCMacro file to the FreeCAD user folder (/home/yourUser/.FreeCAD on unixes, C:\Users\yourUser\Application Data\FreeCAD on windows)
- restart FreeCAD
- Open the Macro manager, select your new macro and click "execute"
Additionally, you can also add your new macro to a custom toolbar
- In FreeCAD, go to Tools -> Customize
- In the Macros tab, add a new macro, and, if you like, define an icon and a keyboard shortcut
- In the Toolbars tab, create a new toolbar, and add your macro, taking it from the "Macros" category.
Adding new macros to this repository
- Create a new page, beginning its name with "Macro", for example "Macro_My_Excellent_Macro"
- In that page, paste the following text:
{{Macro|Name=My Excellent Macro|Description=What my excellent macro does|Author=your username}}
- If you like, upload a .png icon with the exact same name as your macro page (ex. Macro_My_Excellent_Macro.png)
- Add it to the above categories, create a new category if needed