MultiExport-FreeCAD/MultiExport.FCMacro

342 lines
9.6 KiB
Plaintext
Executable file

import importSVG
import FreeCAD
import FreeCADGui
import Draft
import os
import Mesh
from PySide.QtWidgets import QWidget, QLabel, QSpinBox, QHBoxLayout, QListWidgetItem
from datetime import datetime
class ObjectListItem(QWidget):
def __init__(self, obj):
super().__init__()
self.obj = obj
self.label = QLabel(obj.Label)
self.spinbox = QSpinBox()
self.spinbox.setRange(1, 9999)
self.spinbox.setValue(1)
layout = QHBoxLayout()
layout.addWidget(self.label)
layout.addWidget(self.spinbox)
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
def get_value(self):
return self.spinbox.value()
class WindowDialog():
def __init__(self):
self.selectedItems = []
self.outputRacine = ""
self.ui_file = os.path.join(FreeCAD.getUserMacroDir(True), 'MultiExport/MultiExport.ui')
self.form = FreeCADGui.PySideUic.loadUi(self.ui_file)
self.connect_widgets()
self.populate_selector_list()
FreeCADGui.Selection.addObserver(self.on_selection_changed)
self.form.show()
def connect_widgets(self):
self.form.pushButtonExport.pressed.connect(self.export)
self.form.pushButtonSave.pressed.connect(self.saveVarSet)
def populate_selector_list(self):
self.form.listWidgetSelector.clear()
FreeCADGui.Selection.clearSelection()
for obj in FreeCAD.ActiveDocument.Objects:
if obj.Label.endswith("-SVG") or obj.Label.endswith("-STL"):
item = QListWidgetItem()
widget = ObjectListItem(obj)
item.setSizeHint(widget.sizeHint())
self.form.listWidgetSelector.addItem(item)
self.form.listWidgetSelector.setItemWidget(item, widget)
item.setSelected(True)
def on_selection_changed(self, doc, objects):
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
item.setSelected(False)
for obj in FreeCADGui.Selection.getSelection():
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
if widget.obj == obj:
item.setSelected(True)
break
def createFolder(self):
date = datetime.today().strftime('%Y-%m-%d')
time = datetime.today().strftime('%H:%M:%S')
folderPath = f"{FreeCAD.activeDocument().getFileName().rpartition('.')[0]}-{date}-Exports/"
if not os.path.exists(folderPath):
os.makedirs(folderPath)
folderPath += f"{time}/"
if not os.path.exists(folderPath):
os.makedirs(folderPath)
return folderPath
# -------- MODIFICATION DE LA MACRO "exportSketchEnMasse-SVG" de Gauthier Brière -------- #
def exportSketchBasic(self, sketchList):
for __O__ in sketchList:
__obj__ = []
__obj__.append(__O__)
print('Export SVG de : ' + __obj__[0].Label)
fichierSVG = u"" + self.outputRacine + __obj__[0].Label + '-' + '.svg'
importSVG.export(__obj__, fichierSVG)
FreeCAD.ActiveDocument.removeObject(__O__.Label)
FreeCAD.activeDocument().recompute()
def exportSketchCalepinage(self, sketchList, plateLength, plateWidth, spacing):
copy_sketchList = sketchList[:]
__obj__ = []
currentX = 0.0
currentY = 0.0
isSVGFull = False
YBlockCounter = 0
SVGNameCounter = 1
maxY = 0.0
index = 0
listSize = len(copy_sketchList)
errorCount = 0
while listSize > 0:
while index < listSize:
__O__ = copy_sketchList[index]
boundingBox = __O__.Shape.BoundBox
if (boundingBox.XLength > plateLength) or (boundingBox.YLength > plateWidth):
copy_sketchList.pop(index)
listSize = len(copy_sketchList)
errorCount += 1
FreeCAD.ActiveDocument.removeObject(__O__.Label)
FreeCAD.activeDocument().recompute()
continue
if boundingBox.XLength + currentX > plateLength:
if boundingBox.YLength + currentY > plateWidth:
YBlockCounter += 1
if YBlockCounter >= listSize:
isSVGFull = True
break
index += 1
continue
if boundingBox.YLength + currentY > plateWidth:
YBlockCounter += 1
if YBlockCounter >= listSize:
isSVGFull = True
break
index += 1
continue
__obj__.insert(0, __O__)
maxY = boundingBox.YLength if boundingBox.YLength > maxY else maxY
__obj__[0].Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,0), FreeCAD.Rotation(FreeCAD.Vector(1,0,0),0), FreeCAD.Vector(0,0,0))
if currentX == 0.0:
__obj__[0].Placement.Base = FreeCAD.Vector(-boundingBox.XMin + currentX, -boundingBox.YMin + currentY, 0.0)
currentX += boundingBox.XLength
else:
__obj__[0].Placement.Base = FreeCAD.Vector(-boundingBox.XMin + currentX + spacing, -boundingBox.YMin + currentY, 0.0)
currentX += boundingBox.XLength + spacing
copy_sketchList.pop(index)
listSize = len(copy_sketchList)
FreeCAD.activeDocument().recompute()
index = 0
YBlockCounter = 0
currentX = 0.0
currentY += maxY + spacing
maxY = 0.0
index = 0
listSize = len(copy_sketchList)
FreeCAD.activeDocument().recompute()
if listSize <= 0 or isSVGFull:
fichierSVG = u"" + self.outputRacine + 'CALEPINAGE-(' + str(SVGNameCounter) + ')' + '.svg'
print('Export SVG de : ' + u"" + str(os.path.basename(self.outputRacine)) + 'CALEPINAGE-(' + str(SVGNameCounter) + ')' + '.svg')
importSVG.export(__obj__, fichierSVG)
for __i__ in __obj__:
FreeCAD.ActiveDocument.removeObject(__i__.Label)
FreeCAD.activeDocument().recompute()
__obj__.clear()
maxY = 0.0
index = 0
currentX = 0.0
currentY = 0.0
isSVGFull = False
SVGNameCounter += 1
YBlockCounter = 0
listSize = len(copy_sketchList)
if errorCount == 1:
print(f"ERREUR : {errorCount} sketch ne rentre pas sur le plateau")
elif errorCount > 1:
print(f"ERREUR : {errorCount} sketchs ne rentrent pas sur le plateau")
# -------- END -------- #
def getLargestFaceDir(self, obj):
if not hasattr(obj, "Shape") or not obj.Shape.Faces:
return None
maxArea = 0.0
largestFace = None
for face in obj.Shape.Faces:
area = face.Area
if area > maxArea:
maxArea = area
largestFace = face
if largestFace:
u, v = largestFace.Surface.parameter(largestFace.CenterOfMass)
normal = largestFace.normalAt(u, v)
return normal.normalize()
return None
def exportSVG(self, isCalepinage, svgList):
plateLength = self.form.doubleSpinBoxLength.value()
plateWidth = self.form.doubleSpinBoxWidth.value()
spacing = self.form.doubleSpinBoxSpacing.value()
sketchList = []
for _, obj, objCount in svgList:
for _ in range(objCount):
if hasattr(obj, "Dir"):
vector = FreeCAD.Vector(obj.Dir.x, obj.Dir.y, obj.Dir.z)
else:
vector = self.getLargestFaceDir(obj)
sv0 = Draft.make_shape2dview(obj, vector)
FreeCAD.ActiveDocument.recompute()
sk = Draft.make_sketch(sv0, autoconstraints=True)
sk.ViewObject.LineColor = (1.0, 0.0, 0.0)
FreeCAD.ActiveDocument.recompute()
sketchList.append(sk)
if hasattr(sv0, 'Name'):
FreeCAD.ActiveDocument.removeObject(sv0.Name)
if isCalepinage:
self.exportSketchCalepinage(sketchList, plateLength, plateWidth, spacing)
else:
self.exportSketchBasic(sketchList)
def exportSTL(self, singleMode, stlList):
objects_to_export = []
for objLabel, obj, objCount in stlList:
for i in range(objCount):
clone = Draft.clone(obj)
objects_to_export.append((clone, objLabel, i + 1))
FreeCAD.ActiveDocument.recompute()
if not singleMode:
for obj, label, i in objects_to_export:
filename = os.path.join(self.outputRacine, f"{label}_{i}.stl")
Mesh.export([obj], filename)
print(f"Exported STL: {filename}")
FreeCAD.ActiveDocument.removeObject(obj.Name)
else:
export_objs = [obj for obj, _, _ in objects_to_export]
if export_objs:
label = FreeCAD.activeDocument().Name
filename = os.path.join(self.outputRacine, f"{label}.stl")
Mesh.export(export_objs, filename)
print(f"Exported merged STL: {filename}")
for obj in export_objs:
FreeCAD.ActiveDocument.removeObject(obj.Name)
FreeCAD.ActiveDocument.recompute()
def export(self):
isCalepinage = self.form.checkBoxCalepinage.isChecked()
isCombine = self.form.checkBoxCombine.isChecked()
svgList = []
stlList = []
for obj in FreeCAD.ActiveDocument.Objects:
count = 1
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
if not item.isSelected():
continue
if widget.obj == obj:
count = widget.get_value()
if obj.Label.endswith("-SVG"):
svgList.append((obj.Label, obj, count))
elif obj.Label.endswith("-STL"):
stlList.append((obj.Label, obj, count))
break
if not svgList == [] or not stlList == []:
self.outputRacine = self.createFolder()
self.exportSVG(isCalepinage, svgList)
self.exportSTL(isCombine, stlList)
def saveVarSet(self, varSetName = "TestVarSet"):
varSet = FreeCAD.ActiveDocument.addObject("App::VarSet", varSetName)
for obj in FreeCADGui.Selection.getSelection():
count = 1
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
if widget.obj == obj:
count = widget.get_value()
break
varSet.addProperty("App::PropertyStringList", obj.Name)
if obj.Label.endswith("-SVG"):
setattr(varSet, obj.Name, ("SVG", str(count)))
else:
setattr(varSet, obj.Name, ("STL", str(count)))
FreeCAD.ActiveDocument.recompute()
# def loadVarSet(self, varSetName = "TestVarSet", count = 1):
if __name__ == '__main__':
try:
mainWindow = WindowDialog()
except Exception as e:
print(e)