Import: DXF, add dedicated import dialog
This commit is contained in:
@@ -20,6 +20,7 @@ SET(Draft_SRCS_base
|
||||
SET(Draft_import
|
||||
importAirfoilDAT.py
|
||||
importDXF.py
|
||||
DxfImportDialog.py
|
||||
importDWG.py
|
||||
importOCA.py
|
||||
importSVG.py
|
||||
|
||||
116
src/Mod/Draft/DxfImportDialog.py
Normal file
116
src/Mod/Draft/DxfImportDialog.py
Normal file
@@ -0,0 +1,116 @@
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
class DxfImportDialog:
|
||||
"""
|
||||
A controller class that creates, manages, and shows the DXF import dialog.
|
||||
"""
|
||||
def __init__(self, entity_counts, parent=None):
|
||||
# Step 1: Load the UI from the resource file. This returns a new QDialog instance.
|
||||
self.dialog = FreeCADGui.PySideUic.loadUi(":/ui/preferences-dxf-import.ui")
|
||||
|
||||
# Now, all widgets like "label_Summary" are attributes of self.dialog
|
||||
|
||||
self.entity_counts = entity_counts
|
||||
self.total_entities = sum(entity_counts.values())
|
||||
|
||||
self.setup_ui()
|
||||
self.connect_signals()
|
||||
self.load_settings_and_set_initial_state()
|
||||
|
||||
def setup_ui(self):
|
||||
"""Perform initial UI setup."""
|
||||
self.dialog.label_Summary.setText(f"File contains approximately {self.total_entities} geometric entities.")
|
||||
self.dialog.label_Warning.hide()
|
||||
|
||||
def connect_signals(self):
|
||||
"""Connect signals from the dialog's widgets to our methods."""
|
||||
buttonBox = self.dialog.findChild(QtGui.QDialogButtonBox, "buttonBox")
|
||||
if buttonBox:
|
||||
# Connect to our custom slots INSTEAD of the dialog's built-in ones
|
||||
buttonBox.accepted.connect(self.on_accept)
|
||||
buttonBox.rejected.connect(self.on_reject)
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: OK and Cancel buttons connected.\n")
|
||||
else:
|
||||
FreeCAD.Console.PrintWarning("DxfImportDialog: Could not find buttonBox!\n")
|
||||
|
||||
self.dialog.radio_ImportAs_Draft.toggled.connect(self.update_warning_label)
|
||||
self.dialog.radio_ImportAs_Primitives.toggled.connect(self.update_warning_label)
|
||||
self.dialog.radio_ImportAs_Shapes.toggled.connect(self.update_warning_label)
|
||||
self.dialog.radio_ImportAs_Fused.toggled.connect(self.update_warning_label)
|
||||
|
||||
def on_accept(self):
|
||||
"""Custom slot to debug the OK button click."""
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: 'OK' button clicked. Calling self.dialog.accept().\n")
|
||||
# Manually call the original slot
|
||||
self.dialog.accept()
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: self.dialog.accept() has been called.\n")
|
||||
|
||||
def on_reject(self):
|
||||
"""Custom slot to debug the Cancel button click."""
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: 'Cancel' button clicked. Calling self.dialog.reject().\n")
|
||||
# Manually call the original slot
|
||||
self.dialog.reject()
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: self.dialog.reject() has been called.\n")
|
||||
|
||||
def load_settings_and_set_initial_state(self):
|
||||
"""Load saved preferences and set the initial state of the dialog."""
|
||||
hGrp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
|
||||
mode = hGrp.GetInt("DxfImportMode", 2)
|
||||
|
||||
if mode == 0:
|
||||
self.dialog.radio_ImportAs_Draft.setChecked(True)
|
||||
elif mode == 1:
|
||||
self.dialog.radio_ImportAs_Primitives.setChecked(True)
|
||||
elif mode == 3:
|
||||
self.dialog.radio_ImportAs_Fused.setChecked(True)
|
||||
else:
|
||||
self.dialog.radio_ImportAs_Shapes.setChecked(True)
|
||||
|
||||
is_legacy = hGrp.GetBool("dxfUseLegacyImporter", False)
|
||||
if is_legacy:
|
||||
self.dialog.radio_ImportAs_Primitives.setEnabled(False)
|
||||
self.dialog.radio_ImportAs_Draft.setEnabled(True)
|
||||
self.dialog.radio_ImportAs_Shapes.setEnabled(True)
|
||||
self.dialog.radio_ImportAs_Fused.setEnabled(True)
|
||||
else:
|
||||
self.dialog.radio_ImportAs_Draft.setEnabled(False)
|
||||
self.dialog.radio_ImportAs_Primitives.setEnabled(False)
|
||||
self.dialog.radio_ImportAs_Shapes.setEnabled(True)
|
||||
self.dialog.radio_ImportAs_Fused.setEnabled(True)
|
||||
|
||||
self.update_warning_label()
|
||||
|
||||
def update_warning_label(self):
|
||||
"""Updates the warning label based on selection and entity count."""
|
||||
self.dialog.label_Warning.hide()
|
||||
current_mode = self.get_selected_mode()
|
||||
|
||||
if self.total_entities > 5000 and (current_mode == 0 or current_mode == 1):
|
||||
self.dialog.label_Warning.setText("Warning: Importing over 5000 entities as editable objects can be very slow.")
|
||||
self.dialog.label_Warning.show()
|
||||
elif self.total_entities > 20000 and current_mode == 2:
|
||||
self.dialog.label_Warning.setText("Warning: Importing over 20,000 entities as individual shapes may be slow.")
|
||||
self.dialog.label_Warning.show()
|
||||
|
||||
def exec_(self):
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: Calling self.dialog.exec_()...\n")
|
||||
result = self.dialog.exec_()
|
||||
FreeCAD.Console.PrintLog("DxfImportDialog: self.dialog.exec_() returned with result: {}\n".format(result))
|
||||
# QDialog.Accepted is usually 1, Rejected is 0.
|
||||
FreeCAD.Console.PrintLog("(Note: QDialog.Accepted = {}, QDialog.Rejected = {})\n".format(QtGui.QDialog.Accepted, QtGui.QDialog.Rejected))
|
||||
return result
|
||||
|
||||
def get_selected_mode(self):
|
||||
"""Return the integer value of the selected import mode."""
|
||||
if self.dialog.radio_ImportAs_Draft.isChecked(): return 0
|
||||
if self.dialog.radio_ImportAs_Primitives.isChecked(): return 1
|
||||
if self.dialog.radio_ImportAs_Fused.isChecked(): return 3
|
||||
if self.dialog.radio_ImportAs_Shapes.isChecked(): return 2
|
||||
return 2
|
||||
|
||||
def get_show_dialog_again(self):
|
||||
"""Return True if the dialog should be shown next time."""
|
||||
return not self.dialog.checkBox_ShowDialogAgain.isChecked()
|
||||
@@ -185,6 +185,7 @@
|
||||
<file>ui/preferences-draftvisual.ui</file>
|
||||
<file>ui/preferences-dwg.ui</file>
|
||||
<file>ui/preferences-dxf.ui</file>
|
||||
<file>ui/preferences-dxf-import.ui</file>
|
||||
<file>ui/preferences-oca.ui</file>
|
||||
<file>ui/preferences-svg.ui</file>
|
||||
<file>ui/TaskPanel_CircularArray.ui</file>
|
||||
|
||||
154
src/Mod/Draft/Resources/ui/preferences-dxf-import.ui
Normal file
154
src/Mod/Draft/Resources/ui/preferences-dxf-import.ui
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DxfImportDialog</class>
|
||||
<widget class="QDialog" name="DxfImportDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<height>280</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>DXF Import</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_ImportAs">
|
||||
<property name="title">
|
||||
<string>Import as</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_ImportAs">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_ImportAs_Draft">
|
||||
<property name="toolTip">
|
||||
<string>Creates fully parametric Draft objects. Block definitions are imported as
|
||||
reusable objects (Part Compounds) and instances become `App::Link` objects,
|
||||
maintaining the block structure. Best for full integration with the Draft
|
||||
Workbench. (Legacy importer only)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Editable draft objects</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_ImportAs_Primitives">
|
||||
<property name="toolTip">
|
||||
<string>Creates parametric Part objects (e.g., Part::Line, Part::Circle). Block
|
||||
definitions are imported as reusable objects (Part Compounds) and instances
|
||||
become `App::Link` objects, maintaining the block structure. Best for
|
||||
script-based post-processing. (Not yet implemented)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Editable part primitives</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_ImportAs_Shapes">
|
||||
<property name="toolTip">
|
||||
<string>Creates a non-parametric shape for each DXF entity. Block definitions are
|
||||
imported as reusable objects (Part Compounds) and instances become `App::Link`
|
||||
objects, maintaining the block structure. Good for referencing and measuring.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Individual part shapes (recommended)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radio_ImportAs_Fused">
|
||||
<property name="toolTip">
|
||||
<string>Merges all geometry per layer into a single, non-editable shape. Block
|
||||
structures are not preserved; their geometry becomes part of the layer's
|
||||
shape. Best for viewing very large files with maximum performance.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fused part shapes (fastest)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_Summary">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_Summary">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Summary">
|
||||
<property name="text">
|
||||
<string>File summary</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Warning">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: #c00;</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Warning</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_ShowDialogAgain">
|
||||
<property name="text">
|
||||
<string>Do not show this dialog again</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -69,6 +69,7 @@ from draftobjects.dimension import _Dimension
|
||||
from draftutils import params
|
||||
from draftutils import utils
|
||||
from draftutils.utils import pyopen
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
gui = FreeCAD.GuiUp
|
||||
draftui = None
|
||||
@@ -2810,10 +2811,51 @@ def open(filename):
|
||||
-----
|
||||
Use local variables, not global variables.
|
||||
"""
|
||||
readPreferences()
|
||||
hGrp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
use_legacy = hGrp.GetBool("dxfUseLegacyImporter", False)
|
||||
|
||||
# The C++ layer (`Gui::Application::importFrom`) has set the WaitCursor.
|
||||
# We must temporarily suspend it to show our interactive dialog.
|
||||
try:
|
||||
if gui:
|
||||
FreeCADGui.suspendWaitCursor()
|
||||
|
||||
# --- Dialog Workflow ---
|
||||
if gui and not use_legacy and hGrp.GetBool("dxfShowDialog", True):
|
||||
try:
|
||||
import ImportGui
|
||||
# This C++ function will need to be created in a later step
|
||||
entity_counts = ImportGui.preScanDxf(filename)
|
||||
except Exception:
|
||||
entity_counts = {}
|
||||
|
||||
from DxfImportDialog import DxfImportDialog
|
||||
dlg = DxfImportDialog(entity_counts)
|
||||
|
||||
if dlg.exec_():
|
||||
# User clicked OK, save settings from the dialog
|
||||
hGrp.SetInt("DxfImportMode", dlg.get_selected_mode())
|
||||
hGrp.SetBool("dxfShowDialog", dlg.get_show_dialog_again())
|
||||
else:
|
||||
# User clicked Cancel, abort the entire operation
|
||||
FCC.PrintLog("DXF import cancelled by user.\n")
|
||||
return
|
||||
else:
|
||||
# If we don't show the dialog, we still need to read preferences
|
||||
# to ensure the correct backend logic is triggered.
|
||||
readPreferences()
|
||||
|
||||
finally:
|
||||
# --- CRITICAL: Always resume the wait state before returning to C++ ---
|
||||
# This restores the wait cursor and event filter so the subsequent
|
||||
# blocking C++ call behaves as expected within the C++ scope.
|
||||
if gui:
|
||||
FreeCADGui.resumeWaitCursor()
|
||||
|
||||
# --- Proceed with the blocking import logic ---
|
||||
total_start_time = time.perf_counter()
|
||||
|
||||
if dxfUseLegacyImporter:
|
||||
if use_legacy:
|
||||
getDXFlibs()
|
||||
if dxfReader:
|
||||
docname = os.path.splitext(os.path.basename(filename))[0]
|
||||
@@ -2823,12 +2865,14 @@ def open(filename):
|
||||
return doc
|
||||
else:
|
||||
errorDXFLib(gui)
|
||||
else:
|
||||
return None
|
||||
else: # Modern C++ Importer
|
||||
docname = os.path.splitext(os.path.basename(filename))[0]
|
||||
doc = FreeCAD.newDocument(docname)
|
||||
doc.Label = docname
|
||||
FreeCAD.setActiveDocument(doc.Name)
|
||||
stats = None
|
||||
|
||||
if gui:
|
||||
import ImportGui
|
||||
stats = ImportGui.readDXF(filename)
|
||||
@@ -2836,13 +2880,16 @@ def open(filename):
|
||||
import Import
|
||||
stats = Import.readDXF(filename)
|
||||
|
||||
Draft.convert_draft_texts()
|
||||
doc.recompute()
|
||||
|
||||
total_end_time = time.perf_counter()
|
||||
if stats:
|
||||
# Report PROCESSING time only, not user dialog time.
|
||||
reporter = DxfImportReporter(filename, stats, total_end_time - total_start_time)
|
||||
reporter.report_to_console()
|
||||
|
||||
Draft.convert_draft_texts() # convert annotations to Draft texts
|
||||
doc.recompute()
|
||||
return doc
|
||||
|
||||
|
||||
def insert(filename, docname):
|
||||
@@ -2864,20 +2911,53 @@ def insert(filename, docname):
|
||||
-----
|
||||
Use local variables, not global variables.
|
||||
"""
|
||||
readPreferences()
|
||||
hGrp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
use_legacy = hGrp.GetBool("dxfUseLegacyImporter", False)
|
||||
|
||||
try:
|
||||
if gui:
|
||||
FreeCADGui.suspendWaitCursor()
|
||||
|
||||
# --- Dialog Workflow ---
|
||||
if gui and not use_legacy and hGrp.GetBool("dxfShowDialog", True):
|
||||
try:
|
||||
import ImportGui
|
||||
entity_counts = ImportGui.preScanDxf(filename)
|
||||
except Exception:
|
||||
entity_counts = {}
|
||||
|
||||
from DxfImportDialog import DxfImportDialog
|
||||
dlg = DxfImportDialog(entity_counts)
|
||||
|
||||
if dlg.exec_():
|
||||
hGrp.SetInt("DxfImportMode", dlg.get_selected_mode())
|
||||
hGrp.SetBool("dxfShowDialog", dlg.get_show_dialog_again())
|
||||
else:
|
||||
FCC.PrintLog("DXF insert cancelled by user.\n")
|
||||
return
|
||||
else:
|
||||
readPreferences()
|
||||
|
||||
finally:
|
||||
if gui:
|
||||
FreeCADGui.resumeWaitCursor()
|
||||
|
||||
# --- Proceed with the blocking insert logic ---
|
||||
total_start_time = time.perf_counter()
|
||||
|
||||
try:
|
||||
doc = FreeCAD.getDocument(docname)
|
||||
except NameError:
|
||||
doc = FreeCAD.newDocument(docname)
|
||||
FreeCAD.setActiveDocument(docname)
|
||||
if dxfUseLegacyImporter:
|
||||
|
||||
if use_legacy:
|
||||
getDXFlibs()
|
||||
if dxfReader:
|
||||
processdxf(doc, filename)
|
||||
else:
|
||||
errorDXFLib(gui)
|
||||
else:
|
||||
else: # Modern C++ Importer
|
||||
stats = None
|
||||
if gui:
|
||||
import ImportGui
|
||||
@@ -2886,14 +2966,14 @@ def insert(filename, docname):
|
||||
import Import
|
||||
stats = Import.readDXF(filename)
|
||||
|
||||
Draft.convert_draft_texts()
|
||||
doc.recompute()
|
||||
|
||||
total_end_time = time.perf_counter()
|
||||
if stats:
|
||||
reporter = DxfImportReporter(filename, stats, total_end_time - total_start_time)
|
||||
reporter.report_to_console()
|
||||
|
||||
Draft.convert_draft_texts() # convert annotations to Draft texts
|
||||
doc.recompute()
|
||||
|
||||
def getShapes(filename):
|
||||
"""Read a DXF file, and return a list of shapes from its contents.
|
||||
|
||||
@@ -4183,81 +4263,64 @@ def readPreferences():
|
||||
-----
|
||||
Use local variables, not global variables.
|
||||
"""
|
||||
# reading parameters
|
||||
if gui and params.get_param("dxfShowDialog"):
|
||||
FreeCADGui.showPreferencesByName("Import-Export", ":/ui/preferences-dxf.ui")
|
||||
|
||||
global dxfCreatePart, dxfCreateDraft, dxfCreateSketch
|
||||
global dxfDiscretizeCurves, dxfStarBlocks
|
||||
global dxfMakeBlocks, dxfJoin, dxfRenderPolylineWidth
|
||||
global dxfImportTexts, dxfImportLayouts
|
||||
global dxfImportPoints, dxfImportHatches, dxfUseStandardSize
|
||||
global dxfGetColors, dxfUseDraftVisGroups
|
||||
global dxfMakeFaceMode, dxfBrightBackground, dxfDefaultColor
|
||||
global dxfUseLegacyImporter, dxfExportBlocks, dxfScaling
|
||||
global dxfUseLegacyExporter
|
||||
global dxfDiscretizeCurves, dxfStarBlocks, dxfMakeBlocks, dxfJoin, dxfRenderPolylineWidth
|
||||
global dxfImportTexts, dxfImportLayouts, dxfImportPoints, dxfImportHatches, dxfUseStandardSize
|
||||
global dxfGetColors, dxfUseDraftVisGroups, dxfMakeFaceMode, dxfBrightBackground, dxfDefaultColor
|
||||
global dxfUseLegacyImporter, dxfExportBlocks, dxfScaling, dxfUseLegacyExporter
|
||||
|
||||
# --- Read all feature and appearance toggles ---
|
||||
# These are independent settings and can be read directly.
|
||||
dxfDiscretizeCurves = params.get_param("DiscretizeEllipses", False)
|
||||
dxfStarBlocks = params.get_param("dxfstarblocks", False)
|
||||
dxfJoin = params.get_param("joingeometry", False)
|
||||
dxfRenderPolylineWidth = params.get_param("renderPolylineWidth", False)
|
||||
dxfImportTexts = params.get_param("dxftext", True)
|
||||
dxfImportLayouts = params.get_param("dxflayout", False)
|
||||
dxfImportPoints = params.get_param("dxfImportPoints", True)
|
||||
dxfImportHatches = params.get_param("importDxfHatches", True)
|
||||
dxfUseStandardSize = params.get_param("dxfStdSize", False)
|
||||
dxfGetColors = params.get_param("dxfGetOriginalColors", True)
|
||||
dxfUseDraftVisGroups = params.get_param("dxfUseDraftVisGroups", True)
|
||||
dxfMakeFaceMode = params.get_param("MakeFaceMode", False)
|
||||
dxfExportBlocks = params.get_param("dxfExportBlocks", True)
|
||||
dxfScaling = params.get_param("dxfScaling", 1.0)
|
||||
# Use the direct C++ API via Python for all parameter access
|
||||
hGrp = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
|
||||
|
||||
# These control which importer is used. The script should only proceed if
|
||||
# the legacy importer is selected.
|
||||
dxfUseLegacyImporter = params.get_param("dxfUseLegacyImporter", False)
|
||||
dxfUseLegacyExporter = params.get_param("dxfUseLegacyExporter", False)
|
||||
dxfUseLegacyImporter = hGrp.GetBool("dxfUseLegacyImporter", False)
|
||||
|
||||
if not dxfUseLegacyImporter:
|
||||
# If the legacy importer is called when not selected, exit.
|
||||
# This prevents accidental execution.
|
||||
return
|
||||
# This logic is now only needed for the legacy importer.
|
||||
# The modern importer reads its settings directly in C++.
|
||||
if dxfUseLegacyImporter:
|
||||
# Legacy override for sketch creation takes highest priority
|
||||
dxfCreateSketch = hGrp.GetBool("dxfCreateSketch", False)
|
||||
|
||||
# --- New, Centralized Logic for Structural Mode ---
|
||||
|
||||
# Read the legacy-specific override for sketch creation.
|
||||
dxfCreateSketch = params.get_param("dxfCreateSketch", False)
|
||||
|
||||
if dxfCreateSketch:
|
||||
# Sketch mode takes highest priority, other modes are irrelevant.
|
||||
dxfCreatePart = False
|
||||
dxfCreateDraft = False
|
||||
dxfMakeBlocks = False
|
||||
else:
|
||||
# Not in sketch mode, so determine structure from DxfImportMode.
|
||||
# This is where the new parameter is read, with its default value defined.
|
||||
# 0=Draft, 1=Primitives, 2=Shapes, 3=Fused
|
||||
import_mode = params.get_param("DxfImportMode", 2) # Default to "Individual part shapes"
|
||||
|
||||
if import_mode == 3: # Fused part shapes
|
||||
dxfMakeBlocks = True # 'groupLayers' is the legacy equivalent
|
||||
dxfCreatePart = False # In legacy, dxfMakeBlocks overrides these
|
||||
dxfCreateDraft = False
|
||||
elif import_mode == 0: # Editable draft objects
|
||||
dxfMakeBlocks = False
|
||||
if dxfCreateSketch:
|
||||
dxfCreatePart = False
|
||||
dxfCreateDraft = True
|
||||
else: # Covers modes 1 (Primitives) and 2 (Shapes). Legacy maps both to "Simple part shapes"
|
||||
dxfMakeBlocks = False
|
||||
dxfCreatePart = True
|
||||
dxfCreateDraft = False
|
||||
dxfMakeBlocks = False
|
||||
else:
|
||||
# Read the new unified mode parameter and translate it to the old flags
|
||||
# 0=Draft, 1=Primitives, 2=Shapes, 3=Fused
|
||||
import_mode = hGrp.GetInt("DxfImportMode", 2) # Default to "Individual shapes"
|
||||
if import_mode == 3: # Fused part shapes
|
||||
dxfMakeBlocks = True
|
||||
dxfCreatePart = False
|
||||
dxfCreateDraft = False
|
||||
elif import_mode == 0: # Editable draft objects
|
||||
dxfMakeBlocks = False
|
||||
dxfCreatePart = False
|
||||
dxfCreateDraft = True
|
||||
else: # Individual part shapes or Primitives
|
||||
dxfMakeBlocks = False
|
||||
dxfCreatePart = True
|
||||
dxfCreateDraft = False
|
||||
|
||||
# The legacy importer still uses these global variables, so we read them all.
|
||||
dxfDiscretizeCurves = hGrp.GetBool("DiscretizeEllipses", True)
|
||||
dxfStarBlocks = hGrp.GetBool("dxfstarblocks", False)
|
||||
dxfJoin = hGrp.GetBool("joingeometry", False)
|
||||
dxfRenderPolylineWidth = hGrp.GetBool("renderPolylineWidth", False)
|
||||
dxfImportTexts = hGrp.GetBool("dxftext", False)
|
||||
dxfImportLayouts = hGrp.GetBool("dxflayout", False)
|
||||
dxfImportPoints = hGrp.GetBool("dxfImportPoints", True)
|
||||
dxfImportHatches = hGrp.GetBool("importDxfHatches", False)
|
||||
dxfUseStandardSize = hGrp.GetBool("dxfStdSize", False)
|
||||
dxfGetColors = hGrp.GetBool("dxfGetOriginalColors", True)
|
||||
dxfUseDraftVisGroups = hGrp.GetBool("dxfUseDraftVisGroups", True)
|
||||
dxfMakeFaceMode = hGrp.GetBool("MakeFaceMode", False)
|
||||
dxfUseLegacyExporter = hGrp.GetBool("dxfUseLegacyExporter", False)
|
||||
dxfExportBlocks = hGrp.GetBool("dxfExportBlocks", True)
|
||||
dxfScaling = hGrp.GetFloat("dxfScaling", 1.0)
|
||||
|
||||
# --- Other settings that are not checkboxes ---
|
||||
dxfBrightBackground = isBrightBackground()
|
||||
dxfDefaultColor = getColor()
|
||||
|
||||
|
||||
class DxfImportReporter:
|
||||
"""Formats and reports statistics from a DXF import process."""
|
||||
def __init__(self, filename, stats_dict, total_time=0.0):
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include <gp_Vec.hxx>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <App/Annotation.h>
|
||||
#include <App/Application.h>
|
||||
#include <App/Document.h>
|
||||
@@ -80,6 +81,35 @@ using namespace Import;
|
||||
using BRepAdaptor_HCurve = BRepAdaptor_Curve;
|
||||
#endif
|
||||
|
||||
std::map<std::string, int> ImpExpDxfRead::PreScan(const std::string& filepath)
|
||||
{
|
||||
std::map<std::string, int> counts;
|
||||
std::ifstream ifs(filepath);
|
||||
if (!ifs) {
|
||||
// Could throw an exception or log an error
|
||||
return counts;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
bool next_is_entity_name = false;
|
||||
|
||||
while (std::getline(ifs, line)) {
|
||||
// Simple trim for Windows-style carriage returns
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
|
||||
if (next_is_entity_name) {
|
||||
// The line after a " 0" group code is the entity type
|
||||
counts[line]++;
|
||||
next_is_entity_name = false;
|
||||
}
|
||||
else if (line == " 0") {
|
||||
next_is_entity_name = true;
|
||||
}
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// reading
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
{
|
||||
Py_XDECREF(DraftModule);
|
||||
}
|
||||
|
||||
static std::map<std::string, int> PreScan(const std::string& filepath);
|
||||
void StartImport() override;
|
||||
|
||||
Py::Object getStatsAsPyObject();
|
||||
|
||||
@@ -94,6 +94,7 @@ public:
|
||||
add_keyword_method("insert",
|
||||
&Module::insert,
|
||||
"insert(string,string) -- Insert the file into the given document.");
|
||||
add_varargs_method("preScanDxf", &Module::preScanDxf, "preScanDxf(filepath) -> dict");
|
||||
add_varargs_method("readDXF",
|
||||
&Module::readDXF,
|
||||
"readDXF(filename,[document,ignore_errors,option_source]): Imports a "
|
||||
@@ -112,6 +113,26 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Py::Object preScanDxf(const Py::Tuple& args)
|
||||
{
|
||||
char* filepath_char = nullptr;
|
||||
if (!PyArg_ParseTuple(args.ptr(), "et", "utf-8", &filepath_char)) {
|
||||
throw Py::Exception();
|
||||
}
|
||||
std::string filepath(filepath_char);
|
||||
PyMem_Free(filepath_char);
|
||||
|
||||
#include <Mod/Import/App/dxf/ImpExpDxf.h>
|
||||
|
||||
std::map<std::string, int> counts = Import::ImpExpDxfRead::PreScan(filepath);
|
||||
|
||||
Py::Dict result;
|
||||
for (const auto& pair : counts) {
|
||||
result.setItem(Py::String(pair.first), Py::Long(pair.second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Py::Object importOptions(const Py::Tuple& args)
|
||||
{
|
||||
char* Name {};
|
||||
|
||||
Reference in New Issue
Block a user