Macro DXF to 3D Converter/pl

Generic macro icon. Create your personal icon with the same name of the macro Macro DXF to 3D Converter

Opis
Zautomatyzowane narzędzie do konwersji profili DXF do obiektów 3D poprzez definiowanie długości użytkownika.

Macro version: 1.0.0
Last modified: 2026-04-26
FreeCAD version: 0.19 lub nowszy
Autor: Aris Drosiou
Autor
Aris Drosiou
Do pobrania
Odnośniki
Wersja Makrodefinicji
1.0.0
Data zmian
2026-04-26
Wersja FreeCAD
0.19 lub nowszy
Domyślny skrót
Brak
Zobacz również
-

Opis

Zautomatyzowane narzędzie do konwersji profili DXF do obiektów 3D poprzez definiowanie długości użytkownika.

Konwerter DXF do 3D w akcji

Skrypt

__Name__ = "Macro DXF to 3D Converter"
__Comment__ = "Automated tool to convert DXF profiles into 3D objects by defining a custom length."
__Author__ = "Aris Drosiou"
__Version__ = "1.0.0"
__License__ = "LGPL-2.1-or-later"
__Web__ = "https://wiki.freecad.org/Macros"
__Wiki__ = "https://wiki.freecad.org/DXF_to_3D_converter"
__Icon__ = "" 
__Help__ = "Select a DXF file, set the extrusion length, and click Create 3D."
__Status__ = "Stable"
__Requires__ = "FreeCAD >= 0.19"
__Communication__ = "FreeCAD Forum"

import FreeCAD as App
import FreeCADGui as Gui
import importDXF
import Draft
import Part
import Sketcher
import os
from PySide import QtGui, QtCore

class DXFTo3DPanel(QtGui.QWidget):
    """
    Main UI Class for the DXF to 3D converter tool.
    Handles DXF selection, 2D preview, and 3D extrusion logic.
    """
    def __init__(self):
        super(DXFTo3DPanel, self).__init__()
        self.selected_file = None
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('DXF to 3D Converter')
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.resize(400, 250)
        
        main_layout = QtGui.QHBoxLayout()
        
        # --- Left Control Panel ---
        left_panel = QtGui.QVBoxLayout()
        
        self.label_len = QtGui.QLabel('Length:')
        self.label_len.setStyleSheet("font-weight: bold;")
        left_panel.addWidget(self.label_len)
        
        self.length_input = QtGui.QLineEdit()
        self.length_input.setText("100") 
        self.length_input.setFixedHeight(30)
        left_panel.addWidget(self.length_input)
        
        left_panel.addSpacing(15)
        
        self.dims_group = QtGui.QGroupBox("Profile Dimensions")
        dims_layout = QtGui.QVBoxLayout()
        self.width_label = QtGui.QLabel('Width: --')
        self.height_label = QtGui.QLabel('Height: --')
        dims_layout.addWidget(self.width_label)
        dims_layout.addWidget(self.height_label)
        self.dims_group.setLayout(dims_layout)
        left_panel.addWidget(self.dims_group)
        
        left_panel.addSpacing(15)
        
        self.btn_select = QtGui.QPushButton('Select DXF')
        self.btn_select.setFixedHeight(40)
        self.btn_select.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold; border-radius: 5px;")
        self.btn_select.clicked.connect(self.select_dxf)
        left_panel.addWidget(self.btn_select)
        
        self.file_label = QtGui.QLabel('No file selected')
        self.file_label.setStyleSheet("font-style: italic; color: #666;")
        left_panel.addWidget(self.file_label)
        
        left_panel.addStretch()
        
        self.btn_create = QtGui.QPushButton('Create 3D')
        self.btn_create.setFixedHeight(45)
        self.btn_create.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold; font-size: 14px; border-radius: 8px;")
        self.btn_create.clicked.connect(self.create_part)
        left_panel.addWidget(self.btn_create)
        
        # --- Right Preview Panel ---
        right_panel = QtGui.QVBoxLayout()
        right_panel.addWidget(QtGui.QLabel('Cross Section Preview:'))
        
        self.scene = QtGui.QGraphicsScene()
        self.view = QtGui.QGraphicsView(self.scene)
        self.view.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.black))
        self.view.setRenderHint(QtGui.QPainter.Antialiasing)
        self.view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        right_panel.addWidget(self.view)
        
        main_layout.addLayout(left_panel, 1)
        main_layout.addLayout(right_panel, 2)
        self.setLayout(main_layout)
        
        self.update_unit_label()

    def update_unit_label(self):
        q = App.Units.Quantity(1.0, App.Units.Length)
        unit_str = q.UserString
        symbol = "".join([c for c in unit_str if not c.isdigit() and c not in [".", ","]]).strip()
        self.label_len.setText(f"Length ({symbol}):")

    def resizeEvent(self, event):
        super(DXFTo3DPanel, self).resizeEvent(event)
        if not self.scene.itemsBoundingRect().isEmpty():
            self.view.fitInView(self.scene.itemsBoundingRect(), QtCore.Qt.KeepAspectRatio)

    def select_dxf(self):
        file_path, _ = QtGui.QFileDialog.getOpenFileName(self, "Select DXF", "", "DXF Files (*.dxf)")
        if file_path:
            self.selected_file = file_path
            self.file_label.setText(f"File: {os.path.basename(file_path)}")
            self.draw_preview(file_path)

    def draw_preview(self, path):
        self.scene.clear()
        original_doc = App.ActiveDocument
        try:
            temp_doc = App.newDocument("TempPreview")
            importDXF.insert(path, temp_doc.Name)
            pen = QtGui.QPen(QtCore.Qt.cyan, 1)
            pen.setCosmetic(True) 
            
            all_shapes = []
            for obj in temp_doc.Objects:
                if hasattr(obj, "Shape"):
                    all_shapes.append(obj.Shape)
                    for edge in obj.Shape.Edges:
                        if len(edge.Vertexes) >= 2:
                            p1 = edge.Vertexes[0].Point
                            p2 = edge.Vertexes[-1].Point
                            self.scene.addLine(p1.x, -p1.y, p2.x, -p2.y, pen)
            
            if all_shapes:
                comp = Part.Compound(all_shapes)
                bbox = comp.BoundBox
                w_q = App.Units.Quantity(bbox.XMax - bbox.XMin, App.Units.Length)
                h_q = App.Units.Quantity(bbox.YMax - bbox.YMin, App.Units.Length)
                self.width_label.setText(f"Width: {w_q.UserString}")
                self.height_label.setText(f"Height: {h_q.UserString}")
            
            App.closeDocument(temp_doc.Name)
            if original_doc: App.setActiveDocument(original_doc.Name)
            QtCore.QTimer.singleShot(100, lambda: self.view.fitInView(self.scene.itemsBoundingRect(), QtCore.Qt.KeepAspectRatio))
        except Exception as e:
            self.file_label.setText(f"Error: {str(e)}")

    def create_part(self):
        if not self.selected_file: return
        try:
            val_txt = self.length_input.text().replace(',', '.')
            unit_part = self.label_len.text().split('(')[1].split(')')[0]
            q_len = App.Units.Quantity(f"{val_txt} {unit_part}")
            internal_length = q_len.Value 

            doc = App.ActiveDocument if App.ActiveDocument else App.newDocument("DXF_Conversion")
            file_name = os.path.splitext(os.path.basename(self.selected_file))[0]
            clean_name = "".join(x for x in file_name if x.isalnum())
            
            objs_before = doc.Objects[:]
            importDXF.insert(self.selected_file, doc.Name)
            doc.recompute()
            
            new_objs = [o for o in doc.Objects if o not in objs_before]
            if new_objs:
                sketch = doc.addObject('Sketcher::SketchObject', clean_name + "_Sketch")
                Draft.make_sketch(new_objs, autoconstraints=True, addTo=sketch, delete=True)
                extrude = doc.addObject("Part::Extrusion", clean_name + "_3D")
                extrude.Base = sketch
                extrude.Dir = App.Vector(0, 0, internal_length)
                extrude.Solid = True
                doc.recompute()
                Gui.activeDocument().getObject(sketch.Name).Visibility = False
                Gui.SendMsgToActiveView("ViewFit")
        except Exception as e:
            print(f"Error during extrusion: {e}")

# --- UPDATED CLEANUP LOGIC ---
for widget in QtGui.QApplication.allWidgets():
    if widget.windowTitle() == 'DXF to 3D Converter':
        widget.close()
        widget.deleteLater()

steel_panel = DXFTo3DPanel()
steel_panel.show()