MultiExport-FreeCAD/MultiExport.FCMacro

370 lines
11 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(0, 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 refresh(self):
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 _connect_widgets(self):
self.form.pushButtonExport.pressed.connect(self.export)
self.form.pushButtonSave.pressed.connect(self.saveVarSet)
self.form.pushButtonRefresh.pressed.connect(self.refresh)
self.form.listWidgetSelector.itemClicked.connect(self._on_list_item_clicked)
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)
FreeCADGui.Selection.addSelection(obj)
def _on_list_item_clicked(self, item):
widget = self.form.listWidgetSelector.itemWidget(item)
obj = widget.obj
if obj in FreeCADGui.Selection.getSelection():
FreeCADGui.Selection.removeSelection(obj)
else:
FreeCADGui.Selection.addSelection(obj)
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):
plateLength = self.form.doubleSpinBoxLength.value()
plateWidth = self.form.doubleSpinBoxWidth.value()
spacing = self.form.doubleSpinBoxSpacing.value()
sketchList = []
for obj in FreeCADGui.Selection.getSelection():
if not obj.Label.endswith("-SVG"):
continue
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
for _ in range(count):
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)
for obj in FreeCAD.ActiveDocument.Objects:
if obj.Label.endswith("-SVG") or obj.Label.endswith("-STL"):
FreeCADGui.Selection.addSelection(obj)
def exportSTL(self, singleMode):
objects_to_export = []
for obj in FreeCADGui.Selection.getSelection():
if not obj.Label.endswith("-STL"):
continue
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
for i in range(count):
clone = Draft.clone(obj)
objects_to_export.append((clone, obj.Label, 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()
for obj in FreeCAD.ActiveDocument.Objects:
if obj.Label.endswith("-SVG") or obj.Label.endswith("-STL"):
FreeCADGui.Selection.addSelection(obj)
def export(self):
isCalepinage = self.form.checkBoxCalepinage.isChecked()
isCombine = self.form.checkBoxCombine.isChecked()
self.outputRacine = self._createFolder()
self.exportSVG(isCalepinage)
self.exportSTL(isCombine)
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()
if __name__ == '__main__':
try:
mainWindow = WindowDialog()
except Exception as e:
print(e)