Macro Unfold Box
Beschreibung |
---|
Das Makro erlaubt es, die Oberflächen einer Box beliebiger Form zu entfalten und sie auf einer Seite zu zeichnen. This macro must be upgraded cause error indentation and space mixed with tabulation Versionsmakro : 1.0 Datum der letzten Änderung : 2013-09-20 Herunterladen : ToolBar Icon Autor: Hervé B. |
Autor |
Hervé B. |
Herunterladen |
ToolBar Icon |
Links |
Makros Rezepte Wie installiere ich Makros So passen Sie Symbolleisten an |
Macro-Version |
1.0 |
Datum der letzten Änderung |
2013-09-20 |
FreeCAD-Version(s) |
Standardverknüpfung |
None |
Siehe auch |
None |
Beschreibung
Das Makro erlaubt es, die Oberflächen einer Box beliebiger Form zu entfalten und sie auf einer Seite zu zeichnen.
Macro_unfoldBox
Installation
Kopieren Sie die Codedatei des Makros in das Verzeichnis:
- 'Linux & Mac' : $ home/.FreeCad/Mod/UnfoldBox.
- Windows: C:\Programme\FreeCAD0.13
Vorlagen hinzufügen: A3_Landscape_Empty.svg A3_Landscape.svg A4_Landscape_Empty.svg A4_Landscape.svg
Siehe Macro für die Entfaltung von Box-Oberflächen
Optionen
- Maßstab manuell oder automatisch
- Format Seite: a3/a4, Cartridge (siehe FreeCAD Vorlagen)
- Gruppieren Sie Zeichnungen auf der gleichen Seite wie möglich.
- Nähen oder nicht die Kanten der Stücke.
Gebrauchsanweisung
- Wählen Sie eine Box aus, die zum Beispiel mit dem Part :: Loft-Werkzeug erstellt wurde.
- Explode es (siehe Menü Entwurf) in Planstücke
- Wählen Sie die Oberflächen aus
- Führe das Makro aus
Skript
Macro_unfoldBox.FCMacro
'''FreeCAD Macro unfoldBox. Unroll of a ruled surface ''' ##################################### # SEE https://wiki.freecadweb.org/Macro_Unfold_Box. # *************************************************************************** # * * # * Copyright (c) 2013 - DoNovae/Herve BAILLY <hbl13@donovae.com> * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** import os import math import FreeCAD, FreeCADGui, Draft from PySide import QtGui, QtCore from FreeCAD import Base fields_l = [] unroll_l = [] ##################################### # Functions ##################################### def errorDialog(msg): diag = QtGui.QMessageBox(QtGui.QMessageBox.Critical, u'Error Message',msg) diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) diag.exec_() def proceed(): QtGui.qApp.setOverrideCursor(QtCore.Qt.WaitCursor) FreeCAD.Console.PrintMessage('===========================================\n') FreeCAD.Console.PrintMessage('unfoldBox: start.\n') try: file_name = fields_l[0].text() scale = float(fields_l[1].text()) scale_auto = scale_check.isChecked() a3 = a3_check.isChecked() cartridge = cartridge_check.isChecked() onedrawing = onedrawing_check.isChecked() sewed = sewed_check.isChecked() FreeCAD.Console.PrintMessage('unfoldBox.file_name: '+file_name+'\n') FreeCAD.Console.PrintMessage('unfoldBox.scale: '+str(scale)+'\n') FreeCAD.Console.PrintMessage('unfoldBox.scale_check: '+str(scale_auto)+'\n') FreeCAD.Console.PrintMessage('unfoldBox.a3_check: '+str(a3)+'\n') FreeCAD.Console.PrintMessage('unfoldBox.cartridge: '+str(cartridge)+'\n') FreeCAD.Console.PrintMessage('unfoldBox.onedrawing: '+str(onedrawing)+'\n') FreeCAD.Console.PrintMessage('unfoldBox.sewed: '+str(sewed)+'\n') except: msg = 'unfoldBox: wrong inputs...\n' FreeCAD.Console.PrintError(msg) errorDialog(msg) QtGui.qApp.restoreOverrideCursor() DialogBox.hide() # # Get selection # sel = FreeCADGui.Selection.getSelection() objnames_l=[] grp = FreeCAD.activeDocument().addObject('App::DocumentObjectGroup', str(file_name)) for objid in range(sel.__len__()): obj = Draft.clone(sel[objid]) grp.addObject(obj) objnames_l.append([ obj, sel[objid].Name ]) unfold = unfoldBox() if sewed : objnames_l = unfold.done(objnames_l) grp.addObject(objnames_l[0][0]) else: for objid in range(objnames_l.__len__()): unfold.moveXY(objnames_l[objid][0]) id_ = 0 while objnames_l.__len__() > 0: draw = Drawing2d(scale, scale_auto, a3, cartridge, onedrawing, FreeCAD.activeDocument().Name, 'Page'+str(id_)) objnames_l = draw.all_(objnames_l) id_ = id_+1 FreeCAD.Console.PrintMessage('unfoldBox: obj_l= '+str(objnames_l.__len__())+'\n') FreeCAD.Console.PrintMessage('unfoldBox: end.\n') FreeCAD.Console.PrintMessage('===========================================\n') def close(): DialogBox.hide() class unfoldBox: def __init__(self): FreeCAD.Console.PrintMessage('unfoldBox.unfoldBox\n') self.LIMIT = 0.0001 def done(self, objnames_l): tree_l = self.makeTree(objnames_l) for id_ in range(objnames_l.__len__()): face = objnames_l[id_] self.moveXY(face[0]) self.sew(objnames_l, tree_l) return self.fusion(objnames_l) def makeTree(self, objnames_l): # Initialisation of tree_l. tree_l = [] for k in range(objnames_l.__len__()): facek = objnames_l[k][0] facek_l = [] for i in range(facek.Shape.Edges.__len__()): if False and type(facek.Shape.Edges[i].Curve).__name__ != 'GeomLineSegment': facek_l.append([-1, -1]) else: # Search face link to the ith edge vki0 = facek.Shape.Edges[i].Curve.StartPoint vki1 = facek.Shape.Edges[i].Curve.EndPoint found = False for l in range(k+1, objnames_l.__len__()): facel = objnames_l[l][0] for j in range(facel.Shape.Edges.__len__()): vlj0 = facel.Shape.Edges[j].Curve.StartPoint vlj1 = facel.Shape.Edges[j].Curve.EndPoint if vki0.__eq__(vlj0) and vki1.__eq__(vlj1): arelinked = False isfacek = False isfacel = False for kk in range(k-1): for ii in range(tree_l[kk].__len__()): if tree_l[kk][ii][0] == k: isfacek = True if tree_l[kk][ii][0] == l: isfacel = True if isfacek and isfacel: arelinked = True break if not arelinked: facek_l.append([l, j]) found = True break if found: break if not found: facek_l.append([-1, -1]) tree_l.append(facek_l) return tree_l def sew(self, objnames_l, tree_l): placed_l = [] for k in range(tree_l.__len__()): iskplaced = False for p in range(placed_l.__len__()): if placed_l[p] == k: iskplaced = True if not iskplaced: placed_l.append(k) facek = tree_l[k] objk = objnames_l[k][0] for i in range(facek.__len__()): edgeki = facek[i] l = edgeki[0] j = edgeki[1] islplaced = False for p in range(placed_l.__len__()): if placed_l[p] == l: islplaced = True break if not islplaced: placed_l.append(l) if l >= 0 and not (islplaced and iskplaced): iskplaced = True # Move facel.edgelj to facek.edgeki. objl = objnames_l[l][0] vki0 = objk.Shape.Edges[i].Curve.StartPoint vki1 = objk.Shape.Edges[i].Curve.EndPoint vlj0 = objl.Shape.Edges[j].Curve.StartPoint vlj1 = objl.Shape.Edges[j].Curve.EndPoint vk = vki1.sub(vki0) vl = vlj1.sub(vlj0) alpk = vk.getAngle(vl)*180/math.pi alpl = vl.getAngle(vk)*180/math.pi self.isPlanZ(objk) if islplaced: Draft.move(objk, vlj0.sub(vki0)) else: Draft.move(objl, vki0.sub(vlj0)) self.isPlanZ(objk) if math.fabs(vk.dot(FreeCAD.Base.Vector(-vl.y, vl.x, 0))) > self.LIMIT: if islplaced: Draft.rotate(objk, -alpl, vlj0, self.vecto(vl, vk)) else: Draft.rotate(objl, -alpk, vki0, self.vecto(vk, vl)) elif vk.dot(vl) < 0: if islplaced: Draft.rotate(objk, 180, vlj0, self.vecto(vl, FreeCAD.Base.Vector(-vl.y, vl.x, 0))) else: Draft.rotate(objl, 180, vki0, self.vecto(vk, FreeCAD.Base.Vector(-vk.y, vk.x, 0))) # Verifications. vki0 = objk.Shape.Edges[i].Curve.StartPoint vki1 = objk.Shape.Edges[i].Curve.EndPoint vlj0 = objl.Shape.Edges[j].Curve.StartPoint vlj1 = objl.Shape.Edges[j].Curve.EndPoint vk = vki1.sub(vki0) vl = vlj1.sub(vlj0) self.isPlanZ(objk) # Flip or not. L = max(objl.Shape.BoundBox.XMax, objk.Shape.BoundBox.XMax) - min(objl.Shape.BoundBox.XMin, objk.Shape.BoundBox.XMin) W = max(objl.Shape.BoundBox.YMax, objk.Shape.BoundBox.YMax) - min(objl.Shape.BoundBox.YMin, objk.Shape.BoundBox.YMin) S1 = L*W if islplaced: Draft.rotate(objk, 180, vlj0, vl) else: Draft.rotate(objl, 180, vki0, vk) L = max(objl.Shape.BoundBox.XMax, objk.Shape.BoundBox.XMax) - min(objl.Shape.BoundBox.XMin, objk.Shape.BoundBox.XMin) W = max(objl.Shape.BoundBox.YMax, objk.Shape.BoundBox.YMax) - min(objl.Shape.BoundBox.YMin, objk.Shape.BoundBox.YMin) S2 = L * W if (S2 <= S1): if islplaced: Draft.rotate(objk, 180, vlj0, vl) else: Draft.rotate(objl, 180, vki0, vk) self.isPlanZ(objk) def isPlanZ(self, obj): L = obj.Shape.BoundBox.XMax - obj.Shape.BoundBox.XMin W = obj.Shape.BoundBox.YMax - obj.Shape.BoundBox.YMin H = obj.Shape.BoundBox.ZMax - obj.Shape.BoundBox.ZMin if H < self.LIMIT: return True else: return False def fusion(self, objnames_l): # Init. obj_l=[] objna_l=[] obj0 = objnames_l[0][0];name=objnames_l[0][1] objfuse = FreeCAD.activeDocument().addObject('Part::MultiFuse','Unfolding') for k in range(objnames_l.__len__()): objk = objnames_l[k][0] obj_l.append(objk) objfuse.Shapes = obj_l FreeCAD.activeDocument().recompute() objna_l.append([objfuse, name]) return objna_l def get2Vectors(self, shape): v0 = FreeCAD.Base.Vector(0, 0, 0) v1 = FreeCAD.Base.Vector(0, 0, 0) edges= shape.Edges for id_ in range(edges.__len__()-1): va = edges[id_].Curve.EndPoint.sub(edges[id_].Curve.StartPoint) vb = edges[id_+1].Curve.EndPoint.sub(edges[id_+1].Curve.StartPoint) if vb.sub(va).Length > v1.sub(v0).Length: v0 = self.vect_copy(va);v1=self.vect_copy(vb) return [v0, v1] def vecto(self, vect1, vect2): '''Function vecto.''' v= FreeCAD.Base.Vector(0, 0, 0) v.x = vect1.y*vect2.z-vect1.z*vect2.y v.y = vect1.z*vect2.x-vect1.x*vect2.z v.z = vect1.x*vect2.y-vect1.y*vect2.x return v def vect_copy(self, vect): '''Return a copy of vector.''' v = vect.add(FreeCAD.Base.Vector(0, 0, 0)) return v def moveXY(self, obj): # Move to origin Draft.move(obj, FreeCAD.Base.Vector(-obj.Shape.BoundBox.XMin, -obj.Shape.BoundBox.YMin, -obj.Shape.BoundBox.ZMin)) # Find 2 vectors defining the plan of surface tab = self.get2Vectors(obj.Shape) v0 = tab[0] v1 = tab[1] norm = self.vecto(v0, v1) norm.normalize() # Rotate. if math.fabs(norm.x) < self.LIMIT and math.fabs(norm.z) < self.LIMIT: Draft.rotate(obj, 90, FreeCAD.Base.Vector(0, 0, 0), FreeCAD.Base.Vector(1, 0, 0)) elif math.fabs(norm.y) < self.LIMIT and math.fabs(norm.z) < self.LIMIT: Draft.rotate(obj, 90, FreeCAD.Base.Vector(0, 0, 0), FreeCAD.Base.Vector(0, 1, 0)) else: # Rotate following the angle to the normal direction of the plan. oz= FreeCAD.Base.Vector(0, 0, 1) alp = oz.getAngle(norm)*180/math.pi Draft.rotate(obj, -alp, FreeCAD.Base.Vector(0, 0, 0), self.vecto(oz, norm)) # Move to z = 0. Draft.move(obj, FreeCAD.Base.Vector(0, 0, -obj.Shape.BoundBox.ZMin)) class Drawing2d: def __init__(self, scale, scale_auto, a3, cartridge, onedrawing, drawing_name, page_name): """Function __init__ - scale - scale_auto - a3 - cartridge - onedrawing """ self.TopX_H = 0 self.TopY_H = 0 self.TopX_V = 0 self.TopY_V = 0 self.TopX_Hmax = 0 self.TopY_Hmax = 0 self.TopX_Vmax = 0 self.TopY_Vmax = 0 self.a3 = a3 self.pts_nbr = 100 self.scale = scale self.scale_auto = scale_auto self.cartridge = cartridge self.onedrawing = onedrawing if self.a3: self.L = 420 self.H = 297 self.marge = 6 else: self.L = 297 self.H = 210 self.marge = 6 self.page_name = page_name self.drawing_name = drawing_name def newPage(self): freecad_dir = os.getenv('HOME') + '/.FreeCAD/Mod/unfoldBox' page = FreeCAD.activeDocument().addObject( 'Drawing::FeaturePage', self.page_name) if self.a3: if self.cartridge: page.Template = freecad_dir+'/A3_Landscape.svg' else: page.Template = freecad_dir+'/A3_Landscape_Empty.svg' else: if self.cartridge: page.Template = freecad_dir+'/A4_Landscape.svg' else: page.Template = freecad_dir+'/A4_Landscape_Empty.svg' return page def all_(self, objnames_l): obj_l = [] for objid in range(objnames_l.__len__()): if objid == 0 or not self.onedrawing: self.newPage() obj_l.extend(self.done(objid, objnames_l[objid])) return obj_l def done(self, id_, objname): # Init. obj_l = [] obj = objname[0] objname = objname[1] xmax = obj.Shape.BoundBox.XMax-obj.Shape.BoundBox.XMin ymax = obj.Shape.BoundBox.YMax-obj.Shape.BoundBox.YMin if ymax > xmax: Draft.rotate(obj, 90) Draft.move(obj, FreeCAD.Base.Vector( -obj.Shape.BoundBox.XMin, -obj.Shape.BoundBox.YMin, 0)) xmax = obj.Shape.BoundBox.XMax-obj.Shape.BoundBox.XMin ymax = obj.Shape.BoundBox.YMax-obj.Shape.BoundBox.YMin scale = min((self.L-4*self.marge) / xmax, (self.H-4*self.marge) / ymax) if (not self.scale_auto) or (self.onedrawing): scale = self.scale if id_ == 0 or not self.onedrawing: # Init. FreeCAD.Console.PrintMessage('Dawing2d: init\n') self.TopX_H = self.marge*2 self.TopY_H = self.marge*2 TopX = self.TopX_H TopY = self.TopY_H self.TopX_H = self.TopX_H + xmax * scale + self.marge self.TopY_H = self.TopY_H self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H) self.TopY_Hmax = max(self.TopY_Hmax, self.TopY_H + ymax*scale + self.marge) self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax) self.TopX_V = max(self.TopX_Vmax, self.TopX_V) self.TopY_V = self.marge * 2 elif self.onedrawing: if self.TopX_H + xmax * scale < self.L: if self.TopY_H + ymax * scale + self.marge*2 < self.H: # H Add at right on same horizontal line. FreeCAD.Console.PrintMessage('Dawing2d: horizontal\n') TopX = self.TopX_H TopY = self.TopY_H self.TopX_H = self.TopX_H + xmax * scale + self.marge self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H) self.TopY_Hmax = max(self.TopY_Hmax, self.TopY_H + ymax*scale + self.marge) self.TopX_Vmax = max(self.TopX_Hmax, self.TopX_Vmax) self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax) self.TopX_V = max(self.TopX_Vmax, self.TopX_V) else: # # V Add at right on same horizontal line # FreeCAD.Console.PrintMessage('Dawing2d: vertival\n') if self.TopX_V + ymax * scale + 2 * self.marge < self.L and self.TopY_V + xmax * scale + 2*self.marge < self.H: Draft.rotate(obj, 90) Draft.move(obj, FreeCAD.Base.Vector(-obj.BoundBox.XMin, -obj.BoundBox.YMin, 0)) self.TopX_V = max(self.TopX_Vmax, self.TopX_V) TopX = self.TopX_V TopY = self.TopY_V self.TopX_V = self.TopX_V + ymax * scale + self.marge self.TopY_Vmax = max(self.TopY_Vmax, self.TopY_V + xmax * scale + self.marge) else: obj_l.append([obj, 'name']) return obj_l else: # H Carriage return. if (self.TopY_Hmax + ymax * scale + self.marge*2 < self.H): FreeCAD.Console.PrintMessage('Dawing2d: carriage return: '+str(self.TopY_H + ymax * scale)+' > '+str(self.H)+'\n') TopX = self.marge*2 TopY = self.TopY_Hmax self.TopX_H = TopX + xmax * scale + self.marge self.TopY_H = TopY self.TopX_Hmax = max(self.TopX_Hmax, self.TopX_H) self.TopY_Hmax = self.TopY_Hmax + ymax*scale+self.marge self.TopX_Vmax = max(self.TopX_Vmax, self.TopX_Hmax) self.TopX_V = max(self.TopX_Vmax, self.TopX_V) else: # V Add at right on same horizontal line. FreeCAD.Console.PrintMessage('Dawing2d: vertical: ' + str(self.TopX_V) + ', ' + str(self.TopX_Vmax) + '\n') if self.TopX_V + ymax * scale + 2*self.marge < self.L and self.TopY_V + xmax * scale + 2*self.marge < self.H : Draft.rotate(obj, 90) Draft.move(obj, FreeCAD.Base.Vector(-obj.BoundBox.XMin, -obj.BoundBox.YMin, 0)) TopX = self.TopX_V TopY = self.TopY_V self.TopX_V = self.TopX_V + ymax * scale + self.marge self.TopY_Vmax = max(self.TopY_Vmax, self.TopY_V + xmax * scale + self.marge) else: obj_l.append([obj, 'name']) return obj_l page = FreeCAD.activeDocument().getObject(self.page_name) Text = FreeCAD.activeDocument().addObject('Drawing::FeatureViewAnnotation', objname + '_txt') Text.Text = objname Text.X = TopX + xmax / 2 * scale Text.Y = TopY + ymax / 2 * scale Text.Scale = 1 TopView = FreeCAD.activeDocument().addObject('Drawing::FeatureViewPart', 'TopView') TopView.Source = obj TopView.Direction = (0.0, 0.0, 1) TopView.Rotation = 0 TopView.X = TopX TopView.Y = TopY TopView.ShowHiddenLines = True TopView.Scale = scale page.addObject(TopView) page.addObject(Text) FreeCAD.activeDocument().recompute() return obj_l ##################################### # Dialog Box ##################################### fields = [['Group Name', 'Unfolding']] fields.append(['Scale', '1']) DialogBox = QtGui.QDialog() DialogBox.resize(250, 250) DialogBox.setWindowTitle('unfoldBox') la = QtGui.QVBoxLayout(DialogBox) # Input fields. for id_ in range(len(fields)): la.addWidget(QtGui.QLabel(fields[id_][0])) fields_l.append(QtGui.QLineEdit(fields[id_][1])) la.addWidget(fields_l[id_]) scale_check = QtGui.QCheckBox(DialogBox) scale_check.setObjectName('checkBox') scale_check.setChecked(True) la.addWidget(QtGui.QLabel('Scale auto')) la.addWidget(scale_check) a3_check = QtGui.QCheckBox(DialogBox) a3_check.setObjectName('checkBox') la.addWidget(QtGui.QLabel('A3 Format')) a3_check.setChecked(False) la.addWidget(a3_check) cartridge_check = QtGui.QCheckBox(DialogBox) cartridge_check.setObjectName('checkBox') la.addWidget(QtGui.QLabel('Cartridge')) cartridge_check.setChecked(False) la.addWidget(cartridge_check) onedrawing_check = QtGui.QCheckBox(DialogBox) onedrawing_check.setObjectName('checkBox') la.addWidget(QtGui.QLabel('Group drawings in page')) onedrawing_check.setChecked(True) la.addWidget(onedrawing_check) sewed_check = QtGui.QCheckBox(DialogBox) sewed_check.setObjectName('checkBox') la.addWidget(QtGui.QLabel('Sewed surfaces')) sewed_check.setChecked(True) la.addWidget(sewed_check) box = QtGui.QDialogButtonBox(DialogBox) box = QtGui.QDialogButtonBox(DialogBox) box.setOrientation(QtCore.Qt.Horizontal) box.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) la.addWidget(box) QtCore.QObject.connect(box, QtCore.SIGNAL('accepted()'), proceed) QtCore.QObject.connect(box, QtCore.SIGNAL('rejected()'), close) QtCore.QMetaObject.connectSlotsByName(DialogBox) DialogBox.show()