MultiExport-FreeCAD/MultiExport.FCMacro

264 lines
8.3 KiB
Plaintext
Executable file

import importSVG
import FreeCAD
import FreeCADGui
import Draft
import os
import Mesh
from PySide2.QtWidgets import QWidget, QLabel, QSpinBox, QHBoxLayout, QListWidgetItem
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._createFolder()
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()
self.form.show()
def _connect_widgets(self):
self.form.pushButtonSVG.pressed.connect(lambda: self.exportSVG(False))
self.form.pushButtonCalepinage.pressed.connect(lambda: self.exportSVG(True))
self.form.pushButtonSTLSingle.pressed.connect(lambda: self.exportSTL(True))
self.form.pushButtonSTLMulti.pressed.connect(lambda: self.exportSTL(False))
self.form.listWidgetSelector.itemSelectionChanged.connect(self._on_selector_item_changed)
def _populate_selector_list(self):
self.form.listWidgetSelector.clear()
for obj in FreeCAD.ActiveDocument.Objects:
if obj.Label.startswith("SVG-") or obj.Label.startswith("STL-"):
item = QListWidgetItem()
widget = ObjectListItem(obj)
item.setSizeHint(widget.sizeHint())
self.form.listWidgetSelector.addItem(item)
self.form.listWidgetSelector.setItemWidget(item, widget)
def _on_selector_item_changed(self):
self.selectedItems = []
FreeCADGui.Selection.clearSelection()
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
if item.isSelected():
FreeCADGui.Selection.addSelection(widget.obj)
self.selectedItems.append((widget.obj, widget.get_value()))
def _createFolder(self):
folderPath = f"{FreeCAD.activeDocument().getFileName().rpartition('.')[0]}-Exports/"
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 exportSVG(self, isCalepinage):
plateLength = self.form.doubleSpinBoxLength.value()
plateWidth = self.form.doubleSpinBoxWidth.value()
spacing = self.form.doubleSpinBoxSpacing.value()
sketchList = []
# Loop over all selected items in list widget, not GUI selection
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
if item.isSelected():
count = widget.get_value()
obj = widget.obj
for _ in range(count):
# Create 2D view and sketch for each instance
if hasattr(obj, 'Dir'):
sv0 = Draft.make_shape2dview(obj, FreeCAD.Vector(obj.Dir))
elif hasattr(obj, 'Objects'):
for child in obj.Objects:
if hasattr(child, 'Dir'):
sv0 = Draft.make_shape2dview(child, FreeCAD.Vector(child.Dir))
break
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)
FreeCADGui.Selection.clearSelection()
self._populate_selector_list()
def exportSTL(self, singleMode):
objects_to_export = []
for index in range(self.form.listWidgetSelector.count()):
item = self.form.listWidgetSelector.item(index)
widget = self.form.listWidgetSelector.itemWidget(item)
if item.isSelected():
count = widget.get_value()
obj = widget.obj
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:
# Combine all into one STL
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()
FreeCADGui.Selection.clearSelection()
self._populate_selector_list()
if __name__ == '__main__':
try:
WindowDialog()
except Exception as e:
print(e)