← Macro & add-in library

DXF & fabrication · R12

Sheet-Metal DXF Export by Material and Thickness

A SolidWorks VBA branch for native flat-pattern export with material/thickness grouping and configuration selection.

ENGINEERING CONTRIBUTION

Extended the export workflow through R12 with native sheet-metal flat-pattern handling.

Prerequisites

  • SolidWorks VBA; saved CAD with appropriate manufacturing properties and sheet-metal features for native flat-pattern export.
  • Configure local templates; confirm the selected DXF/nesting configuration and material classification.
  • Writable output folder and downstream software compatible with generated quantity JSON and inch thickness buckets.

Additional setup

  • Match the material properties, configuration naming and local template paths to your CAD environment.

SOURCE WALKTHROUGH

How the workflow fits together.

  1. 01

    Resolve the manufacturing configuration

    The module scores candidate DXF/nesting configuration names, evaluates properties and chooses part/assembly/drawing-view processing.

  2. 02

    Classify stock

    Material and thickness resolution combines metadata and geometric extent along the export normal. Thickness folder values are normalized to inch buckets.

  3. 03

    Choose a valid export route

    Native sheet-metal flat-pattern export is enabled with single-body safety rules. Ordinary bodies use the geometry-aware temporary-part route and orientation postprocessing.

  4. 04

    Write a traceable run

    Default output uses timestamped run folders under DXF FOR WATERJET CUT and per-folder QTY.json. CLEAR_DXF_ROOT_BEFORE_RUN defaults to False.

Output & model changes

  • Writes DXF files, quantity JSON and run logs; creates temporary documents.
  • Can switch configurations and alter temporary model/view state.
  • Contains optional cleanup behavior; defaults retain the output root and write a timestamped run folder.

CODE & ENTRY POINTS

Read the implementation.

Find a procedure, follow an API call or download the module for your SolidWorks setup.

SheetMetalDxfExport.bas

Material/thickness export classification, nesting configuration selection, native sheet-metal flat-pattern handling, quantity sidecars and geometry-based fallback export.

VBA · 9,996 lines

Download .bas

Entry points
API & integration calls
Selected line 1
Option Explicit

'=========================================================================================
' SAVE_ALL_DXF_ACCORDING_TO_MATERIAL_THICKNESS_MACRO
'
' REVISION: CRASH_SAFE_R12_NATIVE_SHEET_METAL_FLAT_PATTERN_EXPORT
'
' PURPOSE
'   Production-oriented macro for weldment DXF export:
'
'   PART MODE
'   - Runs on the active part
'   - If the part has real cut-list folders, it is treated as weldment / cut-list mode
'   - Reads evaluated cut-list property "DXF"
'   - For single-body parts, if cut-list DXF is blank, falls back to part property DXF (then legacy DXY)
'   - Exports only qualifying cut-list items where the effective DXF flag resolves to YES
'   - If the part is a regular part (no real cut-list folders), checks part property "DXF" first, then legacy "DXY" as fallback
'   - Exports the whole part only when the part-level export flag resolves to YES
'
'   ASSEMBLY MODE
'   - Runs on the active assembly
'   - Recursively traverses all components / subassemblies
'   - Processes each unique PART + CONFIGURATION once
'   - Exports eligible cut-list items or regular parts from each qualifying part
'
'   EXPORT RULES
'   - Uses native SolidWorks sheet-metal flat-pattern DXF export for eligible single-body sheet-metal parts
'   - Uses largest planar face as export normal for weldment/plate/generic fallback exports
'   - DXF nesting configuration selection is ON by default
'   - Configuration names are scanned for DXF / WATERJET / CUTTING / NESTING intent
'   - Examples recognized: DXF, WATERJET, DXF CUT, WATERJET CUT,
'     FOR WATERJET CUTTING, DXF FOR WATERJET CUTTING, DXF_WATERJET,
'     WATERJET_CUTTING_DXF, and similar names
'   - Exact WATERJET_CUT behavior is preserved as a legacy fallback
'   - Otherwise uses the referenced / active configuration as normal
'   - Sheet-metal native export uses the default SolidWorks flat pattern/unbend state; it does not require a flat configuration
'   - Multi-body sheet-metal/cut-list items intentionally remain on the existing per-body fallback path unless safely single-body
'   - Uses the two longest perpendicular straight edges that share a corner when available
'   - If a longer non-intersecting perpendicular pair exists, it overrides the shared-corner pair to ignore chamfers
'   - Orients that shared or virtual corner as the bottom-left export corner
'   - If no shared-corner perpendicular pair exists, uses the two longest perpendicular straight edges even when separated by chamfers/gaps
'   - Falls back to longest straight edge horizontal when no suitable perpendicular pair exists
'   - Writes DXFs into <active model folder>\DXF\<MATERIAL>\<GEOMETRIC_THICKNESS>
'   - Multi-body uses PART NUMBER.dxf; single-body parts use saved part file name directly
'   - Thickness folders are derived from body extent along the nesting normal, rounded to three decimals
'   - Single-body parts export directly from the source part using the oriented current view
'   - Multi-body / isolated cut-list bodies still use direct temp-part DXF export by named view
'   - Hides sketches before DXF export to avoid stray sketch geometry
'   - DRAWING MODE: if the active doc is a drawing and a drawing view is selected,
'     the macro uses that view orientation for DXF export and uses the view's
'     referenced part/configuration as the source model state
'
' NOTES
'   - Duplicate output names are auto-resolved with _01, _02, etc.
'   - If a component part is used multiple times in the assembly with the same
'     referenced configuration, it is only processed once.
'   - If the same part is used in multiple different configurations, each unique
'     configuration is processed once.
'
'=========================================================================================

'------------------------------------------
' SolidWorks app/document globals
'------------------------------------------
Private swApp           As SldWorks.SldWorks
Private swModel         As SldWorks.ModelDoc2
Private swPart          As SldWorks.PartDoc
Private swExt           As SldWorks.ModelDocExtension
Private swMathUtil      As SldWorks.MathUtility

'------------------------------------------
' Settings
'------------------------------------------
Private Const OUT_FOLDER_NAME               As String = "DXF FOR WATERJET CUT"
Private Const USE_DXF_NESTING_CONFIGURATION As Boolean = True
Private Const DXF_NESTING_CONFIG_MIN_SCORE  As Long = 5000
Private Const LEGACY_WATERJET_CONFIG_NAME   As String = "WATERJET_CUT"
Private Const PROP_DXF                      As String = "DXF"
Private Const PROP_DXY                      As String = "DXY"
Private Const PROP_PARTNO                   As String = "PART NUMBER"

Private Const PROP_MATERIAL                 As String = "MATERIAL"
Private Const PROP_THICKNESS                As String = "THICKNESS"
Private Const PROP_CANDIDATES_MATERIAL      As String = "MATERIAL|Material|SW-Material|Material Description|MATERIAL DESCRIPTION|DESCRIPTION MATERIAL|Stock Material|STOCK MATERIAL"
Private Const PROP_CANDIDATES_THICKNESS     As String = "THICKNESS|Thickness|PLATE THICKNESS|Plate Thickness|MATERIAL THICKNESS|Material Thickness|STOCK THICKNESS|Stock Thickness|SW-Thickness|Sheet Metal Thickness|SW-Sheet Metal Thickness|SheetMetalThickness|Sheet Metal Gauge"
Private Const JSON_FILE_NAME                As String = "QTY.json"
Private Const JSON_SIMPLE_FILE_NAME         As String = "QTY_SIMPLE.json"
Private Const UNKNOWN_MATERIAL_FOLDER       As String = "_UNCLASSIFIED_MATERIAL"
Private Const UNKNOWN_THICKNESS_FOLDER      As String = "_THICKNESS_RESOLUTION_FAILED"
Private Const PROP_TRUE_VALUE               As String = "YES"

Private Const EPS                           As Double = 0.0000001
Private Const PT_TOL                        As Double = 0.000001
Private Const PERP_DOT_TOL                  As Double = 0.001
Private Const SHEET_MARGIN_M                As Double = 0.05
Private Const MIN_SHEET_W_M                 As Double = 0.3
Private Const MIN_SHEET_H_M                 As Double = 0.2
Private Const TEMP_PREFIX                   As String = "WJDXF_"
Private Const TEMP_VIEW_NAME                As String = "WATERJET_EXPORT_VIEW"
Private Const PI_VAL                        As Double = 3.14159265358979
Private Const CUSTOM_DRAWING_TEMPLATE       As String = "C:\Public\Templates\Blank.drwdot"

'------------------------------------------
' Output / nesting-batch behavior
'------------------------------------------
' When True, the macro clears the DXF root folder at the start of the run.
' This prevents stale DXFs from previous runs being picked up by nesting software.
' Safety check: cleanup only runs when the leaf folder name equals OUT_FOLDER_NAME.
Private Const CLEAR_DXF_ROOT_BEFORE_RUN     As Boolean = False

' Production network-safe mode:
' - The macro never deletes the root output folder.
' - Each run writes into DXF FOR WATERJET CUT\RUN_YYYYMMDD_HHMMSS.
' - This avoids Windows/network permission errors caused by deleting/recreating folders
'   while Explorer or nesting software is watching the folder.
Private Const USE_TIMESTAMPED_RUN_FOLDER    As Boolean = True
Private Const RUN_FOLDER_PREFIX             As String = "RUN_"

' QTY.json is intentionally production-minimal for nesting software.
' It contains only file name and quantity records. QTY_SIMPLE.json is disabled by default.
Private Const WRITE_SIMPLE_QTY_JSON         As Boolean = False

' Thickness folders are normalized to inch buckets, for example 0.250_IN.
' Raw MM values with MM in the property are converted to inches.
Private Const NORMALIZE_THICKNESS_TO_INCH_FOLDERS As Boolean = True

' For waterjet nesting, thickness must come from the same orientation used for DXF export.
' This uses the body extent along the export normal (faceN) and formats the folder to three decimals.
Private Const GEOMETRIC_THICKNESS_FOR_NESTING_FOLDER As Boolean = True
Private Const FAIL_ITEM_WHEN_GEOMETRIC_THICKNESS_FAILS As Boolean = True
Private Const THICKNESS_FOLDER_INCLUDE_UNITS As Boolean = True
Private Const METER_TO_INCH As Double = 39.3700787401575

' Write QTY.json/QTY_SIMPLE.json after every successful item/qty update.
' This prevents losing the qty files if SolidWorks crashes later during document cleanup or view events.
Private Const WRITE_QTY_JSON_INCREMENTALLY As Boolean = True

' Persistent event logging writes every macro event to files in the DXF root folder.
' This is intentionally file-based because SolidWorks/VBE can crash before the Immediate Window is useful.
Private Const ENABLE_PERSISTENT_EVENT_LOGGER As Boolean = False
Private Const EVENT_LOG_ECHO_TO_IMMEDIATE As Boolean = False
Private Const EVENT_LOG_FILE_NAME As String = "_SAVE_ALL_DXF_EVENT_LOG.txt"
Private Const EVENT_LAST_FILE_NAME As String = "_SAVE_ALL_DXF_LAST_EVENT.txt"
Private Const EVENT_STATE_FILE_NAME As String = "_SAVE_ALL_DXF_RUN_STATE.json"
Private Const EVENT_LOG_MAX_BUFFER_BEFORE_INIT As Long = 20000
Private Const WRITE_RUN_COMPLETE_FILE As Boolean = False

' SolidWorks 2023 crash report showed a VBE access violation during view/zoom events.
' Orientation still gets set, but batch mode avoids ViewZoomtofit2 to reduce UI-event instability.
Private Const AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH As Boolean = True

' Material aliases reduce accidental split folders from common shop naming variants.
Private Const USE_MATERIAL_ALIAS_NORMALIZATION As Boolean = True

'------------------------------------------
' Production DXF orientation post-processing
'------------------------------------------
' Field result from R8:
'   - Tab-aware candidate selection worked.
'   - Isolated temp-part export was stable.
'   - SolidWorks *Current view export still did not reliably honor in-plane roll.
'
' R10 keeps the stable SolidWorks export path, then normalizes the finished DXF coordinates:
'   1) Reads the exported 2D DXF.
'   2) Prefers a shared-corner perpendicular leg pair so right-triangle/gusset legs win over hypotenuse.
'   3) Places the selected adjacent/opposite edge on the bottom when possible.
'   4) Falls back to longest linear edge only when no right-angle leg pair exists.
'   5) Translates geometry to positive XY for cleaner nesting import.
Private Const POSTPROCESS_DXF_ORIENTATION_TO_HORIZONTAL As Boolean = True
Private Const DXF_POSTPROCESS_PREFER_RIGHT_ANGLE_LEG_PAIR As Boolean = True
Private Const DXF_POSTPROCESS_PREFER_LONGER_RIGHT_ANGLE_LEG_HORIZONTAL As Boolean = True
Private Const DXF_POSTPROCESS_FORCE_WIDE_ENVELOPE       As Boolean = True
Private Const DXF_POSTPROCESS_FORCE_WIDE_ONLY_FOR_FALLBACK As Boolean = True
Private Const DXF_POSTPROCESS_TRANSLATE_TO_POSITIVE_XY  As Boolean = True
Private Const DXF_POSTPROCESS_MIN_SEGMENT_LENGTH        As Double = 0.001
Private Const DXF_POSTPROCESS_POINT_TOL                 As Double = 0.001
Private Const DXF_POSTPROCESS_PERP_DOT_TOL              As Double = 0.02
Private Const DXF_POSTPROCESS_BOTTOM_EDGE_TOL           As Double = 0.01
Private Const DXF_POSTPROCESS_OUTPUT_DECIMALS           As Long = 6
Private Const DXF_POSTPROCESS_KEEP_BACKUP_FILE          As Boolean = False



'------------------------------------------
' Tab-aware gusset orientation toggles
'------------------------------------------
' This block is intentionally ported from WATERJET_DXF_BATCH_EXPORT_V6_CLEANED.
' It affects only orientation candidate selection. Export path, folder logic, JSON,
' quantity aggregation, and crash-safe temp-part-only workflow are preserved.
Private Const ENABLE_TAB_AWARE_GUSSET_MODE              As Boolean = True
Private Const TAB_AWARE_USER_TAB_MAX_M                  As Double = 0.0254      ' 1.00 in
Private Const TAB_AWARE_ALLOWANCE_M                     As Double = 0.03175     ' 1.25 in
Private Const TAB_AWARE_AXIS_STRIP_HALF_WIDTH_M         As Double = 0.03175     ' 1.25 in
Private Const TAB_AWARE_MIN_EFFECTIVE_LEG_M             As Double = 0.0508      ' 2.00 in
Private Const TAB_AWARE_MIN_LEG_TO_TAB_RATIO            As Double = 2#
Private Const TAB_AWARE_PREFER_LONGER_LEG_HORIZONTAL    As Boolean = True



'------------------------------------------
' Direct temp-part DXF export toggles
'------------------------------------------
Private Const USE_FAST_MODE                             As Boolean = True
Private Const FAST_MODE_PRESERVE_LEGACY_OUTPUT         As Boolean = False
Private Const FAST_MODE_SINGLE_TEMP_PART_SAVE          As Boolean = True
Private Const FAST_MODE_SKIP_TEMP_DRAWING_SAVE         As Boolean = True
Private Const FAST_MODE_MINIMIZE_EXTRA_REDRAWS         As Boolean = True
Private Const USE_EXPERIMENTAL_FAST_DIRECT_DXF         As Boolean = True
Private Const EXPERIMENTAL_DIRECT_FALLBACK_TO_DRAWING  As Boolean = False
Private Const EXPERIMENTAL_DIRECT_ALLOW_CURRENT_VIEW_FALLBACK As Boolean = False
Private Const DIRECT_TEMP_PART_FORCE_INCH_UNITS        As Boolean = True

'------------------------------------------
' Native sheet-metal flat-pattern export toggles
'------------------------------------------
' ON by default:
'   If the active/export configuration is a normal single-body sheet-metal part with a
'   SolidWorks Flat-Pattern feature, the macro exports the native flat pattern using
'   PartDoc.ExportToDWG2 with sheet-metal options before trying the generic oriented body path.
'
' Safety rule:
'   Multi-body sheet-metal parts/cut-list items stay on the existing isolated-body workflow.
'   This prevents a per-cut-list item export from accidentally outputting every flat pattern
'   from the source part into one DXF file.
Private Const USE_NATIVE_SHEET_METAL_FLAT_PATTERN_EXPORT As Boolean = True
Private Const SHEET_METAL_NATIVE_SINGLE_BODY_ONLY        As Boolean = True
Private Const SHEET_METAL_NATIVE_SKIP_WHEN_DRAWING_VIEW_ORIENTATION_OVERRIDE As Boolean = True
Private Const SHEET_METAL_NATIVE_TEMPORARILY_FORCE_INCH_UNITS As Boolean = True

' Waterjet/nesting default: export flat pattern profile only, no bend lines/sketches.
Private Const SHEET_METAL_EXPORT_BEND_LINES             As Boolean = False
Private Const SHEET_METAL_EXPORT_SKETCHES               As Boolean = False
Private Const SHEET_METAL_EXPORT_HIDDEN_EDGES           As Boolean = False
Private Const SHEET_METAL_EXPORT_MERGE_COPLANAR_FACES   As Boolean = True
Private Const SHEET_METAL_EXPORT_LIBRARY_FEATURES       As Boolean = False
Private Const SHEET_METAL_EXPORT_FORMING_TOOLS          As Boolean = False
Private Const SHEET_METAL_EXPORT_BOUNDING_BOX           As Boolean = False

' R5 rotation fix:
' Use the V15-proven *Current view export logic on the isolated temp part.
' Named annotation views can preserve the face normal but lose/ignore in-plane roll on some sheet-metal bodies.
' This keeps the crash-safe temp-part workflow while matching V15's current-view rotation behavior.
Private Const TEMP_PART_EXPORT_USE_CURRENT_VIEW_V15_ROTATION As Boolean = True
Private Const TEMP_PART_NAMED_VIEW_EXPORT_FALLBACK As Boolean = False

' R7 stability correction:
' R6 attempted Body.ApplyTransform on copied sheet/weldment bodies. Field logs showed
' Body.ApplyTransform returned False for all eligible parts, resulting in 0 DXFs.
' Keep this OFF by default and use the proven isolated temp-part + current-view export path.
' The source model is still never modified.
Private Const PHYSICALLY_FLATTEN_TEMP_BODY_FOR_DXF As Boolean = False

' If a future test turns physical flatten back ON, this prevents a no-output run by
' falling back to the stable view-oriented isolated temp-part export when ApplyTransform fails.
Private Const FALL_BACK_TO_VIEW_EXPORT_IF_BODY_FLATTEN_FAILS As Boolean = True

' Stability toggles added after field failure investigation.
' Drawing fallback is kept in the code but disabled by default because the provided crash report
' shows document open/close activity around drawing/template usage immediately before a VBE access violation.
' Re-enable only after testing on a small assembly if direct temp-part export cannot handle a specific case.
Private Const HIDE_SKETCHES_BEFORE_DXF_EXPORT          As Boolean = False
Private Const DISABLE_SOURCE_PART_DIRECT_EXPORT_FOR_STABILITY As Boolean = True
Private Const STRIP_THICKNESS_TEXT_FROM_MATERIAL_FOLDER As Boolean = True
Private Const CLOSE_COMPONENT_DOCS_OPENED_BY_MACRO     As Boolean = False

' ExportToDWG2 action value (compile-safe)
Private Const SW_EXPORT_TO_DWG_ANNOTATION_VIEWS As Long = 3
Private Const SW_EXPORT_TO_DWG_SHEET_METAL       As Long = 1

'Sheet-metal DXF option bitmask values used by ExportToDWG2.
Private Const SM_DXF_OPT_FLAT_PATTERN_GEOMETRY   As Long = 1
Private Const SM_DXF_OPT_HIDDEN_EDGES            As Long = 2
Private Const SM_DXF_OPT_BEND_LINES              As Long = 4
Private Const SM_DXF_OPT_SKETCHES                As Long = 8
Private Const SM_DXF_OPT_MERGE_COPLANAR_FACES    As Long = 16
Private Const SM_DXF_OPT_LIBRARY_FEATURES        As Long = 32
Private Const SM_DXF_OPT_FORMING_TOOLS           As Long = 64
Private Const SM_DXF_OPT_BOUNDING_BOX            As Long = 2048

'------------------------------------------
' Body type constants (compile-safe)
'------------------------------------------
Private Const BODYTYPE_SOLID   As Long = 0
Private Const BODYTYPE_SHEET   As Long = 1
Private Const BODYTYPE_WIRE    As Long = 2
Private Const BODYTYPE_MINIMUM As Long = 3
Private Const BODYTYPE_GENERAL As Long = 4
Private Const BODYTYPE_EMPTY   As Long = 5

'------------------------------------------
' Summary counters
'------------------------------------------
Private gTotalChecked              As Long
Private gTotalEligible             As Long
Private gTotalExported             As Long
Private gTotalSkipped              As Long
Private gTotalFailed               As Long

Private gTotalComponentInstances   As Long
Private gTotalUniquePartConfigs    As Long
Private gTotalPartDocsProcessed    As Long
Private gTotalAssemblyNodes        As Long
Private gTotalVirtualSkipped       As Long
Private gTotalSuppressedSkipped    As Long
Private gTotalQtyAccumulated       As Long
Private gTotalJsonFilesWritten     As Long
Private gTotalJsonRecordsWritten   As Long
Private gTotalSimpleJsonFilesWritten As Long
Private gTotalClassifiedFolders    As Long
Private gTotalMissingMaterial      As Long
Private gTotalMissingThickness     As Long
Private gTotalGeometricThicknessUsed As Long
Private gTotalGeometricThicknessFailed As Long
Private gTotalImmediateJsonFlushes As Long
Private gTotalNativeSheetMetalFlatPatternExported As Long
Private gTotalNativeSheetMetalFlatPatternFallbacks As Long
Private gTotalNativeSheetMetalFlatPatternSkipped As Long

'------------------------------------------
' Run-state / quantity aggregation
'------------------------------------------
Private gPartTemplateByKey         As Object
Private gItemMetadataByKey         As Object
Private gItemQtyByKey              As Object
Private gFolderItemsByPath         As Object

'------------------------------------------
' Persistent event logger state
'------------------------------------------
Private gEventLogReady             As Boolean
Private gEventLogPath              As String
Private gEventLastPath             As String
Private gEventStatePath            As String
Private gEventRootFolder           As String
Private gEventSeq                  As Long
Private gEventPendingLines         As Collection
Private gEventLastLine             As String
Private gEventRunLabel             As String
Private gEventLastStage            As String


Private gCurrentPartTemplateKey    As String
Private gCurrentPartInstanceMultiplier As Long
Private gCurrentPartDoExport       As Boolean

'------------------------------------------
' Run-state / orientation override
'------------------------------------------
Private gHasOrientationOverride    As Boolean
Private gOrientationOverrideX(2)   As Double
Private gOrientationOverrideZ(2)   As Double
Private gOrientationOverrideLabel  As String

Private gForceRequestedConfig      As Boolean
Private gDrawingSelectedViewMode   As Boolean
Private gDrawingSelectedViewName   As String
Private gDrawingSelectedViewConfig As String
Private gDrawingSelectedViewModelPath As String

'=========================================================================================
' ENTRY POINT
'=========================================================================================
Public Sub main()

    On Error GoTo EH

    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    Set swMathUtil = swApp.GetMathUtility

    ResetEventLoggerState

    LogEventRaw String(110, "=")
    LogEvent " | START | SAVE_ALL_DXF_ACCORDING_TO_MATERIAL_THICKNESS_MACRO"
    LogEvent " | INFO  | Root output folder name = " & OUT_FOLDER_NAME
    LogEvent " | INFO  | Clear DXF root before run = " & CStr(CLEAR_DXF_ROOT_BEFORE_RUN)
    LogEvent " | INFO  | Timestamped run folder enabled = " & CStr(USE_TIMESTAMPED_RUN_FOLDER)
    LogEvent " | INFO  | Per-folder QTY.json = YES | QTY_SIMPLE.json = " & CStr(WRITE_SIMPLE_QTY_JSON)
    LogEvent " | INFO  | Source-part direct export disabled for stability = " & CStr(DISABLE_SOURCE_PART_DIRECT_EXPORT_FOR_STABILITY)
    LogEvent " | INFO  | Temp-part current-view export = " & CStr(TEMP_PART_EXPORT_USE_CURRENT_VIEW_V15_ROTATION)
    LogEvent " | INFO  | Physical temp-body flatten for DXF orientation = " & CStr(PHYSICALLY_FLATTEN_TEMP_BODY_FOR_DXF) & " (stable default OFF)"
    LogEvent " | INFO  | Tab-aware gusset orientation candidate logic = " & CStr(ENABLE_TAB_AWARE_GUSSET_MODE)
    LogEvent " | INFO  | DXF post-process horizontal normalization = " & CStr(POSTPROCESS_DXF_ORIENTATION_TO_HORIZONTAL)
    LogEvent " | INFO  | Native sheet-metal flat-pattern export = " & CStr(USE_NATIVE_SHEET_METAL_FLAT_PATTERN_EXPORT)
    LogEvent " | INFO  | Native sheet-metal export single-body safety = " & CStr(SHEET_METAL_NATIVE_SINGLE_BODY_ONLY)
    LogEvent " | INFO  | Native sheet-metal options bitmask = " & CStr(BuildNativeSheetMetalDxfOptions())
    LogEvent " | INFO  | DXF/waterjet nesting configuration auto-select = " & CStr(USE_DXF_NESTING_CONFIGURATION)

    ResetCounters

    If Not ValidateActiveModel(swModel) Then Exit Sub

    Dim summaryDocType As Long
    summaryDocType = swModel.GetType

    Select Case swModel.GetType
        Case swDocPART
            Set swExt = swModel.Extension
            Set swPart = swModel

            Dim partModelPath As String
            Dim partModelDir As String
            Dim partOutDir As String

            partModelPath = swModel.GetPathName
            partModelDir = GetFolderFromPath(partModelPath)
            partOutDir = PrepareRootOutputFolder(partModelDir, OUT_FOLDER_NAME)

            If Len(partOutDir) = 0 Then
                MsgBox "Failed to create or access output folder:" & vbCrLf & partModelDir & "\" & OUT_FOLDER_NAME, vbCritical
                Exit Sub
            End If

            InitializeEventLogger partOutDir, "PART"
            LogEvent " | INFO  | Event log file = " & gEventLogPath
            LogEvent " | INFO  | Output folder = " & partOutDir
            LogEvent " | INFO  | Running in PART mode"

            LogEvent " | CHECK | About to process active part document"
            Call ProcessPartDocument(swModel, partOutDir, GetActiveConfigurationName(swModel), swModel.GetPathName, swModel.GetTitle)
            LogEvent " | CHECK | Returned from active part document processing"

        Case swDocASSEMBLY
            Set swExt = swModel.Extension

            Dim assyModelPath As String
            Dim assyModelDir As String
            Dim assyOutDir As String

            assyModelPath = swModel.GetPathName
            assyModelDir = GetFolderFromPath(assyModelPath)
            assyOutDir = PrepareRootOutputFolder(assyModelDir, OUT_FOLDER_NAME)

            If Len(assyOutDir) = 0 Then
                MsgBox "Failed to create or access output folder:" & vbCrLf & assyModelDir & "\" & OUT_FOLDER_NAME, vbCritical
                Exit Sub
            End If

            InitializeEventLogger assyOutDir, "ASSEMBLY"
            LogEvent " | INFO  | Event log file = " & gEventLogPath
            LogEvent " | INFO  | Output folder = " & assyOutDir
            LogEvent " | INFO  | Running in ASSEMBLY mode"

            LogEvent " | CHECK | About to process assembly document"
            Call ProcessAssemblyDocument(swModel, assyOutDir)
            LogEvent " | CHECK | Returned from assembly document processing"

        Case swDocDRAWING
            LogEvent " | INFO  | Running in DRAWING selected-view mode"
            If Not ProcessSelectedDrawingViewMode(swModel) Then Exit Sub

        Case Else
            MsgBox "Unsupported active document type.", vbExclamation
            Exit Sub
    End Select

    LogEvent " | CHECK | About to run final WriteAllQtyJsonFiles"
    If Not WriteAllQtyJsonFiles() Then
        LogEvent " | WARN  | WriteAllQtyJsonFiles returned False"
    End If

    LogEvent " | CHECK | Returned from final WriteAllQtyJsonFiles"

    Dim summary As String
    summary = BuildSummaryText(summaryDocType)

    WriteRunCompleteFile summary

    LogEvent " | DONE  | " & Replace(summary, vbCrLf, " | ")
    LogEventRaw String(110, "=")

    LogEvent " | CHECK | About to show final summary message box"
    MsgBox summary, vbInformation, "Waterjet DXF Export Summary"
    LogEvent " | CHECK | Final summary message box closed"
    Exit Sub

EH:
    LogEvent " | ERROR | Unhandled main error: " & Err.Number & " - " & Err.Description
    MsgBox "Macro terminated with an unexpected error:" & vbCrLf & Err.Number & " - " & Err.Description, vbCritical
End Sub
Private Function BuildSummaryText(ByVal docType As Long) As String
    Dim s As String

    s = "DXF export + quantity JSON complete." & vbCrLf & vbCrLf

    If docType = swDocASSEMBLY Then
        s = s & _
            "Assembly component instances seen: " & gTotalComponentInstances & vbCrLf & _
            "Assembly/subassembly nodes visited: " & gTotalAssemblyNodes & vbCrLf & _
            "Unique part+config processed: " & gTotalUniquePartConfigs & vbCrLf & _
            "Part docs processed: " & gTotalPartDocsProcessed & vbCrLf & _
            "Suppressed components skipped: " & gTotalSuppressedSkipped & vbCrLf & _
            "Virtual/unloadable components skipped: " & gTotalVirtualSkipped & vbCrLf & vbCrLf
    ElseIf docType = swDocDRAWING Then
        s = s & _
            "Drawing selected-view mode: YES" & vbCrLf & _
            "Selected drawing view: " & NzStr(gDrawingSelectedViewName) & vbCrLf & _
            "Selected view configuration: " & NzStr(gDrawingSelectedViewConfig) & vbCrLf & _
            "Selected view model path: " & NzStr(gDrawingSelectedViewModelPath) & vbCrLf & _
            "Part docs processed: " & gTotalPartDocsProcessed & vbCrLf & vbCrLf
    Else
        s = s & _
            "Part docs processed: " & gTotalPartDocsProcessed & vbCrLf & vbCrLf
    End If

    s = s & _
        "Export candidates checked: " & gTotalChecked & vbCrLf & _
        "Eligible (DXF/DXY=YES): " & gTotalEligible & vbCrLf & _
        "Exported: " & gTotalExported & vbCrLf & _
        "Skipped: " & gTotalSkipped & vbCrLf & _
        "Failed: " & gTotalFailed & vbCrLf & vbCrLf & _
        "Classified folders: " & gTotalClassifiedFolders & vbCrLf & _
        "JSON files written: " & gTotalJsonFilesWritten & vbCrLf & _
        "QTY_SIMPLE.json files written: " & gTotalSimpleJsonFilesWritten & vbCrLf & _
        "Detailed JSON item records written: " & gTotalJsonRecordsWritten & vbCrLf & _
        "Total accumulated qty: " & gTotalQtyAccumulated & vbCrLf & _
        "Items missing material: " & gTotalMissingMaterial & vbCrLf & _
        "Items missing thickness: " & gTotalMissingThickness & vbCrLf & _
        "Geometric thickness folders used: " & gTotalGeometricThicknessUsed & vbCrLf & _
        "Geometric thickness failures: " & gTotalGeometricThicknessFailed & vbCrLf & _
        "Native sheet-metal flat-pattern exports: " & gTotalNativeSheetMetalFlatPatternExported & vbCrLf & _
        "Native sheet-metal fallback attempts: " & gTotalNativeSheetMetalFlatPatternFallbacks & vbCrLf & _
        "Native sheet-metal skipped by safety checks: " & gTotalNativeSheetMetalFlatPatternSkipped & vbCrLf & _
        "Immediate JSON flushes: " & gTotalImmediateJsonFlushes

    BuildSummaryText = s
End Function
'=========================================================================================
' VALIDATION / SETUP
'=========================================================================================
Private Function ValidateActiveModel(ByVal mdl As SldWorks.ModelDoc2) As Boolean
    On Error GoTo EH

    ValidateActiveModel = False

    If mdl Is Nothing Then
        MsgBox "No active SolidWorks document found.", vbExclamation
        Exit Function
    End If

    If mdl.GetType <> swDocPART And mdl.GetType <> swDocASSEMBLY And mdl.GetType <> swDocDRAWING Then
        MsgBox "Active document must be a saved PART, ASSEMBLY, or a DRAWING with a selected drawing view.", vbExclamation
        Exit Function
    End If

    If mdl.GetType <> swDocDRAWING Then
        If Len(Trim$(mdl.GetPathName)) = 0 Then
            MsgBox "The active document must be saved before running this macro.", vbExclamation
            Exit Function
        End If
    End If

    LogEvent " | INFO  | Active model = " & mdl.GetTitle
    LogEvent " | INFO  | Path         = " & mdl.GetPathName
    LogEvent " | INFO  | Type         = " & DocTypeName(mdl.GetType)

    ValidateActiveModel = True
    Exit Function

EH:
    LogEvent " | ERROR | ValidateActiveModel: " & Err.Number & " - " & Err.Description
End Function
Private Function DocTypeName(ByVal docType As Long) As String
    Select Case docType
        Case swDocPART:     DocTypeName = "PART"
        Case swDocASSEMBLY: DocTypeName = "ASSEMBLY"
        Case swDocDRAWING:  DocTypeName = "DRAWING"
        Case Else:          DocTypeName = "UNKNOWN"
    End Select
End Function

Private Sub ResetCounters()
    gTotalChecked = 0
    gTotalEligible = 0
    gTotalExported = 0
    gTotalSkipped = 0
    gTotalFailed = 0

    gTotalComponentInstances = 0
    gTotalUniquePartConfigs = 0
    gTotalPartDocsProcessed = 0
    gTotalAssemblyNodes = 0
    gTotalVirtualSkipped = 0
    gTotalSuppressedSkipped = 0
    gTotalQtyAccumulated = 0
    gTotalJsonFilesWritten = 0
    gTotalJsonRecordsWritten = 0
    gTotalSimpleJsonFilesWritten = 0
    gTotalClassifiedFolders = 0
    gTotalMissingMaterial = 0
    gTotalMissingThickness = 0
    gTotalGeometricThicknessUsed = 0
    gTotalGeometricThicknessFailed = 0
    gTotalImmediateJsonFlushes = 0
    gTotalNativeSheetMetalFlatPatternExported = 0
    gTotalNativeSheetMetalFlatPatternFallbacks = 0
    gTotalNativeSheetMetalFlatPatternSkipped = 0

    Set gPartTemplateByKey = CreateObject("Scripting.Dictionary")
    gPartTemplateByKey.CompareMode = vbTextCompare

    Set gItemMetadataByKey = CreateObject("Scripting.Dictionary")
    gItemMetadataByKey.CompareMode = vbTextCompare

    Set gItemQtyByKey = CreateObject("Scripting.Dictionary")
    gItemQtyByKey.CompareMode = vbTextCompare

    Set gFolderItemsByPath = CreateObject("Scripting.Dictionary")
    gFolderItemsByPath.CompareMode = vbTextCompare

    gCurrentPartTemplateKey = ""
    gCurrentPartInstanceMultiplier = 1
    gCurrentPartDoExport = True

    ResetOrientationOverrideState
End Sub


Private Sub ResetOrientationOverrideState()
    gHasOrientationOverride = False
    gOrientationOverrideX(0) = 0#: gOrientationOverrideX(1) = 0#: gOrientationOverrideX(2) = 0#
    gOrientationOverrideZ(0) = 0#: gOrientationOverrideZ(1) = 0#: gOrientationOverrideZ(2) = 0#
    gOrientationOverrideLabel = ""

    gForceRequestedConfig = False
    gDrawingSelectedViewMode = False
    gDrawingSelectedViewName = ""
    gDrawingSelectedViewConfig = ""
    gDrawingSelectedViewModelPath = ""
End Sub

Private Function ProcessSelectedDrawingViewMode(ByVal drwMdl As SldWorks.ModelDoc2) As Boolean
    On Error GoTo EH

    ProcessSelectedDrawingViewMode = False

    If drwMdl Is Nothing Then Exit Function
    If drwMdl.GetType <> swDocDRAWING Then Exit Function

    Dim drawingTitle As String
    drawingTitle = drwMdl.GetTitle

    Dim selView As SldWorks.View
    Set selView = GetSelectedDrawingViewFromActiveDrawing(drwMdl)

    If selView Is Nothing Then
        MsgBox "Drawing mode requires one selected drawing view." & vbCrLf & _
               "Click the drawing view border or select an object that belongs to the target view and run again.", _
               vbExclamation, "Waterjet DXF Export"
        LogEvent " | FAIL  | No selected drawing view could be resolved"
        Exit Function
    End If

    gDrawingSelectedViewMode = True
    gDrawingSelectedViewName = NzStr(selView.Name)
    LogEventRaw String(100, "-")
    LogEvent " | INFO  | DRAWING SELECTED-VIEW MODE"
    LogEvent " | INFO  | Drawing title  | " & drawingTitle
    LogEvent " | INFO  | Selected view  | " & NzStr(selView.Name)

    Dim refView As SldWorks.View
    Set refView = ResolveDrawingViewForReferencedDocument(selView)
    If refView Is Nothing Then
        Set refView = selView
    End If

    Dim openedByUs As Boolean
    Dim partMdl As SldWorks.ModelDoc2
    Set partMdl = GetDrawingViewReferencedPartDocument(refView, openedByUs)

    If partMdl Is Nothing Then
        MsgBox "The selected drawing view does not resolve to a saved part document." & vbCrLf & _
               "Use a part drawing view, not the sheet, and make sure the referenced model is available.", _
               vbExclamation, "Waterjet DXF Export"
        LogEvent " | FAIL  | Selected drawing view did not resolve to a PART document"
        GoTo CleanupAndExit
    End If

    gDrawingSelectedViewModelPath = partMdl.GetPathName
    gDrawingSelectedViewConfig = GetDrawingViewReferencedConfiguration(refView)
    If Len(Trim$(gDrawingSelectedViewConfig)) = 0 Then
        gDrawingSelectedViewConfig = GetActiveConfigurationName(partMdl)
    End If

    LogEvent " | INFO  | Referenced part | " & partMdl.GetTitle
    LogEvent " | INFO  | Part path       | " & gDrawingSelectedViewModelPath
    LogEvent " | INFO  | View config     | " & gDrawingSelectedViewConfig

    If Len(Trim$(gDrawingSelectedViewModelPath)) = 0 Then
        MsgBox "The selected drawing view references an unsaved part." & vbCrLf & _
               "Save the part first and run again.", vbExclamation, "Waterjet DXF Export"
        LogEvent " | FAIL  | Referenced part path is blank"
        GoTo CleanupAndExit
    End If

    Dim outDir As String
    outDir = PrepareRootOutputFolder(GetFolderFromPath(gDrawingSelectedViewModelPath), OUT_FOLDER_NAME)

    If Len(outDir) = 0 Then
        MsgBox "Failed to create or access output folder:" & vbCrLf & _
               GetFolderFromPath(gDrawingSelectedViewModelPath) & "\" & OUT_FOLDER_NAME, vbCritical
        LogEvent " | FAIL  | Could not create output folder for drawing-selected-view mode"
        GoTo CleanupAndExit
    End If

    InitializeEventLogger outDir, "DRAWING_SELECTED_VIEW"
    LogEvent " | INFO  | Event log file = " & gEventLogPath
    LogEvent " | INFO  | Output folder   | " & outDir

    If Not SetOrientationOverrideFromDrawingView(selView) Then
        MsgBox "Could not read orientation from the selected drawing view.", vbCritical, "Waterjet DXF Export"
        LogEvent " | FAIL  | Could not set drawing-view orientation override"
        GoTo CleanupAndExit
    End If

    gForceRequestedConfig = True
    Set swExt = partMdl.Extension
    Set swPart = partMdl

    Call ProcessPartDocument(partMdl, outDir, gDrawingSelectedViewConfig, gDrawingSelectedViewModelPath, _
                             "DRAWING VIEW | " & NzStr(selView.Name))

    ProcessSelectedDrawingViewMode = True

CleanupAndExit:
    gForceRequestedConfig = False
    gHasOrientationOverride = False

    If openedByUs Then
        LogEvent " | INFO  | Closing drawing-opened referenced part: " & gDrawingSelectedViewModelPath
        CloseDocIfOpen gDrawingSelectedViewModelPath
    End If

    If Len(Trim$(drawingTitle)) > 0 Then
        Call ActivateDocumentByTitle(drawingTitle)
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ProcessSelectedDrawingViewMode: " & Err.Number & " - " & Err.Description
    Resume CleanupAndExit
End Function

Private Function GetSelectedDrawingViewFromActiveDrawing(ByVal drwMdl As SldWorks.ModelDoc2) As SldWorks.View
    On Error GoTo EH

    If drwMdl Is Nothing Then Exit Function
    If drwMdl.GetType <> swDocDRAWING Then Exit Function

    Dim selMgr As SldWorks.SelectionMgr
    Set selMgr = drwMdl.SelectionManager
    If selMgr Is Nothing Then
        LogEvent " | WARN  | Drawing SelectionManager is Nothing"
        Exit Function
    End If

    Dim selCount As Long
    selCount = selMgr.GetSelectedObjectCount2(-1)
    LogEvent " | INFO  | Drawing selection count = " & CStr(selCount)

    If selCount < 1 Then Exit Function

    Dim selObj As Object
    Set selObj = selMgr.GetSelectedObject6(1, -1)

    If Not selObj Is Nothing Then
        LogEvent " | INFO  | First selected object type = " & typeName(selObj)
        If typeName(selObj) = "View" Then
            Set GetSelectedDrawingViewFromActiveDrawing = selObj
            Exit Function
        End If
    End If

    Dim objView As Object
    Set objView = Nothing

    On Error Resume Next
    Set objView = CallByName(selMgr, "GetSelectedObjectsDrawingView2", VbMethod, 1, -1)
    If objView Is Nothing Or Err.Number <> 0 Then
        Err.Clear
        Set objView = CallByName(selMgr, "GetSelectedObjectsDrawingView", VbMethod, 1)
    End If
    On Error GoTo EH

    If Not objView Is Nothing Then
        LogEvent " | INFO  | Resolved drawing view from selected object context"
        Set GetSelectedDrawingViewFromActiveDrawing = objView
        Exit Function
    End If

    LogEvent " | WARN  | Could not resolve selected drawing view"
    Exit Function

EH:
    LogEvent " | ERROR | GetSelectedDrawingViewFromActiveDrawing: " & Err.Number & " - " & Err.Description
End Function

Private Function ResolveDrawingViewForReferencedDocument(ByVal srcView As SldWorks.View) As SldWorks.View
    On Error GoTo EH

    Set ResolveDrawingViewForReferencedDocument = srcView

    Dim curView As SldWorks.View
    Set curView = srcView

    Dim depth As Long
    For depth = 1 To 20
        If curView Is Nothing Then Exit For

        Dim mdl As SldWorks.ModelDoc2
        Set mdl = curView.ReferencedDocument
        If Not mdl Is Nothing Then
            Set ResolveDrawingViewForReferencedDocument = curView
            Exit Function
        End If

        Dim baseView As SldWorks.View
        Set baseView = curView.GetBaseView
        If baseView Is Nothing Then Exit For

        LogEvent " | INFO  | ReferencedDocument unavailable on view [" & NzStr(curView.Name) & "] -> trying base view [" & NzStr(baseView.Name) & "]"
        Set curView = baseView
    Next depth

    Exit Function

EH:
    LogEvent " | ERROR | ResolveDrawingViewForReferencedDocument: " & Err.Number & " - " & Err.Description
End Function

Private Function GetDrawingViewReferencedConfiguration(ByVal refView As SldWorks.View) As String
    On Error GoTo EH

    GetDrawingViewReferencedConfiguration = ""

    If refView Is Nothing Then Exit Function

    On Error Resume Next
    GetDrawingViewReferencedConfiguration = Trim$(refView.ReferencedConfiguration)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | Could not read ReferencedConfiguration from drawing view [" & NzStr(refView.Name) & "]: " & Err.Number & " - " & Err.Description
        Err.Clear
    End If
    On Error GoTo EH

    Exit Function

EH:
    LogEvent " | ERROR | GetDrawingViewReferencedConfiguration: " & Err.Number & " - " & Err.Description
End Function

Private Function GetDrawingViewReferencedPartDocument(ByVal refView As SldWorks.View, _
                                                      ByRef openedByUs As Boolean) As SldWorks.ModelDoc2
    On Error GoTo EH

    openedByUs = False

    If refView Is Nothing Then Exit Function

    Dim mdl As SldWorks.ModelDoc2
    Set mdl = refView.ReferencedDocument

    If Not mdl Is Nothing Then
        LogEvent " | INFO  | ReferencedDocument returned loaded model [" & mdl.GetTitle & "] type=" & DocTypeName(mdl.GetType)
        If mdl.GetType = swDocPART Then
            Set GetDrawingViewReferencedPartDocument = mdl
        Else
            LogEvent " | FAIL  | Selected drawing view references non-part model type " & DocTypeName(mdl.GetType)
        End If
        Exit Function
    End If

    Dim refModelName As String
    refModelName = ""

    On Error Resume Next
    refModelName = Trim$(refView.GetReferencedModelName)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | GetReferencedModelName failed on drawing view [" & NzStr(refView.Name) & "]: " & Err.Number & " - " & Err.Description
        Err.Clear
    End If
    On Error GoTo EH

    LogEvent " | INFO  | Referenced model name/path from drawing view = " & refModelName

    If Len(refModelName) = 0 Then Exit Function

    Dim docType As Long
    docType = GetDocTypeFromPath(refModelName)

    If docType <> swDocPART Then
        LogEvent " | FAIL  | Selected drawing view referenced file is not a part: " & refModelName
        Exit Function
    End If

    Dim alreadyOpen As Boolean
    alreadyOpen = Not (swApp.GetOpenDocumentByName(refModelName) Is Nothing)

    Dim errs As Long
    Dim warns As Long
    errs = 0
    warns = 0

    LogEvent " | INFO  | Opening drawing-referenced part silently: " & refModelName
    Set mdl = swApp.OpenDoc6(refModelName, swDocPART, swOpenDocOptions_Silent Or swOpenDocOptions_ReadOnly, "", errs, warns)

    If mdl Is Nothing Then
        LogEvent " | FAIL  | OpenDoc6 failed for drawing-referenced part. errs=" & errs & " warns=" & warns
        Exit Function
    End If

    If Not alreadyOpen Then openedByUs = True
    Set GetDrawingViewReferencedPartDocument = mdl
    Exit Function

EH:
    LogEvent " | ERROR | GetDrawingViewReferencedPartDocument: " & Err.Number & " - " & Err.Description
End Function

Private Function SetOrientationOverrideFromDrawingView(ByVal srcView As SldWorks.View) As Boolean
    On Error GoTo EH

    SetOrientationOverrideFromDrawingView = False

    If srcView Is Nothing Then Exit Function

    Dim xDir(2) As Double
    Dim zDir(2) As Double

    If Not GetOrientationAxesFromDrawingView(srcView, xDir, zDir) Then
        LogEvent " | FAIL  | Could not derive orientation axes from drawing view [" & NzStr(srcView.Name) & "]"
        Exit Function
    End If

    gHasOrientationOverride = True
    gOrientationOverrideX(0) = xDir(0)
    gOrientationOverrideX(1) = xDir(1)
    gOrientationOverrideX(2) = xDir(2)

    gOrientationOverrideZ(0) = zDir(0)
    gOrientationOverrideZ(1) = zDir(1)
    gOrientationOverrideZ(2) = zDir(2)

    gOrientationOverrideLabel = "DRAWING VIEW [" & NzStr(srcView.Name) & "]"

    LogEvent " | INFO  | Drawing-view orientation override enabled"
    LogEvent " | INFO  |   X override = (" & Dbl3ToStr(gOrientationOverrideX) & ")"
    LogEvent " | INFO  |   Z override = (" & Dbl3ToStr(gOrientationOverrideZ) & ")"

    SetOrientationOverrideFromDrawingView = True
    Exit Function

EH:
    LogEvent " | ERROR | SetOrientationOverrideFromDrawingView: " & Err.Number & " - " & Err.Description
End Function

Private Function GetOrientationAxesFromDrawingView(ByVal srcView As SldWorks.View, _
                                                   ByRef xDir() As Double, _
                                                   ByRef zDir() As Double) As Boolean
    On Error GoTo EH

    GetOrientationAxesFromDrawingView = False

    If srcView Is Nothing Then Exit Function

    Dim mtv As SldWorks.MathTransform
    Set mtv = srcView.ModelToViewTransform
    If mtv Is Nothing Then
        LogEvent " | FAIL  | Drawing view ModelToViewTransform is Nothing"
        Exit Function
    End If

    Dim arr As Variant
    arr = mtv.ArrayData

    If Not VariantHasAtLeast9Numbers(arr) Then
        LogEvent " | FAIL  | Drawing view transform array did not contain at least 9 numbers"
        Exit Function
    End If

    xDir(0) = CDbl(arr(0))
    xDir(1) = CDbl(arr(1))
    xDir(2) = CDbl(arr(2))

    Dim yDir(2) As Double
    yDir(0) = CDbl(arr(3))
    yDir(1) = CDbl(arr(4))
    yDir(2) = CDbl(arr(5))

    zDir(0) = CDbl(arr(6))
    zDir(1) = CDbl(arr(7))
    zDir(2) = CDbl(arr(8))

    LogEvent " | INFO  | Drawing view raw transform rows:"
    LogEvent " | INFO  |   RowX = (" & Dbl3ToStr(xDir) & ")"
    LogEvent " | INFO  |   RowY = (" & Dbl3ToStr(yDir) & ")"
    LogEvent " | INFO  |   RowZ = (" & Dbl3ToStr(zDir) & ")"

    If VecLength(xDir) <= EPS Or VecLength(zDir) <= EPS Then
        LogEvent " | FAIL  | Drawing view transform produced zero-length orientation vectors"
        Exit Function
    End If

    NormalizeVec xDir
    NormalizeVec yDir
    NormalizeVec zDir

    Dim crossZ(2) As Double
    CrossProduct xDir, yDir, crossZ
    If VecLength(crossZ) > EPS Then
        NormalizeVec crossZ
        If DotProduct(crossZ, zDir) < 0# Then
            FlipVec zDir
        End If
    End If

    If Abs(DotProduct(xDir, zDir)) > 0.9999 Then
        LogEvent " | FAIL  | Drawing view transform produced near-parallel X/Z vectors"
        Exit Function
    End If

    LogEvent " | INFO  | Drawing view normalized orientation axes:"
    LogEvent " | INFO  |   X = (" & Dbl3ToStr(xDir) & ")"
    LogEvent " | INFO  |   Z = (" & Dbl3ToStr(zDir) & ")"

    GetOrientationAxesFromDrawingView = True
    Exit Function

EH:
    LogEvent " | ERROR | GetOrientationAxesFromDrawingView: " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' PART / ASSEMBLY DISPATCH
'=========================================================================================
Private Sub ProcessPartDocument(ByVal partMdl As SldWorks.ModelDoc2, _
                                ByVal outDir As String, _
                                ByVal targetConfig As String, _
                                ByVal sourcePath As String, _
                                ByVal sourceLabel As String)
    On Error GoTo EH

    If partMdl Is Nothing Then Exit Sub
    If partMdl.GetType <> swDocPART Then Exit Sub

    gTotalPartDocsProcessed = gTotalPartDocsProcessed + 1

    Dim oldCfg As String
    Dim switchedCfg As Boolean
    Dim effectiveConfig As String
    Dim hasRealCutList As Boolean

    oldCfg = GetActiveConfigurationName(partMdl)
    switchedCfg = False

    If gForceRequestedConfig Then
        effectiveConfig = Trim$(targetConfig)
        If Len(effectiveConfig) = 0 Then effectiveConfig = oldCfg
        LogEvent " | INFO  | Drawing-selected-view mode forcing requested configuration [" & effectiveConfig & "]"
    Else
        effectiveConfig = ResolveNestingConfiguration(partMdl, targetConfig, True)
    End If

    If Len(Trim$(effectiveConfig)) > 0 Then
        If StrComp(oldCfg, effectiveConfig, vbTextCompare) <> 0 Then
            LogEvent " | INFO  | Switching part config from [" & oldCfg & "] to [" & effectiveConfig & "] for " & sourceLabel
            If ActivateModelConfiguration(partMdl, effectiveConfig) Then
                switchedCfg = True
            Else
                LogEvent " | WARN  | Could not switch to configuration [" & effectiveConfig & "] for " & sourceLabel & ". Continuing with active config [" & oldCfg & "]"
            End If
        End If
    End If

    partMdl.ForceRebuild3 True

    gCurrentPartTemplateKey = BuildPartTemplateKey(sourcePath, GetActiveConfigurationName(partMdl))
    gCurrentPartInstanceMultiplier = 1
    gCurrentPartDoExport = True
    EnsurePartTemplateExists gCurrentPartTemplateKey

    LogEventRaw String(100, "-")
    LogEvent " | INFO  | PROCESS PART | " & sourceLabel
    LogEvent " | INFO  | Source path  | " & sourcePath
    LogEvent " | INFO  | Requested cfg| " & targetConfig
    LogEvent " | INFO  | Nesting cfg  | " & effectiveConfig
    LogEvent " | INFO  | Active cfg   | " & GetActiveConfigurationName(partMdl)
    LogEvent " | INFO  | Part template key | " & gCurrentPartTemplateKey
    If gHasOrientationOverride Then
        LogEvent " | INFO  | Orientation | OVERRIDE ACTIVE -> " & gOrientationOverrideLabel
    End If

    If Not UpdateAllCutLists(partMdl) Then
        LogEvent " | WARN  | Cut-list update returned False / partial"
    End If

    hasRealCutList = PartHasRealCutList(partMdl)
    LogEvent " | INFO  | Real cut-list detected = " & CStr(hasRealCutList)

    If hasRealCutList Then
        ProcessCutLists partMdl, outDir
    Else
        ProcessRegularPart partMdl, outDir
    End If

Cleanup:
    If switchedCfg Then
        LogEvent " | INFO  | Restoring original part config [" & oldCfg & "] for " & sourceLabel
        Call ActivateModelConfiguration(partMdl, oldCfg)
        partMdl.ForceRebuild3 True
    End If

    gCurrentPartTemplateKey = ""
    gCurrentPartInstanceMultiplier = 1
    gCurrentPartDoExport = True
    Exit Sub

EH:
    LogEvent " | ERROR | ProcessPartDocument(" & sourceLabel & "): " & Err.Number & " - " & Err.Description
    Resume Cleanup
End Sub

Private Sub ProcessAssemblyDocument(ByVal assyMdl As SldWorks.ModelDoc2, ByVal outDir As String)
    On Error GoTo EH

    If assyMdl Is Nothing Then Exit Sub
    If assyMdl.GetType <> swDocASSEMBLY Then Exit Sub

    Dim assy As SldWorks.AssemblyDoc
    Set assy = assyMdl

    ResolveAssemblyLightweight assyMdl

    Dim rootComp As SldWorks.Component2
    Set rootComp = GetAssemblyRootComponent(assyMdl)

    If rootComp Is Nothing Then
        LogEvent " | FAIL  | Could not obtain root component from active assembly"
        Exit Sub
    End If

    Dim dictPartCfg As Object
    Dim dictAsmCfg As Object
    Set dictPartCfg = CreateObject("Scripting.Dictionary")
    Set dictAsmCfg = CreateObject("Scripting.Dictionary")

    LogEvent " | INFO  | Beginning recursive assembly traversal from root: " & rootComp.Name2

    WalkAssemblyTree rootComp, outDir, dictPartCfg, dictAsmCfg

    Exit Sub

EH:
    LogEvent " | ERROR | ProcessAssemblyDocument: " & Err.Number & " - " & Err.Description
End Sub

Private Sub ResolveAssemblyLightweight(ByVal assyMdl As SldWorks.ModelDoc2)
    On Error GoTo EH

    Dim assy As SldWorks.AssemblyDoc
    Set assy = assyMdl

    LogEvent " | INFO  | Attempting to resolve lightweight assembly components"

    On Error Resume Next
    assy.ResolveAllLightWeightComponents True
    Err.Clear
    On Error GoTo EH

    assyMdl.ForceRebuild3 True
    Exit Sub

EH:
    LogEvent " | WARN  | ResolveAssemblyLightweight: " & Err.Number & " - " & Err.Description
End Sub

Private Function GetAssemblyRootComponent(ByVal assyMdl As SldWorks.ModelDoc2) As SldWorks.Component2
    On Error GoTo EH

    Dim cfg As SldWorks.Configuration
    Set cfg = assyMdl.ConfigurationManager.ActiveConfiguration
    If cfg Is Nothing Then Exit Function

    Set GetAssemblyRootComponent = cfg.GetRootComponent3(True)
    Exit Function

EH:
    LogEvent " | ERROR | GetAssemblyRootComponent: " & Err.Number & " - " & Err.Description
End Function

Private Sub WalkAssemblyTree(ByVal parentComp As SldWorks.Component2, _
                             ByVal outDir As String, _
                             ByVal dictPartCfg As Object, _
                             ByVal dictAsmCfg As Object)
    On Error GoTo EH

    If parentComp Is Nothing Then Exit Sub

    gTotalAssemblyNodes = gTotalAssemblyNodes + 1

    Dim vChildren As Variant
    vChildren = parentComp.GetChildren

    If IsEmpty(vChildren) Then Exit Sub
    If Not IsArray(vChildren) Then Exit Sub

    Dim i As Long
    For i = LBound(vChildren) To UBound(vChildren)

        Dim child As SldWorks.Component2
        Set child = vChildren(i)

        gTotalComponentInstances = gTotalComponentInstances + 1

        If child Is Nothing Then
            LogEvent " | WARN  | Child component is Nothing"
            GoTo NextChild
        End If

        If IsComponentSuppressedSafe(child) Then
            gTotalSuppressedSkipped = gTotalSuppressedSkipped + 1
            LogEvent " | SKIP  | Suppressed component: " & child.Name2
            GoTo NextChild
        End If

        Dim openedByUs As Boolean
        Dim compMdl As SldWorks.ModelDoc2
        Set compMdl = EnsureComponentModelLoaded(child, openedByUs)

        If compMdl Is Nothing Then
            gTotalVirtualSkipped = gTotalVirtualSkipped + 1
            LogEvent " | SKIP  | Could not load component model: " & child.Name2
            GoTo NextChild
        End If

        Dim compPath As String
        Dim compCfg As String
        Dim effectivePartCfg As String
        Dim uniqueKey As String

        compPath = GetComponentBestPath(child, compMdl)
        compCfg = Trim$(child.ReferencedConfiguration)
        If Len(compCfg) = 0 Then compCfg = GetActiveConfigurationName(compMdl)

        If compMdl.GetType = swDocPART Then
            effectivePartCfg = ResolveNestingConfiguration(compMdl, compCfg, False)
            uniqueKey = BuildPartTemplateKey(compPath, effectivePartCfg)

            If Not dictPartCfg.Exists(uniqueKey) Then
                dictPartCfg.Add uniqueKey, True
                gTotalUniquePartConfigs = gTotalUniquePartConfigs + 1

                LogEventRaw String(90, "-")
                LogEvent " | INFO  | UNIQUE PART+CFG | " & child.Name2
                LogEvent " | INFO  | Part path       | " & compPath
                LogEvent " | INFO  | Ref config      | " & compCfg
                LogEvent " | INFO  | Nesting config  | " & effectivePartCfg

                ProcessPartDocument compMdl, outDir, effectivePartCfg, compPath, child.Name2
            Else
                LogEvent " | INFO  | Duplicate part+cfg encountered again; qty will be accumulated from template: " & child.Name2 & " | " & compPath & " | " & effectivePartCfg
                AddQtyFromExistingPartTemplate uniqueKey, 1, child.Name2
            End If

        ElseIf compMdl.GetType = swDocASSEMBLY Then
            uniqueKey = UCase$(compPath) & "|" & UCase$(compCfg)

            If Not dictAsmCfg.Exists(uniqueKey) Then
                dictAsmCfg.Add uniqueKey, True
                LogEventRaw String(90, "-")
                LogEvent " | INFO  | ENTER SUBASM FIRST OCCURRENCE | " & child.Name2
                LogEvent " | INFO  | Asm path        | " & compPath
                LogEvent " | INFO  | Ref config      | " & compCfg
            Else
                LogEventRaw String(90, "-")
                LogEvent " | INFO  | ENTER SUBASM DUPLICATE OCCURRENCE FOR QTY | " & child.Name2
                LogEvent " | INFO  | Asm path        | " & compPath
                LogEvent " | INFO  | Ref config      | " & compCfg
                LogEvent " | INFO  | Duplicate subassembly is still traversed so nested part quantities are counted."
            End If

            'Important for nesting quantity accuracy:
            'Do NOT skip duplicate subassemblies. DXF export is deduplicated at the part+config level,
            'but every subassembly occurrence must still be traversed so repeated nested parts add qty.
            WalkAssemblyTree child, outDir, dictPartCfg, dictAsmCfg

        Else
            LogEvent " | SKIP  | Unsupported component doc type: " & child.Name2 & " | " & DocTypeName(compMdl.GetType)
        End If

        If openedByUs Then
            If CLOSE_COMPONENT_DOCS_OPENED_BY_MACRO Then
                LogEvent " | INFO  | Closing component document opened by macro: " & compPath
                CloseDocIfOpen compPath
            Else
                LogEvent " | INFO  | Leaving component document open for SolidWorks stability: " & compPath
            End If
        End If

NextChild:
    Next i

    Exit Sub

EH:
    LogEvent " | ERROR | WalkAssemblyTree(" & parentComp.Name2 & "): " & Err.Number & " - " & Err.Description
End Sub

Private Function EnsureComponentModelLoaded(ByVal comp As SldWorks.Component2, ByRef openedByUs As Boolean) As SldWorks.ModelDoc2
    On Error GoTo EH

    openedByUs = False

    If comp Is Nothing Then Exit Function

    Dim mdl As SldWorks.ModelDoc2
    Set mdl = comp.GetModelDoc2
    If Not mdl Is Nothing Then
        Set EnsureComponentModelLoaded = mdl
        Exit Function
    End If

    Dim path As String
    path = Trim$(comp.GetPathName)
    If Len(path) = 0 Then
        LogEvent " | WARN  | Component path is blank (likely virtual/unresolved): " & comp.Name2
        Exit Function
    End If

    Dim alreadyOpen As Boolean
    alreadyOpen = Not (swApp.GetOpenDocumentByName(path) Is Nothing)

    Dim docType As Long
    docType = GetDocTypeFromPath(path)
    If docType = 0 Then
        LogEvent " | WARN  | Unsupported component file type: " & path
        Exit Function
    End If

    Dim errs As Long, warns As Long
    errs = 0: warns = 0

    LogEvent " | INFO  | Opening component silently: " & path

    Set mdl = swApp.OpenDoc6(path, docType, swOpenDocOptions_Silent Or swOpenDocOptions_ReadOnly, "", errs, warns)

    If mdl Is Nothing Then
        LogEvent " | FAIL  | OpenDoc6 failed. errs=" & errs & " warns=" & warns & " | " & path
        Exit Function
    End If

    If Not alreadyOpen Then openedByUs = True

    Set EnsureComponentModelLoaded = mdl
    Exit Function

EH:
    LogEvent " | ERROR | EnsureComponentModelLoaded(" & comp.Name2 & "): " & Err.Number & " - " & Err.Description
End Function

Private Function GetDocTypeFromPath(ByVal filePath As String) As Long
    Dim ext As String
    ext = LCase$(GetExtensionFromPath(filePath))

    Select Case ext
        Case "sldprt": GetDocTypeFromPath = swDocPART
        Case "sldasm": GetDocTypeFromPath = swDocASSEMBLY
        Case "slddrw": GetDocTypeFromPath = swDocDRAWING
        Case Else:     GetDocTypeFromPath = 0
    End Select
End Function

Private Function GetExtensionFromPath(ByVal filePath As String) As String
    Dim p As Long
    p = InStrRev(filePath, ".")
    If p > 0 Then
        GetExtensionFromPath = Mid$(filePath, p + 1)
    Else
        GetExtensionFromPath = ""
    End If
End Function

Private Function GetComponentBestPath(ByVal comp As SldWorks.Component2, ByVal mdl As SldWorks.ModelDoc2) As String
    On Error GoTo EH

    Dim s As String
    s = Trim$(comp.GetPathName)

    If Len(s) > 0 Then
        GetComponentBestPath = s
        Exit Function
    End If

    If Not mdl Is Nothing Then
        s = Trim$(mdl.GetPathName)
        If Len(s) > 0 Then
            GetComponentBestPath = s
            Exit Function
        End If

        GetComponentBestPath = "[VIRTUAL] " & mdl.GetTitle
        Exit Function
    End If

    GetComponentBestPath = "[UNKNOWN_COMPONENT]"
    Exit Function

EH:
    GetComponentBestPath = "[UNKNOWN_COMPONENT]"
End Function

Private Function IsComponentSuppressedSafe(ByVal comp As SldWorks.Component2) As Boolean
    On Error GoTo EH

    IsComponentSuppressedSafe = False
    If comp Is Nothing Then Exit Function

    On Error Resume Next
    IsComponentSuppressedSafe = CBool(comp.IsSuppressed)
    If Err.Number <> 0 Then
        Err.Clear
        IsComponentSuppressedSafe = False
    End If
    On Error GoTo EH
    Exit Function

EH:
    IsComponentSuppressedSafe = False
End Function

Private Function GetActiveConfigurationName(ByVal mdl As SldWorks.ModelDoc2) As String
    On Error GoTo EH

    GetActiveConfigurationName = ""

    If mdl Is Nothing Then Exit Function
    If mdl.ConfigurationManager Is Nothing Then Exit Function
    If mdl.ConfigurationManager.ActiveConfiguration Is Nothing Then Exit Function

    GetActiveConfigurationName = Trim$(mdl.ConfigurationManager.ActiveConfiguration.Name)
    Exit Function

EH:
    LogEvent " | ERROR | GetActiveConfigurationName: " & Err.Number & " - " & Err.Description
End Function


Private Function FindPreferredWaterjetConfiguration(ByVal mdl As SldWorks.ModelDoc2, _
                                                     Optional ByVal writeLog As Boolean = False) As String
    On Error GoTo EH

    FindPreferredWaterjetConfiguration = ""

    If mdl Is Nothing Then Exit Function

    If writeLog Then
        LogEvent " | INFO  | DXF/waterjet nesting config search enabled = " & CStr(USE_DXF_NESTING_CONFIGURATION)
    End If

    'R11 behavior:
    '  When enabled, score all configuration names for DXF / waterjet / cutting / nesting intent.
    '  This is intentionally more flexible than the old exact WATERJET_CUT check, but still deterministic.
    If USE_DXF_NESTING_CONFIGURATION Then
        FindPreferredWaterjetConfiguration = FindBestDxfNestingConfiguration(mdl, writeLog)
        If Len(Trim$(FindPreferredWaterjetConfiguration)) > 0 Then Exit Function
    Else
        If writeLog Then
            LogEvent " | INFO  | DXF/waterjet keyword config search disabled by setting. Legacy exact " & LEGACY_WATERJET_CONFIG_NAME & " search still allowed."
        End If
    End If

    'Legacy fallback preserved from previous macro behavior.
    FindPreferredWaterjetConfiguration = FindExactConfigurationByName(mdl, LEGACY_WATERJET_CONFIG_NAME)
    If Len(Trim$(FindPreferredWaterjetConfiguration)) > 0 Then
        If writeLog Then
            LogEvent " | INFO  | Legacy nesting config override detected: [" & FindPreferredWaterjetConfiguration & "]"
        End If
    End If

    Exit Function

EH:
    LogEvent " | ERROR | FindPreferredWaterjetConfiguration: " & Err.Number & " - " & Err.Description
End Function

Private Function FindBestDxfNestingConfiguration(ByVal mdl As SldWorks.ModelDoc2, _
                                                 Optional ByVal writeLog As Boolean = False) As String
    On Error GoTo EH

    FindBestDxfNestingConfiguration = ""

    If mdl Is Nothing Then Exit Function

    Dim vCfgNames As Variant
    vCfgNames = mdl.GetConfigurationNames

    If IsEmpty(vCfgNames) Then
        If writeLog Then LogEvent " | WARN  | DXF nesting config search: model returned no configuration names"
        Exit Function
    End If

    If Not IsArray(vCfgNames) Then
        If writeLog Then LogEvent " | WARN  | DXF nesting config search: configuration name list is not an array"
        Exit Function
    End If

    Dim i As Long
    Dim cfgName As String
    Dim normName As String
    Dim score As Long
    Dim bestScore As Long
    Dim bestIndex As Long
    Dim bestName As String

    bestScore = 0
    bestIndex = 2147483647
    bestName = ""

    For i = LBound(vCfgNames) To UBound(vCfgNames)
        cfgName = Trim$(CStr(vCfgNames(i)))
        If Len(cfgName) > 0 Then
            normName = NormalizeConfigurationSearchText(cfgName)
            score = ScoreDxfNestingConfigurationName(cfgName)

            If writeLog Then
                If score > 0 Then
                    LogEvent " | INFO  | DXF nesting config candidate | cfg=[" & cfgName & "] | normalized=[" & normName & "] | score=" & CStr(score)
                Else
                    LogEvent " | INFO  | DXF nesting config ignored   | cfg=[" & cfgName & "] | normalized=[" & normName & "] | score=0"
                End If
            End If

            If score >= DXF_NESTING_CONFIG_MIN_SCORE Then
                If score > bestScore Then
                    bestScore = score
                    bestIndex = i
                    bestName = cfgName
                ElseIf score = bestScore Then
                    'Tie-breaker: prefer the shorter, clearer configuration name.
                    'If still tied, keep the earliest SolidWorks configuration order.
                    If Len(bestName) = 0 Or Len(cfgName) < Len(bestName) Then
                        bestIndex = i
                        bestName = cfgName
                    End If
                End If
            End If
        End If
    Next i

    If Len(bestName) > 0 Then
        FindBestDxfNestingConfiguration = bestName
        If writeLog Then
            LogEvent " | INFO  | Selected DXF/waterjet nesting config [" & bestName & "] | score=" & CStr(bestScore) & " | index=" & CStr(bestIndex)
        End If
    Else
        If writeLog Then
            LogEvent " | INFO  | No DXF/waterjet nesting config met minimum score " & CStr(DXF_NESTING_CONFIG_MIN_SCORE)
        End If
    End If

    Exit Function

EH:
    LogEvent " | ERROR | FindBestDxfNestingConfiguration: " & Err.Number & " - " & Err.Description
End Function

Private Function FindExactConfigurationByName(ByVal mdl As SldWorks.ModelDoc2, _
                                              ByVal desiredConfigName As String) As String
    On Error GoTo EH

    FindExactConfigurationByName = ""

    If mdl Is Nothing Then Exit Function
    If Len(Trim$(desiredConfigName)) = 0 Then Exit Function

    Dim vCfgNames As Variant
    vCfgNames = mdl.GetConfigurationNames

    If IsEmpty(vCfgNames) Then Exit Function
    If Not IsArray(vCfgNames) Then Exit Function

    Dim i As Long
    Dim cfgName As String

    For i = LBound(vCfgNames) To UBound(vCfgNames)
        cfgName = Trim$(CStr(vCfgNames(i)))
        If Len(cfgName) > 0 Then
            If StrComp(cfgName, desiredConfigName, vbTextCompare) = 0 Then
                FindExactConfigurationByName = CStr(vCfgNames(i))
                Exit Function
            End If
        End If
    Next i

    Exit Function

EH:
    LogEvent " | ERROR | FindExactConfigurationByName(" & desiredConfigName & "): " & Err.Number & " - " & Err.Description
End Function

Private Function ScoreDxfNestingConfigurationName(ByVal cfgName As String) As Long
    On Error GoTo EH

    ScoreDxfNestingConfigurationName = 0

    Dim normName As String
    Dim compactName As String

    normName = NormalizeConfigurationSearchText(cfgName)
    compactName = Replace(normName, " ", "")

    If Len(normName) = 0 Then Exit Function

    'Avoid obvious negative/control configurations.
    If ConfigurationNameHasNegativeDxfIntent(normName) Then Exit Function

    'Exact / near-exact high-confidence names.
    Select Case normName
        Case "DXF FOR WATERJET CUTTING"
            ScoreDxfNestingConfigurationName = 10000
            Exit Function
        Case "DXF WATERJET CUTTING", "DXF WATERJET CUT", "WATERJET CUTTING DXF", "WATERJET CUT DXF", "WATERJET DXF CUTTING", "WATERJET DXF CUT"
            ScoreDxfNestingConfigurationName = 9900
            Exit Function
        Case "DXF WATERJET", "WATERJET DXF"
            ScoreDxfNestingConfigurationName = 9700
            Exit Function
        Case "FOR WATERJET CUTTING", "WATERJET CUTTING", "WATERJET CUT", "WATERJET CUT CONFIG", "WATERJET CUTTING CONFIG"
            ScoreDxfNestingConfigurationName = 9500
            Exit Function
        Case LEGACY_WATERJET_CONFIG_NAME
            ScoreDxfNestingConfigurationName = 9400
            Exit Function
        Case "DXF CUT", "DXF CUTTING", "CUT DXF", "CUTTING DXF"
            ScoreDxfNestingConfigurationName = 9300
            Exit Function
        Case "DXF"
            ScoreDxfNestingConfigurationName = 9000
            Exit Function
        Case "WATERJET"
            ScoreDxfNestingConfigurationName = 8800
            Exit Function
    End Select

    'Compact check catches names where separators were unusual.
    Select Case compactName
        Case "DXFFORWATERJETCUTTING"
            ScoreDxfNestingConfigurationName = 10000
            Exit Function
        Case "DXFWATERJETCUTTING", "DXFWATERJETCUT", "WATERJETCUTTINGDXF", "WATERJETCUTDXF", "WATERJETDXFCUTTING", "WATERJETDXFCUT"
            ScoreDxfNestingConfigurationName = 9900
            Exit Function
        Case "DXFWATERJET", "WATERJETDXF"
            ScoreDxfNestingConfigurationName = 9700
            Exit Function
        Case "FORWATERJETCUTTING", "WATERJETCUTTING", "WATERJETCUT", "WATERJETCUTCONFIG", "WATERJETCUTTINGCONFIG"
            ScoreDxfNestingConfigurationName = 9500
            Exit Function
        Case "DXFCUT", "DXFCUTTING", "CUTDXF", "CUTTINGDXF"
            ScoreDxfNestingConfigurationName = 9300
            Exit Function
    End Select

    Dim hasDxf As Boolean
    Dim hasWaterjet As Boolean
    Dim hasWj As Boolean
    Dim hasCut As Boolean
    Dim hasNest As Boolean
    Dim hasExport As Boolean
    Dim hasFlat As Boolean

    hasDxf = ConfigTokenExists(normName, "DXF")
    hasWaterjet = ConfigTokenExists(normName, "WATERJET")
    hasWj = ConfigTokenExists(normName, "WJ")
    hasCut = ConfigTokenExists(normName, "CUT") Or ConfigTokenExists(normName, "CUTTING")
    hasNest = ConfigTokenExists(normName, "NEST") Or ConfigTokenExists(normName, "NESTING")
    hasExport = ConfigTokenExists(normName, "EXPORT")
    hasFlat = ConfigTokenExists(normName, "FLAT") Or ConfigTokenExists(normName, "FLATTEN") Or ConfigTokenExists(normName, "FLATTENED")

    If hasDxf And hasWaterjet And hasCut Then
        ScoreDxfNestingConfigurationName = 8500
    ElseIf hasDxf And hasWaterjet Then
        ScoreDxfNestingConfigurationName = 8200
    ElseIf hasWaterjet And hasCut Then
        ScoreDxfNestingConfigurationName = 7800
    ElseIf hasDxf And hasCut Then
        ScoreDxfNestingConfigurationName = 7600
    ElseIf hasDxf And hasNest Then
        ScoreDxfNestingConfigurationName = 7400
    ElseIf hasWaterjet And hasNest Then
        ScoreDxfNestingConfigurationName = 7200
    ElseIf hasDxf And hasExport Then
        ScoreDxfNestingConfigurationName = 7000
    ElseIf hasWaterjet And hasExport Then
        ScoreDxfNestingConfigurationName = 6900
    ElseIf hasDxf And hasFlat Then
        ScoreDxfNestingConfigurationName = 6600
    ElseIf hasWaterjet And hasFlat Then
        ScoreDxfNestingConfigurationName = 6500
    ElseIf hasDxf Then
        ScoreDxfNestingConfigurationName = 6200
    ElseIf hasWaterjet Then
        ScoreDxfNestingConfigurationName = 6000
    ElseIf hasWj And (hasDxf Or hasCut Or hasNest Or hasExport Or hasFlat) Then
        ScoreDxfNestingConfigurationName = 5800
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ScoreDxfNestingConfigurationName(" & cfgName & "): " & Err.Number & " - " & Err.Description
    ScoreDxfNestingConfigurationName = 0
End Function

Private Function ConfigurationNameHasNegativeDxfIntent(ByVal normName As String) As Boolean
    On Error GoTo EH

    ConfigurationNameHasNegativeDxfIntent = False

    If Len(Trim$(normName)) = 0 Then Exit Function

    'Only block obvious negative phrases. Do not block words like OLD/REV/TEST because
    'some shops intentionally use test configs during setup.
    If InStr(1, " " & normName & " ", " NO DXF ", vbTextCompare) > 0 Then
        ConfigurationNameHasNegativeDxfIntent = True
        Exit Function
    End If

    If InStr(1, " " & normName & " ", " NOT DXF ", vbTextCompare) > 0 Then
        ConfigurationNameHasNegativeDxfIntent = True
        Exit Function
    End If

    If InStr(1, " " & normName & " ", " NON DXF ", vbTextCompare) > 0 Then
        ConfigurationNameHasNegativeDxfIntent = True
        Exit Function
    End If

    If InStr(1, " " & normName & " ", " WITHOUT DXF ", vbTextCompare) > 0 Then
        ConfigurationNameHasNegativeDxfIntent = True
        Exit Function
    End If

    If InStr(1, " " & normName & " ", " DXF DISABLED ", vbTextCompare) > 0 Then
        ConfigurationNameHasNegativeDxfIntent = True
        Exit Function
    End If

    If InStr(1, " " & normName & " ", " DISABLE DXF ", vbTextCompare) > 0 Then
        ConfigurationNameHasNegativeDxfIntent = True
        Exit Function
    End If

    Exit Function

EH:
    ConfigurationNameHasNegativeDxfIntent = False
End Function

Private Function ConfigTokenExists(ByVal normName As String, ByVal token As String) As Boolean
    On Error GoTo EH

    ConfigTokenExists = False

    If Len(Trim$(normName)) = 0 Then Exit Function
    If Len(Trim$(token)) = 0 Then Exit Function

    ConfigTokenExists = (InStr(1, " " & normName & " ", " " & UCase$(Trim$(token)) & " ", vbTextCompare) > 0)
    Exit Function

EH:
    ConfigTokenExists = False
End Function

Private Function NormalizeConfigurationSearchText(ByVal rawText As String) As String
    On Error GoTo EH

    Dim s As String
    Dim i As Long
    Dim ch As String
    Dim code As Long
    Dim outText As String

    s = UCase$(Trim$(rawText))
    outText = ""

    For i = 1 To Len(s)
        ch = Mid$(s, i, 1)
        code = Asc(ch)

        If (code >= 65 And code <= 90) Or (code >= 48 And code <= 57) Then
            outText = outText & ch
        Else
            outText = outText & " "
        End If
    Next i

    Do While InStr(1, outText, "  ", vbBinaryCompare) > 0
        outText = Replace(outText, "  ", " ")
    Loop

    NormalizeConfigurationSearchText = Trim$(outText)
    Exit Function

EH:
    NormalizeConfigurationSearchText = UCase$(Trim$(rawText))
End Function

Private Function ResolveNestingConfiguration(ByVal mdl As SldWorks.ModelDoc2, _
                                             ByVal requestedConfig As String, _
                                             Optional ByVal writeLog As Boolean = False) As String
    On Error GoTo EH

    ResolveNestingConfiguration = ""

    If mdl Is Nothing Then Exit Function

    Dim preferredCfg As String
    Dim fallbackCfg As String

    preferredCfg = Trim$(FindPreferredWaterjetConfiguration(mdl, writeLog))
    fallbackCfg = Trim$(requestedConfig)

    If Len(fallbackCfg) = 0 Then
        fallbackCfg = GetActiveConfigurationName(mdl)
    End If

    If Len(preferredCfg) > 0 Then
        ResolveNestingConfiguration = preferredCfg
        If writeLog Then
            LogEvent " | INFO  | Nesting config override selected: using [" & preferredCfg & "] instead of requested/active [" & fallbackCfg & "]"
        End If
    Else
        ResolveNestingConfiguration = fallbackCfg
        If writeLog Then
            LogEvent " | INFO  | No DXF/waterjet nesting config found. Using requested/active config [" & ResolveNestingConfiguration & "]"
        End If
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ResolveNestingConfiguration: " & Err.Number & " - " & Err.Description
End Function

Private Function ActivateModelConfiguration(ByVal mdl As SldWorks.ModelDoc2, ByVal cfgName As String) As Boolean
    On Error GoTo EH

    ActivateModelConfiguration = False

    If mdl Is Nothing Then Exit Function
    If Len(Trim$(cfgName)) = 0 Then Exit Function

    Dim ok As Boolean
    ok = mdl.ShowConfiguration2(cfgName)

    If ok Then
        mdl.ForceRebuild3 True
        mdl.GraphicsRedraw2
        ActivateModelConfiguration = True
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ActivateModelConfiguration(" & cfgName & "): " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' CUT-LIST TRAVERSAL
'=========================================================================================
Private Sub ProcessCutLists(ByVal mdl As SldWorks.ModelDoc2, ByVal outDir As String)
    On Error GoTo EH

    Dim feat As SldWorks.Feature
    Set feat = mdl.FirstFeature

    Dim foundAnyCutList As Boolean
    foundAnyCutList = False

    LogEvent " | INFO  | ProcessCutLists pass 1: top-level features"

    Do While Not feat Is Nothing
        If IsRealCutListFolderFeature(feat) Then
            foundAnyCutList = True
            ProcessSingleCutList mdl, feat, outDir
        End If
        Set feat = feat.GetNextFeature
    Loop

    If Not foundAnyCutList Then
        LogEvent " | WARN  | No top-level cut-list folders found; starting recursive subfeature fallback"
        Set feat = mdl.FirstFeature
        Do While Not feat Is Nothing
            ProcessCutListFeatureRecursive mdl, feat, outDir, foundAnyCutList
            Set feat = feat.GetNextFeature
        Loop
    End If

    If Not foundAnyCutList Then
        LogEvent " | WARN  | No real cut-list folders found in part after recursive fallback: " & mdl.GetTitle
    End If

    Exit Sub

EH:
    LogEvent " | ERROR | ProcessCutLists: " & Err.Number & " - " & Err.Description
End Sub

Private Function PartHasRealCutList(ByVal mdl As SldWorks.ModelDoc2) As Boolean
    On Error GoTo EH

    PartHasRealCutList = False
    If mdl Is Nothing Then Exit Function

    Dim feat As SldWorks.Feature
    Set feat = mdl.FirstFeature

    Do While Not feat Is Nothing
        If IsRealCutListFolderFeature(feat) Then
            PartHasRealCutList = True
            Exit Function
        End If
        Set feat = feat.GetNextFeature
    Loop

    'Fallback for parts where SolidWorks exposes cut-list items as subfeatures only.
    Set feat = mdl.FirstFeature
    Do While Not feat Is Nothing
        If FeatureTreeHasRealCutList(feat) Then
            PartHasRealCutList = True
            Exit Function
        End If
        Set feat = feat.GetNextFeature
    Loop

    Exit Function

EH:
    LogEvent " | ERROR | PartHasRealCutList: " & Err.Number & " - " & Err.Description
End Function

Private Sub ProcessRegularPart(ByVal mdl As SldWorks.ModelDoc2, ByVal outDir As String)
    On Error GoTo EH

    gTotalChecked = gTotalChecked + 1

    LogEventRaw String(80, "-")
    LogEvent " | INFO  | Processing regular part (non-weldment): " & mdl.GetTitle

    Dim exportPropName As String
    Dim exportRaw As String
    Dim exportResolved As String
    Dim partNoRaw As String
    Dim partNoResolved As String
    Dim bodyCount As Long
    Dim materialResolved As String
    Dim thicknessResolved As String
    Dim materialSource As String
    Dim thicknessSource As String
    Dim classifiedOutDir As String
    Dim perInstanceQty As Long
    Dim itemKey As String
    Dim finalPartNo As String

    exportResolved = GetEffectivePartLevelDxfFlag(mdl, exportPropName, exportRaw)
    partNoResolved = GetEvaluatedModelProperty(mdl, PROP_PARTNO, partNoRaw)
    bodyCount = CountUsableBodiesInPart(mdl)

    LogEvent " | INFO  | Effective regular-part export property = [" & exportPropName & "] raw=[" & exportRaw & "] eval=[" & exportResolved & "]"
    LogEvent " | INFO  | PART PROP " & PROP_PARTNO & " raw=[" & partNoRaw & "] eval=[" & partNoResolved & "]"
    LogEvent " | INFO  | Regular part usable body count = " & CStr(bodyCount)

    If UCase$(Trim$(exportResolved)) <> PROP_TRUE_VALUE Then
        gTotalSkipped = gTotalSkipped + 1
        LogEvent " | SKIP  | Regular part effective export property is not YES"
        Exit Sub
    End If

    gTotalEligible = gTotalEligible + 1

    Dim repBody As SldWorks.Body2
    Set repBody = GetRepresentativeBodyFromPart(mdl)

    If repBody Is Nothing Then
        gTotalFailed = gTotalFailed + 1
        LogEvent " | FAIL  | No valid representative body found for regular part"
        Exit Sub
    End If

    Dim faceN(2) As Double
    Dim xDir(2) As Double
    Dim usedFallbackEdge As Boolean
    Dim usedPerpCorner As Boolean

    If Not GetExportOrientationForBody(repBody, "regular part [" & mdl.GetTitle & "]", faceN, xDir, usedFallbackEdge, usedPerpCorner) Then
        gTotalFailed = gTotalFailed + 1
        Exit Sub
    End If

    If gHasOrientationOverride Then
        LogEvent " | INFO  | Regular part orientation mode = selected drawing view override"
    ElseIf usedPerpCorner Then
        LogEvent " | INFO  | Regular part orientation mode = perpendicular edge pair -> shared or virtual corner driven bottom-left"
    ElseIf usedFallbackEdge Then
        LogEvent " | WARN  | Regular part orientation mode = fallback axis (no usable linear edge found)"
    Else
        LogEvent " | INFO  | Regular part orientation mode = longest single linear edge horizontal fallback"
    End If

    Dim baseName As String
    baseName = ResolveDxfBaseNameForPart(mdl, partNoResolved, bodyCount, "regular part")
    finalPartNo = Trim$(partNoResolved)
    If Len(finalPartNo) = 0 Then finalPartNo = baseName

    materialResolved = ResolveBestModelPropertyByCandidates(mdl, PROP_CANDIDATES_MATERIAL, materialSource)
    thicknessResolved = ResolveBestModelPropertyByCandidates(mdl, PROP_CANDIDATES_THICKNESS, thicknessSource)
    thicknessResolved = ResolveNestingThicknessForBody(repBody, faceN, thicknessResolved, thicknessSource, "regular part [" & mdl.GetTitle & "]")
    If Len(Trim$(thicknessResolved)) = 0 Then
        gTotalFailed = gTotalFailed + 1
        LogEvent " | FAIL  | Could not resolve geometric nesting thickness for regular part [" & mdl.GetTitle & "]; export skipped to prevent unclassified thickness folder"
        Exit Sub
    End If

    classifiedOutDir = ResolveClassifiedOutputFolder(outDir, materialResolved, thicknessResolved)

    LogEvent " | INFO  | Regular part material source = " & materialSource & " | value=[" & materialResolved & "]"
    LogEvent " | INFO  | Regular part thickness source = " & thicknessSource & " | value=[" & thicknessResolved & "]"
    LogEvent " | INFO  | Classified output folder = " & classifiedOutDir

    Dim finalDxfPath As String
    finalDxfPath = GetUniqueOutputPath(classifiedOutDir, baseName, "dxf")

    If bodyCount > 1 Then
        LogEvent " | WARN  | Regular part has multiple usable bodies but no real cut-list. Existing logic exports representative body only."
    End If

    If ShouldAttemptNativeSheetMetalFlatPatternExport(mdl, bodyCount, "regular part [" & mdl.GetTitle & "]") Then
        LogEvent " | INFO  | Export path = NATIVE_SHEET_METAL_FLAT_PATTERN | regular part [" & mdl.GetTitle & "]"
        If ExportNativeSheetMetalFlatPatternDxf(mdl, finalDxfPath, "regular part [" & mdl.GetTitle & "]") Then
            gTotalExported = gTotalExported + 1
            gTotalNativeSheetMetalFlatPatternExported = gTotalNativeSheetMetalFlatPatternExported + 1
            LogEvent " | OK    | Regular part exported native sheet-metal flat pattern => " & finalDxfPath
            GoTo RegisterRegularPartOutput
        Else
            gTotalNativeSheetMetalFlatPatternFallbacks = gTotalNativeSheetMetalFlatPatternFallbacks + 1
            LogEvent " | WARN  | Regular part native sheet-metal flat-pattern export failed; falling back to existing oriented body workflow => " & finalDxfPath
        End If
    End If

    If bodyCount = 1 And Not DISABLE_SOURCE_PART_DIRECT_EXPORT_FOR_STABILITY Then
        LogEvent " | INFO  | Export path = DIRECT_SOURCE_SINGLE_BODY"
        If ExportSingleBodyPartAsOrientedDxfFromSource(mdl, faceN, xDir, finalDxfPath, mdl.GetTitle, usedPerpCorner) Then
            gTotalExported = gTotalExported + 1
            LogEvent " | OK    | Regular part exported directly from source => " & finalDxfPath
        Else
            LogEvent " | WARN  | Regular part direct-from-source export failed; trying isolated temp-part export => " & finalDxfPath
            If ExportBodyAsOrientedDxf(repBody, faceN, xDir, finalDxfPath, mdl.GetTitle, usedPerpCorner) Then
                gTotalExported = gTotalExported + 1
                LogEvent " | OK    | Regular part exported by isolated temp-part fallback => " & finalDxfPath
            Else
                gTotalFailed = gTotalFailed + 1
                LogEvent " | FAIL  | Regular part direct and isolated fallback export both failed => " & finalDxfPath
                Exit Sub
            End If
        End If
    Else
        If bodyCount = 1 Then
            LogEvent " | INFO  | Export path = TEMP_PART_ISOLATED_BODY | source-part direct export disabled for crash stability"
        Else
            LogEvent " | INFO  | Export path = TEMP_PART_ISOLATED_BODY"
        End If

        If ExportBodyAsOrientedDxf(repBody, faceN, xDir, finalDxfPath, mdl.GetTitle, usedPerpCorner) Then
            gTotalExported = gTotalExported + 1
            LogEvent " | OK    | Regular part exported by isolated temp-part workflow => " & finalDxfPath
        Else
            gTotalFailed = gTotalFailed + 1
            LogEvent " | FAIL  | Regular part isolated temp-part export failed => " & finalDxfPath
            Exit Sub
        End If
    End If

RegisterRegularPartOutput:
    LogEvent " | CHECK | About to register regular-part output metadata/qty/json after successful export"
    perInstanceQty = 1
    itemKey = RegisterOutputItem(finalDxfPath, classifiedOutDir, finalPartNo, materialResolved, thicknessResolved, mdl.GetPathName, GetActiveConfigurationName(mdl), mdl.GetTitle, False)
    RegisterPartTemplateItem gCurrentPartTemplateKey, itemKey, perInstanceQty
    AddQtyForItem itemKey, CLng(perInstanceQty) * CLng(gCurrentPartInstanceMultiplier)

    If WRITE_QTY_JSON_INCREMENTALLY Then
        FlushItemFolderQtyJson itemKey, "regular part immediate qty write"
    End If

    Exit Sub

EH:
    gTotalFailed = gTotalFailed + 1
    LogEvent " | ERROR | ProcessRegularPart(" & mdl.GetTitle & "): " & Err.Number & " - " & Err.Description
End Sub
Private Function UpdateAllCutLists(ByVal mdl As SldWorks.ModelDoc2) As Boolean
    On Error GoTo EH

    UpdateAllCutLists = False

    LogEvent " | INFO  | Rebuilding model before cut-list update"
    mdl.ForceRebuild3 True

    Dim feat As SldWorks.Feature
    Set feat = mdl.FirstFeature

    Dim updatedAny As Boolean
    updatedAny = False

    Do While Not feat Is Nothing
        Dim typeName As String
        typeName = feat.GetTypeName2

        If StrComp(typeName, "SolidBodyFolder", vbTextCompare) = 0 _
        Or StrComp(typeName, "CutListFolder", vbTextCompare) = 0 _
        Or StrComp(typeName, "SubWeldFolder", vbTextCompare) = 0 Then

            Dim bf As Object
            Set bf = Nothing

            On Error Resume Next
            Set bf = feat.GetSpecificFeature2
            On Error GoTo EH

            If Not bf Is Nothing Then
                Dim vRet As Variant
                On Error Resume Next
                vRet = bf.UpdateCutList
                On Error GoTo EH

                LogEvent " | INFO  | UpdateCutList on feature [" & feat.Name & "] => " & CStr(vRet)

                If Not IsEmpty(vRet) Then
                    If CBool(vRet) Then updatedAny = True
                End If
            End If
        End If

        Set feat = feat.GetNextFeature
    Loop

    mdl.ForceRebuild3 True
    UpdateAllCutLists = True

    If Not updatedAny Then
        LogEvent " | WARN  | No body folders explicitly updated; rebuild still performed"
    End If

    Exit Function

EH:
    LogEvent " | ERROR | UpdateAllCutLists: " & Err.Number & " - " & Err.Description
End Function

Private Function IsRealCutListFolderFeature(ByVal feat As SldWorks.Feature) As Boolean
    On Error GoTo EH

    IsRealCutListFolderFeature = False

    If feat Is Nothing Then Exit Function
    If StrComp(feat.GetTypeName2, "CutListFolder", vbTextCompare) <> 0 Then Exit Function

    Dim bf As Object
    Set bf = feat.GetSpecificFeature2
    If bf Is Nothing Then Exit Function

    Dim bodyCount As Long
    bodyCount = 0

    On Error Resume Next
    bodyCount = CLng(bf.GetBodyCount)
    On Error GoTo EH

    LogEvent " | INFO  | Cut-list [" & feat.Name & "] body count = " & bodyCount

    If bodyCount > 0 Then
        IsRealCutListFolderFeature = True
    End If

    Exit Function

EH:
    LogEvent " | ERROR | IsRealCutListFolderFeature(" & feat.Name & "): " & Err.Number & " - " & Err.Description
End Function

Private Sub ProcessSingleCutList(ByVal mdl As SldWorks.ModelDoc2, ByVal cutFeat As SldWorks.Feature, ByVal outDir As String)
    On Error GoTo EH

    gTotalChecked = gTotalChecked + 1

    LogEventRaw String(80, "-")
    LogEvent " | INFO  | Processing cut-list feature: " & cutFeat.Name

    Dim cpMgr As SldWorks.CustomPropertyManager
    Set cpMgr = cutFeat.CustomPropertyManager

    Dim dxfRaw As String
    Dim dxfResolved As String
    Dim effectiveDxfRaw As String
    Dim effectiveDxfResolved As String
    Dim effectiveDxfSource As String
    Dim partNoRaw As String
    Dim partNoResolved As String
    Dim bodyCount As Long
    Dim materialResolved As String
    Dim thicknessResolved As String
    Dim materialSource As String
    Dim thicknessSource As String
    Dim classifiedOutDir As String
    Dim itemBodyQty As Long
    Dim itemKey As String
    Dim finalPartNo As String

    dxfResolved = GetEvaluatedCutListProperty(cpMgr, PROP_DXF, dxfRaw)
    effectiveDxfRaw = dxfRaw
    effectiveDxfResolved = dxfResolved
    effectiveDxfSource = "CUTLIST." & PROP_DXF
    partNoResolved = GetEvaluatedCutListProperty(cpMgr, PROP_PARTNO, partNoRaw)
    bodyCount = CountUsableBodiesInPart(mdl)

    LogEvent " | INFO  | PROP " & PROP_DXF & " raw=[" & dxfRaw & "] eval=[" & dxfResolved & "]"
    LogEvent " | INFO  | PROP " & PROP_PARTNO & " raw=[" & partNoRaw & "] eval=[" & partNoResolved & "]"
    LogEvent " | INFO  | Part usable body count = " & CStr(bodyCount)

    If Len(Trim$(effectiveDxfResolved)) = 0 Then
        If bodyCount = 1 Then
            Dim partExportPropName As String
            effectiveDxfResolved = GetEffectivePartLevelDxfFlag(mdl, partExportPropName, effectiveDxfRaw)
            effectiveDxfSource = "PART." & partExportPropName
            LogEvent " | INFO  | Single-body cut-list fallback to part property [" & partExportPropName & "] raw=[" & effectiveDxfRaw & "] eval=[" & effectiveDxfResolved & "]"
        Else
            LogEvent " | INFO  | Cut-list DXF blank and part is not single-body; no part-level fallback used"
        End If
    End If

    LogEvent " | INFO  | Effective DXF source = " & effectiveDxfSource & " raw=[" & effectiveDxfRaw & "] eval=[" & effectiveDxfResolved & "]"

    If UCase$(Trim$(effectiveDxfResolved)) <> PROP_TRUE_VALUE Then
        gTotalSkipped = gTotalSkipped + 1
        LogEvent " | SKIP  | Effective DXF property is not YES"
        Exit Sub
    End If

    gTotalEligible = gTotalEligible + 1

    Dim repBody As SldWorks.Body2
    Set repBody = GetRepresentativeBodyFromCutList(cutFeat)

    If repBody Is Nothing Then
        gTotalFailed = gTotalFailed + 1
        LogEvent " | FAIL  | No representative body found for cut-list [" & cutFeat.Name & "]"
        Exit Sub
    End If

    Dim faceN(2) As Double
    Dim xDir(2) As Double
    Dim usedFallbackEdge As Boolean
    Dim usedPerpCorner As Boolean

    If Not GetExportOrientationForBody(repBody, "cut-list [" & cutFeat.Name & "]", faceN, xDir, usedFallbackEdge, usedPerpCorner) Then
        gTotalFailed = gTotalFailed + 1
        Exit Sub
    End If

    If gHasOrientationOverride Then
        LogEvent " | INFO  | Cut-list orientation mode = selected drawing view override"
    ElseIf usedPerpCorner Then
        LogEvent " | INFO  | Cut-list orientation mode = perpendicular edge pair -> shared or virtual corner driven bottom-left"
    ElseIf usedFallbackEdge Then
        LogEvent " | WARN  | Cut-list orientation mode = fallback axis (no usable linear edge found)"
    Else
        LogEvent " | INFO  | Cut-list orientation mode = longest single linear edge horizontal fallback"
    End If

    Dim baseName As String
    baseName = ResolveDxfBaseNameForPart(mdl, partNoResolved, bodyCount, "cut-list [" & cutFeat.Name & "]")
    finalPartNo = Trim$(partNoResolved)
    If Len(finalPartNo) = 0 Then finalPartNo = baseName

    materialResolved = ResolveBestCutListOrModelProperty(cutFeat, mdl, PROP_CANDIDATES_MATERIAL, materialSource)
    thicknessResolved = ResolveBestCutListOrModelProperty(cutFeat, mdl, PROP_CANDIDATES_THICKNESS, thicknessSource)
    thicknessResolved = ResolveNestingThicknessForBody(repBody, faceN, thicknessResolved, thicknessSource, "cut-list [" & cutFeat.Name & "]")
    If Len(Trim$(thicknessResolved)) = 0 Then
        gTotalFailed = gTotalFailed + 1
        LogEvent " | FAIL  | Could not resolve geometric nesting thickness for cut-list [" & cutFeat.Name & "]; export skipped to prevent unclassified thickness folder"
        Exit Sub
    End If

    classifiedOutDir = ResolveClassifiedOutputFolder(outDir, materialResolved, thicknessResolved)

    LogEvent " | INFO  | Cut-list material source = " & materialSource & " | value=[" & materialResolved & "]"
    LogEvent " | INFO  | Cut-list thickness source = " & thicknessSource & " | value=[" & thicknessResolved & "]"
    LogEvent " | INFO  | Classified output folder = " & classifiedOutDir

    Dim outputPath As String
    outputPath = GetUniqueOutputPath(classifiedOutDir, baseName, "dxf")

    If ShouldAttemptNativeSheetMetalFlatPatternExport(mdl, bodyCount, "cut-list [" & cutFeat.Name & "]") Then
        LogEvent " | INFO  | Export path = NATIVE_SHEET_METAL_FLAT_PATTERN | cut-list [" & cutFeat.Name & "]"
        If ExportNativeSheetMetalFlatPatternDxf(mdl, outputPath, "cut-list [" & cutFeat.Name & "]") Then
            gTotalExported = gTotalExported + 1
            gTotalNativeSheetMetalFlatPatternExported = gTotalNativeSheetMetalFlatPatternExported + 1
            LogEvent " | OK    | Exported native sheet-metal flat pattern => " & outputPath
            GoTo RegisterCutListOutput
        Else
            gTotalNativeSheetMetalFlatPatternFallbacks = gTotalNativeSheetMetalFlatPatternFallbacks + 1
            LogEvent " | WARN  | Native sheet-metal flat-pattern export failed; falling back to existing oriented body workflow => " & outputPath
        End If
    End If

    If bodyCount = 1 And Not DISABLE_SOURCE_PART_DIRECT_EXPORT_FOR_STABILITY Then
        LogEvent " | INFO  | Export path = DIRECT_SOURCE_SINGLE_BODY"
        If ExportSingleBodyPartAsOrientedDxfFromSource(mdl, faceN, xDir, outputPath, cutFeat.Name, usedPerpCorner) Then
            gTotalExported = gTotalExported + 1
            LogEvent " | OK    | Exported directly from source => " & outputPath
        Else
            LogEvent " | WARN  | Direct-from-source export failed; trying isolated temp-part export => " & outputPath
            If ExportBodyAsOrientedDxf(repBody, faceN, xDir, outputPath, cutFeat.Name, usedPerpCorner) Then
                gTotalExported = gTotalExported + 1
                LogEvent " | OK    | Exported by isolated temp-part fallback => " & outputPath
            Else
                gTotalFailed = gTotalFailed + 1
                LogEvent " | FAIL  | Direct and isolated fallback export both failed => " & outputPath
                Exit Sub
            End If
        End If
    Else
        If bodyCount = 1 Then
            LogEvent " | INFO  | Export path = TEMP_PART_ISOLATED_BODY | source-part direct export disabled for crash stability"
        Else
            LogEvent " | INFO  | Export path = TEMP_PART_ISOLATED_BODY"
        End If

        If ExportBodyAsOrientedDxf(repBody, faceN, xDir, outputPath, cutFeat.Name, usedPerpCorner) Then
            gTotalExported = gTotalExported + 1
            LogEvent " | OK    | Exported by isolated temp-part workflow => " & outputPath
        Else
            gTotalFailed = gTotalFailed + 1
            LogEvent " | FAIL  | Isolated temp-part export failed => " & outputPath
            Exit Sub
        End If
    End If

RegisterCutListOutput:
    LogEvent " | CHECK | About to register cut-list output metadata/qty/json after successful export"
    itemBodyQty = GetCutListFolderBodyCountSafe(cutFeat)
    If itemBodyQty < 1 Then itemBodyQty = 1

    itemKey = RegisterOutputItem(outputPath, classifiedOutDir, finalPartNo, materialResolved, thicknessResolved, mdl.GetPathName, GetActiveConfigurationName(mdl), cutFeat.Name, True)
    RegisterPartTemplateItem gCurrentPartTemplateKey, itemKey, itemBodyQty
    AddQtyForItem itemKey, CLng(itemBodyQty) * CLng(gCurrentPartInstanceMultiplier)

    If WRITE_QTY_JSON_INCREMENTALLY Then
        FlushItemFolderQtyJson itemKey, "cut-list immediate qty write"
    End If

    Exit Sub

EH:
    gTotalFailed = gTotalFailed + 1
    LogEvent " | ERROR | ProcessSingleCutList(" & cutFeat.Name & "): " & Err.Number & " - " & Err.Description
End Sub
Private Function ResolveDxfBaseNameForPart(ByVal mdl As SldWorks.ModelDoc2, _
                                           ByVal preferredPartNo As String, _
                                           ByVal bodyCount As Long, _
                                           ByVal contextLabel As String) As String
    On Error GoTo EH

    Dim baseName As String

    baseName = ""

    If bodyCount = 1 Then
        baseName = GetFileStemFromPath(mdl.GetPathName)
        LogEvent " | INFO  | Single-body " & contextLabel & " uses saved part file name directly for DXF base name => [" & baseName & "]"
    Else
        baseName = Trim$(preferredPartNo)

        If Len(baseName) > 0 Then
            LogEvent " | INFO  | Multi-body " & contextLabel & " uses PART NUMBER for DXF base name => [" & baseName & "]"
        Else
            baseName = GetFileStemFromPath(mdl.GetPathName)
            LogEvent " | WARN  | PART NUMBER missing/blank on " & contextLabel & ", using file name fallback => [" & baseName & "]"
        End If
    End If

    baseName = SanitizeFileName(baseName)
    If Len(baseName) = 0 Then
        baseName = "PART"
        LogEvent " | WARN  | Sanitized DXF base name became blank for " & contextLabel & "; using [PART]"
    End If

    ResolveDxfBaseNameForPart = baseName
    Exit Function

EH:
    LogEvent " | ERROR | ResolveDxfBaseNameForPart(" & contextLabel & "): " & Err.Number & " - " & Err.Description
    ResolveDxfBaseNameForPart = "PART"
End Function

Private Function GetRepresentativeBodyFromCutList(ByVal cutFeat As SldWorks.Feature) As SldWorks.Body2
    On Error GoTo EH

    Dim bf As Object
    Set bf = cutFeat.GetSpecificFeature2

    If bf Is Nothing Then
        LogEvent " | FAIL  | GetSpecificFeature2 returned Nothing for cut-list [" & cutFeat.Name & "]"
        Exit Function
    End If

    Dim bodyCount As Long
    bodyCount = 0

    On Error Resume Next
    bodyCount = CLng(bf.GetBodyCount)
    On Error GoTo EH

    LogEvent " | INFO  | [" & cutFeat.Name & "] GetBodyCount = " & bodyCount

    If bodyCount <= 0 Then
        LogEvent " | FAIL  | [" & cutFeat.Name & "] has no bodies"
        Exit Function
    End If

    Dim vBodies As Variant
    vBodies = bf.GetBodies

    If IsEmpty(vBodies) Then
        LogEvent " | FAIL  | [" & cutFeat.Name & "] GetBodies returned Empty"
        Exit Function
    End If

    If Not IsArray(vBodies) Then
        LogEvent " | FAIL  | [" & cutFeat.Name & "] GetBodies did not return an array"
        Exit Function
    End If

    Dim i As Long
    Dim b As SldWorks.Body2
    Dim bt As Long

    For i = LBound(vBodies) To UBound(vBodies)
        Set b = Nothing
        On Error Resume Next
        Set b = vBodies(i)
        On Error GoTo EH

        If Not b Is Nothing Then
            bt = SafeGetBodyType(b)
            LogEvent " | INFO  | [" & cutFeat.Name & "] Body(" & i & ") type = " & bt & " [" & BodyTypeName(bt) & "]"

            If bt = BODYTYPE_SOLID Then
                Set GetRepresentativeBodyFromCutList = b
                LogEvent " | INFO  | [" & cutFeat.Name & "] representative = SOLID body index " & i
                Exit Function
            End If
        Else
            LogEvent " | WARN  | [" & cutFeat.Name & "] Body(" & i & ") is Nothing"
        End If
    Next i

    For i = LBound(vBodies) To UBound(vBodies)
        Set b = Nothing
        On Error Resume Next
        Set b = vBodies(i)
        On Error GoTo EH

        If Not b Is Nothing Then
            bt = SafeGetBodyType(b)

            If bt = BODYTYPE_SHEET Or bt = BODYTYPE_GENERAL Then
                Set GetRepresentativeBodyFromCutList = b
                LogEvent " | INFO  | [" & cutFeat.Name & "] representative = fallback body index " & i & " [" & BodyTypeName(bt) & "]"
                Exit Function
            End If
        End If
    Next i

    LogEvent " | FAIL  | [" & cutFeat.Name & "] no usable representative body found"
    Exit Function

EH:
    LogEvent " | ERROR | GetRepresentativeBodyFromCutList(" & cutFeat.Name & "): " & Err.Number & " - " & Err.Description
End Function

Private Function GetRepresentativeBodyFromPart(ByVal mdl As SldWorks.ModelDoc2) As SldWorks.Body2
    On Error GoTo EH

    If mdl Is Nothing Then Exit Function
    If mdl.GetType <> swDocPART Then Exit Function

    Dim p As SldWorks.PartDoc
    Set p = mdl

    Dim vBodies As Variant
    vBodies = p.GetBodies2(swSolidBody, True)

    If IsEmpty(vBodies) Then
        LogEvent " | WARN  | No solid bodies found. Trying all bodies for regular part."
        vBodies = p.GetBodies2(swAllBodies, True)
    End If

    If IsEmpty(vBodies) Then
        LogEvent " | FAIL  | GetBodies2 returned Empty for regular part"
        Exit Function
    End If

    If Not IsArray(vBodies) Then
        LogEvent " | FAIL  | GetBodies2 did not return an array for regular part"
        Exit Function
    End If

    Dim i As Long
    Dim b As SldWorks.Body2
    Dim bt As Long

    For i = LBound(vBodies) To UBound(vBodies)
        Set b = Nothing
        On Error Resume Next
        Set b = vBodies(i)
        On Error GoTo EH

        If Not b Is Nothing Then
            bt = SafeGetBodyType(b)
            LogEvent " | INFO  | Regular part Body(" & i & ") type = " & bt & " [" & BodyTypeName(bt) & "]"

            If bt = BODYTYPE_SOLID Then
                Set GetRepresentativeBodyFromPart = b
                LogEvent " | INFO  | Regular part representative = SOLID body index " & i
                Exit Function
            End If
        Else
            LogEvent " | WARN  | Regular part Body(" & i & ") is Nothing"
        End If
    Next i

    For i = LBound(vBodies) To UBound(vBodies)
        Set b = Nothing
        On Error Resume Next
        Set b = vBodies(i)
        On Error GoTo EH

        If Not b Is Nothing Then
            bt = SafeGetBodyType(b)

            If bt = BODYTYPE_SHEET Or bt = BODYTYPE_GENERAL Then
                Set GetRepresentativeBodyFromPart = b
                LogEvent " | INFO  | Regular part representative = fallback body index " & i & " [" & BodyTypeName(bt) & "]"
                Exit Function
            End If
        End If
    Next i

    LogEvent " | FAIL  | No usable representative body found for regular part"
    Exit Function

EH:
    LogEvent " | ERROR | GetRepresentativeBodyFromPart(" & mdl.GetTitle & "): " & Err.Number & " - " & Err.Description
End Function


Private Function SafeGetBodyType(ByVal body As SldWorks.Body2) As Long
    On Error GoTo EH
    SafeGetBodyType = body.GetType
    Exit Function
EH:
    LogEvent " | ERROR | SafeGetBodyType: " & Err.Number & " - " & Err.Description
    SafeGetBodyType = -999
End Function

Private Function BodyTypeName(ByVal bodyType As Long) As String
    Select Case bodyType
        Case BODYTYPE_SOLID:   BodyTypeName = "SOLID"
        Case BODYTYPE_SHEET:   BodyTypeName = "SHEET"
        Case BODYTYPE_WIRE:    BodyTypeName = "WIRE"
        Case BODYTYPE_MINIMUM: BodyTypeName = "MINIMUM"
        Case BODYTYPE_GENERAL: BodyTypeName = "GENERAL"
        Case BODYTYPE_EMPTY:   BodyTypeName = "EMPTY"
        Case Else:             BodyTypeName = "UNKNOWN"
    End Select
End Function

Private Function CountUsableBodiesInPart(ByVal mdl As SldWorks.ModelDoc2) As Long
    On Error GoTo EH

    CountUsableBodiesInPart = 0

    If mdl Is Nothing Then Exit Function
    If mdl.GetType <> swDocPART Then Exit Function

    Dim p As SldWorks.PartDoc
    Set p = mdl

    Dim vBodies As Variant
    vBodies = p.GetBodies2(swAllBodies, True)

    If IsEmpty(vBodies) Then
        LogEvent " | WARN  | CountUsableBodiesInPart: GetBodies2 returned Empty"
        Exit Function
    End If

    If Not IsArray(vBodies) Then
        LogEvent " | WARN  | CountUsableBodiesInPart: GetBodies2 did not return an array"
        Exit Function
    End If

    Dim i As Long
    Dim b As SldWorks.Body2
    Dim bt As Long

    For i = LBound(vBodies) To UBound(vBodies)
        Set b = Nothing
        On Error Resume Next
        Set b = vBodies(i)
        On Error GoTo EH

        If Not b Is Nothing Then
            bt = SafeGetBodyType(b)
            If bt = BODYTYPE_SOLID Or bt = BODYTYPE_SHEET Or bt = BODYTYPE_GENERAL Then
                CountUsableBodiesInPart = CountUsableBodiesInPart + 1
            End If
        End If
    Next i

    LogEvent " | INFO  | CountUsableBodiesInPart = " & CStr(CountUsableBodiesInPart)
    Exit Function

EH:
    LogEvent " | ERROR | CountUsableBodiesInPart(" & mdl.GetTitle & "): " & Err.Number & " - " & Err.Description
End Function

Private Function GetEffectivePartLevelDxfFlag(ByVal mdl As SldWorks.ModelDoc2, _
                                              ByRef sourcePropName As String, _
                                              ByRef rawValOut As String) As String
    On Error GoTo EH

    Dim rawPrimary As String
    Dim rawLegacy As String
    Dim evalPrimary As String
    Dim evalLegacy As String

    sourcePropName = PROP_DXF
    rawValOut = ""
    GetEffectivePartLevelDxfFlag = ""

    evalPrimary = GetEvaluatedModelProperty(mdl, PROP_DXF, rawPrimary)
    LogEvent " | INFO  | Effective part export lookup primary [" & PROP_DXF & "] raw=[" & rawPrimary & "] eval=[" & evalPrimary & "]"

    If Len(Trim$(evalPrimary)) > 0 Or Len(Trim$(rawPrimary)) > 0 Then
        sourcePropName = PROP_DXF
        rawValOut = rawPrimary
        GetEffectivePartLevelDxfFlag = evalPrimary
        Exit Function
    End If

    evalLegacy = GetEvaluatedModelProperty(mdl, PROP_DXY, rawLegacy)
    LogEvent " | INFO  | Effective part export lookup legacy [" & PROP_DXY & "] raw=[" & rawLegacy & "] eval=[" & evalLegacy & "]"

    sourcePropName = PROP_DXY
    rawValOut = rawLegacy
    GetEffectivePartLevelDxfFlag = evalLegacy
    Exit Function

EH:
    LogEvent " | ERROR | GetEffectivePartLevelDxfFlag: " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' PROPERTY HELPERS
'=========================================================================================
Private Function GetEvaluatedCutListProperty(ByVal cpMgr As SldWorks.CustomPropertyManager, _
                                             ByVal propName As String, _
                                             ByRef rawValOut As String) As String
    On Error GoTo EH

    rawValOut = ""

    If cpMgr Is Nothing Then Exit Function

    Dim rawVal As String
    Dim evalVal As String
    Dim wasResolved As Boolean
    Dim isLinked As Boolean
    Dim ret As Long

    rawVal = ""
    evalVal = ""
    wasResolved = False
    isLinked = False

    ret = cpMgr.Get6(propName, False, rawVal, evalVal, wasResolved, isLinked)

    rawValOut = NzStr(rawVal)

    If Len(Trim$(evalVal)) > 0 Then
        GetEvaluatedCutListProperty = Trim$(evalVal)
    Else
        GetEvaluatedCutListProperty = Trim$(rawVal)
    End If

    Exit Function
EH:
    LogEvent " | ERROR | GetEvaluatedCutListProperty(" & propName & "): " & Err.Number & " - " & Err.Description
End Function

Private Function GetEvaluatedModelProperty(ByVal mdl As SldWorks.ModelDoc2, _
                                           ByVal propName As String, _
                                           ByRef rawValOut As String) As String
    On Error GoTo EH

    rawValOut = ""
    GetEvaluatedModelProperty = ""

    If mdl Is Nothing Then Exit Function

    Dim cfgName As String
    Dim cpMgr As SldWorks.CustomPropertyManager
    Dim tempRaw As String
    Dim tempEval As String

    cfgName = GetActiveConfigurationName(mdl)

    If Len(cfgName) > 0 Then
        Set cpMgr = mdl.Extension.CustomPropertyManager(cfgName)
        If Not cpMgr Is Nothing Then
            tempEval = GetEvaluatedPropertyValue(cpMgr, propName, tempRaw)
            LogEvent " | INFO  | Config property lookup [" & cfgName & "] " & propName & " raw=[" & tempRaw & "] eval=[" & tempEval & "]"
            If Len(Trim$(tempEval)) > 0 Or Len(Trim$(tempRaw)) > 0 Then
                rawValOut = tempRaw
                GetEvaluatedModelProperty = tempEval
                Exit Function
            End If
        End If
    End If

    Set cpMgr = mdl.Extension.CustomPropertyManager("")
    If Not cpMgr Is Nothing Then
        tempEval = GetEvaluatedPropertyValue(cpMgr, propName, tempRaw)
        LogEvent " | INFO  | File property lookup " & propName & " raw=[" & tempRaw & "] eval=[" & tempEval & "]"
        rawValOut = tempRaw
        GetEvaluatedModelProperty = tempEval
    End If

    Exit Function

EH:
    LogEvent " | ERROR | GetEvaluatedModelProperty(" & propName & "): " & Err.Number & " - " & Err.Description
End Function

Private Function ResolveBestCutListOrModelProperty(ByVal cutFeat As SldWorks.Feature, _
                                                   ByVal mdl As SldWorks.ModelDoc2, _
                                                   ByVal candidateList As String, _
                                                   ByRef sourceOut As String) As String
    On Error GoTo EH

    Dim cpMgr As SldWorks.CustomPropertyManager
    Dim propNames As Variant
    Dim i As Long
    Dim propName As String
    Dim rawVal As String
    Dim evalVal As String

    sourceOut = ""

    If Not cutFeat Is Nothing Then
        Set cpMgr = cutFeat.CustomPropertyManager
    End If

    propNames = Split(candidateList, "|")

    If Not cpMgr Is Nothing Then
        For i = LBound(propNames) To UBound(propNames)
            propName = Trim$(CStr(propNames(i)))
            If Len(propName) > 0 Then
                evalVal = GetEvaluatedCutListProperty(cpMgr, propName, rawVal)
                LogEvent " | INFO  | Cut-list property lookup [" & propName & "] raw=[" & rawVal & "] eval=[" & evalVal & "]"
                If Len(Trim$(evalVal)) > 0 Or Len(Trim$(rawVal)) > 0 Then
                    sourceOut = "CUTLIST." & propName
                    ResolveBestCutListOrModelProperty = evalVal
                    Exit Function
                End If
            End If
        Next i
    End If

    ResolveBestCutListOrModelProperty = ResolveBestModelPropertyByCandidates(mdl, candidateList, sourceOut)
    Exit Function

EH:
    LogEvent " | ERROR | ResolveBestCutListOrModelProperty: " & Err.Number & " - " & Err.Description
End Function

Private Function ResolveBestModelPropertyByCandidates(ByVal mdl As SldWorks.ModelDoc2, _
                                                      ByVal candidateList As String, _
                                                      ByRef sourceOut As String) As String
    On Error GoTo EH

    Dim propNames As Variant
    Dim i As Long
    Dim propName As String
    Dim rawVal As String
    Dim evalVal As String

    sourceOut = ""
    propNames = Split(candidateList, "|")

    For i = LBound(propNames) To UBound(propNames)
        propName = Trim$(CStr(propNames(i)))
        If Len(propName) > 0 Then
            evalVal = GetEvaluatedModelProperty(mdl, propName, rawVal)
            LogEvent " | INFO  | Model property candidate [" & propName & "] raw=[" & rawVal & "] eval=[" & evalVal & "]"
            If Len(Trim$(evalVal)) > 0 Or Len(Trim$(rawVal)) > 0 Then
                sourceOut = "MODEL." & propName
                ResolveBestModelPropertyByCandidates = evalVal
                Exit Function
            End If
        End If
    Next i

    Exit Function

EH:
    LogEvent " | ERROR | ResolveBestModelPropertyByCandidates: " & Err.Number & " - " & Err.Description
End Function

Private Function ResolveClassifiedOutputFolder(ByVal rootOutDir As String, _
                                               ByVal materialVal As String, _
                                               ByVal thicknessVal As String) As String
    On Error GoTo EH

    Dim materialFolder As String
    Dim thicknessFolder As String
    Dim fullPath As String

    materialFolder = NormalizeMaterialFolderName(materialVal)
    thicknessFolder = NormalizeThicknessFolderName(thicknessVal)

    fullPath = EnsureFolderExists(rootOutDir & "\" & materialFolder)
    If Len(fullPath) = 0 Then Exit Function

    fullPath = EnsureFolderExists(fullPath & "\" & thicknessFolder)
    ResolveClassifiedOutputFolder = fullPath
    Exit Function

EH:
    LogEvent " | ERROR | ResolveClassifiedOutputFolder: " & Err.Number & " - " & Err.Description
End Function

Private Function NormalizeMaterialFolderName(ByVal rawVal As String) As String
    Dim s As String
    Dim aliasName As String

    s = Trim$(rawVal)
    If Len(s) = 0 Then
        gTotalMissingMaterial = gTotalMissingMaterial + 1
        NormalizeMaterialFolderName = UNKNOWN_MATERIAL_FOLDER
        Exit Function
    End If

    s = UCase$(s)

    If STRIP_THICKNESS_TEXT_FROM_MATERIAL_FOLDER Then
        s = StripThicknessTextFromMaterialName(s)
    End If

    s = Replace$(s, Chr$(34), " IN ")
    s = Replace$(s, vbTab, " ")
    s = Replace$(s, "-", " ")
    s = Replace$(s, "_", " ")
    s = Replace$(s, "/", " ")
    s = Replace$(s, "\", " ")
    s = Replace$(s, ".", " ")
    s = CollapseSpaces(s)

    If USE_MATERIAL_ALIAS_NORMALIZATION Then
        aliasName = MaterialAliasFolderName(s)
        If Len(aliasName) > 0 Then
            NormalizeMaterialFolderName = aliasName
            Exit Function
        End If
    End If

    s = UCase$(SanitizeFileName(s))
    s = Replace$(s, " ", "_")
    s = CollapseUnderscores(s)
    If Len(s) = 0 Then s = UNKNOWN_MATERIAL_FOLDER

    NormalizeMaterialFolderName = s
End Function

Private Function ResolveNestingThicknessForBody(ByVal srcBody As SldWorks.Body2, _
                                                ByRef faceNormal() As Double, _
                                                ByVal propertyThicknessVal As String, _
                                                ByRef thicknessSource As String, _
                                                ByVal contextLabel As String) As String
    On Error GoTo EH

    ResolveNestingThicknessForBody = ""

    Dim geomInches As Double
    Dim propInches As Double
    Dim hasPropInches As Boolean

    hasPropInches = TryParseThicknessToInches(propertyThicknessVal, propInches)

    If GEOMETRIC_THICKNESS_FOR_NESTING_FOLDER Then
        If GetBodyThicknessInchesAlongNormal(srcBody, faceNormal, geomInches, contextLabel) Then
            ResolveNestingThicknessForBody = FormatThicknessInchesValue(geomInches)
            thicknessSource = "GEOMETRY.NORMAL_EXTENT_INCHES"

            gTotalGeometricThicknessUsed = gTotalGeometricThicknessUsed + 1

            LogEvent " | INFO  | Geometric nesting thickness selected for " & contextLabel & _
                        " | inches=" & Format$(geomInches, "0.000000") & _
                        " | folderValue=" & ResolveNestingThicknessForBody

            If hasPropInches Then
                If Abs(propInches - geomInches) > 0.003 Then
                    LogEvent " | WARN  | Property thickness differs from geometric nesting thickness for " & contextLabel & _
                                " | property=[" & propertyThicknessVal & "] => " & Format$(propInches, "0.000000") & _
                                " | geometry=" & Format$(geomInches, "0.000000") & _
                                " | using GEOMETRY"
                Else
                    LogEvent " | INFO  | Property thickness agrees with geometric nesting thickness for " & contextLabel & _
                                " | property=[" & propertyThicknessVal & "]"
                End If
            ElseIf Len(Trim$(propertyThicknessVal)) > 0 Then
                LogEvent " | WARN  | Thickness property existed but could not be parsed for comparison on " & contextLabel & _
                            " | property=[" & propertyThicknessVal & "] | using GEOMETRY"
            Else
                LogEvent " | INFO  | No usable thickness property found for " & contextLabel & "; using GEOMETRY"
            End If

            Exit Function
        End If

        gTotalGeometricThicknessFailed = gTotalGeometricThicknessFailed + 1
        LogEvent " | FAIL  | Geometric nesting thickness failed for " & contextLabel

        If FAIL_ITEM_WHEN_GEOMETRIC_THICKNESS_FAILS Then
            ResolveNestingThicknessForBody = ""
            Exit Function
        End If
    End If

    If hasPropInches Then
        ResolveNestingThicknessForBody = FormatThicknessInchesValue(propInches)
        If Len(Trim$(thicknessSource)) = 0 Then thicknessSource = "PROPERTY.PARSED_FALLBACK"
        LogEvent " | WARN  | Falling back to parsed property thickness for " & contextLabel & _
                    " | property=[" & propertyThicknessVal & "] | folderValue=" & ResolveNestingThicknessForBody
        Exit Function
    End If

    gTotalMissingThickness = gTotalMissingThickness + 1
    LogEvent " | FAIL  | No geometric or property thickness could be resolved for " & contextLabel
    ResolveNestingThicknessForBody = ""
    Exit Function

EH:
    gTotalGeometricThicknessFailed = gTotalGeometricThicknessFailed + 1
    LogEvent " | ERROR | ResolveNestingThicknessForBody(" & contextLabel & "): " & Err.Number & " - " & Err.Description
    ResolveNestingThicknessForBody = ""
End Function

Private Function GetBodyThicknessInchesAlongNormal(ByVal srcBody As SldWorks.Body2, _
                                                   ByRef faceNormal() As Double, _
                                                   ByRef thicknessInchesOut As Double, _
                                                   ByVal contextLabel As String) As Boolean
    On Error GoTo EH

    GetBodyThicknessInchesAlongNormal = False
    thicknessInchesOut = 0#

    If srcBody Is Nothing Then
        LogEvent " | FAIL  | GetBodyThicknessInchesAlongNormal: srcBody is Nothing for " & contextLabel
        Exit Function
    End If

    If Not ArrayHasThreeVectorValues(faceNormal) Then
        LogEvent " | FAIL  | GetBodyThicknessInchesAlongNormal: faceNormal is not usable for " & contextLabel
        Exit Function
    End If

    Dim n(2) As Double
    n(0) = CDbl(faceNormal(0))
    n(1) = CDbl(faceNormal(1))
    n(2) = CDbl(faceNormal(2))
    NormalizeVec n

    If VecLength(n) <= EPS Then
        LogEvent " | FAIL  | GetBodyThicknessInchesAlongNormal: normalized normal length is zero for " & contextLabel
        Exit Function
    End If

    Dim pxMax As Double, pyMax As Double, pzMax As Double
    Dim pxMin As Double, pyMin As Double, pzMin As Double
    Dim okMax As Boolean, okMin As Boolean

    okMax = srcBody.GetExtremePoint(n(0), n(1), n(2), pxMax, pyMax, pzMax)
    okMin = srcBody.GetExtremePoint(-n(0), -n(1), -n(2), pxMin, pyMin, pzMin)

    LogEvent " | INFO  | Thickness extreme-point status for " & contextLabel & _
                " | okMax=" & CStr(okMax) & " | okMin=" & CStr(okMin)

    If Not okMax Or Not okMin Then
        LogEvent " | FAIL  | Body2.GetExtremePoint failed while calculating nesting thickness for " & contextLabel
        Exit Function
    End If

    Dim dx As Double, dy As Double, dz As Double
    Dim distM As Double

    dx = pxMax - pxMin
    dy = pyMax - pyMin
    dz = pzMax - pzMin

    distM = Abs(dx * n(0) + dy * n(1) + dz * n(2))

    LogEvent " | INFO  | Thickness points for " & contextLabel & _
                " | Pmax=(" & Format$(pxMax, "0.00000000") & ", " & Format$(pyMax, "0.00000000") & ", " & Format$(pzMax, "0.00000000") & ")" & _
                " | Pmin=(" & Format$(pxMin, "0.00000000") & ", " & Format$(pyMin, "0.00000000") & ", " & Format$(pzMin, "0.00000000") & ")" & _
                " | distM=" & Format$(distM, "0.00000000")

    If distM <= EPS Then
        LogEvent " | FAIL  | Calculated nesting thickness distance is zero/too small for " & contextLabel
        Exit Function
    End If

    thicknessInchesOut = distM * METER_TO_INCH

    If thicknessInchesOut <= 0# Then
        LogEvent " | FAIL  | Calculated nesting thickness inches is invalid for " & contextLabel
        Exit Function
    End If

    LogEvent " | INFO  | Geometric nesting thickness for " & contextLabel & _
                " = " & Format$(thicknessInchesOut, "0.000000") & " in -> folder " & FormatThicknessInchesFolder(thicknessInchesOut)

    GetBodyThicknessInchesAlongNormal = True
    Exit Function

EH:
    LogEvent " | ERROR | GetBodyThicknessInchesAlongNormal(" & contextLabel & "): " & Err.Number & " - " & Err.Description
    GetBodyThicknessInchesAlongNormal = False
End Function

Private Function ArrayHasThreeVectorValues(ByRef arr() As Double) As Boolean
    On Error GoTo EH
    Dim lb As Long
    Dim ub As Long

    lb = LBound(arr)
    ub = UBound(arr)

    If (ub - lb + 1) < 3 Then Exit Function

    ArrayHasThreeVectorValues = True
    Exit Function

EH:
    ArrayHasThreeVectorValues = False
End Function

Private Function NormalizeThicknessFolderName(ByVal rawVal As String) As String
    Dim s As String
    Dim inches As Double

    s = Trim$(rawVal)
    If Len(s) = 0 Then
        gTotalMissingThickness = gTotalMissingThickness + 1
        NormalizeThicknessFolderName = UNKNOWN_THICKNESS_FOLDER
        Exit Function
    End If

    If NORMALIZE_THICKNESS_TO_INCH_FOLDERS Then
        If TryParseThicknessToInches(s, inches) Then
            If inches > 0# Then
                NormalizeThicknessFolderName = FormatThicknessInchesFolder(inches)
                Exit Function
            End If
        End If
    End If

    s = Replace$(s, Chr$(34), " IN ")
    s = Replace$(s, vbTab, " ")
    s = CollapseSpaces(s)
    s = UCase$(SanitizeFileName(s))
    s = Replace$(s, " ", "_")
    s = CollapseUnderscores(s)
    If Len(s) = 0 Then s = UNKNOWN_THICKNESS_FOLDER

    NormalizeThicknessFolderName = s
End Function

Private Function GetCutListFolderBodyCountSafe(ByVal cutFeat As SldWorks.Feature) As Long
    On Error GoTo EH

    GetCutListFolderBodyCountSafe = 0

    If cutFeat Is Nothing Then Exit Function

    Dim bf As Object
    Set bf = cutFeat.GetSpecificFeature2
    If bf Is Nothing Then Exit Function

    On Error Resume Next
    GetCutListFolderBodyCountSafe = CLng(bf.GetBodyCount)
    If Err.Number <> 0 Then
        Err.Clear
        GetCutListFolderBodyCountSafe = 0
    End If
    On Error GoTo EH

    Exit Function

EH:
    LogEvent " | ERROR | GetCutListFolderBodyCountSafe: " & Err.Number & " - " & Err.Description
End Function

Private Function BuildPartTemplateKey(ByVal modelPath As String, ByVal cfgName As String) As String
    BuildPartTemplateKey = UCase$(Trim$(modelPath)) & "|" & UCase$(Trim$(cfgName))
End Function

Private Sub EnsurePartTemplateExists(ByVal partKey As String)
    On Error GoTo EH

    If Len(Trim$(partKey)) = 0 Then Exit Sub
    If gPartTemplateByKey Is Nothing Then Exit Sub

    If Not gPartTemplateByKey.Exists(partKey) Then
        Dim dictTemplate As Object
        Set dictTemplate = CreateObject("Scripting.Dictionary")
        dictTemplate.CompareMode = vbTextCompare
        gPartTemplateByKey.Add partKey, dictTemplate
        LogEvent " | INFO  | Created part qty template bucket => " & partKey
    End If

    Exit Sub

EH:
    LogEvent " | ERROR | EnsurePartTemplateExists: " & Err.Number & " - " & Err.Description
End Sub

Private Sub RegisterPartTemplateItem(ByVal partKey As String, ByVal itemKey As String, ByVal qtyPerInstance As Long)
    On Error GoTo EH

    If Len(Trim$(partKey)) = 0 Then Exit Sub
    If Len(Trim$(itemKey)) = 0 Then Exit Sub

    EnsurePartTemplateExists partKey

    Dim dictTemplate As Object
    Set dictTemplate = gPartTemplateByKey(partKey)

    If dictTemplate.Exists(itemKey) Then
        dictTemplate(itemKey) = CLng(dictTemplate(itemKey)) + CLng(qtyPerInstance)
    Else
        dictTemplate.Add itemKey, CLng(qtyPerInstance)
    End If

    LogEvent " | INFO  | Template item registered | partKey=" & partKey & " | itemKey=" & itemKey & " | qtyPerInstance=" & CStr(qtyPerInstance)
    Exit Sub

EH:
    LogEvent " | ERROR | RegisterPartTemplateItem: " & Err.Number & " - " & Err.Description
End Sub

Private Sub AddQtyFromExistingPartTemplate(ByVal partKey As String, ByVal instanceMultiplier As Long, ByVal sourceLabel As String)
    On Error GoTo EH

    If Len(Trim$(partKey)) = 0 Then Exit Sub
    If instanceMultiplier < 1 Then instanceMultiplier = 1

    If gPartTemplateByKey Is Nothing Then Exit Sub
    If Not gPartTemplateByKey.Exists(partKey) Then
        LogEvent " | WARN  | No qty template exists for duplicate part occurrence: " & sourceLabel & " | partKey=" & partKey
        Exit Sub
    End If

    Dim dictTemplate As Object
    Dim k As Variant
    Set dictTemplate = gPartTemplateByKey(partKey)

    If dictTemplate Is Nothing Then Exit Sub

    For Each k In dictTemplate.Keys
        AddQtyForItem CStr(k), CLng(dictTemplate(k)) * CLng(instanceMultiplier)
        If WRITE_QTY_JSON_INCREMENTALLY Then
            FlushItemFolderQtyJson CStr(k), "duplicate part occurrence immediate qty write"
        End If
    Next k

    LogEvent " | INFO  | Added qty from existing template | source=" & sourceLabel & " | partKey=" & partKey & " | multiplier=" & CStr(instanceMultiplier)
    Exit Sub

EH:
    LogEvent " | ERROR | AddQtyFromExistingPartTemplate: " & Err.Number & " - " & Err.Description
End Sub

Private Function RegisterOutputItem(ByVal finalDxfPath As String, _
                                    ByVal folderPath As String, _
                                    ByVal partNumber As String, _
                                    ByVal materialVal As String, _
                                    ByVal thicknessVal As String, _
                                    ByVal sourceModelPath As String, _
                                    ByVal sourceConfig As String, _
                                    ByVal sourceItemLabel As String, _
                                    ByVal isCutList As Boolean) As String
    On Error GoTo EH

    Dim itemKey As String
    itemKey = UCase$(Trim$(finalDxfPath))

    If Len(itemKey) = 0 Then Exit Function

    If Not gItemMetadataByKey.Exists(itemKey) Then
        Dim rec As Object
        Set rec = CreateObject("Scripting.Dictionary")
        rec.CompareMode = vbTextCompare
        rec.Add "file", GetFileNameFromPath(finalDxfPath)
        rec.Add "partNumber", NzStr(partNumber)
        rec.Add "material", NzStr(materialVal)
        rec.Add "thickness", NzStr(thicknessVal)
        rec.Add "folderPath", folderPath
        rec.Add "sourceModelPath", sourceModelPath
        rec.Add "configuration", sourceConfig
        rec.Add "sourceItem", sourceItemLabel
        rec.Add "sourceType", IIf(isCutList, "CUTLIST", "PART")
        gItemMetadataByKey.Add itemKey, rec
        LogEvent " | INFO  | Registered output item => " & finalDxfPath
    End If

    AddItemKeyToFolderBucket folderPath, itemKey

    RegisterOutputItem = itemKey
    Exit Function

EH:
    LogEvent " | ERROR | RegisterOutputItem: " & Err.Number & " - " & Err.Description
End Function

Private Sub AddItemKeyToFolderBucket(ByVal folderPath As String, ByVal itemKey As String)
    On Error GoTo EH

    If Len(Trim$(folderPath)) = 0 Then Exit Sub
    If Len(Trim$(itemKey)) = 0 Then Exit Sub

    Dim bucket As Object

    If Not gFolderItemsByPath.Exists(folderPath) Then
        Set bucket = CreateObject("Scripting.Dictionary")
        bucket.CompareMode = vbTextCompare
        gFolderItemsByPath.Add folderPath, bucket
        gTotalClassifiedFolders = gTotalClassifiedFolders + 1
        LogEvent " | INFO  | New classified folder bucket registered => " & folderPath
    Else
        Set bucket = gFolderItemsByPath(folderPath)
    End If

    If Not bucket.Exists(itemKey) Then
        bucket.Add itemKey, True
    End If

    Exit Sub

EH:
    LogEvent " | ERROR | AddItemKeyToFolderBucket: " & Err.Number & " - " & Err.Description
End Sub

Private Sub AddQtyForItem(ByVal itemKey As String, ByVal qtyToAdd As Long)
    On Error GoTo EH

    If Len(Trim$(itemKey)) = 0 Then Exit Sub
    If qtyToAdd <= 0 Then Exit Sub

    If gItemQtyByKey.Exists(itemKey) Then
        gItemQtyByKey(itemKey) = CLng(gItemQtyByKey(itemKey)) + CLng(qtyToAdd)
    Else
        gItemQtyByKey.Add itemKey, CLng(qtyToAdd)
    End If

    gTotalQtyAccumulated = gTotalQtyAccumulated + CLng(qtyToAdd)
    LogEvent " | INFO  | Qty added | itemKey=" & itemKey & " | add=" & CStr(qtyToAdd) & " | total=" & CStr(gItemQtyByKey(itemKey))
    Exit Sub

EH:
    LogEvent " | ERROR | AddQtyForItem: " & Err.Number & " - " & Err.Description
End Sub

Private Function WriteAllQtyJsonFiles() As Boolean
    On Error GoTo EH

    WriteAllQtyJsonFiles = False

    If gFolderItemsByPath Is Nothing Then
        WriteAllQtyJsonFiles = True
        Exit Function
    End If

    Dim folderPath As Variant

    For Each folderPath In gFolderItemsByPath.Keys
        If WriteQtyJsonForFolder(CStr(folderPath), True, "final batch write") Then
            LogEvent " | INFO  | Final QTY JSON write complete for folder => " & CStr(folderPath)
        Else
            LogEvent " | WARN  | Final QTY JSON write failed for folder => " & CStr(folderPath)
        End If
    Next folderPath

    WriteAllQtyJsonFiles = True
    Exit Function

EH:
    LogEvent " | ERROR | WriteAllQtyJsonFiles: " & Err.Number & " - " & Err.Description
End Function

Private Function WriteQtyJsonForFolder(ByVal folderPath As String, ByVal countAsFinalWrite As Boolean, ByVal reason As String) As Boolean
    On Error GoTo EH

    WriteQtyJsonForFolder = False

    If Len(Trim$(folderPath)) = 0 Then Exit Function
    If Not FolderExistsSafe(folderPath) Then
        LogEvent " | WARN  | WriteQtyJsonForFolder target folder does not exist: " & folderPath
        Exit Function
    End If

    Dim jsonText As String
    Dim simpleJsonText As String
    Dim recordCount As Long
    Dim simpleRecordCount As Long
    Dim jsonPath As String
    Dim simpleJsonPath As String

    jsonText = BuildFolderQtyJson(folderPath, recordCount)
    jsonPath = folderPath & "\" & JSON_FILE_NAME

    If WriteTextFile(jsonPath, jsonText) Then
        If countAsFinalWrite Then
            gTotalJsonFilesWritten = gTotalJsonFilesWritten + 1
            gTotalJsonRecordsWritten = gTotalJsonRecordsWritten + recordCount
        End If
        LogEvent " | INFO  | Wrote QTY.json => " & jsonPath & " | records=" & CStr(recordCount) & " | reason=" & reason
    Else
        LogEvent " | WARN  | Failed to write QTY.json => " & jsonPath & " | reason=" & reason
        Exit Function
    End If

    If WRITE_SIMPLE_QTY_JSON Then
        simpleJsonText = BuildFolderSimpleQtyJson(folderPath, simpleRecordCount)
        simpleJsonPath = folderPath & "\" & JSON_SIMPLE_FILE_NAME

        If WriteTextFile(simpleJsonPath, simpleJsonText) Then
            If countAsFinalWrite Then
                gTotalJsonFilesWritten = gTotalJsonFilesWritten + 1
                gTotalSimpleJsonFilesWritten = gTotalSimpleJsonFilesWritten + 1
            End If
            LogEvent " | INFO  | Wrote QTY_SIMPLE.json => " & simpleJsonPath & " | records=" & CStr(simpleRecordCount) & " | reason=" & reason
        Else
            LogEvent " | WARN  | Failed to write QTY_SIMPLE.json => " & simpleJsonPath & " | reason=" & reason
            Exit Function
        End If
    End If

    If Not countAsFinalWrite Then
        gTotalImmediateJsonFlushes = gTotalImmediateJsonFlushes + 1
    End If

    WriteQtyJsonForFolder = True
    Exit Function

EH:
    LogEvent " | ERROR | WriteQtyJsonForFolder(" & folderPath & "): " & Err.Number & " - " & Err.Description
End Function

Private Sub FlushItemFolderQtyJson(ByVal itemKey As String, ByVal reason As String)
    On Error GoTo EH

    If Len(Trim$(itemKey)) = 0 Then Exit Sub
    If gItemMetadataByKey Is Nothing Then Exit Sub
    If Not gItemMetadataByKey.Exists(itemKey) Then Exit Sub

    Dim rec As Object
    Set rec = gItemMetadataByKey(itemKey)
    If rec Is Nothing Then Exit Sub
    If Not rec.Exists("folderPath") Then Exit Sub

    Dim folderPath As String
    folderPath = CStr(rec("folderPath"))

    If Len(Trim$(folderPath)) = 0 Then Exit Sub

    If Not WriteQtyJsonForFolder(folderPath, False, reason) Then
        LogEvent " | WARN  | Immediate QTY JSON flush failed for itemKey=" & itemKey & " | folder=" & folderPath
    End If

    Exit Sub

EH:
    LogEvent " | ERROR | FlushItemFolderQtyJson: " & Err.Number & " - " & Err.Description
End Sub
Private Function BuildFolderQtyJson(ByVal folderPath As String, ByRef recordCountOut As Long) As String
    On Error GoTo EH

    'Production nesting import format:
    '[
    '  { "file": "PART-001.dxf", "qty": 4 },
    '  { "file": "PART-002.dxf", "qty": 2 }
    ']
    '
    'All traceability metadata remains internal to the macro dictionaries during the run.
    'The JSON file intentionally contains only what the nesting software needs.

    Dim bucket As Object
    Dim itemKeys() As String
    Dim i As Long
    Dim k As Variant
    Dim rec As Object
    Dim itemKey As String
    Dim s As String

    recordCountOut = 0
    s = "["

    If gFolderItemsByPath Is Nothing Then
        BuildFolderQtyJson = "[]"
        Exit Function
    End If

    If Not gFolderItemsByPath.Exists(folderPath) Then
        BuildFolderQtyJson = "[]"
        Exit Function
    End If

    Set bucket = gFolderItemsByPath(folderPath)
    If bucket Is Nothing Then
        BuildFolderQtyJson = "[]"
        Exit Function
    End If

    If bucket.Count > 0 Then
        ReDim itemKeys(0 To bucket.Count - 1) As String
        i = 0
        For Each k In bucket.Keys
            itemKeys(i) = CStr(k)
            i = i + 1
        Next k

        SortStringArray itemKeys

        For i = LBound(itemKeys) To UBound(itemKeys)
            itemKey = itemKeys(i)
            If gItemMetadataByKey.Exists(itemKey) Then
                Set rec = gItemMetadataByKey(itemKey)
                If recordCountOut > 0 Then s = s & ","
                s = s & vbCrLf & "  {" & _
                    vbCrLf & "    ""file"": """ & JsonEscape(CStr(rec("file"))) & """," & _
                    vbCrLf & "    ""qty"": " & CStr(GetItemQtySafe(itemKey)) & _
                    vbCrLf & "  }"
                recordCountOut = recordCountOut + 1
            End If
        Next i
    End If

    If recordCountOut > 0 Then
        s = s & vbCrLf
    End If
    s = s & "]"

    BuildFolderQtyJson = s
    Exit Function

EH:
    LogEvent " | ERROR | BuildFolderQtyJson: " & Err.Number & " - " & Err.Description
    BuildFolderQtyJson = "[]"
End Function

Private Function GetItemQtySafe(ByVal itemKey As String) As Long
    If gItemQtyByKey Is Nothing Then Exit Function
    If gItemQtyByKey.Exists(itemKey) Then GetItemQtySafe = CLng(gItemQtyByKey(itemKey))
End Function

Private Function WriteTextFile(ByVal filePath As String, ByVal textOut As String) As Boolean
    On Error GoTo EH

    WriteTextFile = False

    'UTF-8 output is safer for external nesting software and non-ASCII paths/properties.
    Dim stm As Object
    Set stm = CreateObject("ADODB.Stream")

    stm.Type = 2 'adTypeText
    stm.Charset = "utf-8"
    stm.Open
    stm.WriteText textOut
    stm.SaveToFile filePath, 2 'adSaveCreateOverWrite
    stm.Close

    WriteTextFile = True
    Exit Function

EH:
    LogEvent " | WARN  | UTF-8 WriteTextFile failed; trying VBA text fallback. Path=" & filePath & " | Err=" & Err.Number & " - " & Err.Description

    On Error Resume Next
    If Not stm Is Nothing Then
        If stm.State <> 0 Then stm.Close
    End If
    On Error GoTo EH2

    Dim ff As Integer
    ff = FreeFile

    Open filePath For Output As #ff
    Print #ff, textOut
    Close #ff

    WriteTextFile = True
    Exit Function

EH2:
    On Error Resume Next
    If ff <> 0 Then Close #ff
    On Error GoTo 0
    LogEvent " | ERROR | WriteTextFile(" & filePath & "): " & Err.Number & " - " & Err.Description
End Function

Private Function JsonEscape(ByVal s As String) As String
    'JSON escape helper.
    'Important: VBA does not use backslash as a string escape character.
    'The replacement strings below are JSON escape sequences made from real backslash characters.
    s = Replace$(s, "\", "\\")
    s = Replace$(s, Chr$(34), "\" & Chr$(34))
    s = Replace$(s, vbBack, "\b")
    s = Replace$(s, vbFormFeed, "\f")
    s = Replace$(s, vbTab, "\t")
    s = Replace$(s, vbCrLf, "\n")
    s = Replace$(s, vbCr, "\n")
    s = Replace$(s, vbLf, "\n")
    JsonEscape = s
End Function

Private Function BuildFolderSimpleQtyJson(ByVal folderPath As String, ByRef recordCountOut As Long) As String
    On Error GoTo EH

    Dim bucket As Object
    Dim itemKeys() As String
    Dim i As Long
    Dim k As Variant
    Dim rec As Object
    Dim itemKey As String
    Dim s As String

    recordCountOut = 0
    s = "{"

    If gFolderItemsByPath Is Nothing Then
        BuildFolderSimpleQtyJson = "{}"
        Exit Function
    End If

    If Not gFolderItemsByPath.Exists(folderPath) Then
        BuildFolderSimpleQtyJson = "{}"
        Exit Function
    End If

    Set bucket = gFolderItemsByPath(folderPath)
    If bucket Is Nothing Then
        BuildFolderSimpleQtyJson = "{}"
        Exit Function
    End If

    If bucket.Count > 0 Then
        ReDim itemKeys(0 To bucket.Count - 1) As String
        i = 0
        For Each k In bucket.Keys
            itemKeys(i) = CStr(k)
            i = i + 1
        Next k

        SortStringArray itemKeys

        For i = LBound(itemKeys) To UBound(itemKeys)
            itemKey = itemKeys(i)
            If gItemMetadataByKey.Exists(itemKey) Then
                Set rec = gItemMetadataByKey(itemKey)
                If recordCountOut > 0 Then s = s & ","
                s = s & vbCrLf & "  """ & JsonEscape(CStr(rec("file"))) & """: " & CStr(GetItemQtySafe(itemKey))
                recordCountOut = recordCountOut + 1
            End If
        Next i
    End If

    If recordCountOut > 0 Then s = s & vbCrLf
    s = s & "}"

    BuildFolderSimpleQtyJson = s
    Exit Function

EH:
    LogEvent " | ERROR | BuildFolderSimpleQtyJson: " & Err.Number & " - " & Err.Description
    BuildFolderSimpleQtyJson = "{}"
End Function


Private Function StripThicknessTextFromMaterialName(ByVal rawMaterial As String) As String
    On Error GoTo EH

    Dim s As String
    Dim p As Long
    Dim leftPart As String
    Dim rightPart As String

    s = UCase$(Trim$(rawMaterial))
    If Len(s) = 0 Then
        StripThicknessTextFromMaterialName = ""
        Exit Function
    End If

    'If material is stored as "44W, 0.25"" THK", keep only the material side.
    p = InStr(1, s, ",", vbTextCompare)
    If p > 0 Then
        leftPart = Trim$(Left$(s, p - 1))
        rightPart = Trim$(Mid$(s, p + 1))

        If LooksLikeThicknessDescription(rightPart) Then
            StripThicknessTextFromMaterialName = leftPart
            Exit Function
        End If
    End If

    'If material is stored as "44W 0.25"" THK", remove from the first explicit thickness marker.
    p = FirstThicknessMarkerPosition(s)
    If p > 1 Then
        leftPart = Trim$(Left$(s, p - 1))
        If Len(leftPart) > 0 Then
            StripThicknessTextFromMaterialName = leftPart
            Exit Function
        End If
    End If

    StripThicknessTextFromMaterialName = s
    Exit Function

EH:
    StripThicknessTextFromMaterialName = rawMaterial
End Function

Private Function LooksLikeThicknessDescription(ByVal textVal As String) As Boolean
    Dim s As String
    s = " " & UCase$(Trim$(textVal)) & " "

    LooksLikeThicknessDescription = False

    If InStr(1, s, " THK ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, " THICK ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, " THICKNESS ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, Chr$(34), vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, " IN ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, " MM ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, " GA ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True
    If InStr(1, s, " GAUGE ", vbTextCompare) > 0 Then LooksLikeThicknessDescription = True

    If Not LooksLikeThicknessDescription Then
        Dim numericCount As Long
        numericCount = CountNumericCharacters(s)
        If numericCount > 0 And (InStr(1, s, ".", vbTextCompare) > 0 Or InStr(1, s, "/", vbTextCompare) > 0) Then
            LooksLikeThicknessDescription = True
        End If
    End If
End Function

Private Function FirstThicknessMarkerPosition(ByVal textVal As String) As Long
    Dim s As String
    Dim candidates As Variant
    Dim i As Long
    Dim p As Long
    Dim best As Long

    s = UCase$(textVal)
    candidates = Array(" THK", " THICK", " THICKNESS", Chr$(34) & " THK", " MM THK", " IN THK")

    best = 0
    For i = LBound(candidates) To UBound(candidates)
        p = InStr(1, s, CStr(candidates(i)), vbTextCompare)
        If p > 0 Then
            If best = 0 Or p < best Then best = p
        End If
    Next i

    FirstThicknessMarkerPosition = best
End Function

Private Function CountNumericCharacters(ByVal textVal As String) As Long
    Dim i As Long
    Dim ch As String
    CountNumericCharacters = 0

    For i = 1 To Len(textVal)
        ch = Mid$(textVal, i, 1)
        If ch >= "0" And ch <= "9" Then CountNumericCharacters = CountNumericCharacters + 1
    Next i
End Function

Private Function MaterialAliasFolderName(ByVal normalizedMaterialText As String) As String
    Dim s As String
    s = " " & UCase$(CollapseSpaces(normalizedMaterialText)) & " "

    'Common steel aliases.
    If InStr(1, s, " A36 ", vbTextCompare) > 0 Or _
       InStr(1, s, " ASTM A36 ", vbTextCompare) > 0 Then
        MaterialAliasFolderName = "A36_STEEL"
        Exit Function
    End If

    If InStr(1, s, " MILD STEEL ", vbTextCompare) > 0 Or _
       InStr(1, s, " CARBON STEEL ", vbTextCompare) > 0 Or _
       InStr(1, s, " HRPO ", vbTextCompare) > 0 Or _
       InStr(1, s, " HRS ", vbTextCompare) > 0 Then
        MaterialAliasFolderName = "MILD_STEEL"
        Exit Function
    End If

    If InStr(1, s, " AR400 ", vbTextCompare) > 0 Then
        MaterialAliasFolderName = "AR400"
        Exit Function
    End If

    If InStr(1, s, " AR500 ", vbTextCompare) > 0 Then
        MaterialAliasFolderName = "AR500"
        Exit Function
    End If

    'Common stainless aliases.
    If InStr(1, s, " 304 ", vbTextCompare) > 0 And _
       (InStr(1, s, " SS ", vbTextCompare) > 0 Or InStr(1, s, " STAINLESS ", vbTextCompare) > 0) Then
        MaterialAliasFolderName = "304_STAINLESS"
        Exit Function
    End If

    If InStr(1, s, " 316 ", vbTextCompare) > 0 And _
       (InStr(1, s, " SS ", vbTextCompare) > 0 Or InStr(1, s, " STAINLESS ", vbTextCompare) > 0) Then
        MaterialAliasFolderName = "316_STAINLESS"
        Exit Function
    End If

    'Common aluminum aliases.
    If InStr(1, s, " 5052 ", vbTextCompare) > 0 And _
       (InStr(1, s, " AL ", vbTextCompare) > 0 Or InStr(1, s, " ALUMINUM ", vbTextCompare) > 0 Or InStr(1, s, " ALUMINIUM ", vbTextCompare) > 0) Then
        MaterialAliasFolderName = "5052_ALUMINUM"
        Exit Function
    End If

    If InStr(1, s, " 6061 ", vbTextCompare) > 0 And _
       (InStr(1, s, " AL ", vbTextCompare) > 0 Or InStr(1, s, " ALUMINUM ", vbTextCompare) > 0 Or InStr(1, s, " ALUMINIUM ", vbTextCompare) > 0) Then
        MaterialAliasFolderName = "6061_ALUMINUM"
        Exit Function
    End If

    MaterialAliasFolderName = ""
End Function

Private Function TryParseThicknessToInches(ByVal rawVal As String, ByRef inchesOut As Double) As Boolean
    On Error GoTo EH

    Dim s As String
    Dim tokens As Variant
    Dim i As Long
    Dim totalVal As Double
    Dim parsedAny As Boolean
    Dim isMM As Boolean

    TryParseThicknessToInches = False
    inchesOut = 0#

    s = UCase$(Trim$(rawVal))
    If Len(s) = 0 Then Exit Function

    isMM = (InStr(1, s, "MM", vbTextCompare) > 0) Or _
           (InStr(1, s, "MILLIMETER", vbTextCompare) > 0) Or _
           (InStr(1, s, "MILLIMETRE", vbTextCompare) > 0)

    s = Replace$(s, Chr$(34), " IN ")
    s = Replace$(s, "INCHES", " IN ")
    s = Replace$(s, "INCH", " IN ")
    s = Replace$(s, "MILLIMETERS", " MM ")
    s = Replace$(s, "MILLIMETRES", " MM ")
    s = Replace$(s, "MILLIMETER", " MM ")
    s = Replace$(s, "MILLIMETRE", " MM ")
    s = Replace$(s, "MM", " MM ")
    s = Replace$(s, "IN", " IN ")

    s = Replace$(s, "(", " ")
    s = Replace$(s, ")", " ")
    s = Replace$(s, "[", " ")
    s = Replace$(s, "]", " ")
    s = Replace$(s, "X", " ")
    s = Replace$(s, "*", " ")
    s = Replace$(s, ",", ".")
    s = CollapseSpaces(s)

    tokens = Split(s, " ")

    For i = LBound(tokens) To UBound(tokens)
        Dim tok As String
        Dim v As Double

        tok = Trim$(CStr(tokens(i)))
        If Len(tok) = 0 Then GoTo NextToken

        If TryParseThicknessToken(tok, v) Then
            totalVal = totalVal + v
            parsedAny = True

            'Support mixed fractions like "1 1/2 IN" by summing adjacent numeric tokens.
            'For normal values like "0.250 IN", there is only one numeric token.
        End If

NextToken:
    Next i

    If Not parsedAny Then Exit Function

    If isMM Then
        inchesOut = totalVal / 25.4
    Else
        inchesOut = totalVal
    End If

    If inchesOut <= 0# Then Exit Function
    TryParseThicknessToInches = True
    Exit Function

EH:
    LogEvent " | WARN  | TryParseThicknessToInches failed for [" & rawVal & "]: " & Err.Number & " - " & Err.Description
    TryParseThicknessToInches = False
End Function

Private Function TryParseThicknessToken(ByVal tokenText As String, ByRef valueOut As Double) As Boolean
    On Error GoTo EH

    Dim p As Long
    Dim n As Double
    Dim d As Double
    Dim leftPart As String
    Dim rightPart As String

    TryParseThicknessToken = False
    valueOut = 0#

    tokenText = Trim$(tokenText)
    If Len(tokenText) = 0 Then Exit Function

    p = InStr(1, tokenText, "/", vbTextCompare)
    If p > 0 Then
        leftPart = Trim$(Left$(tokenText, p - 1))
        rightPart = Trim$(Mid$(tokenText, p + 1))

        If IsThicknessNumericToken(leftPart) And IsThicknessNumericToken(rightPart) Then
            n = Val(leftPart)
            d = Val(rightPart)
            If d <> 0# Then
                valueOut = n / d
                TryParseThicknessToken = True
            End If
        End If
        Exit Function
    End If

    If IsThicknessNumericToken(tokenText) Then
        valueOut = Val(tokenText)
        TryParseThicknessToken = True
    End If

    Exit Function

EH:
    TryParseThicknessToken = False
End Function

Private Function IsThicknessNumericToken(ByVal tokenText As String) As Boolean
    Dim c As String

    tokenText = Trim$(tokenText)
    If Len(tokenText) = 0 Then Exit Function

    c = Left$(tokenText, 1)
    If (c >= "0" And c <= "9") Or c = "." Then
        IsThicknessNumericToken = (Val(tokenText) <> 0# Or tokenText = "0" Or tokenText = "0.0" Or tokenText = ".0")
    End If
End Function

Private Function FormatThicknessInchesFolder(ByVal inchesVal As Double) As String
    Dim roundedVal As Double

    'Three decimal places are required for nesting folder grouping.
    'Use normal three-place rounding after converting SolidWorks meters to inches.
    roundedVal = Round(inchesVal, 3)

    If THICKNESS_FOLDER_INCLUDE_UNITS Then
        FormatThicknessInchesFolder = Format$(roundedVal, "0.000") & "_IN"
    Else
        FormatThicknessInchesFolder = Format$(roundedVal, "0.000")
    End If
End Function

Private Function FormatThicknessInchesValue(ByVal inchesVal As Double) As String
    FormatThicknessInchesValue = Format$(Round(inchesVal, 3), "0.000")
End Function

Private Function CollapseSpaces(ByVal s As String) As String
    s = Trim$(s)
    Do While InStr(1, s, "  ", vbBinaryCompare) > 0
        s = Replace$(s, "  ", " ")
    Loop
    CollapseSpaces = s
End Function

Private Function CollapseUnderscores(ByVal s As String) As String
    s = Trim$(s)
    Do While InStr(1, s, "__", vbBinaryCompare) > 0
        s = Replace$(s, "__", "_")
    Loop
    Do While Left$(s, 1) = "_"
        s = Mid$(s, 2)
    Loop
    Do While Right$(s, 1) = "_"
        s = Left$(s, Len(s) - 1)
    Loop
    CollapseUnderscores = s
End Function

Private Function FeatureTreeHasRealCutList(ByVal feat As SldWorks.Feature) As Boolean
    On Error GoTo EH

    FeatureTreeHasRealCutList = False
    If feat Is Nothing Then Exit Function

    If IsRealCutListFolderFeature(feat) Then
        FeatureTreeHasRealCutList = True
        Exit Function
    End If

    Dim subFeat As SldWorks.Feature
    Set subFeat = feat.GetFirstSubFeature

    Do While Not subFeat Is Nothing
        If FeatureTreeHasRealCutList(subFeat) Then
            FeatureTreeHasRealCutList = True
            Exit Function
        End If
        Set subFeat = subFeat.GetNextSubFeature
    Loop

    Exit Function

EH:
    LogEvent " | ERROR | FeatureTreeHasRealCutList(" & SafeFeatureName(feat) & "): " & Err.Number & " - " & Err.Description
End Function

Private Sub ProcessCutListFeatureRecursive(ByVal mdl As SldWorks.ModelDoc2, _
                                           ByVal feat As SldWorks.Feature, _
                                           ByVal outDir As String, _
                                           ByRef foundAnyCutList As Boolean)
    On Error GoTo EH

    If feat Is Nothing Then Exit Sub

    If IsRealCutListFolderFeature(feat) Then
        foundAnyCutList = True
        ProcessSingleCutList mdl, feat, outDir
    End If

    Dim subFeat As SldWorks.Feature
    Set subFeat = feat.GetFirstSubFeature

    Do While Not subFeat Is Nothing
        ProcessCutListFeatureRecursive mdl, subFeat, outDir, foundAnyCutList
        Set subFeat = subFeat.GetNextSubFeature
    Loop

    Exit Sub

EH:
    LogEvent " | ERROR | ProcessCutListFeatureRecursive(" & SafeFeatureName(feat) & "): " & Err.Number & " - " & Err.Description
End Sub

Private Function SafeFeatureName(ByVal feat As SldWorks.Feature) As String
    On Error Resume Next
    If feat Is Nothing Then
        SafeFeatureName = "(Nothing)"
    Else
        SafeFeatureName = feat.Name
    End If
End Function


Private Sub SortStringArray(ByRef arr() As String)
    On Error GoTo EH

    Dim i As Long
    Dim j As Long
    Dim tmp As String

    For i = LBound(arr) To UBound(arr) - 1
        For j = i + 1 To UBound(arr)
            If StrComp(arr(j), arr(i), vbTextCompare) < 0 Then
                tmp = arr(i)
                arr(i) = arr(j)
                arr(j) = tmp
            End If
        Next j
    Next i

    Exit Sub

EH:
    LogEvent " | ERROR | SortStringArray: " & Err.Number & " - " & Err.Description
End Sub


Private Function GetEvaluatedPropertyValue(ByVal cpMgr As SldWorks.CustomPropertyManager, _
                                           ByVal propName As String, _
                                           ByRef rawValOut As String) As String
    On Error GoTo EH

    rawValOut = ""

    If cpMgr Is Nothing Then Exit Function

    Dim rawVal As String
    Dim evalVal As String
    Dim wasResolved As Boolean
    Dim isLinked As Boolean
    Dim ret As Long

    rawVal = ""
    evalVal = ""
    wasResolved = False
    isLinked = False

    ret = cpMgr.Get6(propName, False, rawVal, evalVal, wasResolved, isLinked)

    rawValOut = NzStr(rawVal)

    If Len(Trim$(evalVal)) > 0 Then
        GetEvaluatedPropertyValue = Trim$(evalVal)
    Else
        GetEvaluatedPropertyValue = Trim$(rawVal)
    End If

    Exit Function

EH:
    LogEvent " | ERROR | GetEvaluatedPropertyValue(" & propName & "): " & Err.Number & " - " & Err.Description
End Function




'=========================================================================================
' NATIVE SHEET-METAL FLAT-PATTERN EXPORT HELPERS
'=========================================================================================
Private Function ShouldAttemptNativeSheetMetalFlatPatternExport(ByVal mdl As SldWorks.ModelDoc2, _
                                                               ByVal usableBodyCount As Long, _
                                                               ByVal contextLabel As String) As Boolean
    On Error GoTo EH

    ShouldAttemptNativeSheetMetalFlatPatternExport = False

    If Not USE_NATIVE_SHEET_METAL_FLAT_PATTERN_EXPORT Then
        LogEvent " | INFO  | Native sheet-metal flat-pattern export disabled by setting | context=" & contextLabel
        Exit Function
    End If

    If mdl Is Nothing Then
        gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
        LogEvent " | WARN  | Native sheet-metal skipped: model is Nothing | context=" & contextLabel
        Exit Function
    End If

    If mdl.GetType <> swDocPART Then
        gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
        LogEvent " | WARN  | Native sheet-metal skipped: source document is not a part | context=" & contextLabel
        Exit Function
    End If

    If Len(Trim$(mdl.GetPathName)) = 0 Then
        gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
        LogEvent " | WARN  | Native sheet-metal skipped: part is unsaved | context=" & contextLabel
        Exit Function
    End If

    If SHEET_METAL_NATIVE_SKIP_WHEN_DRAWING_VIEW_ORIENTATION_OVERRIDE And gHasOrientationOverride Then
        gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
        LogEvent " | INFO  | Native sheet-metal skipped to preserve selected drawing-view orientation override | context=" & contextLabel
        Exit Function
    End If

    If SHEET_METAL_NATIVE_SINGLE_BODY_ONLY Then
        If usableBodyCount <> 1 Then
            gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
            LogEvent " | INFO  | Native sheet-metal skipped by single-body safety rule | context=" & contextLabel & _
                     " | usableBodyCount=" & CStr(usableBodyCount) & _
                     " | fallback=existing isolated per-body export"
            Exit Function
        End If
    End If

    Dim flatPatternInfo As String
    flatPatternInfo = ""

    If Not PartHasSheetMetalFlatPatternSignal(mdl, flatPatternInfo) Then
        gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
        LogEvent " | INFO  | Native sheet-metal not used: no Flat-Pattern feature signal found | context=" & contextLabel
        Exit Function
    End If

    LogEvent " | INFO  | Native sheet-metal flat-pattern candidate accepted | context=" & contextLabel & _
             " | flatPatternSignal=" & flatPatternInfo

    ShouldAttemptNativeSheetMetalFlatPatternExport = True
    Exit Function

EH:
    gTotalNativeSheetMetalFlatPatternSkipped = gTotalNativeSheetMetalFlatPatternSkipped + 1
    LogEvent " | ERROR | ShouldAttemptNativeSheetMetalFlatPatternExport(" & contextLabel & "): " & Err.Number & " - " & Err.Description
End Function

Private Function ExportNativeSheetMetalFlatPatternDxf(ByVal mdl As SldWorks.ModelDoc2, _
                                                      ByVal finalDxfPath As String, _
                                                      ByVal contextLabel As String) As Boolean
    On Error GoTo EH

    ExportNativeSheetMetalFlatPatternDxf = False

    If mdl Is Nothing Then
        LogEvent " | FAIL  | Native sheet-metal export: model is Nothing | context=" & contextLabel
        Exit Function
    End If

    If mdl.GetType <> swDocPART Then
        LogEvent " | FAIL  | Native sheet-metal export requires PART doc, got " & DocTypeName(mdl.GetType) & " | context=" & contextLabel
        Exit Function
    End If

    If Len(Trim$(finalDxfPath)) = 0 Then
        LogEvent " | FAIL  | Native sheet-metal export: output path is blank | context=" & contextLabel
        Exit Function
    End If

    Dim modelPath As String
    modelPath = Trim$(mdl.GetPathName)

    If Len(modelPath) = 0 Then
        LogEvent " | FAIL  | Native sheet-metal export requires saved part path | context=" & contextLabel
        Exit Function
    End If

    If Not FileExists(modelPath) Then
        LogEvent " | FAIL  | Native sheet-metal export source file not found: " & modelPath & " | context=" & contextLabel
        Exit Function
    End If

    Dim swSrcPart As SldWorks.PartDoc
    Set swSrcPart = mdl

    Dim options As Long
    options = BuildNativeSheetMetalDxfOptions()

    Dim emptyAlignment As Variant
    Dim emptyViews As Variant
    Dim resultVar As Variant
    Dim ok As Boolean

    Dim oldUnits As Long
    Dim haveOldUnits As Boolean
    haveOldUnits = False
    oldUnits = 0

    LogEvent " | INFO  | Native sheet-metal ExportToDWG2 start"
    LogEvent " | INFO  |   context      = " & contextLabel
    LogEvent " | INFO  |   modelPath    = " & modelPath
    LogEvent " | INFO  |   finalDxfPath = " & finalDxfPath
    LogEvent " | INFO  |   action       = SHEET_METAL(" & CStr(SW_EXPORT_TO_DWG_SHEET_METAL) & ")"
    LogEvent " | INFO  |   options      = " & CStr(options) & " | " & DescribeNativeSheetMetalDxfOptions(options)

    If Not ActivateDocumentByTitle(mdl.GetTitle) Then
        LogEvent " | WARN  | Native sheet-metal export could not explicitly activate source part | context=" & contextLabel
    End If

    mdl.ForceRebuild3 True

    If SHEET_METAL_NATIVE_TEMPORARILY_FORCE_INCH_UNITS Then
        On Error Resume Next
        oldUnits = mdl.GetUserPreferenceIntegerValue(swUnitsLinear)
        If Err.Number = 0 Then
            haveOldUnits = True
            LogEvent " | INFO  | Native sheet-metal source linear units before temporary export change = " & CStr(oldUnits)
            mdl.SetUserPreferenceIntegerValue swUnitsLinear, swINCHES
            LogEvent " | INFO  | Native sheet-metal source linear units temporarily set to INCHES for DXF export"
        Else
            LogEvent " | WARN  | Native sheet-metal could not read/set linear units before export: " & Err.Number & " - " & Err.Description
            Err.Clear
        End If
        On Error GoTo EH
    End If

    DeleteFileIfExists finalDxfPath

    On Error Resume Next
    resultVar = CallByName(swSrcPart, "ExportToDWG2", VbMethod, _
                           finalDxfPath, _
                           modelPath, _
                           SW_EXPORT_TO_DWG_SHEET_METAL, _
                           True, _
                           emptyAlignment, _
                           False, _
                           False, _
                           options, _
                           emptyViews)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | Native sheet-metal CallByName ExportToDWG2 failed: " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        GoTo CleanupAndExit
    End If
    On Error GoTo EH

    ok = False
    On Error Resume Next
    ok = CBool(resultVar)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | Native sheet-metal ExportToDWG2 result could not be converted to Boolean: " & Err.Number & " - " & Err.Description
        Err.Clear
        ok = False
    End If
    On Error GoTo EH

    LogEvent " | INFO  | Native sheet-metal ExportToDWG2 result = " & CStr(ok)

    If Not ok Then GoTo CleanupAndExit

    If Not FileExists(finalDxfPath) Then
        LogEvent " | WARN  | Native sheet-metal ExportToDWG2 returned True but output file was not found: " & finalDxfPath
        GoTo CleanupAndExit
    End If

    If GetFileSizeSafe(finalDxfPath) <= 0 Then
        LogEvent " | WARN  | Native sheet-metal ExportToDWG2 created zero-byte DXF: " & finalDxfPath
        GoTo CleanupAndExit
    End If

    LogEvent " | INFO  | Native sheet-metal ExportToDWG2 created DXF. File size = " & CStr(GetFileSizeSafe(finalDxfPath))

    Call FinalizeWaterjetDxfAfterExport(finalDxfPath, contextLabel & " | native sheet-metal flat pattern", True)

    If FileExists(finalDxfPath) And GetFileSizeSafe(finalDxfPath) > 0 Then
        ExportNativeSheetMetalFlatPatternDxf = True
    Else
        LogEvent " | WARN  | Native sheet-metal DXF missing/empty after finalization: " & finalDxfPath
    End If

CleanupAndExit:
    If haveOldUnits Then
        On Error Resume Next
        mdl.SetUserPreferenceIntegerValue swUnitsLinear, oldUnits
        If Err.Number = 0 Then
            LogEvent " | INFO  | Native sheet-metal source linear units restored to " & CStr(oldUnits)
        Else
            LogEvent " | WARN  | Native sheet-metal failed to restore original linear units: " & Err.Number & " - " & Err.Description
            Err.Clear
        End If
        On Error GoTo EH
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ExportNativeSheetMetalFlatPatternDxf(" & contextLabel & "): " & Err.Number & " - " & Err.Description
    Resume CleanupAndExit
End Function

Private Function BuildNativeSheetMetalDxfOptions() As Long
    On Error GoTo EH

    Dim options As Long
    options = SM_DXF_OPT_FLAT_PATTERN_GEOMETRY

    If SHEET_METAL_EXPORT_HIDDEN_EDGES Then options = options Or SM_DXF_OPT_HIDDEN_EDGES
    If SHEET_METAL_EXPORT_BEND_LINES Then options = options Or SM_DXF_OPT_BEND_LINES
    If SHEET_METAL_EXPORT_SKETCHES Then options = options Or SM_DXF_OPT_SKETCHES
    If SHEET_METAL_EXPORT_MERGE_COPLANAR_FACES Then options = options Or SM_DXF_OPT_MERGE_COPLANAR_FACES
    If SHEET_METAL_EXPORT_LIBRARY_FEATURES Then options = options Or SM_DXF_OPT_LIBRARY_FEATURES
    If SHEET_METAL_EXPORT_FORMING_TOOLS Then options = options Or SM_DXF_OPT_FORMING_TOOLS
    If SHEET_METAL_EXPORT_BOUNDING_BOX Then options = options Or SM_DXF_OPT_BOUNDING_BOX

    BuildNativeSheetMetalDxfOptions = options
    Exit Function

EH:
    LogEvent " | ERROR | BuildNativeSheetMetalDxfOptions: " & Err.Number & " - " & Err.Description
    BuildNativeSheetMetalDxfOptions = SM_DXF_OPT_FLAT_PATTERN_GEOMETRY
End Function

Private Function DescribeNativeSheetMetalDxfOptions(ByVal options As Long) As String
    On Error GoTo EH

    Dim s As String
    s = ""

    If (options And SM_DXF_OPT_FLAT_PATTERN_GEOMETRY) <> 0 Then s = AppendDelimitedText(s, "FlatPatternGeometry", ", ")
    If (options And SM_DXF_OPT_HIDDEN_EDGES) <> 0 Then s = AppendDelimitedText(s, "HiddenEdges", ", ")
    If (options And SM_DXF_OPT_BEND_LINES) <> 0 Then s = AppendDelimitedText(s, "BendLines", ", ")
    If (options And SM_DXF_OPT_SKETCHES) <> 0 Then s = AppendDelimitedText(s, "Sketches", ", ")
    If (options And SM_DXF_OPT_MERGE_COPLANAR_FACES) <> 0 Then s = AppendDelimitedText(s, "MergeCoplanarFaces", ", ")
    If (options And SM_DXF_OPT_LIBRARY_FEATURES) <> 0 Then s = AppendDelimitedText(s, "LibraryFeatures", ", ")
    If (options And SM_DXF_OPT_FORMING_TOOLS) <> 0 Then s = AppendDelimitedText(s, "FormingTools", ", ")
    If (options And SM_DXF_OPT_BOUNDING_BOX) <> 0 Then s = AppendDelimitedText(s, "BoundingBox", ", ")

    If Len(s) = 0 Then s = "(none)"
    DescribeNativeSheetMetalDxfOptions = s
    Exit Function

EH:
    DescribeNativeSheetMetalDxfOptions = "(option description failed)"
End Function

Private Function PartHasSheetMetalFlatPatternSignal(ByVal mdl As SldWorks.ModelDoc2, _
                                                    ByRef flatPatternInfoOut As String) As Boolean
    On Error GoTo EH

    PartHasSheetMetalFlatPatternSignal = False
    flatPatternInfoOut = ""

    If mdl Is Nothing Then Exit Function
    If mdl.GetType <> swDocPART Then Exit Function

    Dim topFeat As SldWorks.Feature
    Set topFeat = mdl.FirstFeature

    Do While Not topFeat Is Nothing
        If FeatureNodeOrSubFeaturesHasFlatPatternSignal(topFeat, flatPatternInfoOut, 0) Then
            PartHasSheetMetalFlatPatternSignal = True
            Exit Function
        End If
        Set topFeat = topFeat.GetNextFeature
    Loop

    Exit Function

EH:
    LogEvent " | ERROR | PartHasSheetMetalFlatPatternSignal(" & mdl.GetTitle & "): " & Err.Number & " - " & Err.Description
End Function

Private Function FeatureNodeOrSubFeaturesHasFlatPatternSignal(ByVal feat As SldWorks.Feature, _
                                                              ByRef flatPatternInfoOut As String, _
                                                              ByVal depth As Long) As Boolean
    On Error GoTo EH

    FeatureNodeOrSubFeaturesHasFlatPatternSignal = False

    If feat Is Nothing Then Exit Function
    If depth > 200 Then
        LogEvent " | WARN  | Flat-pattern feature scan depth limit reached at feature [" & feat.Name & "]"
        Exit Function
    End If

    If FeatureLooksLikeSheetMetalFlatPattern(feat) Then
        flatPatternInfoOut = "FeatureName=[" & NzStr(feat.Name) & "] Type=[" & NzStr(feat.GetTypeName2) & "] Suppressed=" & CStr(IsFeatureSuppressedSafe(feat))
        FeatureNodeOrSubFeaturesHasFlatPatternSignal = True
        Exit Function
    End If

    Dim subFeat As SldWorks.Feature
    Set subFeat = feat.GetFirstSubFeature

    Do While Not subFeat Is Nothing
        If FeatureNodeOrSubFeaturesHasFlatPatternSignal(subFeat, flatPatternInfoOut, depth + 1) Then
            FeatureNodeOrSubFeaturesHasFlatPatternSignal = True
            Exit Function
        End If

        Set subFeat = subFeat.GetNextSubFeature
    Loop

    Exit Function

EH:
    LogEvent " | ERROR | FeatureNodeOrSubFeaturesHasFlatPatternSignal: " & Err.Number & " - " & Err.Description
End Function

Private Function FeatureLooksLikeSheetMetalFlatPattern(ByVal feat As SldWorks.Feature) As Boolean
    On Error GoTo EH

    FeatureLooksLikeSheetMetalFlatPattern = False

    If feat Is Nothing Then Exit Function

    Dim typeText As String
    Dim nameText As String
    Dim compact As String
    Dim normalized As String

    typeText = NzStr(feat.GetTypeName2)
    nameText = NzStr(feat.Name)
    compact = UCase$(typeText & " " & nameText)
    compact = Replace(compact, " ", "")
    compact = Replace(compact, "-", "")
    compact = Replace(compact, "_", "")
    compact = Replace(compact, ".", "")

    normalized = NormalizeConfigurationSearchText(typeText & " " & nameText)

    If InStr(1, compact, "FLATPATTERN", vbTextCompare) > 0 Then
        FeatureLooksLikeSheetMetalFlatPattern = True
        Exit Function
    End If

    If ConfigTokenExists(normalized, "FLAT") And ConfigTokenExists(normalized, "PATTERN") Then
        FeatureLooksLikeSheetMetalFlatPattern = True
        Exit Function
    End If

    FeatureLooksLikeSheetMetalFlatPattern = False
    Exit Function

EH:
    FeatureLooksLikeSheetMetalFlatPattern = False
End Function

Private Function IsFeatureSuppressedSafe(ByVal feat As SldWorks.Feature) As Boolean
    On Error GoTo EH

    IsFeatureSuppressedSafe = False

    If feat Is Nothing Then Exit Function

    Dim resultVar As Variant
    Dim state As Boolean
    state = False

    'Use late-bound calls here because Feature.IsSuppressed signatures have varied across API versions.
    On Error Resume Next
    resultVar = CallByName(feat, "IsSuppressed", VbMethod)
    If Err.Number <> 0 Then
        Err.Clear
        resultVar = CallByName(feat, "IsSuppressed", VbGet)
    End If

    If Err.Number = 0 Then
        state = CBool(resultVar)
    Else
        Err.Clear
        state = False
    End If
    On Error GoTo EH

    IsFeatureSuppressedSafe = state
    Exit Function

EH:
    IsFeatureSuppressedSafe = False
End Function

Private Function AppendDelimitedText(ByVal existingText As String, _
                                     ByVal textToAppend As String, _
                                     ByVal delimiter As String) As String
    If Len(existingText) = 0 Then
        AppendDelimitedText = textToAppend
    Else
        AppendDelimitedText = existingText & delimiter & textToAppend
    End If
End Function


Private Function GetExportOrientationForBody(ByVal srcBody As SldWorks.Body2, _
                                             ByVal contextLabel As String, _
                                             ByRef faceN() As Double, _
                                             ByRef xDir() As Double, _
                                             ByRef usedFallbackEdge As Boolean, _
                                             ByRef usedPerpCorner As Boolean) As Boolean
    On Error GoTo EH

    GetExportOrientationForBody = False
    usedFallbackEdge = False
    usedPerpCorner = False

    If srcBody Is Nothing Then
        LogEvent " | FAIL  | GetExportOrientationForBody: srcBody is Nothing for " & contextLabel
        Exit Function
    End If

    If gHasOrientationOverride Then
        faceN(0) = gOrientationOverrideZ(0)
        faceN(1) = gOrientationOverrideZ(1)
        faceN(2) = gOrientationOverrideZ(2)

        xDir(0) = gOrientationOverrideX(0)
        xDir(1) = gOrientationOverrideX(1)
        xDir(2) = gOrientationOverrideX(2)

        LogEvent " | INFO  | Orientation mode = DRAWING_SELECTED_VIEW override"
        LogEvent " | INFO  | Override label   = " & gOrientationOverrideLabel
        LogEvent " | INFO  | Override X       = (" & Dbl3ToStr(xDir) & ")"
        LogEvent " | INFO  | Override Z       = (" & Dbl3ToStr(faceN) & ")"

        GetExportOrientationForBody = True
        Exit Function
    End If

    Dim refFace As SldWorks.Face2
    Set refFace = FindLargestPlanarFace(srcBody)

    If refFace Is Nothing Then
        LogEvent " | FAIL  | No planar face found on representative body for " & contextLabel
        Exit Function
    End If

    If Not GetStableFaceNormal(refFace, faceN) Then
        LogEvent " | FAIL  | Could not obtain face normal for " & contextLabel
        Exit Function
    End If

    If Not FindHorizontalDirectionFromFace(refFace, faceN, xDir, usedFallbackEdge, usedPerpCorner) Then
        LogEvent " | FAIL  | Could not determine horizontal direction for " & contextLabel
        Exit Function
    End If

    GetExportOrientationForBody = True
    Exit Function

EH:
    LogEvent " | ERROR | GetExportOrientationForBody(" & contextLabel & "): " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' GEOMETRY / ORIENTATION
'=========================================================================================
Private Function FindLargestPlanarFace(ByVal body As SldWorks.Body2) As SldWorks.Face2
    On Error GoTo EH

    Dim vFaces As Variant
    vFaces = body.GetFaces

    If IsEmpty(vFaces) Then Exit Function
    If Not IsArray(vFaces) Then Exit Function

    Dim i As Long
    Dim bestArea As Double
    bestArea = -1#

    For i = LBound(vFaces) To UBound(vFaces)
        Dim f As SldWorks.Face2
        Set f = vFaces(i)

        If Not f Is Nothing Then
            Dim surf As SldWorks.Surface
            Set surf = f.GetSurface

            If Not surf Is Nothing Then
                If surf.IsPlane Then
                    Dim a As Double
                    a = 0#
                    On Error Resume Next
                    a = f.GetArea
                    On Error GoTo EH

                    If a > bestArea Then
                        bestArea = a
                        Set FindLargestPlanarFace = f
                    End If
                End If
            End If
        End If
    Next i

    LogEvent " | INFO  | Largest planar face area = " & FormatNumber(bestArea, 8)
    Exit Function

EH:
    LogEvent " | ERROR | FindLargestPlanarFace: " & Err.Number & " - " & Err.Description
End Function

Private Function GetStableFaceNormal(ByVal face As SldWorks.Face2, ByRef n() As Double) As Boolean
    On Error GoTo EH

    GetStableFaceNormal = False

    LogEvent " | INFO  | GetStableFaceNormal: start"

    If face Is Nothing Then
        LogEvent " | FAIL  | GetStableFaceNormal: face is Nothing"
        Exit Function
    End If

    If TryGetNormalFromFaceVertices(face, n) Then
        NormalizeVec n
        If VecLength(n) > EPS Then
            StabilizeVectorSign n
            LogEvent " | INFO  | Face normal from face vertices = (" & Dbl3ToStr(n) & ")"
            GetStableFaceNormal = True
            Exit Function
        End If
    End If

    LogEvent " | WARN  | Face vertex normal method failed, trying Face2.Normal"

    Dim vNorm As Variant
    On Error Resume Next
    vNorm = face.Normal
    On Error GoTo EH

    If VariantHas3Numbers(vNorm) Then
        n(0) = CDbl(vNorm(0))
        n(1) = CDbl(vNorm(1))
        n(2) = CDbl(vNorm(2))
        NormalizeVec n
        If VecLength(n) > EPS Then
            StabilizeVectorSign n
            LogEvent " | INFO  | Face normal from Face2.Normal = (" & Dbl3ToStr(n) & ")"
            GetStableFaceNormal = True
            Exit Function
        End If
    Else
        LogEvent " | WARN  | Face2.Normal did not return usable data"
    End If

    LogEvent " | WARN  | Face2.Normal failed, trying Surface.PlaneParams"

    Dim surf As SldWorks.Surface
    Set surf = face.GetSurface

    If Not surf Is Nothing Then
        Dim planeProps As Variant
        On Error Resume Next
        planeProps = surf.PlaneParams
        On Error GoTo EH

        If VariantHasAtLeast6Numbers(planeProps) Then
            n(0) = CDbl(planeProps(3))
            n(1) = CDbl(planeProps(4))
            n(2) = CDbl(planeProps(5))
            NormalizeVec n
            If VecLength(n) > EPS Then
                StabilizeVectorSign n
                LogEvent " | INFO  | Face normal from Surface.PlaneParams = (" & Dbl3ToStr(n) & ")"
                GetStableFaceNormal = True
                Exit Function
            End If
        Else
            LogEvent " | WARN  | Surface.PlaneParams did not return usable data"
        End If
    Else
        LogEvent " | WARN  | face.GetSurface returned Nothing inside GetStableFaceNormal"
    End If

    LogEvent " | FAIL  | GetStableFaceNormal exhausted all methods"
    Exit Function

EH:
    LogEvent " | ERROR | GetStableFaceNormal: " & Err.Number & " - " & Err.Description
End Function

Private Function TryGetNormalFromFaceVertices(ByVal face As SldWorks.Face2, ByRef n() As Double) As Boolean
    On Error GoTo EH

    TryGetNormalFromFaceVertices = False

    Dim vEdges As Variant
    vEdges = face.GetEdges

    If IsEmpty(vEdges) Then
        LogEvent " | WARN  | TryGetNormalFromFaceVertices: face.GetEdges returned Empty"
        Exit Function
    End If

    If Not IsArray(vEdges) Then
        LogEvent " | WARN  | TryGetNormalFromFaceVertices: face.GetEdges did not return array"
        Exit Function
    End If

    Dim pts() As Double
    Dim ptCount As Long
    ptCount = 0

    Dim i As Long
    For i = LBound(vEdges) To UBound(vEdges)
        Dim ed As SldWorks.Edge
        Set ed = vEdges(i)

        If Not ed Is Nothing Then
            Dim p0(2) As Double, p1(2) As Double
            If GetEdgeEndPoints(ed, p0, p1) Then
                AddUniquePoint3 pts, ptCount, p0
                AddUniquePoint3 pts, ptCount, p1
            End If
        End If
    Next i

    LogEvent " | INFO  | TryGetNormalFromFaceVertices: unique point count = " & ptCount

    If ptCount < 3 Then
        LogEvent " | WARN  | TryGetNormalFromFaceVertices: fewer than 3 unique points"
        Exit Function
    End If

    Dim i0 As Long, i1 As Long, i2 As Long
    For i0 = 0 To ptCount - 3
        For i1 = i0 + 1 To ptCount - 2
            For i2 = i1 + 1 To ptCount - 1

                Dim a(2) As Double, b(2) As Double, cr(2) As Double
                a(0) = pts(0, i1) - pts(0, i0)
                a(1) = pts(1, i1) - pts(1, i0)
                a(2) = pts(2, i1) - pts(2, i0)

                b(0) = pts(0, i2) - pts(0, i0)
                b(1) = pts(1, i2) - pts(1, i0)
                b(2) = pts(2, i2) - pts(2, i0)

                CrossProduct a, b, cr

                If VecLength(cr) > EPS Then
                    NormalizeVec cr
                    n(0) = cr(0)
                    n(1) = cr(1)
                    n(2) = cr(2)

                    LogEvent " | INFO  | TryGetNormalFromFaceVertices: using point indices " & i0 & "," & i1 & "," & i2
                    TryGetNormalFromFaceVertices = True
                    Exit Function
                End If
            Next i2
        Next i1
    Next i0

    LogEvent " | WARN  | TryGetNormalFromFaceVertices: no non-collinear triplet found"
    Exit Function

EH:
    LogEvent " | ERROR | TryGetNormalFromFaceVertices: " & Err.Number & " - " & Err.Description
End Function

Private Sub AddUniquePoint3(ByRef pts() As Double, ByRef ptCount As Long, ByRef p() As Double)
    Dim i As Long

    For i = 0 To ptCount - 1
        If Abs(pts(0, i) - p(0)) <= PT_TOL _
        And Abs(pts(1, i) - p(1)) <= PT_TOL _
        And Abs(pts(2, i) - p(2)) <= PT_TOL Then
            Exit Sub
        End If
    Next i

    If ptCount = 0 Then
        ReDim pts(0 To 2, 0 To 0)
    Else
        ReDim Preserve pts(0 To 2, 0 To ptCount)
    End If

    pts(0, ptCount) = p(0)
    pts(1, ptCount) = p(1)
    pts(2, ptCount) = p(2)
    ptCount = ptCount + 1
End Sub

Private Function VariantHas3Numbers(ByVal v As Variant) As Boolean
    On Error GoTo EH

    VariantHas3Numbers = False
    If IsEmpty(v) Then Exit Function
    If Not IsArray(v) Then Exit Function

    Dim lb As Long, ub As Long
    lb = LBound(v)
    ub = UBound(v)

    If (ub - lb + 1) < 3 Then Exit Function

    Dim t0 As Double, t1 As Double, t2 As Double
    t0 = CDbl(v(lb + 0))
    t1 = CDbl(v(lb + 1))
    t2 = CDbl(v(lb + 2))

    VariantHas3Numbers = True
    Exit Function

EH:
    VariantHas3Numbers = False
End Function

Private Function VariantHasAtLeast6Numbers(ByVal v As Variant) As Boolean
    On Error GoTo EH

    VariantHasAtLeast6Numbers = False
    If IsEmpty(v) Then Exit Function
    If Not IsArray(v) Then Exit Function

    Dim lb As Long, ub As Long
    lb = LBound(v)
    ub = UBound(v)

    If (ub - lb + 1) < 6 Then Exit Function

    Dim i As Long, tmp As Double
    For i = 0 To 5
        tmp = CDbl(v(lb + i))
    Next i

    VariantHasAtLeast6Numbers = True
    Exit Function

EH:
    VariantHasAtLeast6Numbers = False
End Function

Private Function GetBestTabAwareGussetOrientationCandidate(ByVal face As SldWorks.Face2, _
                                                           ByRef faceNormal() As Double, _
                                                           ByRef bestPrimaryLen As Double, _
                                                           ByRef bestSecondaryLen As Double, _
                                                           ByRef bestX() As Double, _
                                                           ByRef bestY() As Double, _
                                                           ByRef bestCorner() As Double) As Boolean
    On Error GoTo EH

    GetBestTabAwareGussetOrientationCandidate = False

    If face Is Nothing Then Exit Function

    Dim pts() As Double
    Dim ptCount As Long
    ptCount = 0

    If Not CollectUniqueFaceBoundaryPoints(face, pts, ptCount) Then
        LogEvent " | INFO  | Tab-aware gusset scan: no usable boundary points"
        Exit Function
    End If

    LogEvent " | INFO  | Tab-aware gusset scan: boundary point count = " & ptCount

    Dim vEdges As Variant
    vEdges = face.GetEdges

    If IsEmpty(vEdges) Then Exit Function
    If Not IsArray(vEdges) Then Exit Function

    bestPrimaryLen = -1#
    bestSecondaryLen = -1#

    Dim bestArea As Double
    Dim bestNegMax As Double
    bestArea = -1#
    bestNegMax = 1E+30

    Dim i As Long
    Dim j As Long

    For i = LBound(vEdges) To UBound(vEdges)
        Dim ed1 As SldWorks.Edge
        Set ed1 = vEdges(i)

        If Not ed1 Is Nothing Then
            If EdgeIsLinear(ed1) Then
                Dim e1p0(2) As Double, e1p1(2) As Double

                If GetEdgeEndPoints(ed1, e1p0, e1p1) Then
                    For j = i + 1 To UBound(vEdges)
                        Dim ed2 As SldWorks.Edge
                        Set ed2 = vEdges(j)

                        If Not ed2 Is Nothing Then
                            If EdgeIsLinear(ed2) Then
                                Dim e2p0(2) As Double, e2p1(2) As Double

                                If GetEdgeEndPoints(ed2, e2p0, e2p1) Then
                                    Dim corner(2) As Double
                                    Dim e1Far(2) As Double
                                    Dim e2Far(2) As Double

                                    If TryGetSharedCornerFromEdgeEndpoints(e1p0, e1p1, e2p0, e2p1, corner, e1Far, e2Far) Then
                                        Dim dir1(2) As Double
                                        Dim dir2(2) As Double
                                        Dim len1 As Double
                                        Dim len2 As Double

                                        dir1(0) = e1Far(0) - corner(0)
                                        dir1(1) = e1Far(1) - corner(1)
                                        dir1(2) = e1Far(2) - corner(2)

                                        dir2(0) = e2Far(0) - corner(0)
                                        dir2(1) = e2Far(1) - corner(1)
                                        dir2(2) = e2Far(2) - corner(2)

                                        ProjectVectorOntoPlane dir1, faceNormal, dir1
                                        ProjectVectorOntoPlane dir2, faceNormal, dir2

                                        len1 = VecLength(dir1)
                                        len2 = VecLength(dir2)

                                        If len1 > EPS And len2 > EPS Then
                                            NormalizeVec dir1
                                            NormalizeVec dir2

                                            Dim perpDot As Double
                                            perpDot = Abs(DotProduct(dir1, dir2))

                                            If perpDot <= PERP_DOT_TOL Then
                                                Dim candPrimaryLen As Double
                                                Dim candSecondaryLen As Double
                                                Dim candX(2) As Double
                                                Dim candY(2) As Double
                                                Dim candNegMax As Double
                                                Dim candArea As Double

                                                If EvaluateTabAwareCornerCandidate(pts, ptCount, corner, dir1, dir2, candPrimaryLen, candSecondaryLen, candX, candY, candNegMax, candArea) Then
                                                    LogEvent " | INFO  | Tab-aware candidate accepted | EdgeIdx=" & i & "/" & j & _
                                                                " | corner=(" & Dbl3ToStr(corner) & ")" & _
                                                                " | primary=" & FormatNumber(candPrimaryLen, 8) & _
                                                                " | secondary=" & FormatNumber(candSecondaryLen, 8) & _
                                                                " | negMax=" & FormatNumber(candNegMax, 8) & _
                                                                " | area=" & FormatNumber(candArea, 8)

                                                    If IsTabAwareCandidateBetter(candPrimaryLen, candSecondaryLen, candArea, candNegMax, candX, _
                                                                                 bestPrimaryLen, bestSecondaryLen, bestArea, bestNegMax, bestX) Then
                                                        bestPrimaryLen = candPrimaryLen
                                                        bestSecondaryLen = candSecondaryLen
                                                        bestArea = candArea
                                                        bestNegMax = candNegMax

                                                        bestX(0) = candX(0): bestX(1) = candX(1): bestX(2) = candX(2)
                                                        bestY(0) = candY(0): bestY(1) = candY(1): bestY(2) = candY(2)
                                                        bestCorner(0) = corner(0): bestCorner(1) = corner(1): bestCorner(2) = corner(2)

                                                        GetBestTabAwareGussetOrientationCandidate = True
                                                    End If
                                                Else
                                                    LogEvent " | INFO  | Tab-aware candidate rejected | EdgeIdx=" & i & "/" & j & _
                                                                " | corner=(" & Dbl3ToStr(corner) & ")"
                                                End If
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    Next j
                End If
            End If
        End If
    Next i

    Exit Function

EH:
    LogEvent " | ERROR | GetBestTabAwareGussetOrientationCandidate: " & Err.Number & " - " & Err.Description
End Function

Private Function CollectUniqueFaceBoundaryPoints(ByVal face As SldWorks.Face2, _
                                                 ByRef pts() As Double, _
                                                 ByRef ptCount As Long) As Boolean
    On Error GoTo EH

    CollectUniqueFaceBoundaryPoints = False
    ptCount = 0

    If face Is Nothing Then Exit Function

    Dim vEdges As Variant
    vEdges = face.GetEdges

    If IsEmpty(vEdges) Then Exit Function
    If Not IsArray(vEdges) Then Exit Function

    Dim i As Long
    For i = LBound(vEdges) To UBound(vEdges)
        Dim ed As SldWorks.Edge
        Set ed = vEdges(i)

        If Not ed Is Nothing Then
            Dim p0(2) As Double, p1(2) As Double
            If GetEdgeEndPoints(ed, p0, p1) Then
                AddUniquePoint3 pts, ptCount, p0
                AddUniquePoint3 pts, ptCount, p1
            End If
        End If
    Next i

    CollectUniqueFaceBoundaryPoints = (ptCount >= 3)
    Exit Function

EH:
    LogEvent " | ERROR | CollectUniqueFaceBoundaryPoints: " & Err.Number & " - " & Err.Description
End Function

Private Function EvaluateTabAwareCornerCandidate(ByRef pts() As Double, _
                                                 ByVal ptCount As Long, _
                                                 ByRef corner() As Double, _
                                                 ByRef dir1() As Double, _
                                                 ByRef dir2() As Double, _
                                                 ByRef bestPrimaryLen As Double, _
                                                 ByRef bestSecondaryLen As Double, _
                                                 ByRef bestX() As Double, _
                                                 ByRef bestY() As Double, _
                                                 ByRef bestNegMax As Double, _
                                                 ByRef bestArea As Double) As Boolean
    On Error GoTo EH

    EvaluateTabAwareCornerCandidate = False

    If ptCount < 3 Then Exit Function

    Dim requiredLeg As Double
    requiredLeg = TAB_AWARE_MIN_EFFECTIVE_LEG_M

    Dim ratioLeg As Double
    ratioLeg = TAB_AWARE_USER_TAB_MAX_M * TAB_AWARE_MIN_LEG_TO_TAB_RATIO
    If ratioLeg > requiredLeg Then requiredLeg = ratioLeg

    bestPrimaryLen = -1#
    bestSecondaryLen = -1#
    bestNegMax = 1E+30
    bestArea = -1#

    Dim sx As Long
    Dim sy As Long

    For sx = -1 To 1 Step 2
        For sy = -1 To 1 Step 2

            Dim candX(2) As Double
            Dim candY(2) As Double

            candX(0) = sx * dir1(0)
            candX(1) = sx * dir1(1)
            candX(2) = sx * dir1(2)

            candY(0) = sy * dir2(0)
            candY(1) = sy * dir2(1)
            candY(2) = sy * dir2(2)

            NormalizeVec candX
            NormalizeVec candY

            Dim maxNegX As Double
            Dim maxNegY As Double
            Dim effX As Double
            Dim effY As Double

            maxNegX = 0#
            maxNegY = 0#
            effX = 0#
            effY = 0#

            Dim i As Long
            For i = 0 To ptCount - 1
                Dim rel(2) As Double
                rel(0) = pts(0, i) - corner(0)
                rel(1) = pts(1, i) - corner(1)
                rel(2) = pts(2, i) - corner(2)

                Dim u As Double
                Dim v As Double
                u = DotProduct(rel, candX)
                v = DotProduct(rel, candY)

                If u < 0# Then
                    If -u > maxNegX Then maxNegX = -u
                Else
                    If Abs(v) <= TAB_AWARE_AXIS_STRIP_HALF_WIDTH_M + EPS Then
                        If u > effX Then effX = u
                    End If
                End If

                If v < 0# Then
                    If -v > maxNegY Then maxNegY = -v
                Else
                    If Abs(u) <= TAB_AWARE_AXIS_STRIP_HALF_WIDTH_M + EPS Then
                        If v > effY Then effY = v
                    End If
                End If
            Next i

            Dim candNegMax As Double
            candNegMax = maxNegX
            If maxNegY > candNegMax Then candNegMax = maxNegY

            Dim candPrimary As Double
            Dim candSecondary As Double
            Dim candArea As Double
            Dim finalX(2) As Double
            Dim finalY(2) As Double

            If TAB_AWARE_PREFER_LONGER_LEG_HORIZONTAL Then
                If effY > effX + EPS Then
                    candPrimary = effY
                    candSecondary = effX
                    finalX(0) = candY(0): finalX(1) = candY(1): finalX(2) = candY(2)
                    finalY(0) = candX(0): finalY(1) = candX(1): finalY(2) = candX(2)
                Else
                    candPrimary = effX
                    candSecondary = effY
                    finalX(0) = candX(0): finalX(1) = candX(1): finalX(2) = candX(2)
                    finalY(0) = candY(0): finalY(1) = candY(1): finalY(2) = candY(2)
                End If
            Else
                candPrimary = effX
                candSecondary = effY
                finalX(0) = candX(0): finalX(1) = candX(1): finalX(2) = candX(2)
                finalY(0) = candY(0): finalY(1) = candY(1): finalY(2) = candY(2)
            End If

            candArea = candPrimary * candSecondary

            LogEvent " | INFO  | Tab-aware sign combo | sx=" & sx & " sy=" & sy & _
                        " | negX=" & FormatNumber(maxNegX, 8) & _
                        " | negY=" & FormatNumber(maxNegY, 8) & _
                        " | effX=" & FormatNumber(effX, 8) & _
                        " | effY=" & FormatNumber(effY, 8) & _
                        " | chosenPrimary=" & FormatNumber(candPrimary, 8) & _
                        " | chosenSecondary=" & FormatNumber(candSecondary, 8)

            If candNegMax <= TAB_AWARE_ALLOWANCE_M + EPS Then
                If candPrimary >= requiredLeg - EPS And candSecondary >= requiredLeg - EPS Then
                    If IsTabAwareCandidateBetter(candPrimary, candSecondary, candArea, candNegMax, finalX, _
                                                 bestPrimaryLen, bestSecondaryLen, bestArea, bestNegMax, bestX) Then
                        bestPrimaryLen = candPrimary
                        bestSecondaryLen = candSecondary
                        bestNegMax = candNegMax
                        bestArea = candArea

                        bestX(0) = finalX(0): bestX(1) = finalX(1): bestX(2) = finalX(2)
                        bestY(0) = finalY(0): bestY(1) = finalY(1): bestY(2) = finalY(2)

                        EvaluateTabAwareCornerCandidate = True
                    End If
                Else
                    LogEvent " | INFO  | Tab-aware sign combo rejected by minimum effective leg requirement = " & FormatNumber(requiredLeg, 8)
                End If
            Else
                LogEvent " | INFO  | Tab-aware sign combo rejected by negative extent allowance = " & FormatNumber(candNegMax, 8)
            End If
        Next sy
    Next sx

    Exit Function

EH:
    LogEvent " | ERROR | EvaluateTabAwareCornerCandidate: " & Err.Number & " - " & Err.Description
End Function

Private Function IsTabAwareCandidateBetter(ByVal candPrimary As Double, _
                                           ByVal candSecondary As Double, _
                                           ByVal candArea As Double, _
                                           ByVal candNegMax As Double, _
                                           ByRef candX() As Double, _
                                           ByVal bestPrimary As Double, _
                                           ByVal bestSecondary As Double, _
                                           ByVal bestArea As Double, _
                                           ByVal bestNegMax As Double, _
                                           ByRef bestX() As Double) As Boolean
    IsTabAwareCandidateBetter = False

    If candSecondary > bestSecondary + EPS Then
        IsTabAwareCandidateBetter = True
        Exit Function
    End If

    If Abs(candSecondary - bestSecondary) <= EPS Then
        If candArea > bestArea + EPS Then
            IsTabAwareCandidateBetter = True
            Exit Function
        End If

        If Abs(candArea - bestArea) <= EPS Then
            If candPrimary > bestPrimary + EPS Then
                IsTabAwareCandidateBetter = True
                Exit Function
            End If

            If Abs(candPrimary - bestPrimary) <= EPS Then
                If candNegMax < bestNegMax - EPS Then
                    IsTabAwareCandidateBetter = True
                    Exit Function
                End If

                If Abs(candNegMax - bestNegMax) <= EPS Then
                    If CompareVectorLex(candX, bestX) > 0 Then
                        IsTabAwareCandidateBetter = True
                        Exit Function
                    End If
                End If
            End If
        End If
    End If
End Function

Private Function FindHorizontalDirectionFromFace(ByVal face As SldWorks.Face2, _
                                                 ByRef faceNormal() As Double, _
                                                 ByRef xDir() As Double, _
                                                 ByRef usedFallback As Boolean, _
                                                 ByRef usedPerpCorner As Boolean) As Boolean
    On Error GoTo EH

    FindHorizontalDirectionFromFace = False
    usedFallback = False
    usedPerpCorner = False

    Dim tabAwareFound As Boolean
    Dim sharedFound As Boolean
    Dim virtualFound As Boolean

    Dim tabPrimaryLen As Double
    Dim tabSecondaryLen As Double
    Dim tabX(2) As Double
    Dim tabY(2) As Double
    Dim tabCorner(2) As Double

    Dim sharedPrimaryLen As Double
    Dim sharedSecondaryLen As Double
    Dim sharedX(2) As Double
    Dim sharedY(2) As Double
    Dim sharedCorner(2) As Double

    Dim virtualPrimaryLen As Double
    Dim virtualSecondaryLen As Double
    Dim virtualX(2) As Double
    Dim virtualY(2) As Double
    Dim virtualCorner(2) As Double

    If ENABLE_TAB_AWARE_GUSSET_MODE Then
        LogEvent " | INFO  | Tab-aware gusset orientation scan: start"
        tabAwareFound = GetBestTabAwareGussetOrientationCandidate(face, faceNormal, tabPrimaryLen, tabSecondaryLen, tabX, tabY, tabCorner)

        If tabAwareFound Then
            LogEvent " | INFO  | Tab-aware gusset orientation candidate accepted before legacy pair-length logic"
            If ApplyBottomLeftOrientationCandidate(faceNormal, xDir, tabX, tabY, tabCorner, tabPrimaryLen, tabSecondaryLen, "Tab-aware gusset orientation", "Manufacturing corner") Then
                usedPerpCorner = True
                FindHorizontalDirectionFromFace = True
                Exit Function
            Else
                LogEvent " | WARN  | Tab-aware gusset candidate was found but could not be applied"
            End If
        Else
            LogEvent " | INFO  | Tab-aware gusset orientation scan found no qualifying manufacturing corner"
        End If
    End If

    sharedFound = GetBestSharedCornerOrientationCandidate(face, faceNormal, sharedPrimaryLen, sharedSecondaryLen, sharedX, sharedY, sharedCorner)

    If sharedFound Then
        LogEvent " | INFO  | Shared-corner perpendicular pair found; checking non-intersecting perpendicular pairs for chamfer override"
        virtualFound = GetBestVirtualCornerOrientationCandidate(face, faceNormal, virtualPrimaryLen, virtualSecondaryLen, virtualX, virtualY, virtualCorner)

        If virtualFound Then
            LogEvent " | INFO  | Best shared-corner pair lengths     = " & FormatNumber(sharedPrimaryLen, 8) & " / " & FormatNumber(sharedSecondaryLen, 8)
            LogEvent " | INFO  | Best non-intersecting pair lengths = " & FormatNumber(virtualPrimaryLen, 8) & " / " & FormatNumber(virtualSecondaryLen, 8)

            If IsPairLengthBetter(virtualPrimaryLen, virtualSecondaryLen, sharedPrimaryLen, sharedSecondaryLen) Then
                LogEvent " | INFO  | Non-intersecting perpendicular pair is longer than shared-corner pair; using chamfer-ignore virtual corner orientation"
                If ApplyBottomLeftOrientationCandidate(faceNormal, xDir, virtualX, virtualY, virtualCorner, virtualPrimaryLen, virtualSecondaryLen, "Virtual corner orientation", "Virtual corner") Then
                    usedPerpCorner = True
                    FindHorizontalDirectionFromFace = True
                    Exit Function
                End If
            Else
                LogEvent " | INFO  | Shared-corner pair remains preferred because non-intersecting pair is not longer"
                If ApplyBottomLeftOrientationCandidate(faceNormal, xDir, sharedX, sharedY, sharedCorner, sharedPrimaryLen, sharedSecondaryLen, "Corner orientation", "Shared corner") Then
                    usedPerpCorner = True
                    FindHorizontalDirectionFromFace = True
                    Exit Function
                End If
            End If
        Else
            LogEvent " | INFO  | No qualifying non-intersecting perpendicular pair found; using shared-corner pair"
            If ApplyBottomLeftOrientationCandidate(faceNormal, xDir, sharedX, sharedY, sharedCorner, sharedPrimaryLen, sharedSecondaryLen, "Corner orientation", "Shared corner") Then
                usedPerpCorner = True
                FindHorizontalDirectionFromFace = True
                Exit Function
            End If
        End If
    Else
        LogEvent " | INFO  | No valid perpendicular shared-corner pair found; trying non-intersecting perpendicular pair fallback"

        virtualFound = GetBestVirtualCornerOrientationCandidate(face, faceNormal, virtualPrimaryLen, virtualSecondaryLen, virtualX, virtualY, virtualCorner)
        If virtualFound Then
            If ApplyBottomLeftOrientationCandidate(faceNormal, xDir, virtualX, virtualY, virtualCorner, virtualPrimaryLen, virtualSecondaryLen, "Virtual corner orientation", "Virtual corner") Then
                usedPerpCorner = True
                FindHorizontalDirectionFromFace = True
                Exit Function
            End If
        End If
    End If

    LogEvent " | INFO  | No usable perpendicular edge pair found; trying longest single edge fallback"

    Dim vEdges As Variant
    vEdges = face.GetEdges

    Dim bestLen As Double
    bestLen = -1#

    Dim bestVec(2) As Double
    Dim foundLine As Boolean
    foundLine = False

    If Not IsEmpty(vEdges) Then
        If IsArray(vEdges) Then
            Dim i As Long
            For i = LBound(vEdges) To UBound(vEdges)
                Dim ed As SldWorks.Edge
                Set ed = vEdges(i)
                If Not ed Is Nothing Then
                    If EdgeIsLinear(ed) Then
                        Dim p0(2) As Double, p1(2) As Double
                        If GetEdgeEndPoints(ed, p0, p1) Then
                            Dim v(2) As Double
                            v(0) = p1(0) - p0(0)
                            v(1) = p1(1) - p0(1)
                            v(2) = p1(2) - p0(2)

                            ProjectVectorOntoPlane v, faceNormal, v
                            Dim L As Double
                            L = VecLength(v)

                            If L > EPS Then
                                NormalizeVec v
                                StabilizeVectorSign v

                                Dim trueLen As Double
                                trueLen = Distance3(p0, p1)

                                If (trueLen > bestLen + EPS) Or _
                                   (Abs(trueLen - bestLen) <= EPS And CompareVectorLex(v, bestVec) > 0) Then
                                    bestLen = trueLen
                                    bestVec(0) = v(0)
                                    bestVec(1) = v(1)
                                    bestVec(2) = v(2)
                                    foundLine = True
                                End If
                            End If
                        End If
                    End If
                End If
            Next i
        End If
    End If

    If foundLine Then
        xDir(0) = bestVec(0)
        xDir(1) = bestVec(1)
        xDir(2) = bestVec(2)
        NormalizeVec xDir
        LogEvent " | INFO  | Longest edge dir fallback = (" & Dbl3ToStr(xDir) & "), length = " & FormatNumber(bestLen, 8)
        FindHorizontalDirectionFromFace = True
        Exit Function
    End If

    LogEvent " | WARN  | No valid linear edge found on face; using fallback orientation axis"
    ChooseFallbackXAxis faceNormal, xDir
    usedFallback = True
    FindHorizontalDirectionFromFace = True
    Exit Function

EH:
    LogEvent " | ERROR | FindHorizontalDirectionFromFace: " & Err.Number & " - " & Err.Description
End Function


Private Function EdgeIsLinear(ByVal ed As SldWorks.Edge) As Boolean
    On Error GoTo EH

    EdgeIsLinear = False

    Dim crv As SldWorks.Curve
    Set crv = ed.GetCurve
    If crv Is Nothing Then Exit Function

    EdgeIsLinear = crv.IsLine
    Exit Function

EH:
    LogEvent " | ERROR | EdgeIsLinear: " & Err.Number & " - " & Err.Description
End Function

Private Function GetEdgeEndPoints(ByVal ed As SldWorks.Edge, ByRef p0() As Double, ByRef p1() As Double) As Boolean
    On Error GoTo EH

    GetEdgeEndPoints = False

    Dim vStart As SldWorks.Vertex
    Dim vEnd As SldWorks.Vertex

    Set vStart = ed.GetStartVertex
    Set vEnd = ed.GetEndVertex

    If vStart Is Nothing Or vEnd Is Nothing Then Exit Function

    Dim a As Variant, b As Variant
    a = vStart.GetPoint
    b = vEnd.GetPoint

    If IsEmpty(a) Or IsEmpty(b) Then Exit Function

    p0(0) = CDbl(a(0)): p0(1) = CDbl(a(1)): p0(2) = CDbl(a(2))
    p1(0) = CDbl(b(0)): p1(1) = CDbl(b(1)): p1(2) = CDbl(b(2))

    GetEdgeEndPoints = True
    Exit Function

EH:
    LogEvent " | ERROR | GetEdgeEndPoints: " & Err.Number & " - " & Err.Description
End Function

Private Function TryGetBottomLeftCornerOrientation(ByVal face As SldWorks.Face2, _
                                                   ByRef faceNormal() As Double, _
                                                   ByRef xDir() As Double) As Boolean
    On Error GoTo EH

    Dim bestPrimaryLen As Double
    Dim bestSecondaryLen As Double
    Dim bestX(2) As Double
    Dim bestY(2) As Double
    Dim bestCorner(2) As Double

    TryGetBottomLeftCornerOrientation = False

    If GetBestSharedCornerOrientationCandidate(face, faceNormal, bestPrimaryLen, bestSecondaryLen, bestX, bestY, bestCorner) Then
        TryGetBottomLeftCornerOrientation = ApplyBottomLeftOrientationCandidate(faceNormal, xDir, bestX, bestY, bestCorner, bestPrimaryLen, bestSecondaryLen, "Corner orientation", "Shared corner")
    Else
        LogEvent " | INFO  | Corner orientation scan: no perpendicular shared-corner pair satisfied tolerance"
    End If
    Exit Function

EH:
    LogEvent " | ERROR | TryGetBottomLeftCornerOrientation: " & Err.Number & " - " & Err.Description
End Function

Private Function GetBestSharedCornerOrientationCandidate(ByVal face As SldWorks.Face2, _
                                                         ByRef faceNormal() As Double, _
                                                         ByRef bestPrimaryLen As Double, _
                                                         ByRef bestSecondaryLen As Double, _
                                                         ByRef bestX() As Double, _
                                                         ByRef bestY() As Double, _
                                                         ByRef bestCorner() As Double) As Boolean
    On Error GoTo EH

    GetBestSharedCornerOrientationCandidate = False

    If face Is Nothing Then Exit Function

    Dim vEdges As Variant
    vEdges = face.GetEdges

    If IsEmpty(vEdges) Then
        LogEvent " | INFO  | Corner orientation scan: face has no edges"
        Exit Function
    End If

    If Not IsArray(vEdges) Then
        LogEvent " | INFO  | Corner orientation scan: face edges are not an array"
        Exit Function
    End If

    Dim foundPair As Boolean
    foundPair = False

    bestPrimaryLen = -1#
    bestSecondaryLen = -1#

    Dim i As Long
    Dim j As Long

    For i = LBound(vEdges) To UBound(vEdges)
        Dim ed1 As SldWorks.Edge
        Set ed1 = vEdges(i)

        If Not ed1 Is Nothing Then
            If EdgeIsLinear(ed1) Then

                Dim e1p0(2) As Double, e1p1(2) As Double
                If GetEdgeEndPoints(ed1, e1p0, e1p1) Then

                    For j = i + 1 To UBound(vEdges)
                        Dim ed2 As SldWorks.Edge
                        Set ed2 = vEdges(j)

                        If Not ed2 Is Nothing Then
                            If EdgeIsLinear(ed2) Then

                                Dim e2p0(2) As Double, e2p1(2) As Double
                                If GetEdgeEndPoints(ed2, e2p0, e2p1) Then

                                    Dim corner(2) As Double
                                    Dim e1Far(2) As Double
                                    Dim e2Far(2) As Double

                                    If TryGetSharedCornerFromEdgeEndpoints(e1p0, e1p1, e2p0, e2p1, corner, e1Far, e2Far) Then

                                        Dim dir1(2) As Double, dir2(2) As Double
                                        dir1(0) = e1Far(0) - corner(0)
                                        dir1(1) = e1Far(1) - corner(1)
                                        dir1(2) = e1Far(2) - corner(2)

                                        dir2(0) = e2Far(0) - corner(0)
                                        dir2(1) = e2Far(1) - corner(1)
                                        dir2(2) = e2Far(2) - corner(2)

                                        ProjectVectorOntoPlane dir1, faceNormal, dir1
                                        ProjectVectorOntoPlane dir2, faceNormal, dir2

                                        Dim len1 As Double, len2 As Double
                                        len1 = VecLength(dir1)
                                        len2 = VecLength(dir2)

                                        If len1 > EPS And len2 > EPS Then
                                            NormalizeVec dir1
                                            NormalizeVec dir2

                                            Dim perpDot As Double
                                            perpDot = Abs(DotProduct(dir1, dir2))

                                            LogEvent " | INFO  | Corner pair candidate | EdgeIdx=" & i & "/" & j & _
                                                        " | corner=(" & Dbl3ToStr(corner) & ")" & _
                                                        " | len1=" & FormatNumber(len1, 8) & _
                                                        " | len2=" & FormatNumber(len2, 8) & _
                                                        " | |dot|=" & FormatNumber(perpDot, 8)

                                            If perpDot <= PERP_DOT_TOL Then

                                                Dim primaryLen As Double
                                                Dim secondaryLen As Double
                                                Dim candX(2) As Double
                                                Dim candY(2) As Double

                                                If (len1 > len2 + EPS) Or _
                                                   (Abs(len1 - len2) <= EPS And CompareVectorLex(dir1, dir2) >= 0) Then
                                                    primaryLen = len1
                                                    secondaryLen = len2
                                                    candX(0) = dir1(0): candX(1) = dir1(1): candX(2) = dir1(2)
                                                    candY(0) = dir2(0): candY(1) = dir2(1): candY(2) = dir2(2)
                                                Else
                                                    primaryLen = len2
                                                    secondaryLen = len1
                                                    candX(0) = dir2(0): candX(1) = dir2(1): candX(2) = dir2(2)
                                                    candY(0) = dir1(0): candY(1) = dir1(1): candY(2) = dir1(2)
                                                End If

                                                If (primaryLen > bestPrimaryLen + EPS) Or _
                                                   (Abs(primaryLen - bestPrimaryLen) <= EPS And secondaryLen > bestSecondaryLen + EPS) Or _
                                                   (Abs(primaryLen - bestPrimaryLen) <= EPS And Abs(secondaryLen - bestSecondaryLen) <= EPS And CompareVectorLex(candX, bestX) > 0) Then

                                                    bestPrimaryLen = primaryLen
                                                    bestSecondaryLen = secondaryLen

                                                    bestX(0) = candX(0): bestX(1) = candX(1): bestX(2) = candX(2)
                                                    bestY(0) = candY(0): bestY(1) = candY(1): bestY(2) = candY(2)

                                                    bestCorner(0) = corner(0)
                                                    bestCorner(1) = corner(1)
                                                    bestCorner(2) = corner(2)

                                                    foundPair = True
                                                End If
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    Next j
                End If
            End If
        End If
    Next i

    GetBestSharedCornerOrientationCandidate = foundPair
    Exit Function

EH:
    LogEvent " | ERROR | GetBestSharedCornerOrientationCandidate: " & Err.Number & " - " & Err.Description
End Function

Private Function TryGetBottomLeftVirtualCornerOrientation(ByVal face As SldWorks.Face2, _
                                                         ByRef faceNormal() As Double, _
                                                         ByRef xDir() As Double) As Boolean
    On Error GoTo EH

    Dim bestPrimaryLen As Double
    Dim bestSecondaryLen As Double
    Dim bestX(2) As Double
    Dim bestY(2) As Double
    Dim bestCorner(2) As Double

    TryGetBottomLeftVirtualCornerOrientation = False

    If GetBestVirtualCornerOrientationCandidate(face, faceNormal, bestPrimaryLen, bestSecondaryLen, bestX, bestY, bestCorner) Then
        TryGetBottomLeftVirtualCornerOrientation = ApplyBottomLeftOrientationCandidate(faceNormal, xDir, bestX, bestY, bestCorner, bestPrimaryLen, bestSecondaryLen, "Virtual corner orientation", "Virtual corner")
    Else
        LogEvent " | INFO  | Virtual corner orientation scan: no non-intersecting perpendicular pair satisfied tolerance"
    End If
    Exit Function

EH:
    LogEvent " | ERROR | TryGetBottomLeftVirtualCornerOrientation: " & Err.Number & " - " & Err.Description
End Function

Private Function GetBestVirtualCornerOrientationCandidate(ByVal face As SldWorks.Face2, _
                                                          ByRef faceNormal() As Double, _
                                                          ByRef bestPrimaryLen As Double, _
                                                          ByRef bestSecondaryLen As Double, _
                                                          ByRef bestX() As Double, _
                                                          ByRef bestY() As Double, _
                                                          ByRef bestCorner() As Double) As Boolean
    On Error GoTo EH

    GetBestVirtualCornerOrientationCandidate = False

    If face Is Nothing Then Exit Function

    Dim vEdges As Variant
    vEdges = face.GetEdges

    If IsEmpty(vEdges) Then
        LogEvent " | INFO  | Virtual corner orientation scan: face has no edges"
        Exit Function
    End If

    If Not IsArray(vEdges) Then
        LogEvent " | INFO  | Virtual corner orientation scan: face edges are not an array"
        Exit Function
    End If

    Dim foundPair As Boolean
    foundPair = False

    bestPrimaryLen = -1#
    bestSecondaryLen = -1#

    Dim i As Long
    Dim j As Long

    For i = LBound(vEdges) To UBound(vEdges)
        Dim ed1 As SldWorks.Edge
        Set ed1 = vEdges(i)

        If Not ed1 Is Nothing Then
            If EdgeIsLinear(ed1) Then
                Dim e1p0(2) As Double, e1p1(2) As Double

                If GetEdgeEndPoints(ed1, e1p0, e1p1) Then
                    For j = i + 1 To UBound(vEdges)
                        Dim ed2 As SldWorks.Edge
                        Set ed2 = vEdges(j)

                        If Not ed2 Is Nothing Then
                            If EdgeIsLinear(ed2) Then
                                Dim e2p0(2) As Double, e2p1(2) As Double

                                If GetEdgeEndPoints(ed2, e2p0, e2p1) Then
                                    Dim sharedCorner(2) As Double
                                    Dim sharedFar1(2) As Double
                                    Dim sharedFar2(2) As Double

                                    If Not TryGetSharedCornerFromEdgeEndpoints(e1p0, e1p1, e2p0, e2p1, sharedCorner, sharedFar1, sharedFar2) Then
                                        Dim dir1Raw(2) As Double
                                        Dim dir2Raw(2) As Double
                                        Dim trueLen1 As Double
                                        Dim trueLen2 As Double

                                        dir1Raw(0) = e1p1(0) - e1p0(0)
                                        dir1Raw(1) = e1p1(1) - e1p0(1)
                                        dir1Raw(2) = e1p1(2) - e1p0(2)

                                        dir2Raw(0) = e2p1(0) - e2p0(0)
                                        dir2Raw(1) = e2p1(1) - e2p0(1)
                                        dir2Raw(2) = e2p1(2) - e2p0(2)

                                        ProjectVectorOntoPlane dir1Raw, faceNormal, dir1Raw
                                        ProjectVectorOntoPlane dir2Raw, faceNormal, dir2Raw

                                        trueLen1 = Distance3(e1p0, e1p1)
                                        trueLen2 = Distance3(e2p0, e2p1)

                                        If VecLength(dir1Raw) > EPS And VecLength(dir2Raw) > EPS Then
                                            NormalizeVec dir1Raw
                                            NormalizeVec dir2Raw

                                            Dim perpDot As Double
                                            perpDot = Abs(DotProduct(dir1Raw, dir2Raw))

                                            LogEvent " | INFO  | Virtual corner pair candidate | EdgeIdx=" & i & "/" & j & _
                                                        " | len1=" & FormatNumber(trueLen1, 8) & _
                                                        " | len2=" & FormatNumber(trueLen2, 8) & _
                                                        " | |dot|=" & FormatNumber(perpDot, 8)

                                            If perpDot <= PERP_DOT_TOL Then
                                                Dim virtualCorner(2) As Double

                                                If TryGetProjectedLineIntersection(e1p0, dir1Raw, e2p0, dir2Raw, faceNormal, virtualCorner) Then
                                                    Dim dir1(2) As Double
                                                    Dim dir2(2) As Double

                                                    If GetEdgeDirectionAwayFromReference(e1p0, e1p1, virtualCorner, dir1) Then
                                                        If GetEdgeDirectionAwayFromReference(e2p0, e2p1, virtualCorner, dir2) Then
                                                            Dim primaryLen As Double
                                                            Dim secondaryLen As Double
                                                            Dim candX(2) As Double
                                                            Dim candY(2) As Double

                                                            If (trueLen1 > trueLen2 + EPS) Or _
                                                               (Abs(trueLen1 - trueLen2) <= EPS And CompareVectorLex(dir1, dir2) >= 0) Then
                                                                primaryLen = trueLen1
                                                                secondaryLen = trueLen2
                                                                candX(0) = dir1(0): candX(1) = dir1(1): candX(2) = dir1(2)
                                                                candY(0) = dir2(0): candY(1) = dir2(1): candY(2) = dir2(2)
                                                            Else
                                                                primaryLen = trueLen2
                                                                secondaryLen = trueLen1
                                                                candX(0) = dir2(0): candX(1) = dir2(1): candX(2) = dir2(2)
                                                                candY(0) = dir1(0): candY(1) = dir1(1): candY(2) = dir1(2)
                                                            End If

                                                            If (primaryLen > bestPrimaryLen + EPS) Or _
                                                               (Abs(primaryLen - bestPrimaryLen) <= EPS And secondaryLen > bestSecondaryLen + EPS) Or _
                                                               (Abs(primaryLen - bestPrimaryLen) <= EPS And Abs(secondaryLen - bestSecondaryLen) <= EPS And CompareVectorLex(candX, bestX) > 0) Then
                                                                bestPrimaryLen = primaryLen
                                                                bestSecondaryLen = secondaryLen

                                                                bestX(0) = candX(0): bestX(1) = candX(1): bestX(2) = candX(2)
                                                                bestY(0) = candY(0): bestY(1) = candY(1): bestY(2) = candY(2)

                                                                bestCorner(0) = virtualCorner(0)
                                                                bestCorner(1) = virtualCorner(1)
                                                                bestCorner(2) = virtualCorner(2)

                                                                foundPair = True
                                                            End If
                                                        End If
                                                    End If
                                                End If
                                            End If
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    Next j
                End If
            End If
        End If
    Next i

    GetBestVirtualCornerOrientationCandidate = foundPair
    Exit Function

EH:
    LogEvent " | ERROR | GetBestVirtualCornerOrientationCandidate: " & Err.Number & " - " & Err.Description
End Function

Private Function IsPairLengthBetter(ByVal candidatePrimaryLen As Double, _
                                    ByVal candidateSecondaryLen As Double, _
                                    ByVal referencePrimaryLen As Double, _
                                    ByVal referenceSecondaryLen As Double) As Boolean
    IsPairLengthBetter = False

    If candidatePrimaryLen > referencePrimaryLen + EPS Then
        IsPairLengthBetter = True
        Exit Function
    End If

    If Abs(candidatePrimaryLen - referencePrimaryLen) <= EPS Then
        If candidateSecondaryLen > referenceSecondaryLen + EPS Then
            IsPairLengthBetter = True
            Exit Function
        End If
    End If
End Function

Private Function ApplyBottomLeftOrientationCandidate(ByRef faceNormal() As Double, _
                                                     ByRef xDir() As Double, _
                                                     ByRef bestX() As Double, _
                                                     ByRef bestY() As Double, _
                                                     ByRef bestCorner() As Double, _
                                                     ByVal bestPrimaryLen As Double, _
                                                     ByVal bestSecondaryLen As Double, _
                                                     ByVal selectionLabel As String, _
                                                     ByVal cornerLabel As String) As Boolean
    On Error GoTo EH

    ApplyBottomLeftOrientationCandidate = False

    xDir(0) = bestX(0)
    xDir(1) = bestX(1)
    xDir(2) = bestX(2)
    NormalizeVec xDir

    Dim currentY(2) As Double
    CrossProduct faceNormal, xDir, currentY
    NormalizeVec currentY

    Dim flippedNormal As Boolean
    flippedNormal = False

    If DotProduct(currentY, bestY) < 0# Then
        FlipVec faceNormal
        flippedNormal = True
        CrossProduct faceNormal, xDir, currentY
        NormalizeVec currentY
    End If

    LogEvent " | INFO  | " & selectionLabel & " selected"
    LogEvent " | INFO  |   " & cornerLabel & " = (" & Dbl3ToStr(bestCorner) & ")"
    LogEvent " | INFO  |   Bottom edge X = (" & Dbl3ToStr(xDir) & ") | len = " & FormatNumber(bestPrimaryLen, 8)
    LogEvent " | INFO  |   Left edge Y   = (" & Dbl3ToStr(bestY) & ") | len = " & FormatNumber(bestSecondaryLen, 8)
    LogEvent " | INFO  |   Face normal   = (" & Dbl3ToStr(faceNormal) & ") | flipped=" & CStr(flippedNormal)

    ApplyBottomLeftOrientationCandidate = True
    Exit Function

EH:
    LogEvent " | ERROR | ApplyBottomLeftOrientationCandidate: " & Err.Number & " - " & Err.Description
End Function


Private Function TryGetProjectedLineIntersection(ByRef line1Point() As Double, _
                                                 ByRef line1DirUnit() As Double, _
                                                 ByRef line2Point() As Double, _
                                                 ByRef line2DirUnit() As Double, _
                                                 ByRef faceNormal() As Double, _
                                                 ByRef intersection() As Double) As Boolean
    On Error GoTo EH

    TryGetProjectedLineIntersection = False

    Dim uv As Double
    uv = DotProduct(line1DirUnit, line2DirUnit)

    Dim denom As Double
    denom = 1# - (uv * uv)

    If denom <= EPS Then Exit Function

    Dim delta(2) As Double
    delta(0) = line2Point(0) - line1Point(0)
    delta(1) = line2Point(1) - line1Point(1)
    delta(2) = line2Point(2) - line1Point(2)
    ProjectVectorOntoPlane delta, faceNormal, delta

    Dim du As Double
    Dim dv As Double
    du = DotProduct(delta, line1DirUnit)
    dv = DotProduct(delta, line2DirUnit)

    Dim t As Double
    t = (du - (uv * dv)) / denom

    intersection(0) = line1Point(0) + (line1DirUnit(0) * t)
    intersection(1) = line1Point(1) + (line1DirUnit(1) * t)
    intersection(2) = line1Point(2) + (line1DirUnit(2) * t)

    TryGetProjectedLineIntersection = True
    Exit Function

EH:
    LogEvent " | ERROR | TryGetProjectedLineIntersection: " & Err.Number & " - " & Err.Description
End Function

Private Function GetEdgeDirectionAwayFromReference(ByRef p0() As Double, _
                                                   ByRef p1() As Double, _
                                                   ByRef refPoint() As Double, _
                                                   ByRef dirOut() As Double) As Boolean
    On Error GoTo EH

    GetEdgeDirectionAwayFromReference = False

    Dim d0 As Double
    Dim d1 As Double
    d0 = Distance3(p0, refPoint)
    d1 = Distance3(p1, refPoint)

    If (d0 <= PT_TOL) And (d1 <= PT_TOL) Then Exit Function

    If d0 < d1 - PT_TOL Then
        dirOut(0) = p1(0) - p0(0)
        dirOut(1) = p1(1) - p0(1)
        dirOut(2) = p1(2) - p0(2)
    ElseIf d1 < d0 - PT_TOL Then
        dirOut(0) = p0(0) - p1(0)
        dirOut(1) = p0(1) - p1(1)
        dirOut(2) = p0(2) - p1(2)
    Else
        dirOut(0) = p1(0) - p0(0)
        dirOut(1) = p1(1) - p0(1)
        dirOut(2) = p1(2) - p0(2)
        StabilizeVectorSign dirOut
    End If

    If VecLength(dirOut) <= EPS Then Exit Function

    NormalizeVec dirOut
    GetEdgeDirectionAwayFromReference = True
    Exit Function

EH:
    LogEvent " | ERROR | GetEdgeDirectionAwayFromReference: " & Err.Number & " - " & Err.Description
End Function

Private Function TryGetSharedCornerFromEdgeEndpoints(ByRef a0() As Double, _
                                                     ByRef a1() As Double, _
                                                     ByRef b0() As Double, _
                                                     ByRef b1() As Double, _
                                                     ByRef corner() As Double, _
                                                     ByRef aFar() As Double, _
                                                     ByRef bFar() As Double) As Boolean
    TryGetSharedCornerFromEdgeEndpoints = False

    If PointsCoincident3(a0, b0) Then
        CopyPoint3 a0, corner
        CopyPoint3 a1, aFar
        CopyPoint3 b1, bFar
        TryGetSharedCornerFromEdgeEndpoints = True
        Exit Function
    End If

    If PointsCoincident3(a0, b1) Then
        CopyPoint3 a0, corner
        CopyPoint3 a1, aFar
        CopyPoint3 b0, bFar
        TryGetSharedCornerFromEdgeEndpoints = True
        Exit Function
    End If

    If PointsCoincident3(a1, b0) Then
        CopyPoint3 a1, corner
        CopyPoint3 a0, aFar
        CopyPoint3 b1, bFar
        TryGetSharedCornerFromEdgeEndpoints = True
        Exit Function
    End If

    If PointsCoincident3(a1, b1) Then
        CopyPoint3 a1, corner
        CopyPoint3 a0, aFar
        CopyPoint3 b0, bFar
        TryGetSharedCornerFromEdgeEndpoints = True
        Exit Function
    End If
End Function

Private Function PointsCoincident3(ByRef p1() As Double, ByRef p2() As Double) As Boolean
    PointsCoincident3 = (Distance3(p1, p2) <= PT_TOL)
End Function

Private Sub CopyPoint3(ByRef src() As Double, ByRef dst() As Double)
    dst(0) = src(0)
    dst(1) = src(1)
    dst(2) = src(2)
End Sub

Private Sub ChooseFallbackXAxis(ByRef n() As Double, ByRef x() As Double)
    Dim ref(2) As Double

    If Abs(n(2)) < 0.9 Then
        ref(0) = 0#: ref(1) = 0#: ref(2) = 1#
    Else
        ref(0) = 0#: ref(1) = 1#: ref(2) = 0#
    End If

    CrossProduct ref, n, x
    NormalizeVec x
    StabilizeVectorSign x
End Sub

Private Function BuildViewOrientationTransform(ByRef xAxis() As Double, _
                                               ByRef zAxis() As Double) As SldWorks.MathTransform
    On Error GoTo EH

    Dim x(2) As Double, y(2) As Double, z(2) As Double

    x(0) = xAxis(0): x(1) = xAxis(1): x(2) = xAxis(2)
    z(0) = zAxis(0): z(1) = zAxis(1): z(2) = zAxis(2)

    NormalizeVec x
    NormalizeVec z

    ProjectVectorOntoPlane x, z, x
    NormalizeVec x

    CrossProduct z, x, y
    NormalizeVec y

    CrossProduct y, z, x
    NormalizeVec x

    Dim data(15) As Double
    Dim i As Long
    For i = 0 To 15
        data(i) = 0#
    Next i

    ' Basis vectors as COLUMNS
    data(0) = x(0): data(1) = y(0): data(2) = z(0)
    data(3) = x(1): data(4) = y(1): data(5) = z(1)
    data(6) = x(2): data(7) = y(2): data(8) = z(2)

    data(9) = 0#
    data(10) = 0#
    data(11) = 0#
    data(12) = 1#
    data(13) = 0#
    data(14) = 0#
    data(15) = 0#

    LogEvent " | INFO  | BuildViewOrientationTransform axes:"
    LogEvent " | INFO  |   X = (" & Dbl3ToStr(x) & ")"
    LogEvent " | INFO  |   Y = (" & Dbl3ToStr(y) & ")"
    LogEvent " | INFO  |   Z = (" & Dbl3ToStr(z) & ")"

    Set BuildViewOrientationTransform = swMathUtil.CreateTransform(data)
    Exit Function

EH:
    LogEvent " | ERROR | BuildViewOrientationTransform: " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' EXPORT
'=========================================================================================


Private Function ExportSingleBodyPartAsOrientedDxfFromSource(ByVal srcDoc As SldWorks.ModelDoc2, _
                                                             ByRef faceNormal() As Double, _
                                                             ByRef xDir() As Double, _
                                                             ByVal finalDxfPath As String, _
                                                             ByVal contextLabel As String, _
                                                             ByVal preserveCornerOrientation As Boolean) As Boolean
    On Error GoTo EH

    ExportSingleBodyPartAsOrientedDxfFromSource = False

    If srcDoc Is Nothing Then
        LogEvent " | FAIL  | Direct single-body source export: srcDoc is Nothing"
        Exit Function
    End If

    If srcDoc.GetType <> swDocPART Then
        LogEvent " | FAIL  | Direct single-body source export requires PART doc, got " & DocTypeName(srcDoc.GetType)
        Exit Function
    End If

    If Len(Trim$(srcDoc.GetPathName)) = 0 Then
        LogEvent " | FAIL  | Direct single-body source export requires saved part path"
        Exit Function
    End If

    If Not ShouldAttemptFastDirectDxfExport(preserveCornerOrientation) Then
        LogEvent " | FAIL  | Direct single-body source export is disabled by current toggle settings"
        Exit Function
    End If

    Dim originalUnits As Long
    Dim restoreUnits As Boolean
    Dim originalViewXf As Object
    Dim alignmentData(0 To 11) As Double
    Dim varAlignment As Variant
    Dim swSrcPart As SldWorks.PartDoc

    Set swSrcPart = srcDoc
    BuildIdentityDwgAlignment alignmentData
    varAlignment = alignmentData

    LogEvent " | INFO  | Direct single-body source export start"
    LogEvent " | INFO  |   contextLabel = " & contextLabel
    LogEvent " | INFO  |   sourcePath   = " & srcDoc.GetPathName
    LogEvent " | INFO  |   finalDxfPath = " & finalDxfPath
    LogEvent " | INFO  |   mode         = *Current view on source part"
    LogEvent " | INFO  |   preserveCornerOrientation = " & CStr(preserveCornerOrientation)

    If Not ActivateDocumentByTitle(srcDoc.GetTitle) Then
        LogEvent " | WARN  | Could not explicitly activate source part before direct export"
    End If

    Set originalViewXf = GetCurrentModelViewTransform(srcDoc)
    If originalViewXf Is Nothing Then
        LogEvent " | WARN  | Could not capture original source-part view transform"
    Else
        LogEvent " | INFO  | Captured original source-part view transform"
    End If

    originalUnits = GetModelLinearUnitsSafe(srcDoc)
    restoreUnits = (originalUnits <> -1)

    If Not OrientModelCurrentView(srcDoc, xDir, faceNormal) Then
        LogEvent " | FAIL  | Could not orient source part current view for direct export"
        GoTo CleanupAndExit
    End If

    If Not HideAllSketchesInModel(srcDoc) Then
        LogEvent " | WARN  | HideAllSketchesInModel returned False on source part before direct export"
    End If

    If DIRECT_TEMP_PART_FORCE_INCH_UNITS Then
        If ForceModelLinearUnitsToInches(srcDoc) Then
            LogEvent " | INFO  | Source part linear units forced to inches for direct export"
        Else
            LogEvent " | WARN  | Source part units could not be forced to inches before direct export"
        End If
    End If

    srcDoc.ForceRebuild3 True
    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then srcDoc.GraphicsRedraw2
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        srcDoc.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Source ViewZoomtofit2 skipped before direct export for batch stability"
    End If

    If TryDirectExportToDxfByViewName(swSrcPart, srcDoc.GetPathName, finalDxfPath, "*Current", varAlignment) Then
        ExportSingleBodyPartAsOrientedDxfFromSource = True
    Else
        LogEvent " | FAIL  | Direct single-body source export failed using *Current view"
    End If

CleanupAndExit:
    If restoreUnits Then
        If RestoreModelLinearUnits(srcDoc, originalUnits) Then
            LogEvent " | INFO  | Restored source part linear units after direct export"
        Else
            LogEvent " | WARN  | Could not restore source part linear units after direct export"
        End If
    End If

    If Not originalViewXf Is Nothing Then
        If RestoreCurrentModelViewTransform(srcDoc, originalViewXf) Then
            LogEvent " | INFO  | Restored source part original view transform after direct export"
        Else
            LogEvent " | WARN  | Could not restore source part original view transform"
        End If
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ExportSingleBodyPartAsOrientedDxfFromSource(" & contextLabel & "): " & Err.Number & " - " & Err.Description
End Function

Private Function OrientModelCurrentView(ByVal mdl As SldWorks.ModelDoc2, _
                                        ByRef xDir() As Double, _
                                        ByRef faceNormal() As Double) As Boolean
    On Error GoTo EH

    OrientModelCurrentView = False

    If mdl Is Nothing Then Exit Function

    Dim viewXf As SldWorks.MathTransform
    Set viewXf = BuildViewOrientationTransform(xDir, faceNormal)

    If viewXf Is Nothing Then
        LogEvent " | FAIL  | BuildViewOrientationTransform returned Nothing"
        Exit Function
    End If

    Dim mvObj As Object
    Set mvObj = mdl.ActiveView

    If mvObj Is Nothing Then
        LogEvent " | FAIL  | mdl.ActiveView returned Nothing"
        Exit Function
    End If

    LogEvent " | INFO  | Setting current model view orientation without temp-part save/reopen"
    On Error Resume Next
    CallByName mvObj, "Orientation3", VbSet, viewXf
    If Err.Number <> 0 Then
        LogEvent " | FAIL  | Setting current view Orientation3 failed: " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        Exit Function
    End If
    On Error GoTo EH

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then
        mdl.GraphicsRedraw2
    End If

    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        mdl.ViewZoomtofit2
    Else
        LogEvent " | INFO  | ViewZoomtofit2 skipped for batch stability"
    End If

    OrientModelCurrentView = True
    Exit Function

EH:
    LogEvent " | ERROR | OrientModelCurrentView: " & Err.Number & " - " & Err.Description
End Function

Private Function GetCurrentModelViewTransform(ByVal mdl As SldWorks.ModelDoc2) As Object
    On Error GoTo EH

    Set GetCurrentModelViewTransform = Nothing

    If mdl Is Nothing Then Exit Function

    Dim mvObj As Object
    Dim xfObj As Object

    Set mvObj = mdl.ActiveView
    If mvObj Is Nothing Then
        LogEvent " | WARN  | GetCurrentModelViewTransform: ActiveView is Nothing"
        Exit Function
    End If

    On Error Resume Next
    Set xfObj = CallByName(mvObj, "Orientation3", VbGet)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | GetCurrentModelViewTransform failed: " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        Exit Function
    End If
    On Error GoTo EH

    Set GetCurrentModelViewTransform = xfObj
    Exit Function

EH:
    LogEvent " | ERROR | GetCurrentModelViewTransform: " & Err.Number & " - " & Err.Description
End Function

Private Function RestoreCurrentModelViewTransform(ByVal mdl As SldWorks.ModelDoc2, ByVal xfObj As Object) As Boolean
    On Error GoTo EH

    RestoreCurrentModelViewTransform = False

    If mdl Is Nothing Then Exit Function
    If xfObj Is Nothing Then Exit Function

    Dim mvObj As Object
    Set mvObj = mdl.ActiveView

    If mvObj Is Nothing Then
        LogEvent " | WARN  | RestoreCurrentModelViewTransform: ActiveView is Nothing"
        Exit Function
    End If

    On Error Resume Next
    CallByName mvObj, "Orientation3", VbSet, xfObj
    If Err.Number <> 0 Then
        LogEvent " | WARN  | RestoreCurrentModelViewTransform failed: " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        Exit Function
    End If
    On Error GoTo EH

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then
        mdl.GraphicsRedraw2
    End If

    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        mdl.ViewZoomtofit2
    Else
        LogEvent " | INFO  | ViewZoomtofit2 skipped while restoring view for batch stability"
    End If

    RestoreCurrentModelViewTransform = True
    Exit Function

EH:
    LogEvent " | ERROR | RestoreCurrentModelViewTransform: " & Err.Number & " - " & Err.Description
End Function

Private Function GetModelLinearUnitsSafe(ByVal mdl As SldWorks.ModelDoc2) As Long
    On Error GoTo EH

    GetModelLinearUnitsSafe = -1

    If mdl Is Nothing Then Exit Function

    On Error Resume Next
    GetModelLinearUnitsSafe = mdl.GetUserPreferenceIntegerValue(swUnitsLinear)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | GetModelLinearUnitsSafe failed: " & Err.Number & " - " & Err.Description
        Err.Clear
        GetModelLinearUnitsSafe = -1
    End If
    On Error GoTo EH

    Exit Function

EH:
    LogEvent " | ERROR | GetModelLinearUnitsSafe: " & Err.Number & " - " & Err.Description
    GetModelLinearUnitsSafe = -1
End Function

Private Function RestoreModelLinearUnits(ByVal mdl As SldWorks.ModelDoc2, ByVal targetUnits As Long) As Boolean
    On Error GoTo EH

    RestoreModelLinearUnits = False

    If mdl Is Nothing Then Exit Function
    If targetUnits < 0 Then Exit Function

    mdl.SetUserPreferenceIntegerValue swUnitsLinear, targetUnits
    RestoreModelLinearUnits = (GetModelLinearUnitsSafe(mdl) = targetUnits)
    Exit Function

EH:
    LogEvent " | ERROR | RestoreModelLinearUnits: " & Err.Number & " - " & Err.Description
End Function

Private Function ExportBodyAsOrientedDxf(ByVal srcBody As SldWorks.Body2, _
                                         ByRef faceNormal() As Double, _
                                         ByRef xDir() As Double, _
                                         ByVal finalDxfPath As String, _
                                         ByVal cutListName As String, _
                                         ByVal preserveCornerOrientation As Boolean) As Boolean
    On Error GoTo EH

    ExportBodyAsOrientedDxf = False

    Dim tempRoot As String
    tempRoot = GetLocalTempRoot()

    If Len(tempRoot) = 0 Then
        LogEvent " | FAIL  | Could not create local temp root"
        Exit Function
    End If

    LogEvent " | INFO  | Local temp workspace = " & tempRoot
    LogEvent " | INFO  | DXF export mode = " & GetDxfExportModeName()
    LogEvent " | INFO  | R7 export mode: isolated temp part + view orientation; physical body flatten = " & CStr(PHYSICALLY_FLATTEN_TEMP_BODY_FOR_DXF)
    LogEvent " | INFO  | Current-view export after physical flatten = " & CStr(TEMP_PART_EXPORT_USE_CURRENT_VIEW_V15_ROTATION)

    Dim tempPartPath As String
    Dim tempDrwPath As String
    tempPartPath = CombinePathSafe(tempRoot, "body_temp.sldprt")
    tempDrwPath = CombinePathSafe(tempRoot, "body_temp.slddrw")

    LogEvent " | INFO  | Temp part path = " & tempPartPath
    LogEvent " | INFO  | Temp drawing path = " & tempDrwPath
    If ContainsControlCharacters(tempPartPath) Or ContainsControlCharacters(tempDrwPath) Then
        LogEvent " | FAIL  | Temp path contains a control character; aborting this export to prevent SolidWorks invalid-argument crash"
        GoTo CleanupAndExit
    End If

    Dim tempPartDoc As SldWorks.ModelDoc2
    Dim tempBody As SldWorks.Body2
    Dim exportFaceN(2) As Double
    Dim exportXDir(2) As Double

    CopyVector3 faceNormal, exportFaceN
    CopyVector3 xDir, exportXDir

    If PHYSICALLY_FLATTEN_TEMP_BODY_FOR_DXF Then
        Set tempBody = CopyAndFlattenBodyForDxf(srcBody, xDir, faceNormal, cutListName)
        If tempBody Is Nothing Then
            If FALL_BACK_TO_VIEW_EXPORT_IF_BODY_FLATTEN_FAILS Then
                LogEvent " | WARN  | Physical temp-body flatten failed; falling back to stable view-oriented isolated temp-part export"
                Set tempBody = srcBody.Copy
                If tempBody Is Nothing Then
                    LogEvent " | FAIL  | Body copy returned Nothing after physical-flatten fallback"
                    GoTo CleanupAndExit
                End If
                CopyVector3 faceNormal, exportFaceN
                CopyVector3 xDir, exportXDir
            Else
                LogEvent " | FAIL  | Physical temp-body flatten failed and fallback is disabled"
                GoTo CleanupAndExit
            End If
        Else
            exportXDir(0) = 1#: exportXDir(1) = 0#: exportXDir(2) = 0#
            exportFaceN(0) = 0#: exportFaceN(1) = 0#: exportFaceN(2) = 1#
            LogEvent " | INFO  | Temp body physically flattened. Export axes forced to X=(1,0,0), Z=(0,0,1)"
        End If
    Else
        Set tempBody = srcBody.Copy
        If tempBody Is Nothing Then
            LogEvent " | FAIL  | Body copy returned Nothing"
            GoTo CleanupAndExit
        End If
        LogEvent " | INFO  | Physical body flatten skipped; using stable view-oriented isolated temp-part export"
    End If

    Set tempPartDoc = CreateTempPartFromBody(tempBody, tempPartPath, Not (USE_FAST_MODE And FAST_MODE_SINGLE_TEMP_PART_SAVE))
    If tempPartDoc Is Nothing Then
        LogEvent " | FAIL  | Temp part creation failed"
        GoTo CleanupAndExit
    End If

    If TEMP_PART_EXPORT_USE_CURRENT_VIEW_V15_ROTATION Then
        LogEvent " | INFO  | Orienting temp part using stable current-view logic after physical flatten"
        If Not OrientModelCurrentView(tempPartDoc, exportXDir, exportFaceN) Then
            LogEvent " | FAIL  | Could not orient temp part current view"
            GoTo CleanupAndExit
        End If

        'Keep the named view as a diagnostic/safety artifact, but R5 does not export from it by default.
        On Error Resume Next
        tempPartDoc.DeleteNamedView TEMP_VIEW_NAME
        Err.Clear
        tempPartDoc.NameView TEMP_VIEW_NAME
        Err.Clear
        On Error GoTo EH
    Else
        If Not OrientAndNameTempPartView(tempPartDoc, exportXDir, exportFaceN, TEMP_VIEW_NAME) Then
            LogEvent " | FAIL  | Could not orient/name temp part view"
            GoTo CleanupAndExit
        End If
    End If

    If Not HideAllSketchesInModel(tempPartDoc) Then
        LogEvent " | WARN  | HideAllSketchesInModel returned False after view orientation"
    End If

    LogEvent " | INFO  | Saving temp part after custom orientation"
    If Not TrySaveModelToPath(tempPartDoc, tempPartPath) Then
        LogEvent " | FAIL  | Could not persist temp part file before DXF export"
        GoTo CleanupAndExit
    End If

    If ShouldAttemptFastDirectDxfExport(preserveCornerOrientation) Then

        If TEMP_PART_EXPORT_USE_CURRENT_VIEW_V15_ROTATION Then
            LogEvent " | INFO  | Trying direct temp-part DXF export by *Current view (V15 rotation match)"
            If ExportTempPartToDxf_DirectByCurrentView(tempPartDoc, tempPartPath, finalDxfPath, exportXDir, exportFaceN, preserveCornerOrientation) Then
                Call FinalizeWaterjetDxfAfterExport(finalDxfPath, cutListName, preserveCornerOrientation)
                ExportBodyAsOrientedDxf = True
                GoTo CleanupAndExit
            End If

            If TEMP_PART_NAMED_VIEW_EXPORT_FALLBACK Then
                LogEvent " | WARN  | *Current view export failed; named-view fallback enabled"
                If ExportTempPartToDxf_DirectByAnnotationView(tempPartDoc, tempPartPath, finalDxfPath, TEMP_VIEW_NAME, preserveCornerOrientation) Then
                    Call FinalizeWaterjetDxfAfterExport(finalDxfPath, cutListName, preserveCornerOrientation)
                    ExportBodyAsOrientedDxf = True
                    GoTo CleanupAndExit
                End If
            Else
                LogEvent " | FAIL  | *Current view export failed; named-view fallback is disabled to prevent wrong in-plane rotation"
            End If

        Else
            Set tempPartDoc = ReopenTempPartForDirectExport(tempPartDoc, tempPartPath)
            If tempPartDoc Is Nothing Then
                LogEvent " | WARN  | Could not reopen temp part for direct export; drawing fallback may still be attempted"
            Else
                If Not HideAllSketchesInModel(tempPartDoc) Then
                    LogEvent " | WARN  | HideAllSketchesInModel returned False after temp-part reopen"
                End If

                LogEvent " | INFO  | Trying direct part DXF export by named annotation view"
                If ExportTempPartToDxf_DirectByAnnotationView(tempPartDoc, tempPartPath, finalDxfPath, TEMP_VIEW_NAME, preserveCornerOrientation) Then
                    Call FinalizeWaterjetDxfAfterExport(finalDxfPath, cutListName, preserveCornerOrientation)
                    ExportBodyAsOrientedDxf = True
                    GoTo CleanupAndExit
                End If
            End If
        End If

    Else
        LogEvent " | WARN  | Direct part DXF export disabled by current toggles; checking drawing fallback"
    End If

    If EXPERIMENTAL_DIRECT_FALLBACK_TO_DRAWING Then
        LogEvent " | WARN  | Direct part DXF export failed or was skipped; attempting named-view drawing fallback"

        If tempPartDoc Is Nothing Then
            Dim reopenErrs As Long
            Dim reopenWarns As Long
            reopenErrs = 0
            reopenWarns = 0

            LogEvent " | INFO  | Reopening temp part for drawing fallback: " & tempPartPath
            Set tempPartDoc = swApp.OpenDoc6(tempPartPath, swDocPART, swOpenDocOptions_Silent Or swOpenDocOptions_ReadOnly, "", reopenErrs, reopenWarns)
            LogEvent " | INFO  | Drawing fallback temp reopen errs=" & CStr(reopenErrs) & " warns=" & CStr(reopenWarns)
        End If

        DeleteFileIfExists finalDxfPath
        If ExportTempPartToDxf_ByNamedViewDrawing(tempPartDoc, tempPartPath, tempDrwPath, finalDxfPath, TEMP_VIEW_NAME, exportXDir, exportFaceN, preserveCornerOrientation) Then
            Call FinalizeWaterjetDxfAfterExport(finalDxfPath, cutListName, preserveCornerOrientation)
            ExportBodyAsOrientedDxf = True
            LogEvent " | OK    | Drawing fallback DXF export succeeded => " & finalDxfPath
            GoTo CleanupAndExit
        Else
            LogEvent " | FAIL  | Drawing fallback DXF export failed => " & finalDxfPath
        End If
    Else
        LogEvent " | FAIL  | Direct part DXF export failed and drawing fallback is disabled"
    End If

CleanupAndExit:
    CloseModelDocSafe tempPartDoc
    DeleteFileIfExists tempPartPath
    DeleteFileIfExists tempDrwPath
    DeleteFolderIfEmpty tempRoot
    Exit Function

EH:
    LogEvent " | ERROR | ExportBodyAsOrientedDxf(" & cutListName & "): " & Err.Number & " - " & Err.Description
End Function



'=========================================================================================
' R9 DXF POST-EXPORT ORIENTATION NORMALIZATION
'=========================================================================================
' SolidWorks current-view DXF export has proven stable on isolated temp parts, but field
' output showed that it can still ignore / distort arbitrary in-plane roll. This section
' makes the final DXF deterministic for nesting by correcting the actual exported 2D
' coordinates after SolidWorks writes the file.
'
' The macro does NOT touch the source model and does NOT re-enable Body.ApplyTransform.
' It only edits the generated DXF text file.
'=========================================================================================

Private Sub FinalizeWaterjetDxfAfterExport(ByVal dxfPath As String, _
                                           ByVal contextLabel As String, _
                                           ByVal preserveCornerOrientation As Boolean)
    On Error GoTo EH

    If Not POSTPROCESS_DXF_ORIENTATION_TO_HORIZONTAL Then
        LogEvent " | INFO  | DXF post-process orientation normalization disabled"
        Exit Sub
    End If

    If Len(Trim$(dxfPath)) = 0 Then
        LogEvent " | WARN  | DXF post-process skipped: output path is blank"
        Exit Sub
    End If

    If Not FileExists(dxfPath) Then
        LogEvent " | WARN  | DXF post-process skipped: file does not exist => " & dxfPath
        Exit Sub
    End If

    LogEvent " | CHECK | R10 DXF post-process orientation start | context=" & contextLabel & _
             " | preserveCornerOrientation=" & CStr(preserveCornerOrientation)

    If NormalizeDxfForHorizontalNesting(dxfPath, contextLabel) Then
        LogEvent " | OK    | R10 DXF post-process orientation completed => " & dxfPath
    Else
        LogEvent " | WARN  | R10 DXF post-process orientation could not normalize this file. Keeping SolidWorks DXF as exported => " & dxfPath
    End If

    Exit Sub

EH:
    LogEvent " | WARN  | FinalizeWaterjetDxfAfterExport(" & contextLabel & "): " & Err.Number & " - " & Err.Description
End Sub
Private Function NormalizeDxfForHorizontalNesting(ByVal dxfPath As String, _
                                                  ByVal contextLabel As String) As Boolean
    On Error GoTo EH

    NormalizeDxfForHorizontalNesting = False

    Dim lines() As String
    Dim lineCount As Long

    If Not ReadTextFileLinesANSI(dxfPath, lines, lineCount) Then
        LogEvent " | WARN  | DXF normalize: could not read file => " & dxfPath
        Exit Function
    End If

    If lineCount < 4 Then
        LogEvent " | WARN  | DXF normalize: file has too few lines => " & dxfPath
        Exit Function
    End If

    Dim entStartIndex As Long
    Dim entEndIndex As Long

    If Not FindDxfEntitiesRange(lines, lineCount, entStartIndex, entEndIndex) Then
        LogEvent " | WARN  | DXF normalize: ENTITIES section not found. File left unchanged | context=" & contextLabel
        Exit Function
    End If

    LogEvent " | INFO  | DXF normalize ENTITIES range | startLineIndex=" & CStr(entStartIndex) & _
             " | endLineIndex=" & CStr(entEndIndex)

    Dim rotationRad As Double
    Dim selectedLen As Double
    Dim secondaryLen As Double
    Dim segmentCount As Long
    Dim selectionMode As String
    Dim usedRightAnglePair As Boolean

    If Not FindProductionDxfNestingRotation(lines, lineCount, entStartIndex, entEndIndex, _
                                            rotationRad, selectedLen, secondaryLen, segmentCount, _
                                            selectionMode, usedRightAnglePair) Then
        LogEvent " | WARN  | DXF normalize: no usable linear segments found | context=" & contextLabel
        Exit Function
    End If

    LogEvent " | INFO  | DXF normalize selected orientation | context=" & contextLabel & _
             " | mode=" & selectionMode & _
             " | segments=" & CStr(segmentCount) & _
             " | primaryLen=" & FormatDxfLogNumber(selectedLen) & _
             " | secondaryLen=" & FormatDxfLogNumber(secondaryLen) & _
             " | rotationDeg=" & FormatDxfLogNumber(RadToDeg(rotationRad)) & _
             " | rightAnglePair=" & CStr(usedRightAnglePair)

    Dim minX As Double, minY As Double, maxX As Double, maxY As Double
    Dim pointCount As Long

    If Not GetRotatedDxfPointBounds(lines, lineCount, entStartIndex, entEndIndex, rotationRad, minX, minY, maxX, maxY, pointCount) Then
        LogEvent " | WARN  | DXF normalize: could not calculate rotated bounds | context=" & contextLabel
        Exit Function
    End If

    LogEvent " | INFO  | DXF normalize bounds after production rotation | W=" & FormatDxfLogNumber(maxX - minX) & _
             " | H=" & FormatDxfLogNumber(maxY - minY) & _
             " | points=" & CStr(pointCount)

    If DXF_POSTPROCESS_FORCE_WIDE_ENVELOPE Then
        If (Not DXF_POSTPROCESS_FORCE_WIDE_ONLY_FOR_FALLBACK) Or (Not usedRightAnglePair) Then
            If (maxY - minY) > (maxX - minX) + EPS Then
                rotationRad = rotationRad + (PI_VAL / 2#)

                If Not GetRotatedDxfPointBounds(lines, lineCount, entStartIndex, entEndIndex, rotationRad, minX, minY, maxX, maxY, pointCount) Then
                    LogEvent " | WARN  | DXF normalize: could not calculate bounds after secondary 90-degree correction"
                    Exit Function
                End If

                LogEvent " | INFO  | DXF normalize applied secondary +90 deg correction for fallback wide nesting envelope"
                LogEvent " | INFO  | DXF normalize bounds after secondary correction | W=" & FormatDxfLogNumber(maxX - minX) & _
                         " | H=" & FormatDxfLogNumber(maxY - minY)
            End If
        Else
            LogEvent " | INFO  | DXF normalize skipped automatic wide-envelope correction because right-angle bottom-leg orientation was selected"
        End If
    End If

    Dim offsetX As Double
    Dim offsetY As Double
    offsetX = 0#
    offsetY = 0#

    If DXF_POSTPROCESS_TRANSLATE_TO_POSITIVE_XY Then
        offsetX = -minX
        offsetY = -minY
        LogEvent " | INFO  | DXF normalize translate to positive XY | offsetX=" & FormatDxfLogNumber(offsetX) & _
                 " | offsetY=" & FormatDxfLogNumber(offsetY)
    End If

    If DXF_POSTPROCESS_KEEP_BACKUP_FILE Then
        CopyFileIfExists dxfPath, dxfPath & ".pre_R10_orientation_backup"
    End If

    If Not ApplyDxf2DRotationToLines(lines, lineCount, entStartIndex, entEndIndex, rotationRad, offsetX, offsetY) Then
        LogEvent " | WARN  | DXF normalize: coordinate rewrite failed | context=" & contextLabel
        Exit Function
    End If

    If Not WriteTextFileLinesANSI(dxfPath, lines, lineCount) Then
        LogEvent " | WARN  | DXF normalize: failed to write normalized DXF => " & dxfPath
        Exit Function
    End If

    NormalizeDxfForHorizontalNesting = True
    Exit Function

EH:
    LogEvent " | WARN  | NormalizeDxfForHorizontalNesting(" & contextLabel & "): " & Err.Number & " - " & Err.Description
End Function

Private Function ReadTextFileLinesANSI(ByVal filePath As String, _
                                       ByRef lines() As String, _
                                       ByRef lineCount As Long) As Boolean
    On Error GoTo EH

    ReadTextFileLinesANSI = False
    lineCount = 0

    If Len(Trim$(filePath)) = 0 Then Exit Function
    If Not FileExists(filePath) Then Exit Function

    Dim ff As Integer
    Dim s As String

    ff = FreeFile
    Open filePath For Input As #ff

    Do Until EOF(ff)
        Line Input #ff, s

        If lineCount = 0 Then
            ReDim lines(0 To 0)
        Else
            ReDim Preserve lines(0 To lineCount)
        End If

        lines(lineCount) = s
        lineCount = lineCount + 1
    Loop

    Close #ff

    ReadTextFileLinesANSI = (lineCount > 0)
    Exit Function

EH:
    On Error Resume Next
    If ff <> 0 Then Close #ff
    LogEvent " | WARN  | ReadTextFileLinesANSI(" & filePath & "): " & Err.Number & " - " & Err.Description
End Function

Private Function WriteTextFileLinesANSI(ByVal filePath As String, _
                                        ByRef lines() As String, _
                                        ByVal lineCount As Long) As Boolean
    On Error GoTo EH

    WriteTextFileLinesANSI = False
    If Len(Trim$(filePath)) = 0 Then Exit Function
    If lineCount <= 0 Then Exit Function

    Dim ff As Integer
    Dim i As Long

    ff = FreeFile
    Open filePath For Output As #ff

    For i = 0 To lineCount - 1
        Print #ff, lines(i)
    Next i

    Close #ff

    WriteTextFileLinesANSI = True
    Exit Function

EH:
    On Error Resume Next
    If ff <> 0 Then Close #ff
    LogEvent " | WARN  | WriteTextFileLinesANSI(" & filePath & "): " & Err.Number & " - " & Err.Description
End Function


Private Function FindProductionDxfNestingRotation(ByRef lines() As String, _
                                                  ByVal lineCount As Long, _
                                                  ByVal entStartIndex As Long, _
                                                  ByVal entEndIndex As Long, _
                                                  ByRef rotationRad As Double, _
                                                  ByRef selectedLen As Double, _
                                                  ByRef secondaryLen As Double, _
                                                  ByRef segmentCount As Long, _
                                                  ByRef selectionMode As String, _
                                                  ByRef usedRightAnglePair As Boolean) As Boolean
    On Error GoTo EH

    FindProductionDxfNestingRotation = False
    rotationRad = 0#
    selectedLen = 0#
    secondaryLen = 0#
    segmentCount = 0
    selectionMode = ""
    usedRightAnglePair = False

    Dim sx0() As Double
    Dim sy0() As Double
    Dim sx1() As Double
    Dim sy1() As Double
    Dim slen() As Double

    If Not CollectDxfLinearSegments(lines, lineCount, entStartIndex, entEndIndex, sx0, sy0, sx1, sy1, slen, segmentCount) Then
        LogEvent " | WARN  | Production DXF rotation: no linear segments collected"
        Exit Function
    End If

    LogEvent " | INFO  | Production DXF rotation: linear segment count = " & CStr(segmentCount)

    If DXF_POSTPROCESS_PREFER_RIGHT_ANGLE_LEG_PAIR Then
        If SelectDxfRightAngleBottomLegRotation(sx0, sy0, sx1, sy1, slen, segmentCount, _
                                                rotationRad, selectedLen, secondaryLen) Then
            selectionMode = "RIGHT_ANGLE_LEG_PAIR_BOTTOM_EDGE"
            usedRightAnglePair = True
            FindProductionDxfNestingRotation = True
            Exit Function
        End If

        LogEvent " | INFO  | Production DXF rotation: no qualifying right-angle leg pair found; falling back to dominant edge"
    End If

    If SelectDxfDominantBottomEdgeRotation(sx0, sy0, sx1, sy1, slen, segmentCount, _
                                           rotationRad, selectedLen, secondaryLen) Then
        selectionMode = "DOMINANT_EDGE_BOTTOM_FALLBACK"
        usedRightAnglePair = False
        FindProductionDxfNestingRotation = True
        Exit Function
    End If

    Exit Function

EH:
    LogEvent " | WARN  | FindProductionDxfNestingRotation: " & Err.Number & " - " & Err.Description
End Function

Private Function CollectDxfLinearSegments(ByRef lines() As String, _
                                          ByVal lineCount As Long, _
                                          ByVal entStartIndex As Long, _
                                          ByVal entEndIndex As Long, _
                                          ByRef sx0() As Double, _
                                          ByRef sy0() As Double, _
                                          ByRef sx1() As Double, _
                                          ByRef sy1() As Double, _
                                          ByRef slen() As Double, _
                                          ByRef segmentCount As Long) As Boolean
    On Error GoTo EH

    CollectDxfLinearSegments = False
    segmentCount = 0

    Dim currentEntity As String
    Dim inOldPolyline As Boolean
    Dim oldPolylineClosed As Boolean

    Dim lineHaveStart As Boolean
    Dim lineHaveEnd As Boolean
    Dim lineX0 As Double, lineY0 As Double
    Dim lineX1 As Double, lineY1 As Double

    Dim polyX() As Double
    Dim polyY() As Double
    Dim polyCount As Long
    Dim polyClosed As Boolean

    Dim oldPolyX() As Double
    Dim oldPolyY() As Double
    Dim oldPolyCount As Long

    Dim i As Long
    Dim codeNum As Long
    Dim valText As String

    currentEntity = ""
    inOldPolyline = False
    oldPolylineClosed = False
    polyCount = 0
    oldPolyCount = 0

    For i = entStartIndex To entEndIndex Step 2
        codeNum = DxfGroupCodeToLong(lines(i))
        valText = Trim$(lines(i + 1))

        If codeNum = 0 Then
            AddPendingDxfEntitySegments currentEntity, _
                                        lineHaveStart, lineHaveEnd, lineX0, lineY0, lineX1, lineY1, _
                                        polyX, polyY, polyCount, polyClosed, _
                                        sx0, sy0, sx1, sy1, slen, segmentCount

            currentEntity = UCase$(valText)

            lineHaveStart = False
            lineHaveEnd = False
            polyCount = 0
            polyClosed = False

            If currentEntity = "POLYLINE" Then
                inOldPolyline = True
                oldPolylineClosed = False
                oldPolyCount = 0
            ElseIf currentEntity = "SEQEND" Then
                If inOldPolyline Then
                    AddDxfPolylineSegmentsToArrays oldPolyX, oldPolyY, oldPolyCount, oldPolylineClosed, _
                                                   sx0, sy0, sx1, sy1, slen, segmentCount
                    inOldPolyline = False
                    oldPolylineClosed = False
                    oldPolyCount = 0
                End If
            End If

        Else
            Select Case currentEntity
                Case "LINE"
                    If codeNum = 10 Then
                        If TryReadDxfXYAt(lines, lineCount, i, 10, lineX0, lineY0) Then lineHaveStart = True
                    ElseIf codeNum = 11 Then
                        If TryReadDxfXYAt(lines, lineCount, i, 11, lineX1, lineY1) Then lineHaveEnd = True
                    End If

                Case "LWPOLYLINE"
                    If codeNum = 10 Then
                        Dim px As Double, py As Double
                        If TryReadDxfXYAt(lines, lineCount, i, 10, px, py) Then
                            AddDxf2DPoint polyX, polyY, polyCount, px, py
                        End If
                    ElseIf codeNum = 70 Then
                        polyClosed = ((CLng(Val(valText)) And 1) <> 0)
                    End If

                Case "POLYLINE"
                    If codeNum = 70 Then
                        oldPolylineClosed = ((CLng(Val(valText)) And 1) <> 0)
                    End If

                Case "VERTEX"
                    If inOldPolyline Then
                        If codeNum = 10 Then
                            Dim vx As Double, vy As Double
                            If TryReadDxfXYAt(lines, lineCount, i, 10, vx, vy) Then
                                AddDxf2DPoint oldPolyX, oldPolyY, oldPolyCount, vx, vy
                            End If
                        End If
                    End If
            End Select
        End If
    Next i

    AddPendingDxfEntitySegments currentEntity, _
                                lineHaveStart, lineHaveEnd, lineX0, lineY0, lineX1, lineY1, _
                                polyX, polyY, polyCount, polyClosed, _
                                sx0, sy0, sx1, sy1, slen, segmentCount

    If inOldPolyline Then
        AddDxfPolylineSegmentsToArrays oldPolyX, oldPolyY, oldPolyCount, oldPolylineClosed, _
                                       sx0, sy0, sx1, sy1, slen, segmentCount
    End If

    CollectDxfLinearSegments = (segmentCount > 0)
    Exit Function

EH:
    LogEvent " | WARN  | CollectDxfLinearSegments: " & Err.Number & " - " & Err.Description
End Function

Private Sub AddPendingDxfEntitySegments(ByVal entityName As String, _
                                        ByVal lineHaveStart As Boolean, _
                                        ByVal lineHaveEnd As Boolean, _
                                        ByVal lineX0 As Double, _
                                        ByVal lineY0 As Double, _
                                        ByVal lineX1 As Double, _
                                        ByVal lineY1 As Double, _
                                        ByRef polyX() As Double, _
                                        ByRef polyY() As Double, _
                                        ByVal polyCount As Long, _
                                        ByVal polyClosed As Boolean, _
                                        ByRef sx0() As Double, _
                                        ByRef sy0() As Double, _
                                        ByRef sx1() As Double, _
                                        ByRef sy1() As Double, _
                                        ByRef slen() As Double, _
                                        ByRef segmentCount As Long)
    On Error GoTo EH

    Select Case UCase$(entityName)
        Case "LINE"
            If lineHaveStart And lineHaveEnd Then
                AddDxfLinearSegmentToArrays lineX0, lineY0, lineX1, lineY1, sx0, sy0, sx1, sy1, slen, segmentCount
            End If

        Case "LWPOLYLINE"
            AddDxfPolylineSegmentsToArrays polyX, polyY, polyCount, polyClosed, sx0, sy0, sx1, sy1, slen, segmentCount
    End Select

    Exit Sub

EH:
    LogEvent " | WARN  | AddPendingDxfEntitySegments(" & entityName & "): " & Err.Number & " - " & Err.Description
End Sub

Private Sub AddDxfPolylineSegmentsToArrays(ByRef px() As Double, _
                                           ByRef py() As Double, _
                                           ByVal ptCount As Long, _
                                           ByVal isClosed As Boolean, _
                                           ByRef sx0() As Double, _
                                           ByRef sy0() As Double, _
                                           ByRef sx1() As Double, _
                                           ByRef sy1() As Double, _
                                           ByRef slen() As Double, _
                                           ByRef segmentCount As Long)
    On Error GoTo EH

    If ptCount < 2 Then Exit Sub

    Dim i As Long
    For i = 0 To ptCount - 2
        AddDxfLinearSegmentToArrays px(i), py(i), px(i + 1), py(i + 1), sx0, sy0, sx1, sy1, slen, segmentCount
    Next i

    If isClosed And ptCount > 2 Then
        AddDxfLinearSegmentToArrays px(ptCount - 1), py(ptCount - 1), px(0), py(0), sx0, sy0, sx1, sy1, slen, segmentCount
    End If

    Exit Sub

EH:
    LogEvent " | WARN  | AddDxfPolylineSegmentsToArrays: " & Err.Number & " - " & Err.Description
End Sub

Private Sub AddDxfLinearSegmentToArrays(ByVal x0 As Double, _
                                        ByVal y0 As Double, _
                                        ByVal x1 As Double, _
                                        ByVal y1 As Double, _
                                        ByRef sx0() As Double, _
                                        ByRef sy0() As Double, _
                                        ByRef sx1() As Double, _
                                        ByRef sy1() As Double, _
                                        ByRef slen() As Double, _
                                        ByRef segmentCount As Long)
    On Error GoTo EH

    Dim dx As Double
    Dim dy As Double
    Dim L As Double

    dx = x1 - x0
    dy = y1 - y0
    L = Sqr(dx * dx + dy * dy)

    If L < DXF_POSTPROCESS_MIN_SEGMENT_LENGTH Then Exit Sub

    If segmentCount = 0 Then
        ReDim sx0(0 To 0)
        ReDim sy0(0 To 0)
        ReDim sx1(0 To 0)
        ReDim sy1(0 To 0)
        ReDim slen(0 To 0)
    Else
        ReDim Preserve sx0(0 To segmentCount)
        ReDim Preserve sy0(0 To segmentCount)
        ReDim Preserve sx1(0 To segmentCount)
        ReDim Preserve sy1(0 To segmentCount)
        ReDim Preserve slen(0 To segmentCount)
    End If

    sx0(segmentCount) = x0
    sy0(segmentCount) = y0
    sx1(segmentCount) = x1
    sy1(segmentCount) = y1
    slen(segmentCount) = L

    segmentCount = segmentCount + 1
    Exit Sub

EH:
    LogEvent " | WARN  | AddDxfLinearSegmentToArrays: " & Err.Number & " - " & Err.Description
End Sub

Private Function SelectDxfRightAngleBottomLegRotation(ByRef sx0() As Double, _
                                                      ByRef sy0() As Double, _
                                                      ByRef sx1() As Double, _
                                                      ByRef sy1() As Double, _
                                                      ByRef slen() As Double, _
                                                      ByVal segmentCount As Long, _
                                                      ByRef bestRotationRad As Double, _
                                                      ByRef bestPrimaryLen As Double, _
                                                      ByRef bestSecondaryLen As Double) As Boolean
    On Error GoTo EH

    SelectDxfRightAngleBottomLegRotation = False

    Dim bestBottomPenalty As Double
    Dim bestArea As Double
    bestBottomPenalty = 1E+30
    bestPrimaryLen = -1#
    bestSecondaryLen = -1#
    bestArea = -1#

    Dim i As Long
    Dim j As Long

    For i = 0 To segmentCount - 2
        For j = i + 1 To segmentCount - 1
            Dim cornerX As Double, cornerY As Double
            Dim iFarX As Double, iFarY As Double
            Dim jFarX As Double, jFarY As Double

            If TryGetSharedDxfSegmentCorner(sx0(i), sy0(i), sx1(i), sy1(i), _
                                            sx0(j), sy0(j), sx1(j), sy1(j), _
                                            cornerX, cornerY, iFarX, iFarY, jFarX, jFarY) Then

                Dim ix As Double, iy As Double
                Dim jx As Double, jy As Double
                Dim iLen As Double, jLen As Double

                ix = iFarX - cornerX
                iy = iFarY - cornerY
                jx = jFarX - cornerX
                jy = jFarY - cornerY

                iLen = Sqr(ix * ix + iy * iy)
                jLen = Sqr(jx * jx + jy * jy)

                If iLen >= DXF_POSTPROCESS_MIN_SEGMENT_LENGTH And jLen >= DXF_POSTPROCESS_MIN_SEGMENT_LENGTH Then
                    ix = ix / iLen
                    iy = iy / iLen
                    jx = jx / jLen
                    jy = jy / jLen

                    Dim dotAbs As Double
                    dotAbs = Abs((ix * jx) + (iy * jy))

                    If dotAbs <= DXF_POSTPROCESS_PERP_DOT_TOL Then
                        Dim xVecX As Double, xVecY As Double
                        Dim yVecX As Double, yVecY As Double
                        Dim primaryLen As Double
                        Dim secondaryLen As Double

                        If DXF_POSTPROCESS_PREFER_LONGER_RIGHT_ANGLE_LEG_HORIZONTAL Then
                            If iLen >= jLen Then
                                xVecX = ix: xVecY = iy
                                yVecX = jx: yVecY = jy
                                primaryLen = iLen
                                secondaryLen = jLen
                            Else
                                xVecX = jx: xVecY = jy
                                yVecX = ix: yVecY = iy
                                primaryLen = jLen
                                secondaryLen = iLen
                            End If
                        Else
                            xVecX = ix: xVecY = iy
                            yVecX = jx: yVecY = jy
                            primaryLen = iLen
                            secondaryLen = jLen
                        End If

                        Dim rotationRad As Double
                        rotationRad = -Atn2(xVecY, xVecX)

                        Dim c As Double, s As Double
                        Dim yRotX As Double, yRotY As Double
                        c = Cos(rotationRad)
                        s = Sin(rotationRad)
                        RotatePoint2D yVecX, yVecY, c, s, yRotX, yRotY

                        'If the adjacent/opposite leg points downward after rotation,
                        'rotate 180 degrees. The selected edge remains horizontal,
                        'but the right-angle corner becomes the lower corner.
                        If yRotY < -EPS Then
                            rotationRad = rotationRad + PI_VAL
                        End If

                        Dim minX As Double, minY As Double, maxX As Double, maxY As Double
                        Dim pointCount As Long
                        If GetDxfSegmentEndpointBoundsAfterRotation(sx0, sy0, sx1, sy1, segmentCount, rotationRad, minX, minY, maxX, maxY, pointCount) Then
                            Dim edgeRX As Double, edgeRY As Double
                            c = Cos(rotationRad)
                            s = Sin(rotationRad)
                            RotatePoint2D cornerX, cornerY, c, s, edgeRX, edgeRY

                            Dim bottomPenalty As Double
                            bottomPenalty = Abs(edgeRY - minY)

                            Dim area As Double
                            area = primaryLen * secondaryLen

                            If IsDxfRightAngleCandidateBetter(bottomPenalty, primaryLen, secondaryLen, area, _
                                                              bestBottomPenalty, bestPrimaryLen, bestSecondaryLen, bestArea) Then
                                bestBottomPenalty = bottomPenalty
                                bestPrimaryLen = primaryLen
                                bestSecondaryLen = secondaryLen
                                bestArea = area
                                bestRotationRad = rotationRad
                                SelectDxfRightAngleBottomLegRotation = True

                                LogEvent " | INFO  | DXF right-angle candidate accepted | pair=" & CStr(i) & "/" & CStr(j) & _
                                         " | primary=" & FormatDxfLogNumber(primaryLen) & _
                                         " | secondary=" & FormatDxfLogNumber(secondaryLen) & _
                                         " | bottomPenalty=" & FormatDxfLogNumber(bottomPenalty) & _
                                         " | rotationDeg=" & FormatDxfLogNumber(RadToDeg(rotationRad))
                            End If
                        End If
                    End If
                End If
            End If
        Next j
    Next i

    If SelectDxfRightAngleBottomLegRotation Then
        LogEvent " | INFO  | DXF right-angle bottom-leg orientation selected | primary=" & FormatDxfLogNumber(bestPrimaryLen) & _
                 " | secondary=" & FormatDxfLogNumber(bestSecondaryLen) & _
                 " | bottomPenalty=" & FormatDxfLogNumber(bestBottomPenalty)
    End If

    Exit Function

EH:
    LogEvent " | WARN  | SelectDxfRightAngleBottomLegRotation: " & Err.Number & " - " & Err.Description
End Function

Private Function IsDxfRightAngleCandidateBetter(ByVal candBottomPenalty As Double, _
                                                ByVal candPrimaryLen As Double, _
                                                ByVal candSecondaryLen As Double, _
                                                ByVal candArea As Double, _
                                                ByVal bestBottomPenalty As Double, _
                                                ByVal bestPrimaryLen As Double, _
                                                ByVal bestSecondaryLen As Double, _
                                                ByVal bestArea As Double) As Boolean
    IsDxfRightAngleCandidateBetter = False

    'First priority: selected leg should be on the bottom, not on the top.
    If candBottomPenalty < bestBottomPenalty - DXF_POSTPROCESS_BOTTOM_EDGE_TOL Then
        IsDxfRightAngleCandidateBetter = True
        Exit Function
    End If

    If Abs(candBottomPenalty - bestBottomPenalty) <= DXF_POSTPROCESS_BOTTOM_EDGE_TOL Then
        'Then prefer a stronger real corner: larger shorter leg first, then area, then primary length.
        If candSecondaryLen > bestSecondaryLen + EPS Then
            IsDxfRightAngleCandidateBetter = True
            Exit Function
        End If

        If Abs(candSecondaryLen - bestSecondaryLen) <= EPS Then
            If candArea > bestArea + EPS Then
                IsDxfRightAngleCandidateBetter = True
                Exit Function
            End If

            If Abs(candArea - bestArea) <= EPS Then
                If candPrimaryLen > bestPrimaryLen + EPS Then
                    IsDxfRightAngleCandidateBetter = True
                    Exit Function
                End If
            End If
        End If
    End If
End Function

Private Function SelectDxfDominantBottomEdgeRotation(ByRef sx0() As Double, _
                                                     ByRef sy0() As Double, _
                                                     ByRef sx1() As Double, _
                                                     ByRef sy1() As Double, _
                                                     ByRef slen() As Double, _
                                                     ByVal segmentCount As Long, _
                                                     ByRef bestRotationRad As Double, _
                                                     ByRef bestLen As Double, _
                                                     ByRef secondaryLen As Double) As Boolean
    On Error GoTo EH

    SelectDxfDominantBottomEdgeRotation = False
    bestLen = -1#
    secondaryLen = 0#

    Dim i As Long
    Dim bestIndex As Long
    bestIndex = -1

    For i = 0 To segmentCount - 1
        If slen(i) > bestLen + EPS Then
            bestLen = slen(i)
            bestIndex = i
        ElseIf Abs(slen(i) - bestLen) <= EPS Then
            Dim candAngle As Double
            Dim bestAngle As Double
            candAngle = NormalizeAngleToHalfPi(Atn2(sy1(i) - sy0(i), sx1(i) - sx0(i)))
            bestAngle = NormalizeAngleToHalfPi(Atn2(sy1(bestIndex) - sy0(bestIndex), sx1(bestIndex) - sx0(bestIndex)))
            If Abs(candAngle) < Abs(bestAngle) - EPS Then bestIndex = i
        End If
    Next i

    If bestIndex < 0 Then Exit Function

    Dim angleRad As Double
    angleRad = Atn2(sy1(bestIndex) - sy0(bestIndex), sx1(bestIndex) - sx0(bestIndex))
    bestRotationRad = -NormalizeAngleToHalfPi(angleRad)

    Dim minX As Double, minY As Double, maxX As Double, maxY As Double
    Dim pointCount As Long

    If GetDxfSegmentEndpointBoundsAfterRotation(sx0, sy0, sx1, sy1, segmentCount, bestRotationRad, minX, minY, maxX, maxY, pointCount) Then
        Dim c As Double, s As Double
        Dim r0x As Double, r0y As Double
        Dim r1x As Double, r1y As Double
        c = Cos(bestRotationRad)
        s = Sin(bestRotationRad)

        RotatePoint2D sx0(bestIndex), sy0(bestIndex), c, s, r0x, r0y
        RotatePoint2D sx1(bestIndex), sy1(bestIndex), c, s, r1x, r1y

        Dim edgeY As Double
        edgeY = (r0y + r1y) / 2#

        'If the selected dominant edge is closer to the top than the bottom,
        'rotate 180 degrees so the same edge becomes the bottom nesting edge.
        If Abs(edgeY - maxY) < Abs(edgeY - minY) Then
            bestRotationRad = bestRotationRad + PI_VAL
            LogEvent " | INFO  | DXF dominant fallback rotated 180 degrees to place longest edge on bottom"
        End If
    End If

    SelectDxfDominantBottomEdgeRotation = True
    Exit Function

EH:
    LogEvent " | WARN  | SelectDxfDominantBottomEdgeRotation: " & Err.Number & " - " & Err.Description
End Function

Private Function TryGetSharedDxfSegmentCorner(ByVal a0x As Double, _
                                              ByVal a0y As Double, _
                                              ByVal a1x As Double, _
                                              ByVal a1y As Double, _
                                              ByVal b0x As Double, _
                                              ByVal b0y As Double, _
                                              ByVal b1x As Double, _
                                              ByVal b1y As Double, _
                                              ByRef cornerX As Double, _
                                              ByRef cornerY As Double, _
                                              ByRef aFarX As Double, _
                                              ByRef aFarY As Double, _
                                              ByRef bFarX As Double, _
                                              ByRef bFarY As Double) As Boolean
    TryGetSharedDxfSegmentCorner = False

    If DxfPointsCoincident2(a0x, a0y, b0x, b0y) Then
        cornerX = a0x: cornerY = a0y
        aFarX = a1x: aFarY = a1y
        bFarX = b1x: bFarY = b1y
        TryGetSharedDxfSegmentCorner = True
        Exit Function
    End If

    If DxfPointsCoincident2(a0x, a0y, b1x, b1y) Then
        cornerX = a0x: cornerY = a0y
        aFarX = a1x: aFarY = a1y
        bFarX = b0x: bFarY = b0y
        TryGetSharedDxfSegmentCorner = True
        Exit Function
    End If

    If DxfPointsCoincident2(a1x, a1y, b0x, b0y) Then
        cornerX = a1x: cornerY = a1y
        aFarX = a0x: aFarY = a0y
        bFarX = b1x: bFarY = b1y
        TryGetSharedDxfSegmentCorner = True
        Exit Function
    End If

    If DxfPointsCoincident2(a1x, a1y, b1x, b1y) Then
        cornerX = a1x: cornerY = a1y
        aFarX = a0x: aFarY = a0y
        bFarX = b0x: bFarY = b0y
        TryGetSharedDxfSegmentCorner = True
        Exit Function
    End If
End Function

Private Function DxfPointsCoincident2(ByVal x1 As Double, _
                                      ByVal y1 As Double, _
                                      ByVal x2 As Double, _
                                      ByVal y2 As Double) As Boolean
    DxfPointsCoincident2 = (Sqr((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) <= DXF_POSTPROCESS_POINT_TOL)
End Function

Private Function GetDxfSegmentEndpointBoundsAfterRotation(ByRef sx0() As Double, _
                                                          ByRef sy0() As Double, _
                                                          ByRef sx1() As Double, _
                                                          ByRef sy1() As Double, _
                                                          ByVal segmentCount As Long, _
                                                          ByVal rotationRad As Double, _
                                                          ByRef minX As Double, _
                                                          ByRef minY As Double, _
                                                          ByRef maxX As Double, _
                                                          ByRef maxY As Double, _
                                                          ByRef pointCount As Long) As Boolean
    On Error GoTo EH

    GetDxfSegmentEndpointBoundsAfterRotation = False
    pointCount = 0

    Dim c As Double, s As Double
    c = Cos(rotationRad)
    s = Sin(rotationRad)

    Dim i As Long
    Dim rx As Double, ry As Double

    For i = 0 To segmentCount - 1
        RotatePoint2D sx0(i), sy0(i), c, s, rx, ry
        ExpandDxfBounds rx, ry, minX, minY, maxX, maxY, pointCount

        RotatePoint2D sx1(i), sy1(i), c, s, rx, ry
        ExpandDxfBounds rx, ry, minX, minY, maxX, maxY, pointCount
    Next i

    GetDxfSegmentEndpointBoundsAfterRotation = (pointCount > 0)
    Exit Function

EH:
    LogEvent " | WARN  | GetDxfSegmentEndpointBoundsAfterRotation: " & Err.Number & " - " & Err.Description
End Function

Private Sub ExpandDxfBounds(ByVal x As Double, _
                            ByVal y As Double, _
                            ByRef minX As Double, _
                            ByRef minY As Double, _
                            ByRef maxX As Double, _
                            ByRef maxY As Double, _
                            ByRef pointCount As Long)
    If pointCount = 0 Then
        minX = x: maxX = x
        minY = y: maxY = y
    Else
        If x < minX Then minX = x
        If x > maxX Then maxX = x
        If y < minY Then minY = y
        If y > maxY Then maxY = y
    End If

    pointCount = pointCount + 1
End Sub



Private Function FindDxfEntitiesRange(ByRef lines() As String, _
                                      ByVal lineCount As Long, _
                                      ByRef entStartIndex As Long, _
                                      ByRef entEndIndex As Long) As Boolean
    On Error GoTo EH

    FindDxfEntitiesRange = False
    entStartIndex = 0
    entEndIndex = 0

    If lineCount < 6 Then Exit Function

    Dim i As Long
    Dim codeNum As Long
    Dim valueText As String
    Dim pendingSection As Boolean
    Dim insideEntities As Boolean

    pendingSection = False
    insideEntities = False

    For i = 0 To lineCount - 2 Step 2
        codeNum = DxfGroupCodeToLong(lines(i))
        valueText = UCase$(Trim$(lines(i + 1)))

        If pendingSection And codeNum = 2 Then
            If valueText = "ENTITIES" Then
                insideEntities = True
                entStartIndex = i + 2
            End If
            pendingSection = False

        ElseIf codeNum = 0 And valueText = "SECTION" Then
            pendingSection = True

        ElseIf insideEntities And codeNum = 0 And valueText = "ENDSEC" Then
            entEndIndex = i - 2
            If entEndIndex >= entStartIndex Then
                FindDxfEntitiesRange = True
            End If
            Exit Function
        End If
    Next i

    If insideEntities Then
        entEndIndex = lineCount - 2
        FindDxfEntitiesRange = (entEndIndex >= entStartIndex)
    End If

    Exit Function

EH:
    LogEvent " | WARN  | FindDxfEntitiesRange: " & Err.Number & " - " & Err.Description
End Function


Private Function FindDominantDxfLinearAngle(ByRef lines() As String, _
                                            ByVal lineCount As Long, _
                                            ByVal entStartIndex As Long, _
                                            ByVal entEndIndex As Long, _
                                            ByRef bestAngleRad As Double, _
                                            ByRef bestLen As Double, _
                                            ByRef segmentCount As Long) As Boolean
    On Error GoTo EH

    FindDominantDxfLinearAngle = False
    bestAngleRad = 0#
    bestLen = -1#
    segmentCount = 0

    Dim currentEntity As String
    Dim inOldPolyline As Boolean
    Dim oldPolylineClosed As Boolean

    Dim lineHaveStart As Boolean
    Dim lineHaveEnd As Boolean
    Dim lineX0 As Double, lineY0 As Double
    Dim lineX1 As Double, lineY1 As Double

    Dim polyX() As Double
    Dim polyY() As Double
    Dim polyCount As Long
    Dim polyClosed As Boolean

    Dim oldPolyX() As Double
    Dim oldPolyY() As Double
    Dim oldPolyCount As Long

    Dim i As Long
    Dim codeNum As Long
    Dim valText As String

    currentEntity = ""
    inOldPolyline = False
    oldPolylineClosed = False
    polyCount = 0
    oldPolyCount = 0

    For i = entStartIndex To entEndIndex Step 2
        codeNum = DxfGroupCodeToLong(lines(i))
        valText = Trim$(lines(i + 1))

        If codeNum = 0 Then
            FinalizeDxfSegmentEntity currentEntity, _
                                     lineHaveStart, lineHaveEnd, lineX0, lineY0, lineX1, lineY1, _
                                     polyX, polyY, polyCount, polyClosed, _
                                     bestAngleRad, bestLen, segmentCount

            currentEntity = UCase$(valText)

            lineHaveStart = False
            lineHaveEnd = False
            polyCount = 0
            polyClosed = False

            If currentEntity = "POLYLINE" Then
                inOldPolyline = True
                oldPolylineClosed = False
                oldPolyCount = 0
            ElseIf currentEntity = "SEQEND" Then
                If inOldPolyline Then
                    AddDxfPolylineSegments oldPolyX, oldPolyY, oldPolyCount, oldPolylineClosed, bestAngleRad, bestLen, segmentCount
                    inOldPolyline = False
                    oldPolylineClosed = False
                    oldPolyCount = 0
                End If
            End If

        Else
            Select Case currentEntity
                Case "LINE"
                    If codeNum = 10 Then
                        If TryReadDxfXYAt(lines, lineCount, i, 10, lineX0, lineY0) Then lineHaveStart = True
                    ElseIf codeNum = 11 Then
                        If TryReadDxfXYAt(lines, lineCount, i, 11, lineX1, lineY1) Then lineHaveEnd = True
                    End If

                Case "LWPOLYLINE"
                    If codeNum = 10 Then
                        Dim px As Double, py As Double
                        If TryReadDxfXYAt(lines, lineCount, i, 10, px, py) Then
                            AddDxf2DPoint polyX, polyY, polyCount, px, py
                        End If
                    ElseIf codeNum = 70 Then
                        polyClosed = ((CLng(Val(valText)) And 1) <> 0)
                    End If

                Case "POLYLINE"
                    If codeNum = 70 Then
                        oldPolylineClosed = ((CLng(Val(valText)) And 1) <> 0)
                    End If

                Case "VERTEX"
                    If inOldPolyline Then
                        If codeNum = 10 Then
                            Dim vx As Double, vy As Double
                            If TryReadDxfXYAt(lines, lineCount, i, 10, vx, vy) Then
                                AddDxf2DPoint oldPolyX, oldPolyY, oldPolyCount, vx, vy
                            End If
                        End If
                    End If
            End Select
        End If
    Next i

    FinalizeDxfSegmentEntity currentEntity, _
                             lineHaveStart, lineHaveEnd, lineX0, lineY0, lineX1, lineY1, _
                             polyX, polyY, polyCount, polyClosed, _
                             bestAngleRad, bestLen, segmentCount

    If inOldPolyline Then
        AddDxfPolylineSegments oldPolyX, oldPolyY, oldPolyCount, oldPolylineClosed, bestAngleRad, bestLen, segmentCount
    End If

    FindDominantDxfLinearAngle = (segmentCount > 0 And bestLen > 0#)
    Exit Function

EH:
    LogEvent " | WARN  | FindDominantDxfLinearAngle: " & Err.Number & " - " & Err.Description
End Function

Private Sub FinalizeDxfSegmentEntity(ByVal entityName As String, _
                                     ByVal lineHaveStart As Boolean, _
                                     ByVal lineHaveEnd As Boolean, _
                                     ByVal lineX0 As Double, _
                                     ByVal lineY0 As Double, _
                                     ByVal lineX1 As Double, _
                                     ByVal lineY1 As Double, _
                                     ByRef polyX() As Double, _
                                     ByRef polyY() As Double, _
                                     ByVal polyCount As Long, _
                                     ByVal polyClosed As Boolean, _
                                     ByRef bestAngleRad As Double, _
                                     ByRef bestLen As Double, _
                                     ByRef segmentCount As Long)
    On Error GoTo EH

    Select Case UCase$(entityName)
        Case "LINE"
            If lineHaveStart And lineHaveEnd Then
                ConsiderDxfLinearSegment lineX0, lineY0, lineX1, lineY1, bestAngleRad, bestLen, segmentCount
            End If

        Case "LWPOLYLINE"
            AddDxfPolylineSegments polyX, polyY, polyCount, polyClosed, bestAngleRad, bestLen, segmentCount
    End Select

    Exit Sub

EH:
    LogEvent " | WARN  | FinalizeDxfSegmentEntity(" & entityName & "): " & Err.Number & " - " & Err.Description
End Sub

Private Sub AddDxfPolylineSegments(ByRef px() As Double, _
                                   ByRef py() As Double, _
                                   ByVal ptCount As Long, _
                                   ByVal isClosed As Boolean, _
                                   ByRef bestAngleRad As Double, _
                                   ByRef bestLen As Double, _
                                   ByRef segmentCount As Long)
    On Error GoTo EH

    If ptCount < 2 Then Exit Sub

    Dim i As Long
    For i = 0 To ptCount - 2
        ConsiderDxfLinearSegment px(i), py(i), px(i + 1), py(i + 1), bestAngleRad, bestLen, segmentCount
    Next i

    If isClosed And ptCount > 2 Then
        ConsiderDxfLinearSegment px(ptCount - 1), py(ptCount - 1), px(0), py(0), bestAngleRad, bestLen, segmentCount
    End If

    Exit Sub

EH:
    LogEvent " | WARN  | AddDxfPolylineSegments: " & Err.Number & " - " & Err.Description
End Sub

Private Sub ConsiderDxfLinearSegment(ByVal x0 As Double, _
                                     ByVal y0 As Double, _
                                     ByVal x1 As Double, _
                                     ByVal y1 As Double, _
                                     ByRef bestAngleRad As Double, _
                                     ByRef bestLen As Double, _
                                     ByRef segmentCount As Long)
    On Error GoTo EH

    Dim dx As Double
    Dim dy As Double
    Dim L As Double
    Dim a As Double

    dx = x1 - x0
    dy = y1 - y0
    L = Sqr(dx * dx + dy * dy)

    If L < DXF_POSTPROCESS_MIN_SEGMENT_LENGTH Then Exit Sub

    a = NormalizeAngleToHalfPi(Atn2(dy, dx))

    segmentCount = segmentCount + 1

    If L > bestLen + EPS Then
        bestLen = L
        bestAngleRad = a
    ElseIf Abs(L - bestLen) <= EPS Then
        'Tie-breaker: prefer the segment requiring less rotation, then stable positive angle.
        If Abs(a) < Abs(bestAngleRad) - EPS Then
            bestAngleRad = a
        ElseIf Abs(Abs(a) - Abs(bestAngleRad)) <= EPS Then
            If a > bestAngleRad Then bestAngleRad = a
        End If
    End If

    Exit Sub

EH:
    LogEvent " | WARN  | ConsiderDxfLinearSegment: " & Err.Number & " - " & Err.Description
End Sub

Private Function NormalizeAngleToHalfPi(ByVal angleRad As Double) As Double
    Do While angleRad <= -PI_VAL / 2#
        angleRad = angleRad + PI_VAL
    Loop

    Do While angleRad > PI_VAL / 2#
        angleRad = angleRad - PI_VAL
    Loop

    NormalizeAngleToHalfPi = angleRad
End Function

Private Function GetRotatedDxfPointBounds(ByRef lines() As String, _
                                          ByVal lineCount As Long, _
                                          ByVal entStartIndex As Long, _
                                          ByVal entEndIndex As Long, _
                                          ByVal rotationRad As Double, _
                                          ByRef minX As Double, _
                                          ByRef minY As Double, _
                                          ByRef maxX As Double, _
                                          ByRef maxY As Double, _
                                          ByRef pointCount As Long) As Boolean
    On Error GoTo EH

    GetRotatedDxfPointBounds = False
    pointCount = 0

    Dim c As Double
    Dim s As Double
    c = Cos(rotationRad)
    s = Sin(rotationRad)

    Dim i As Long
    Dim codeNum As Long
    Dim x As Double, y As Double
    Dim rx As Double, ry As Double
    Dim currentEntity As String

    currentEntity = ""

    For i = entStartIndex To entEndIndex Step 2
        codeNum = DxfGroupCodeToLong(lines(i))

        If codeNum = 0 Then
            currentEntity = UCase$(Trim$(lines(i + 1)))
        ElseIf IsDxfPointXCode(codeNum) Then
            If IsDxfCoordinatePairAllowedForEntity(currentEntity, codeNum) Then
                If TryReadDxfXYAt(lines, lineCount, i, codeNum, x, y) Then
                    RotatePoint2D x, y, c, s, rx, ry

                    If pointCount = 0 Then
                        minX = rx: maxX = rx
                        minY = ry: maxY = ry
                    Else
                        If rx < minX Then minX = rx
                        If rx > maxX Then maxX = rx
                        If ry < minY Then minY = ry
                        If ry > maxY Then maxY = ry
                    End If

                    pointCount = pointCount + 1
                End If
            End If
        End If
    Next i

    GetRotatedDxfPointBounds = (pointCount > 0)
    Exit Function

EH:
    LogEvent " | WARN  | GetRotatedDxfPointBounds: " & Err.Number & " - " & Err.Description
End Function

Private Function ApplyDxf2DRotationToLines(ByRef lines() As String, _
                                           ByVal lineCount As Long, _
                                           ByVal entStartIndex As Long, _
                                           ByVal entEndIndex As Long, _
                                           ByVal rotationRad As Double, _
                                           ByVal offsetX As Double, _
                                           ByVal offsetY As Double) As Boolean
    On Error GoTo EH

    ApplyDxf2DRotationToLines = False

    Dim c As Double
    Dim s As Double
    Dim rotDeg As Double

    c = Cos(rotationRad)
    s = Sin(rotationRad)
    rotDeg = RadToDeg(rotationRad)

    Dim i As Long
    Dim codeNum As Long
    Dim x As Double, y As Double
    Dim rx As Double, ry As Double
    Dim currentEntity As String
    Dim useTranslation As Boolean

    currentEntity = ""

    For i = entStartIndex To entEndIndex Step 2
        codeNum = DxfGroupCodeToLong(lines(i))

        If codeNum = 0 Then
            currentEntity = UCase$(Trim$(lines(i + 1)))

        ElseIf IsDxfPointXCode(codeNum) Then
            If IsDxfCoordinatePairAllowedForEntity(currentEntity, codeNum) Then
                If TryReadDxfXYAt(lines, lineCount, i, codeNum, x, y) Then
                    RotatePoint2D x, y, c, s, rx, ry

                    useTranslation = True
                    If currentEntity = "ELLIPSE" And codeNum = 11 Then
                        'Ellipse 11/21 is the major-axis vector, not a point.
                        useTranslation = False
                    End If

                    If useTranslation Then
                        rx = rx + offsetX
                        ry = ry + offsetY
                    End If

                    lines(i + 1) = FormatDxfDouble(rx)
                    lines(i + 3) = FormatDxfDouble(ry)
                End If
            End If

        ElseIf currentEntity = "ARC" Then
            If codeNum = 50 Or codeNum = 51 Then
                lines(i + 1) = FormatDxfDouble(NormalizeDegrees360(DxfTextToDouble(lines(i + 1)) + rotDeg))
            End If

        ElseIf currentEntity = "TEXT" Or currentEntity = "MTEXT" Or currentEntity = "INSERT" Then
            If codeNum = 50 Then
                lines(i + 1) = FormatDxfDouble(NormalizeDegrees360(DxfTextToDouble(lines(i + 1)) + rotDeg))
            End If
        End If
    Next i

    ApplyDxf2DRotationToLines = True
    Exit Function

EH:
    LogEvent " | WARN  | ApplyDxf2DRotationToLines: " & Err.Number & " - " & Err.Description
End Function

Private Function IsDxfPointXCode(ByVal codeNum As Long) As Boolean
    'Waterjet exports mostly use 10/20, 11/21, etc.
    'Do not include 210/220 extrusion vectors here; changing extrusion vectors can corrupt DXF import.
    IsDxfPointXCode = (codeNum >= 10 And codeNum <= 18)
End Function

Private Function IsDxfCoordinatePairAllowedForEntity(ByVal entityName As String, ByVal xCode As Long) As Boolean
    'Default to allowing common 2D geometry point codes.
    'A small deny-list protects known vector-only pairs.
    IsDxfCoordinatePairAllowedForEntity = True

    Select Case UCase$(entityName)
        Case "ELLIPSE"
            '10/20 center is a point; 11/21 major-axis is a vector.
            If xCode = 11 Then
                IsDxfCoordinatePairAllowedForEntity = True
            End If
    End Select
End Function

Private Function TryReadDxfXYAt(ByRef lines() As String, _
                                ByVal lineCount As Long, _
                                ByVal codeIndex As Long, _
                                ByVal xCode As Long, _
                                ByRef xOut As Double, _
                                ByRef yOut As Double) As Boolean
    On Error GoTo EH

    TryReadDxfXYAt = False

    If codeIndex < 0 Then Exit Function
    If codeIndex + 3 >= lineCount Then Exit Function

    If DxfGroupCodeToLong(lines(codeIndex)) <> xCode Then Exit Function
    If DxfGroupCodeToLong(lines(codeIndex + 2)) <> xCode + 10 Then Exit Function

    xOut = DxfTextToDouble(lines(codeIndex + 1))
    yOut = DxfTextToDouble(lines(codeIndex + 3))

    TryReadDxfXYAt = True
    Exit Function

EH:
    TryReadDxfXYAt = False
End Function

Private Sub AddDxf2DPoint(ByRef px() As Double, _
                          ByRef py() As Double, _
                          ByRef ptCount As Long, _
                          ByVal x As Double, _
                          ByVal y As Double)
    On Error GoTo EH

    If ptCount = 0 Then
        ReDim px(0 To 0)
        ReDim py(0 To 0)
    Else
        ReDim Preserve px(0 To ptCount)
        ReDim Preserve py(0 To ptCount)
    End If

    px(ptCount) = x
    py(ptCount) = y
    ptCount = ptCount + 1
    Exit Sub

EH:
    LogEvent " | WARN  | AddDxf2DPoint: " & Err.Number & " - " & Err.Description
End Sub

Private Sub RotatePoint2D(ByVal x As Double, _
                          ByVal y As Double, _
                          ByVal c As Double, _
                          ByVal s As Double, _
                          ByRef xOut As Double, _
                          ByRef yOut As Double)
    xOut = (x * c) - (y * s)
    yOut = (x * s) + (y * c)
End Sub

Private Function DxfGroupCodeToLong(ByVal codeText As String) As Long
    On Error GoTo EH

    codeText = Trim$(codeText)
    If Len(codeText) = 0 Then
        DxfGroupCodeToLong = -999999
    Else
        DxfGroupCodeToLong = CLng(Val(codeText))
    End If
    Exit Function

EH:
    DxfGroupCodeToLong = -999999
End Function

Private Function DxfTextToDouble(ByVal valueText As String) As Double
    On Error GoTo EH

    valueText = Trim$(valueText)
    valueText = Replace$(valueText, ",", ".")

    If Len(valueText) = 0 Then
        DxfTextToDouble = 0#
    Else
        DxfTextToDouble = Val(valueText)
    End If
    Exit Function

EH:
    DxfTextToDouble = 0#
End Function

Private Function FormatDxfDouble(ByVal value As Double) As String
    On Error GoTo EH

    Dim fmt As String
    Dim s As String

    If DXF_POSTPROCESS_OUTPUT_DECIMALS <= 0 Then
        FormatDxfDouble = Trim$(Str$(value))
        Exit Function
    End If

    fmt = "0." & String$(DXF_POSTPROCESS_OUTPUT_DECIMALS, "0")
    s = Format$(value, fmt)
    s = Replace$(s, ",", ".")
    FormatDxfDouble = s
    Exit Function

EH:
    FormatDxfDouble = Trim$(Str$(value))
End Function

Private Function FormatDxfLogNumber(ByVal value As Double) As String
    On Error Resume Next
    FormatDxfLogNumber = Replace$(Format$(value, "0.000000"), ",", ".")
End Function

Private Function NormalizeDegrees360(ByVal degVal As Double) As Double
    Do While degVal < 0#
        degVal = degVal + 360#
    Loop

    Do While degVal >= 360#
        degVal = degVal - 360#
    Loop

    NormalizeDegrees360 = degVal
End Function

Private Sub CopyFileIfExists(ByVal sourcePath As String, ByVal destPath As String)
    On Error GoTo EH

    If Len(Trim$(sourcePath)) = 0 Then Exit Sub
    If Len(Trim$(destPath)) = 0 Then Exit Sub
    If Not FileExists(sourcePath) Then Exit Sub

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    If fso.FileExists(destPath) Then fso.DeleteFile destPath, True
    fso.CopyFile sourcePath, destPath, True

    LogEvent " | INFO  | DXF post-process backup written => " & destPath
    Exit Sub

EH:
    LogEvent " | WARN  | CopyFileIfExists failed: " & Err.Number & " - " & Err.Description
End Sub


Private Function CopyAndFlattenBodyForDxf(ByVal srcBody As SldWorks.Body2, _
                                          ByRef xDir() As Double, _
                                          ByRef faceNormal() As Double, _
                                          ByVal contextLabel As String) As SldWorks.Body2
    On Error GoTo EH

    Set CopyAndFlattenBodyForDxf = Nothing

    If srcBody Is Nothing Then
        LogEvent " | FAIL  | CopyAndFlattenBodyForDxf: source body is Nothing for " & contextLabel
        Exit Function
    End If

    Dim tempBody As SldWorks.Body2
    Set tempBody = srcBody.Copy

    If tempBody Is Nothing Then
        LogEvent " | FAIL  | CopyAndFlattenBodyForDxf: Body.Copy returned Nothing for " & contextLabel
        Exit Function
    End If

    Dim xf As SldWorks.MathTransform
    Set xf = BuildBodyFlattenTransform(xDir, faceNormal)

    If xf Is Nothing Then
        LogEvent " | FAIL  | CopyAndFlattenBodyForDxf: BuildBodyFlattenTransform returned Nothing for " & contextLabel
        Exit Function
    End If

    Dim ok As Boolean
    ok = False

    On Error Resume Next
    ok = CBool(tempBody.ApplyTransform(xf))
    If Err.Number <> 0 Then
        LogEvent " | FAIL  | CopyAndFlattenBodyForDxf: Body.ApplyTransform failed for " & contextLabel & ": " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        Exit Function
    End If
    On Error GoTo EH

    If Not ok Then
        LogEvent " | FAIL  | CopyAndFlattenBodyForDxf: Body.ApplyTransform returned False for " & contextLabel
        Exit Function
    End If

    LogEvent " | INFO  | Physical body flatten transform applied for " & contextLabel
    Set CopyAndFlattenBodyForDxf = tempBody
    Exit Function

EH:
    LogEvent " | ERROR | CopyAndFlattenBodyForDxf(" & contextLabel & "): " & Err.Number & " - " & Err.Description
End Function

Private Function BuildBodyFlattenTransform(ByRef xAxis() As Double, _
                                           ByRef zAxis() As Double) As SldWorks.MathTransform
    On Error GoTo EH

    Set BuildBodyFlattenTransform = Nothing

    Dim x(2) As Double
    Dim y(2) As Double
    Dim z(2) As Double

    CopyVector3 xAxis, x
    CopyVector3 zAxis, z

    If VecLength(x) <= EPS Or VecLength(z) <= EPS Then
        LogEvent " | FAIL  | BuildBodyFlattenTransform: input axis length was zero"
        Exit Function
    End If

    NormalizeVec x
    NormalizeVec z

    ProjectVectorOntoPlane x, z, x
    If VecLength(x) <= EPS Then
        LogEvent " | WARN  | BuildBodyFlattenTransform: projected X was zero; choosing fallback X"
        ChooseFallbackXAxis z, x
    End If
    NormalizeVec x

    CrossProduct z, x, y
    If VecLength(y) <= EPS Then
        LogEvent " | FAIL  | BuildBodyFlattenTransform: computed Y axis was zero"
        Exit Function
    End If
    NormalizeVec y

    CrossProduct y, z, x
    NormalizeVec x

    ' Body transform maps source model coordinates into nesting/export coordinates:
    '   newX = dot(oldPoint, selectedX)
    '   newY = dot(oldPoint, selectedY)
    '   newZ = dot(oldPoint, selectedNormal)
    ' This physically places the copied body flat on the XY plane with the nesting X axis horizontal.
    Dim data(15) As Double
    Dim i As Long
    For i = 0 To 15
        data(i) = 0#
    Next i

    data(0) = x(0): data(1) = x(1): data(2) = x(2)
    data(3) = y(0): data(4) = y(1): data(5) = y(2)
    data(6) = z(0): data(7) = z(1): data(8) = z(2)

    data(9) = 0#
    data(10) = 0#
    data(11) = 0#
    data(12) = 1#
    data(13) = 0#
    data(14) = 0#
    data(15) = 0#

    LogEvent " | INFO  | BuildBodyFlattenTransform axes mapped to output:"
    LogEvent " | INFO  |   Source X-to-output horizontal = (" & Dbl3ToStr(x) & ")"
    LogEvent " | INFO  |   Source Y-to-output vertical   = (" & Dbl3ToStr(y) & ")"
    LogEvent " | INFO  |   Source Z-to-output normal     = (" & Dbl3ToStr(z) & ")"
    LogEvent " | INFO  |   Matrix mode = ROW_DOT_PRODUCT_WORLD_TO_NESTING"

    Set BuildBodyFlattenTransform = swMathUtil.CreateTransform(data)
    Exit Function

EH:
    LogEvent " | ERROR | BuildBodyFlattenTransform: " & Err.Number & " - " & Err.Description
End Function

Private Sub CopyVector3(ByRef src() As Double, ByRef dst() As Double)
    On Error Resume Next
    dst(0) = src(0)
    dst(1) = src(1)
    dst(2) = src(2)
End Sub

Private Function CreateTempPartFromBody(ByVal body As SldWorks.Body2, ByVal tempPartPath As String, Optional ByVal saveImmediately As Boolean = True) As SldWorks.ModelDoc2
    On Error GoTo EH

    Dim partTemplate As String
    partTemplate = GetPartTemplatePath()
    If Len(partTemplate) = 0 Then
        LogEvent " | FAIL  | No default part template available"
        Exit Function
    End If

    LogEvent " | INFO  | Temp part template = " & partTemplate
    LogEvent " | INFO  | Temp part target   = " & tempPartPath

    Dim tempDoc As SldWorks.ModelDoc2
    Set tempDoc = swApp.NewDocument(partTemplate, 0, 0#, 0#)

    If tempDoc Is Nothing Then
        LogEvent " | FAIL  | New temp part document creation failed"
        Exit Function
    End If

    Dim tempPart As SldWorks.PartDoc
    Set tempPart = tempDoc

    tempDoc.ClearSelection2 True

    Dim newFeat As SldWorks.Feature
    Set newFeat = tempPart.CreateFeatureFromBody3(body, False, swCreateFeatureBodySimplify)

    If newFeat Is Nothing Then
        LogEvent " | FAIL  | CreateFeatureFromBody3 returned Nothing"
        swApp.CloseDoc tempDoc.GetTitle
        Exit Function
    End If

    tempDoc.ForceRebuild3 True

    If Not HideAllSketchesInModel(tempDoc) Then
        LogEvent " | WARN  | HideAllSketchesInModel returned False during temp part creation"
    End If

    If DIRECT_TEMP_PART_FORCE_INCH_UNITS Then
        If ForceModelLinearUnitsToInches(tempDoc) Then
            LogEvent " | INFO  | Temp part units forced to inches for direct DXF export"
        Else
            LogEvent " | WARN  | Temp part units could not be forced to inches"
        End If
    End If

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then
        tempDoc.ViewZoomtofit2
    End If

    If saveImmediately Then
        If Not TrySaveModelToPath(tempDoc, tempPartPath) Then
            LogEvent " | FAIL  | All temp part save attempts failed"
            swApp.CloseDoc tempDoc.GetTitle
            Exit Function
        End If

        LogEvent " | INFO  | Temp part saved = " & tempPartPath
    Else
        LogEvent " | INFO  | Temp part created in memory; initial disk save deferred"
    End If

    Set CreateTempPartFromBody = tempDoc
    Exit Function

EH:
    LogEvent " | ERROR | CreateTempPartFromBody: " & Err.Number & " - " & Err.Description
End Function

Private Function TrySaveModelToPath(ByVal mdl As SldWorks.ModelDoc2, ByVal filePath As String) As Boolean
    On Error GoTo EH

    TrySaveModelToPath = False

    If mdl Is Nothing Then Exit Function
    If Len(filePath) = 0 Then Exit Function

    DeleteFileIfExists filePath

    Dim actErr As Long
    actErr = 0
    On Error Resume Next
    swApp.ActivateDoc3 mdl.GetTitle, False, swDontRebuildActiveDoc, actErr
    Err.Clear
    On Error GoTo EH

    mdl.ForceRebuild3 True
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        mdl.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Save ViewZoomtofit2 skipped for batch stability"
    End If
    DoEvents

    Dim errs As Long, warns As Long
    errs = 0: warns = 0

    LogEvent " | INFO  | Save attempt 1: Extension.SaveAs"
    If mdl.Extension.SaveAs(filePath, swSaveAsCurrentVersion, swSaveAsOptions_Silent, Nothing, errs, warns) Then
        LogEvent " | INFO  | Save attempt 1 returned True. errs=" & errs & " warns=" & warns
        If FileExists(filePath) Then
            TrySaveModelToPath = True
            Exit Function
        End If
        LogEvent " | WARN  | Save attempt 1 returned True but file not found"
    Else
        LogEvent " | WARN  | Save attempt 1 returned False. errs=" & errs & " warns=" & warns
    End If

    errs = 0: warns = 0
    LogEvent " | INFO  | Save attempt 2: Extension.SaveAs with COPY option"
    If mdl.Extension.SaveAs(filePath, swSaveAsCurrentVersion, swSaveAsOptions_Silent Or swSaveAsOptions_Copy, Nothing, errs, warns) Then
        LogEvent " | INFO  | Save attempt 2 returned True. errs=" & errs & " warns=" & warns
        If FileExists(filePath) Then
            TrySaveModelToPath = True
            Exit Function
        End If
        LogEvent " | WARN  | Save attempt 2 returned True but file not found"
    Else
        LogEvent " | WARN  | Save attempt 2 returned False. errs=" & errs & " warns=" & warns
    End If

    errs = 0: warns = 0
    LogEvent " | INFO  | Save attempt 3: Extension.SaveAs after re-activate"
    actErr = 0
    On Error Resume Next
    swApp.ActivateDoc3 mdl.GetTitle, True, swDontRebuildActiveDoc, actErr
    Err.Clear
    On Error GoTo EH

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then mdl.GraphicsRedraw2
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        mdl.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Save retry ViewZoomtofit2 skipped for batch stability"
    End If
    DoEvents

    If mdl.Extension.SaveAs(filePath, swSaveAsCurrentVersion, swSaveAsOptions_Silent, Nothing, errs, warns) Then
        LogEvent " | INFO  | Save attempt 3 returned True. errs=" & errs & " warns=" & warns
        If FileExists(filePath) Then
            TrySaveModelToPath = True
            Exit Function
        End If
        LogEvent " | WARN  | Save attempt 3 returned True but file not found"
    Else
        LogEvent " | WARN  | Save attempt 3 returned False. errs=" & errs & " warns=" & warns
    End If

    Exit Function

EH:
    LogEvent " | ERROR | TrySaveModelToPath: " & Err.Number & " - " & Err.Description
End Function

Private Function OrientAndNameTempPartView(ByVal tempDoc As SldWorks.ModelDoc2, _
                                           ByRef xDir() As Double, _
                                           ByRef faceNormal() As Double, _
                                           ByVal viewName As String) As Boolean
    On Error GoTo EH

    OrientAndNameTempPartView = False

    If tempDoc Is Nothing Then Exit Function

    Dim viewXf As SldWorks.MathTransform
    Set viewXf = BuildViewOrientationTransform(xDir, faceNormal)

    If viewXf Is Nothing Then
        LogEvent " | FAIL  | BuildViewOrientationTransform returned Nothing"
        Exit Function
    End If

    Dim mvObj As Object
    Set mvObj = tempDoc.ActiveView

    If mvObj Is Nothing Then
        LogEvent " | FAIL  | tempDoc.ActiveView returned Nothing"
        Exit Function
    End If

    LogEvent " | INFO  | Setting current model view orientation"
    On Error Resume Next
    CallByName mvObj, "Orientation3", VbSet, viewXf
    If Err.Number <> 0 Then
        LogEvent " | FAIL  | Setting Orientation3 failed: " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        Exit Function
    End If
    On Error GoTo EH

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then tempDoc.GraphicsRedraw2
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        tempDoc.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Temp part ViewZoomtofit2 skipped after orientation for batch stability"
    End If

    On Error Resume Next
    tempDoc.DeleteNamedView viewName
    Err.Clear
    On Error GoTo EH

    LogEvent " | INFO  | Naming current view as [" & viewName & "]"
    tempDoc.NameView viewName
    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then tempDoc.GraphicsRedraw2
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        tempDoc.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Temp part ViewZoomtofit2 skipped after NameView for batch stability"
    End If

    OrientAndNameTempPartView = True
    Exit Function

EH:
    LogEvent " | ERROR | OrientAndNameTempPartView: " & Err.Number & " - " & Err.Description
End Function

Private Function ReopenTempPartForDirectExport(ByRef currentDoc As SldWorks.ModelDoc2, ByVal tempPartPath As String) As SldWorks.ModelDoc2
    On Error GoTo EH

    Set ReopenTempPartForDirectExport = Nothing

    If Len(Trim$(tempPartPath)) = 0 Then Exit Function
    If Not FileExists(tempPartPath) Then
        LogEvent " | FAIL  | ReopenTempPartForDirectExport: temp part file does not exist: " & tempPartPath
        Exit Function
    End If

    LogEvent " | INFO  | Closing in-memory temp part before direct reopen"
    CloseModelDocSafe currentDoc

    Dim errs As Long
    Dim warns As Long
    errs = 0
    warns = 0

    LogEvent " | INFO  | Reopening persisted temp part for direct export: " & tempPartPath
    Set ReopenTempPartForDirectExport = swApp.OpenDoc6(tempPartPath, swDocPART, swOpenDocOptions_Silent Or swOpenDocOptions_ReadOnly, "", errs, warns)

    LogEvent " | INFO  | Reopen temp part result errs=" & errs & " warns=" & warns

    If ReopenTempPartForDirectExport Is Nothing Then
        LogEvent " | FAIL  | ReopenTempPartForDirectExport returned Nothing"
    End If
    Exit Function

EH:
    LogEvent " | ERROR | ReopenTempPartForDirectExport: " & Err.Number & " - " & Err.Description
End Function

Private Function ExportTempPartToDxf_DirectByCurrentView(ByVal tempPartDoc As SldWorks.ModelDoc2, _
                                                        ByVal tempPartPath As String, _
                                                        ByVal finalDxfPath As String, _
                                                        ByRef xDir() As Double, _
                                                        ByRef faceNormal() As Double, _
                                                        ByVal preserveCornerOrientation As Boolean) As Boolean
    On Error GoTo EH

    ExportTempPartToDxf_DirectByCurrentView = False

    If tempPartDoc Is Nothing Then
        LogEvent " | FAIL  | Current-view export: tempPartDoc is Nothing"
        Exit Function
    End If

    If tempPartDoc.GetType <> swDocPART Then
        LogEvent " | FAIL  | Current-view export requires PART doc, got " & DocTypeName(tempPartDoc.GetType)
        Exit Function
    End If

    If Len(Trim$(tempPartPath)) = 0 Then
        LogEvent " | FAIL  | Current-view export requires saved temp part path"
        Exit Function
    End If

    If Not FileExists(tempPartPath) Then
        LogEvent " | FAIL  | Current-view export temp part file does not exist: " & tempPartPath
        Exit Function
    End If

    Dim swTempPart As SldWorks.PartDoc
    Set swTempPart = tempPartDoc

    Dim alignmentData(0 To 11) As Double
    Dim varAlignment As Variant
    BuildIdentityDwgAlignment alignmentData
    varAlignment = alignmentData

    LogEvent " | INFO  | Direct temp-part current-view export start"
    LogEvent " | INFO  |   tempPartPath = " & tempPartPath
    LogEvent " | INFO  |   finalDxfPath = " & finalDxfPath
    LogEvent " | INFO  |   mode         = *Current view on isolated temp part"
    LogEvent " | INFO  |   preserveCornerOrientation = " & CStr(preserveCornerOrientation)

    If Not ActivateDocumentByTitle(tempPartDoc.GetTitle) Then
        LogEvent " | WARN  | Current-view export could not explicitly activate temp part"
    End If

    If DIRECT_TEMP_PART_FORCE_INCH_UNITS Then
        If ForceModelLinearUnitsToInches(tempPartDoc) Then
            LogEvent " | INFO  | Current-view export temp part linear units = INCHES"
        Else
            LogEvent " | WARN  | Current-view export could not confirm INCH units on temp part"
        End If
    End If

    'Critical R5 change:
    'Re-apply the view immediately before ExportToDWG2 and export *Current.
    'This mirrors the V15 single-body direct-source path, but on an isolated temp part so the source model is not touched.
    If Not OrientModelCurrentView(tempPartDoc, xDir, faceNormal) Then
        LogEvent " | FAIL  | Could not orient temp part current view immediately before DXF export"
        Exit Function
    End If

    If Not HideAllSketchesInModel(tempPartDoc) Then
        LogEvent " | WARN  | HideAllSketchesInModel returned False immediately before current-view DXF export"
    End If

    tempPartDoc.ForceRebuild3 True

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then tempPartDoc.GraphicsRedraw2
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        tempPartDoc.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Current-view temp-part ViewZoomtofit2 skipped for batch stability"
    End If

    LogEvent " | INFO  | Direct export requested view name = [*Current]"
    If TryDirectExportToDxfByViewName(swTempPart, tempPartPath, finalDxfPath, "*Current", varAlignment) Then
        ExportTempPartToDxf_DirectByCurrentView = True
        Exit Function
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ExportTempPartToDxf_DirectByCurrentView: " & Err.Number & " - " & Err.Description
End Function

Private Function ExportTempPartToDxf_DirectByAnnotationView(ByVal tempPartDoc As SldWorks.ModelDoc2, _
                                                            ByVal tempPartPath As String, _
                                                            ByVal finalDxfPath As String, _
                                                            ByVal modelViewName As String, _
                                                            ByVal preserveCornerOrientation As Boolean) As Boolean
    On Error GoTo EH

    ExportTempPartToDxf_DirectByAnnotationView = False

    If tempPartDoc Is Nothing Then
        LogEvent " | FAIL  | Direct export: tempPartDoc is Nothing"
        Exit Function
    End If

    If tempPartDoc.GetType <> swDocPART Then
        LogEvent " | FAIL  | Direct export requires PART doc, got " & DocTypeName(tempPartDoc.GetType)
        Exit Function
    End If

    Dim swTempPart As SldWorks.PartDoc
    Set swTempPart = tempPartDoc

    Dim alignmentData(0 To 11) As Double
    Dim varAlignment As Variant
    BuildIdentityDwgAlignment alignmentData
    varAlignment = alignmentData

    If Not ActivateDocumentByTitle(tempPartDoc.GetTitle) Then
        LogEvent " | WARN  | Direct export could not explicitly activate temp part"
    End If

    tempPartDoc.ForceRebuild3 True

    If Not HideAllSketchesInModel(tempPartDoc) Then
        LogEvent " | WARN  | HideAllSketchesInModel returned False immediately before direct DXF export"
    End If

    If DIRECT_TEMP_PART_FORCE_INCH_UNITS Then
        If ForceModelLinearUnitsToInches(tempPartDoc) Then
            LogEvent " | INFO  | Direct export temp part linear units = INCHES"
        Else
            LogEvent " | WARN  | Direct export could not confirm INCH units on temp part"
        End If
    End If

    If Not FAST_MODE_MINIMIZE_EXTRA_REDRAWS Then tempPartDoc.GraphicsRedraw2
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then
        tempPartDoc.ViewZoomtofit2
    Else
        LogEvent " | INFO  | Direct temp-part ViewZoomtofit2 skipped for batch stability"
    End If

    LogEvent " | INFO  | Direct export preserveCornerOrientation = " & CStr(preserveCornerOrientation)
    LogEvent " | INFO  | Direct export requested view name = [" & modelViewName & "]"

    If TryDirectExportToDxfByViewName(swTempPart, tempPartPath, finalDxfPath, modelViewName, varAlignment) Then
        ExportTempPartToDxf_DirectByAnnotationView = True
        Exit Function
    End If

    If EXPERIMENTAL_DIRECT_ALLOW_CURRENT_VIEW_FALLBACK Then
        LogEvent " | WARN  | Experimental direct export by named view failed; trying *Current fallback"
        If TryDirectExportToDxfByViewName(swTempPart, tempPartPath, finalDxfPath, "*Current", varAlignment) Then
            ExportTempPartToDxf_DirectByAnnotationView = True
            Exit Function
        End If
    Else
        LogEvent " | INFO  | *Current fallback disabled to avoid losing deterministic orientation"
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ExportTempPartToDxf_DirectByAnnotationView: " & Err.Number & " - " & Err.Description
End Function

Private Function TryDirectExportToDxfByViewName(ByVal swTempPart As SldWorks.PartDoc, _
                                                ByVal modelPath As String, _
                                                ByVal finalDxfPath As String, _
                                                ByVal viewName As String, _
                                                ByVal varAlignment As Variant) As Boolean
    On Error GoTo EH

    Dim dataViews(0 To 0) As String
    Dim varViews As Variant
    Dim resultVar As Variant
    Dim ok As Boolean

    TryDirectExportToDxfByViewName = False

    dataViews(0) = viewName
    varViews = dataViews

    DeleteFileIfExists finalDxfPath

    LogEvent " | INFO  | Direct ExportToDWG2 start"
    LogEvent " | INFO  |   modelPath    = " & modelPath
    LogEvent " | INFO  |   finalDxfPath = " & finalDxfPath
    LogEvent " | INFO  |   viewName     = " & viewName

    On Error Resume Next
    resultVar = CallByName(swTempPart, "ExportToDWG2", VbMethod, _
                           finalDxfPath, _
                           modelPath, _
                           SW_EXPORT_TO_DWG_ANNOTATION_VIEWS, _
                           True, _
                           varAlignment, _
                           False, _
                           False, _
                           0, _
                           varViews)
    If Err.Number <> 0 Then
        LogEvent " | WARN  | CallByName ExportToDWG2 failed for [" & viewName & "]: " & Err.Number & " - " & Err.Description
        Err.Clear
        On Error GoTo EH
        Exit Function
    End If
    On Error GoTo EH

    ok = False
    On Error Resume Next
    ok = CBool(resultVar)
    On Error GoTo EH

    LogEvent " | INFO  | ExportToDWG2 result = " & CStr(ok)

    If Not ok Then Exit Function

    If Not FileExists(finalDxfPath) Then
        LogEvent " | WARN  | ExportToDWG2 returned True but output file not found"
        Exit Function
    End If

    If GetFileSizeSafe(finalDxfPath) <= 0 Then
        LogEvent " | WARN  | ExportToDWG2 created zero-byte DXF"
        Exit Function
    End If

    LogEvent " | INFO  | Direct ExportToDWG2 succeeded. File size = " & CStr(GetFileSizeSafe(finalDxfPath))
    TryDirectExportToDxfByViewName = True
    Exit Function

EH:
    LogEvent " | ERROR | TryDirectExportToDxfByViewName(" & viewName & "): " & Err.Number & " - " & Err.Description
End Function

Private Sub BuildIdentityDwgAlignment(ByRef alignmentData() As Double)
    alignmentData(0) = 0#
    alignmentData(1) = 0#
    alignmentData(2) = 0#
    alignmentData(3) = 1#
    alignmentData(4) = 0#
    alignmentData(5) = 0#
    alignmentData(6) = 0#
    alignmentData(7) = 1#
    alignmentData(8) = 0#
    alignmentData(9) = 0#
    alignmentData(10) = 0#
    alignmentData(11) = 1#
End Sub

Private Function ActivateDocumentByTitle(ByVal docTitle As String) As Boolean
    On Error GoTo EH

    ActivateDocumentByTitle = False

    If Len(Trim$(docTitle)) = 0 Then Exit Function

    Dim actErr As Long
    Dim mdl As SldWorks.ModelDoc2

    Set mdl = swApp.ActivateDoc3(docTitle, False, 0, actErr)
    LogEvent " | INFO  | ActivateDoc3 [" & docTitle & "] err=" & actErr

    If Not mdl Is Nothing Then
        ActivateDocumentByTitle = True
        Exit Function
    End If

    If Not swApp.ActiveDoc Is Nothing Then
        If StrComp(swApp.ActiveDoc.GetTitle, docTitle, vbTextCompare) = 0 Then
            ActivateDocumentByTitle = True
        End If
    End If

    Exit Function

EH:
    LogEvent " | ERROR | ActivateDocumentByTitle(" & docTitle & "): " & Err.Number & " - " & Err.Description
End Function

Private Function ForceModelLinearUnitsToInches(ByVal mdl As SldWorks.ModelDoc2) As Boolean
    On Error GoTo EH

    ForceModelLinearUnitsToInches = False

    If mdl Is Nothing Then Exit Function

    Dim beforeUnits As Long
    Dim afterUnits As Long

    On Error Resume Next
    beforeUnits = mdl.GetUserPreferenceIntegerValue(swUnitsLinear)
    Err.Clear
    On Error GoTo EH

    LogEvent " | INFO  | ForceModelLinearUnitsToInches before = " & CStr(beforeUnits)

    mdl.SetUserPreferenceIntegerValue swUnitsLinear, swINCHES

    On Error Resume Next
    afterUnits = mdl.GetUserPreferenceIntegerValue(swUnitsLinear)
    Err.Clear
    On Error GoTo EH

    LogEvent " | INFO  | ForceModelLinearUnitsToInches after  = " & CStr(afterUnits)

    ForceModelLinearUnitsToInches = (afterUnits = swINCHES)
    Exit Function

EH:
    LogEvent " | ERROR | ForceModelLinearUnitsToInches: " & Err.Number & " - " & Err.Description
End Function

Private Sub CloseModelDocSafe(ByRef mdl As SldWorks.ModelDoc2)
    On Error Resume Next

    If mdl Is Nothing Then Exit Sub

    Dim ttl As String
    ttl = mdl.GetTitle

    If Len(ttl) > 0 Then
        swApp.CloseDoc ttl
    End If

    Set mdl = Nothing
End Sub

Private Function GetFileSizeSafe(ByVal filePath As String) As Double
    On Error GoTo EH
    GetFileSizeSafe = 0#
    If Not FileExists(filePath) Then Exit Function
    GetFileSizeSafe = CDbl(FileLen(filePath))
    Exit Function
EH:
    GetFileSizeSafe = 0#
End Function

Private Function GetDxfExportModeName() As String
    If USE_FAST_MODE Then
        If USE_EXPERIMENTAL_FAST_DIRECT_DXF Then
            If TEMP_PART_EXPORT_USE_CURRENT_VIEW_V15_ROTATION Then
                If TEMP_PART_NAMED_VIEW_EXPORT_FALLBACK Then
                    GetDxfExportModeName = "FAST_MODE_TEMP_PART_CURRENT_VIEW_V15_ROTATION_WITH_NAMED_VIEW_FALLBACK"
                Else
                    GetDxfExportModeName = "FAST_MODE_TEMP_PART_CURRENT_VIEW_V15_ROTATION_ONLY"
                End If
            ElseIf EXPERIMENTAL_DIRECT_FALLBACK_TO_DRAWING Then
                GetDxfExportModeName = "FAST_MODE_DIRECT_PART_EXPORT_WITH_MANUAL_DRAWING_FALLBACK"
            Else
                GetDxfExportModeName = "FAST_MODE_DIRECT_PART_EXPORT_ONLY"
            End If
        Else
            GetDxfExportModeName = "FAST_MODE_DIRECT_PART_EXPORT_DISABLED"
        End If
    Else
        GetDxfExportModeName = "LEGACY_SAFE_MODE"
    End If
End Function

Private Function ShouldAttemptFastDirectDxfExport(ByVal preserveCornerOrientation As Boolean) As Boolean
    ShouldAttemptFastDirectDxfExport = False

    If Not USE_FAST_MODE Then Exit Function
    If Not USE_EXPERIMENTAL_FAST_DIRECT_DXF Then Exit Function

    LogEvent " | INFO  | Direct part-export path enabled. preserveCornerOrientation=" & CStr(preserveCornerOrientation)
    ShouldAttemptFastDirectDxfExport = True
End Function

Private Function ExportTempPartToDxf_ByNamedViewDrawing(ByVal tempPartDoc As SldWorks.ModelDoc2, _
                                                        ByVal tempPartPath As String, _
                                                        ByVal tempDrwPath As String, _
                                                        ByVal finalDxfPath As String, _
                                                        ByVal modelViewName As String, _
                                                        ByRef xDir() As Double, _
                                                        ByRef faceNormal() As Double, _
                                                        ByVal preserveCornerOrientation As Boolean) As Boolean
    On Error GoTo EH

    ExportTempPartToDxf_ByNamedViewDrawing = False

    If tempPartDoc Is Nothing Then
        LogEvent " | FAIL  | Drawing fallback: tempPartDoc is Nothing"
        Exit Function
    End If

    If Len(Trim$(tempPartPath)) = 0 Or Not FileExists(tempPartPath) Then
        LogEvent " | FAIL  | Drawing fallback: temp part path is invalid/missing: " & tempPartPath
        Exit Function
    End If

    Dim drwTemplate As String
    drwTemplate = GetDrawingTemplatePath()
    If Len(drwTemplate) = 0 Then
        LogEvent " | FAIL  | No drawing template available for export"
        Exit Function
    End If

    Dim bbox As Variant
    bbox = GetFirstBodyBoxFromPart(tempPartDoc)

    Dim w As Double, h As Double
    If Not IsEmpty(bbox) Then
        w = Abs(CDbl(bbox(3)) - CDbl(bbox(0))) + 2# * SHEET_MARGIN_M
        h = Abs(CDbl(bbox(4)) - CDbl(bbox(1))) + 2# * SHEET_MARGIN_M
    Else
        w = MIN_SHEET_W_M
        h = MIN_SHEET_H_M
    End If

    If w < MIN_SHEET_W_M Then w = MIN_SHEET_W_M
    If h < MIN_SHEET_H_M Then h = MIN_SHEET_H_M

    LogEvent " | INFO  | Drawing export sheet size (m) = " & FormatNumber(w, 4) & " x " & FormatNumber(h, 4)
    LogEvent " | INFO  | Creating drawing view from model view [" & modelViewName & "]"

    Dim drwDoc As SldWorks.ModelDoc2
    Set drwDoc = swApp.NewDocument(drwTemplate, swDwgPapersUserDefined, w, h)

    If drwDoc Is Nothing Then
        LogEvent " | FAIL  | New drawing creation failed"
        Exit Function
    End If

    Dim drw As SldWorks.DrawingDoc
    Set drw = drwDoc

    Dim viewX As Double, viewY As Double
    viewX = w / 2#
    viewY = h / 2#

    Dim v As SldWorks.View
    Set v = drw.CreateDrawViewFromModelView3(tempPartPath, modelViewName, viewX, viewY, 0#)

    If v Is Nothing Then
        LogEvent " | FAIL  | CreateDrawViewFromModelView3 returned Nothing for view [" & modelViewName & "]"
        GoTo CleanupAndExit
    End If

    On Error Resume Next
    v.UseSheetScale = False
    v.ScaleDecimal = 1#
    On Error GoTo EH

    drwDoc.ForceRebuild3 True
    If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then drwDoc.ViewZoomtofit2

    If CorrectDrawingViewRoll(v, xDir, faceNormal, preserveCornerOrientation) Then
        drwDoc.ForceRebuild3 True
        If Not AVOID_VIEW_ZOOM_TO_FIT_DURING_BATCH Then drwDoc.ViewZoomtofit2
    Else
        LogEvent " | WARN  | CorrectDrawingViewRoll did not make a change"
    End If

    If Not TrySaveModelToPath(drwDoc, tempDrwPath) Then
        LogEvent " | WARN  | Temp drawing save failed; continuing DXF save"
    End If

    Dim errs As Long, warns As Long
    errs = 0: warns = 0
    If drwDoc.Extension.SaveAs(finalDxfPath, swSaveAsCurrentVersion, swSaveAsOptions_Silent, Nothing, errs, warns) Then
        LogEvent " | INFO  | Drawing SaveAs DXF succeeded. errs=" & errs & " warns=" & warns
        If FileExists(finalDxfPath) Then
            If GetFileSizeSafe(finalDxfPath) > 0 Then
                ExportTempPartToDxf_ByNamedViewDrawing = True
            Else
                LogEvent " | WARN  | Drawing fallback created zero-byte DXF"
            End If
        Else
            LogEvent " | WARN  | Drawing SaveAs returned True but DXF file was not found"
        End If
    Else
        LogEvent " | FAIL  | Drawing SaveAs DXF failed. errs=" & errs & " warns=" & warns
    End If

CleanupAndExit:
    CloseModelDocSafe drwDoc
    Exit Function

EH:
    LogEvent " | ERROR | ExportTempPartToDxf_ByNamedViewDrawing: " & Err.Number & " - " & Err.Description
    Resume CleanupAndExit
End Function

Private Function CorrectDrawingViewRoll(ByVal v As SldWorks.View, _
                                        ByRef xDir() As Double, _
                                        ByRef faceNormal() As Double, _
                                        ByVal preserveCornerOrientation As Boolean) As Boolean
    On Error GoTo EH

    CorrectDrawingViewRoll = False

    If v Is Nothing Then Exit Function

    Dim ang As Double
    If GetModelVectorAngleInView(v, xDir, ang) Then
        LogEvent " | INFO  | View roll correction angle = " & FormatNumber(RadToDeg(ang), 4) & " deg"

        Dim curAngle As Double
        curAngle = 0#
        On Error Resume Next
        curAngle = CDbl(CallByName(v, "Angle", VbGet))
        If Err.Number <> 0 Then
            LogEvent " | WARN  | Could not read View.Angle: " & Err.Number & " - " & Err.Description
            Err.Clear
            On Error GoTo EH
        Else
            CallByName v, "Angle", VbLet, (curAngle - ang)
            If Err.Number <> 0 Then
                LogEvent " | WARN  | Could not write View.Angle: " & Err.Number & " - " & Err.Description
                Err.Clear
                On Error GoTo EH
            Else
                CorrectDrawingViewRoll = True
            End If
        End If
        On Error GoTo EH
    Else
        LogEvent " | WARN  | Could not determine in-view angle for xDir"
    End If

    Dim outline As Variant
    outline = v.GetOutline

    If VariantHasAtLeast4Numbers(outline) Then
        Dim width As Double, height As Double
        width = Abs(CDbl(outline(2)) - CDbl(outline(0)))
        height = Abs(CDbl(outline(3)) - CDbl(outline(1)))

        LogEvent " | INFO  | Post-roll outline W x H = " & FormatNumber(width, 6) & " x " & FormatNumber(height, 6)

        If preserveCornerOrientation Then
            LogEvent " | INFO  | Corner-driven orientation active -> skipping legacy 90-degree width/height auto-rotate"
        ElseIf height > width + EPS Then
            LogEvent " | INFO  | Applying additional +90 deg correction because view is taller than wide"

            Dim curAngle2 As Double
            curAngle2 = 0#
            On Error Resume Next
            curAngle2 = CDbl(CallByName(v, "Angle", VbGet))
            If Err.Number = 0 Then
                CallByName v, "Angle", VbLet, (curAngle2 + PI_VAL / 2#)
                If Err.Number = 0 Then
                    CorrectDrawingViewRoll = True
                Else
                    LogEvent " | WARN  | Secondary 90-degree correction failed: " & Err.Number & " - " & Err.Description
                    Err.Clear
                End If
            Else
                LogEvent " | WARN  | Could not read View.Angle for 90-degree correction: " & Err.Number & " - " & Err.Description
                Err.Clear
            End If
            On Error GoTo EH
        End If
    End If

    Dim vx As Double, vy As Double, vz As Double
    If TransformModelVectorToView(v, faceNormal, vx, vy, vz) Then
        LogEvent " | INFO  | Face normal in view coords = (" & _
                    FormatNumber(vx, 6) & ", " & FormatNumber(vy, 6) & ", " & FormatNumber(vz, 6) & ")"
    End If

    Exit Function

EH:
    LogEvent " | ERROR | CorrectDrawingViewRoll: " & Err.Number & " - " & Err.Description
End Function

Private Function GetModelVectorAngleInView(ByVal v As SldWorks.View, _
                                           ByRef modelVec() As Double, _
                                           ByRef angRad As Double) As Boolean
    On Error GoTo EH

    GetModelVectorAngleInView = False
    angRad = 0#

    Dim vx As Double, vy As Double, vz As Double
    If Not TransformModelVectorToView(v, modelVec, vx, vy, vz) Then Exit Function

    If Abs(vx) <= EPS And Abs(vy) <= EPS Then Exit Function

    angRad = Atn2(vy, vx)
    GetModelVectorAngleInView = True
    Exit Function

EH:
    LogEvent " | ERROR | GetModelVectorAngleInView: " & Err.Number & " - " & Err.Description
End Function

Private Function TransformModelVectorToView(ByVal v As SldWorks.View, _
                                            ByRef modelVec() As Double, _
                                            ByRef outX As Double, _
                                            ByRef outY As Double, _
                                            ByRef outZ As Double) As Boolean
    On Error GoTo EH

    TransformModelVectorToView = False

    If v Is Nothing Then Exit Function

    Dim mtv As SldWorks.MathTransform
    Set mtv = v.ModelToViewTransform
    If mtv Is Nothing Then Exit Function

    Dim data(2) As Double
    data(0) = modelVec(0)
    data(1) = modelVec(1)
    data(2) = modelVec(2)

    Dim mv As SldWorks.MathVector
    Set mv = swMathUtil.CreateVector(data)
    If mv Is Nothing Then Exit Function

    Dim tv As SldWorks.MathVector
    Set tv = mv.MultiplyTransform(mtv)
    If tv Is Nothing Then Exit Function

    Dim arr As Variant
    arr = tv.ArrayData
    If Not VariantHas3Numbers(arr) Then Exit Function

    outX = CDbl(arr(0))
    outY = CDbl(arr(1))
    outZ = CDbl(arr(2))

    TransformModelVectorToView = True
    Exit Function

EH:
    LogEvent " | ERROR | TransformModelVectorToView: " & Err.Number & " - " & Err.Description
End Function

Private Function VariantHasAtLeast9Numbers(ByVal v As Variant) As Boolean
    On Error GoTo EH

    VariantHasAtLeast9Numbers = False
    If IsEmpty(v) Then Exit Function
    If Not IsArray(v) Then Exit Function

    Dim lb As Long, ub As Long
    lb = LBound(v)
    ub = UBound(v)

    If (ub - lb + 1) < 9 Then Exit Function

    Dim i As Long, tmp As Double
    For i = 0 To 8
        tmp = CDbl(v(lb + i))
    Next i

    VariantHasAtLeast9Numbers = True
    Exit Function

EH:
    VariantHasAtLeast9Numbers = False
End Function

Private Function VariantHasAtLeast4Numbers(ByVal v As Variant) As Boolean
    On Error GoTo EH

    VariantHasAtLeast4Numbers = False
    If IsEmpty(v) Then Exit Function
    If Not IsArray(v) Then Exit Function

    Dim lb As Long, ub As Long
    lb = LBound(v)
    ub = UBound(v)

    If (ub - lb + 1) < 4 Then Exit Function

    Dim i As Long, tmp As Double
    For i = 0 To 3
        tmp = CDbl(v(lb + i))
    Next i

    VariantHasAtLeast4Numbers = True
    Exit Function

EH:
    VariantHasAtLeast4Numbers = False
End Function

Private Function GetFirstBodyBoxFromPart(ByVal mdl As SldWorks.ModelDoc2) As Variant
    On Error GoTo EH

    Dim p As SldWorks.PartDoc
    Set p = mdl

    Dim vBodies As Variant
    vBodies = p.GetBodies2(swSolidBody, True)

    If IsEmpty(vBodies) Then
        vBodies = p.GetBodies2(swAllBodies, True)
    End If

    If IsEmpty(vBodies) Then Exit Function
    If Not IsArray(vBodies) Then Exit Function

    Dim b As SldWorks.Body2
    Set b = vBodies(LBound(vBodies))

    If b Is Nothing Then Exit Function

    GetFirstBodyBoxFromPart = b.GetBodyBox
    Exit Function

EH:
    LogEvent " | ERROR | GetFirstBodyBoxFromPart: " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' TEMPLATE HELPERS
'=========================================================================================
Private Function GetPartTemplatePath() As String
    On Error GoTo EH

    GetPartTemplatePath = Trim$(swApp.GetUserPreferenceStringValue(swDefaultTemplatePart))
    If Len(GetPartTemplatePath) = 0 Then
        GetPartTemplatePath = Trim$(swApp.GetDocumentTemplate(swDocPART, "", 0#, 0#, 0#))
    End If
    Exit Function

EH:
    LogEvent " | ERROR | GetPartTemplatePath: " & Err.Number & " - " & Err.Description
End Function

Private Function GetDrawingTemplatePath() As String
    On Error GoTo EH

    If FileExists(CUSTOM_DRAWING_TEMPLATE) Then
        GetDrawingTemplatePath = CUSTOM_DRAWING_TEMPLATE
        LogEvent " | INFO  | Using custom drawing template = " & GetDrawingTemplatePath
        Exit Function
    End If

    LogEvent " | WARN  | Custom drawing template not found, falling back"

    GetDrawingTemplatePath = Trim$(swApp.GetUserPreferenceStringValue(swDefaultTemplateDrawing))
    If Len(GetDrawingTemplatePath) = 0 Then
        GetDrawingTemplatePath = Trim$(swApp.GetDocumentTemplate(swDocDRAWING, "", 0#, 0#, 0#))
    End If
    Exit Function

EH:
    LogEvent " | ERROR | GetDrawingTemplatePath: " & Err.Number & " - " & Err.Description
End Function

'=========================================================================================
' TEMP PATH HELPERS
'=========================================================================================
Private Function HideAllSketchesInModel(ByVal mdl As SldWorks.ModelDoc2) As Boolean
    On Error GoTo EH

    HideAllSketchesInModel = False

    If mdl Is Nothing Then Exit Function

    If Not HIDE_SKETCHES_BEFORE_DXF_EXPORT Then
        LogEvent " | INFO  | Sketch hiding skipped by stability setting HIDE_SKETCHES_BEFORE_DXF_EXPORT=False"
        HideAllSketchesInModel = True
        Exit Function
    End If

    If Not ActivateDocumentByTitle(mdl.GetTitle) Then
        LogEvent " | WARN  | HideAllSketchesInModel could not explicitly activate [" & mdl.GetTitle & "]"
    End If

    Dim feat As SldWorks.Feature
    Dim hiddenCount As Long
    Dim visitCount As Long

    Set feat = mdl.FirstFeature

    Do While Not feat Is Nothing
        visitCount = visitCount + 1
        HideSketchFeatureRecursive feat, hiddenCount
        Set feat = feat.GetNextFeature
    Loop

    mdl.ClearSelection2 True
    mdl.GraphicsRedraw2

    LogEvent " | INFO  | HideAllSketchesInModel visited top-level features = " & CStr(visitCount) & " | sketches hidden = " & CStr(hiddenCount)
    HideAllSketchesInModel = True
    Exit Function

EH:
    LogEvent " | ERROR | HideAllSketchesInModel: " & Err.Number & " - " & Err.Description
End Function

Private Sub HideSketchFeatureRecursive(ByVal feat As SldWorks.Feature, ByRef hiddenCount As Long)
    On Error GoTo EH

    If feat Is Nothing Then Exit Sub

    Dim typeName As String
    typeName = feat.GetTypeName2

    If IsSketchFeatureType(typeName) Then
        LogEvent " | INFO  | Hiding sketch feature [" & feat.Name & "] type=[" & typeName & "]"
        If BlankSketchFeatureBySelection(feat) Then
            hiddenCount = hiddenCount + 1
        Else
            LogEvent " | WARN  | Could not blank sketch feature [" & feat.Name & "]"
        End If
    End If

    Dim subFeat As SldWorks.Feature
    Set subFeat = feat.GetFirstSubFeature

    Do While Not subFeat Is Nothing
        HideSketchFeatureRecursive subFeat, hiddenCount
        Set subFeat = subFeat.GetNextSubFeature
    Loop

    Exit Sub

EH:
    LogEvent " | ERROR | HideSketchFeatureRecursive(" & feat.Name & "): " & Err.Number & " - " & Err.Description
End Sub

Private Function IsSketchFeatureType(ByVal typeName As String) As Boolean
    Dim t As String
    t = UCase$(Trim$(typeName))

    Select Case t
        Case "PROFILEFEATURE", "SKETCH", "3DSKETCH", "3DSKETCHPROFILE", "DERIVEDSKETCH"
            IsSketchFeatureType = True
        Case Else
            IsSketchFeatureType = False
    End Select
End Function

Private Function BlankSketchFeatureBySelection(ByVal feat As SldWorks.Feature) As Boolean
    On Error GoTo EH

    BlankSketchFeatureBySelection = False

    If feat Is Nothing Then Exit Function
    If swApp.ActiveDoc Is Nothing Then Exit Function

    swApp.ActiveDoc.ClearSelection2 True

    If Not feat.Select2(False, -1) Then
        LogEvent " | WARN  | Select2 failed while trying to blank sketch [" & feat.Name & "]"
        Exit Function
    End If

    swApp.ActiveDoc.BlankSketch
    swApp.ActiveDoc.ClearSelection2 True
    BlankSketchFeatureBySelection = True
    Exit Function

EH:
    LogEvent " | ERROR | BlankSketchFeatureBySelection(" & feat.Name & "): " & Err.Number & " - " & Err.Description
End Function

Private Function GetLocalTempRoot() As String
    On Error GoTo EH

    Dim baseTemp As String
    baseTemp = Trim$(Environ$("TEMP"))
    If Len(baseTemp) = 0 Then baseTemp = Trim$(Environ$("TMP"))
    If Len(baseTemp) = 0 Then baseTemp = "C:\Temp"

    Dim root As String
    root = baseTemp & "\" & TEMP_PREFIX & SafeNowStamp()

    GetLocalTempRoot = EnsureFolderExists(root)
    Exit Function

EH:
    LogEvent " | ERROR | GetLocalTempRoot: " & Err.Number & " - " & Err.Description
    GetLocalTempRoot = ""
End Function

'=========================================================================================
' FILE / PATH HELPERS
'=========================================================================================



Private Sub WriteRunCompleteFile(ByVal summaryText As String)
    On Error GoTo EH

    If Not WRITE_RUN_COMPLETE_FILE Then Exit Sub
    If Len(Trim$(gEventRootFolder)) = 0 Then Exit Sub

    Dim completePath As String
    completePath = CombinePathSafe(gEventRootFolder, "RUN_COMPLETE.txt")

    Dim content As String
    content = "SAVE_ALL_DXF_ACCORDING_TO_MATERIAL_THICKNESS_MACRO" & vbCrLf & _
              "Revision: CRASH_SAFE_R10_PRODUCTION_VALIDATION_RIGHT_ANGLE_ORIENTATION" & vbCrLf & _
              "Completed: " & TimeStamp() & vbCrLf & _
              "Output folder: " & gEventRootFolder & vbCrLf & _
              "Source-part direct export disabled: " & CStr(DISABLE_SOURCE_PART_DIRECT_EXPORT_FOR_STABILITY) & vbCrLf & _
              "Physical temp-body flatten for DXF orientation: " & CStr(PHYSICALLY_FLATTEN_TEMP_BODY_FOR_DXF) & " (R7 default OFF)" & vbCrLf & _
              vbCrLf & _
              summaryText & vbCrLf

    WriteTextFile completePath, content
    LogEvent " | INFO  | RUN_COMPLETE written => " & completePath
    Exit Sub

EH:
    LogEvent " | WARN  | WriteRunCompleteFile failed: " & Err.Number & " - " & Err.Description
End Sub

Private Function PrepareRootOutputFolder(ByVal parentFolder As String, ByVal outFolderName As String) As String
    On Error GoTo EH

    PrepareRootOutputFolder = ""

    parentFolder = Trim$(parentFolder)
    outFolderName = Trim$(outFolderName)

    If Len(parentFolder) = 0 Then Exit Function
    If Len(outFolderName) = 0 Then Exit Function

    Dim baseRootPath As String
    Dim runPath As String

    baseRootPath = CombinePathSafe(parentFolder, outFolderName)

    ' R6 network-safe behavior:
    ' The root folder is only ensured, not deleted. Each run gets a new child folder.
    If Len(EnsureFolderExists(baseRootPath)) = 0 Then
        LogEvent " | FAIL  | Could not create/access base output root: " & baseRootPath
        Exit Function
    End If

    If USE_TIMESTAMPED_RUN_FOLDER Then
        runPath = CombinePathSafe(baseRootPath, BuildRunFolderName())
        PrepareRootOutputFolder = EnsureFolderExists(runPath)
        LogEvent " | INFO  | Base output root = " & baseRootPath
        LogEvent " | INFO  | Timestamped run output folder = " & PrepareRootOutputFolder
    Else
        If CLEAR_DXF_ROOT_BEFORE_RUN Then
            If Not ClearFolderContentsSafe(baseRootPath, outFolderName) Then
                LogEvent " | WARN  | DXF root cleanup returned False. Continuing after ensuring folder exists."
            End If
        Else
            LogEvent " | INFO  | Cleanup disabled. Reusing base output root without deleting contents: " & baseRootPath
        End If

        PrepareRootOutputFolder = EnsureFolderExists(baseRootPath)
    End If

    Exit Function

EH:
    LogEvent " | ERROR | PrepareRootOutputFolder(" & parentFolder & ", " & outFolderName & "): " & Err.Number & " - " & Err.Description
End Function

Private Function BuildRunFolderName() As String
    On Error GoTo EH
    BuildRunFolderName = RUN_FOLDER_PREFIX & Format$(Now, "yyyymmdd_hhnnss")
    Exit Function
EH:
    BuildRunFolderName = RUN_FOLDER_PREFIX & "UNKNOWN_TIME"
End Function

Private Function ClearFolderContentsSafe(ByVal folderPath As String, ByVal expectedLeafName As String) As Boolean
    On Error GoTo EH

    ClearFolderContentsSafe = False

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    If Len(Trim$(folderPath)) = 0 Then Exit Function

    If Not fso.FolderExists(folderPath) Then
        ClearFolderContentsSafe = True
        Exit Function
    End If

    If Not IsSafeOutputRootForCleanup(folderPath, expectedLeafName) Then
        LogEvent " | FAIL  | Cleanup refused. Folder did not pass safety check: " & folderPath
        Exit Function
    End If

    LogEvent " | INFO  | Clearing previous nesting batch contents from: " & folderPath

    Dim fld As Object
    Dim fil As Object
    Dim subFld As Object

    Set fld = fso.GetFolder(folderPath)

    For Each fil In fld.Files
        LogEvent " | INFO  | Delete old output file: " & fil.path
        fil.Delete True
    Next fil

    For Each subFld In fld.SubFolders
        LogEvent " | INFO  | Delete old output folder: " & subFld.path
        subFld.Delete True
    Next subFld

    ClearFolderContentsSafe = True
    Exit Function

EH:
    LogEvent " | ERROR | ClearFolderContentsSafe(" & folderPath & "): " & Err.Number & " - " & Err.Description
End Function

Private Function IsSafeOutputRootForCleanup(ByVal folderPath As String, ByVal expectedLeafName As String) As Boolean
    On Error GoTo EH

    IsSafeOutputRootForCleanup = False

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    If Len(Trim$(folderPath)) < 6 Then Exit Function
    If StrComp(fso.GetFileName(folderPath), expectedLeafName, vbTextCompare) <> 0 Then Exit Function
    If StrComp(expectedLeafName, OUT_FOLDER_NAME, vbTextCompare) <> 0 Then Exit Function

    IsSafeOutputRootForCleanup = True
    Exit Function

EH:
    LogEvent " | ERROR | IsSafeOutputRootForCleanup(" & folderPath & "): " & Err.Number & " - " & Err.Description
End Function
Private Function EnsureFolderExists(ByVal folderPath As String) As String
    On Error GoTo EH

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    folderPath = Trim$(folderPath)
    If Len(folderPath) = 0 Then Exit Function

    If fso.FolderExists(folderPath) Then
        EnsureFolderExists = folderPath
        Exit Function
    End If

    Dim parentPath As String
    parentPath = fso.GetParentFolderName(folderPath)

    If Len(parentPath) > 0 Then
        If Not fso.FolderExists(parentPath) Then
            If Len(EnsureFolderExists(parentPath)) = 0 Then
                EnsureFolderExists = ""
                Exit Function
            End If
        End If
    End If

    If Not fso.FolderExists(folderPath) Then
        fso.CreateFolder folderPath
    End If

    If fso.FolderExists(folderPath) Then
        EnsureFolderExists = folderPath
    Else
        EnsureFolderExists = ""
    End If
    Exit Function

EH:
    LogEvent " | ERROR | EnsureFolderExists(" & folderPath & "): " & Err.Number & " - " & Err.Description
    EnsureFolderExists = ""
End Function


Private Function CombinePathSafe(ByVal folderPath As String, ByVal leafName As String) As String
    'Builds Windows paths without accidental control characters or double separators.
    folderPath = Trim$(folderPath)
    leafName = Trim$(leafName)

    If Len(folderPath) = 0 Then
        CombinePathSafe = leafName
    ElseIf Right$(folderPath, 1) = "\" Then
        CombinePathSafe = folderPath & leafName
    Else
        CombinePathSafe = folderPath & "\" & leafName
    End If
End Function


Private Function ContainsControlCharacters(ByVal valueText As String) As Boolean
    Dim i As Long
    Dim c As Integer

    ContainsControlCharacters = False
    For i = 1 To Len(valueText)
        c = Asc(Mid$(valueText, i, 1))
        If c >= 0 And c < 32 Then
            ContainsControlCharacters = True
            Exit Function
        End If
    Next i
End Function

Private Function GetFolderFromPath(ByVal fullPath As String) As String
    Dim p As Long
    p = InStrRev(fullPath, "\")
    If p > 0 Then
        GetFolderFromPath = Left$(fullPath, p - 1)
    Else
        GetFolderFromPath = ""
    End If
End Function

Private Function GetUniqueOutputPath(ByVal folderPath As String, ByVal baseFileNameNoExt As String, ByVal extNoDot As String) As String
    On Error GoTo EH

    Dim candidate As String
    Dim i As Long

    candidate = folderPath & "\" & baseFileNameNoExt & "." & extNoDot
    If Not FileExists(candidate) Then
        GetUniqueOutputPath = candidate
        Exit Function
    End If

    For i = 1 To 9999
        candidate = folderPath & "\" & baseFileNameNoExt & "_" & Format$(i, "00") & "." & extNoDot
        If Not FileExists(candidate) Then
            GetUniqueOutputPath = candidate
            Exit Function
        End If
    Next i

    GetUniqueOutputPath = folderPath & "\" & baseFileNameNoExt & "_" & SafeNowStamp() & "." & extNoDot
    Exit Function

EH:
    LogEvent " | ERROR | GetUniqueOutputPath: " & Err.Number & " - " & Err.Description
End Function

Private Function FileExists(ByVal filePath As String) As Boolean
    On Error Resume Next
    FileExists = (Len(Dir$(filePath, vbNormal)) > 0)
End Function

Private Function FolderExistsSafe(ByVal folderPath As String) As Boolean
    On Error GoTo EH

    FolderExistsSafe = False
    If Len(Trim$(folderPath)) = 0 Then Exit Function

    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")

    FolderExistsSafe = fso.FolderExists(folderPath)
    Exit Function

EH:
    LogEvent " | WARN  | FolderExistsSafe(" & folderPath & "): " & Err.Number & " - " & Err.Description
    FolderExistsSafe = False
End Function

Private Sub DeleteFileIfExists(ByVal filePath As String)
    On Error Resume Next
    If Len(filePath) > 0 Then
        If FileExists(filePath) Then Kill filePath
    End If
End Sub

Private Sub DeleteFolderIfEmpty(ByVal folderPath As String)
    On Error Resume Next
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    If fso.FolderExists(folderPath) Then
        If fso.GetFolder(folderPath).Files.Count = 0 And fso.GetFolder(folderPath).SubFolders.Count = 0 Then
            fso.DeleteFolder folderPath, True
        End If
    End If
End Sub

Private Sub CloseDocIfOpen(ByVal filePath As String)
    On Error Resume Next
    If Len(filePath) = 0 Then Exit Sub

    Dim openDoc As SldWorks.ModelDoc2
    Set openDoc = swApp.GetOpenDocumentByName(filePath)
    If Not openDoc Is Nothing Then
        swApp.CloseDoc openDoc.GetTitle
        Exit Sub
    End If

    swApp.CloseDoc GetFileNameFromPath(filePath)
End Sub

Private Function GetFileNameFromPath(ByVal filePath As String) As String
    Dim p As Long
    p = InStrRev(filePath, "\")
    If p > 0 Then
        GetFileNameFromPath = Mid$(filePath, p + 1)
    Else
        GetFileNameFromPath = filePath
    End If
End Function

Private Function GetFileStemFromPath(ByVal filePath As String) As String
    Dim fileNameOnly As String
    Dim p As Long

    fileNameOnly = GetFileNameFromPath(filePath)
    p = InStrRev(fileNameOnly, ".")

    If p > 1 Then
        GetFileStemFromPath = Left$(fileNameOnly, p - 1)
    Else
        GetFileStemFromPath = fileNameOnly
    End If
End Function


Private Function SanitizeFileName(ByVal s As String) As String
    Dim badChars As Variant
    Dim i As Long

    s = Trim$(s)
    badChars = Array("\", "/", ":", "*", "?", """", "<", ">", "|")

    For i = LBound(badChars) To UBound(badChars)
        s = Replace$(s, badChars(i), "_")
    Next i

    Do While InStr(s, "__") > 0
        s = Replace$(s, "__", "_")
    Loop

    s = Trim$(s)
    s = TrimDotsAndSpaces(s)

    SanitizeFileName = s
End Function

Private Function TrimDotsAndSpaces(ByVal s As String) As String
    Do While Len(s) > 0 And (Right$(s, 1) = "." Or Right$(s, 1) = " ")
        s = Left$(s, Len(s) - 1)
    Loop
    Do While Len(s) > 0 And (Left$(s, 1) = "." Or Left$(s, 1) = " ")
        s = Mid$(s, 2)
    Loop
    TrimDotsAndSpaces = s
End Function

'=========================================================================================
' VECTOR MATH
'=========================================================================================
Private Function VecLength(ByRef v() As Double) As Double
    VecLength = Sqr(v(0) * v(0) + v(1) * v(1) + v(2) * v(2))
End Function

Private Sub NormalizeVec(ByRef v() As Double)
    Dim L As Double
    L = VecLength(v)
    If L > EPS Then
        v(0) = v(0) / L
        v(1) = v(1) / L
        v(2) = v(2) / L
    End If
End Sub

Private Function DotProduct(ByRef a() As Double, ByRef b() As Double) As Double
    DotProduct = a(0) * b(0) + a(1) * b(1) + a(2) * b(2)
End Function

Private Sub CrossProduct(ByRef a() As Double, ByRef b() As Double, ByRef outV() As Double)
    outV(0) = a(1) * b(2) - a(2) * b(1)
    outV(1) = a(2) * b(0) - a(0) * b(2)
    outV(2) = a(0) * b(1) - a(1) * b(0)
End Sub

Private Sub ProjectVectorOntoPlane(ByRef v() As Double, ByRef n() As Double, ByRef outV() As Double)
    Dim d As Double
    d = DotProduct(v, n)
    outV(0) = v(0) - d * n(0)
    outV(1) = v(1) - d * n(1)
    outV(2) = v(2) - d * n(2)
End Sub

Private Sub StabilizeVectorSign(ByRef v() As Double)
    If Abs(v(0)) > EPS Then
        If v(0) < 0# Then FlipVec v
    ElseIf Abs(v(1)) > EPS Then
        If v(1) < 0# Then FlipVec v
    ElseIf Abs(v(2)) > EPS Then
        If v(2) < 0# Then FlipVec v
    End If
End Sub

Private Sub FlipVec(ByRef v() As Double)
    v(0) = -v(0)
    v(1) = -v(1)
    v(2) = -v(2)
End Sub

Private Function CompareVectorLex(ByRef a() As Double, ByRef b() As Double) As Long
    If Abs(a(0) - b(0)) > EPS Then
        CompareVectorLex = Sgn(a(0) - b(0))
        Exit Function
    End If
    If Abs(a(1) - b(1)) > EPS Then
        CompareVectorLex = Sgn(a(1) - b(1))
        Exit Function
    End If
    If Abs(a(2) - b(2)) > EPS Then
        CompareVectorLex = Sgn(a(2) - b(2))
        Exit Function
    End If
    CompareVectorLex = 0
End Function

Private Function Distance3(ByRef p0() As Double, ByRef p1() As Double) As Double
    Distance3 = Sqr((p1(0) - p0(0)) ^ 2 + (p1(1) - p0(1)) ^ 2 + (p1(2) - p0(2)) ^ 2)
End Function

Private Function Dbl3ToStr(ByRef v() As Double) As String
    Dbl3ToStr = FormatNumber(v(0), 8) & ", " & FormatNumber(v(1), 8) & ", " & FormatNumber(v(2), 8)
End Function

Private Function Atn2(ByVal y As Double, ByVal x As Double) As Double
    If Abs(x) < EPS Then
        If y > 0# Then
            Atn2 = PI_VAL / 2#
        ElseIf y < 0# Then
            Atn2 = -PI_VAL / 2#
        Else
            Atn2 = 0#
        End If
    ElseIf x > 0# Then
        Atn2 = Atn(y / x)
    ElseIf x < 0# Then
        If y >= 0# Then
            Atn2 = Atn(y / x) + PI_VAL
        Else
            Atn2 = Atn(y / x) - PI_VAL
        End If
    End If
End Function

Private Function RadToDeg(ByVal rad As Double) As Double
    RadToDeg = rad * 180# / PI_VAL
End Function

'=========================================================================================
' STRING / LOG HELPERS
'=========================================================================================
Private Function NzStr(ByVal s As String) As String
    NzStr = Trim$(s & "")
End Function


'=========================================================================================
' PERSISTENT EVENT LOGGER
'=========================================================================================

Private Sub ResetEventLoggerState()
    On Error Resume Next

    gEventLogReady = False
    gEventLogPath = ""
    gEventLastPath = ""
    gEventStatePath = ""
    gEventRootFolder = ""
    gEventSeq = 0
    gEventLastLine = ""
    gEventRunLabel = ""
    gEventLastStage = ""
    Set gEventPendingLines = New Collection
End Sub

Private Sub InitializeEventLogger(ByVal dxfRootFolder As String, ByVal runLabel As String)
    On Error GoTo EH

    If Not ENABLE_PERSISTENT_EVENT_LOGGER Then Exit Sub

    gEventRootFolder = Trim$(dxfRootFolder)
    gEventRunLabel = Trim$(runLabel)
    If Len(gEventRunLabel) = 0 Then gEventRunLabel = "RUN"

    If Len(gEventRootFolder) = 0 Then Exit Sub

    gEventLogPath = CombinePathSafe(gEventRootFolder, EVENT_LOG_FILE_NAME)
    gEventLastPath = CombinePathSafe(gEventRootFolder, EVENT_LAST_FILE_NAME)
    gEventStatePath = CombinePathSafe(gEventRootFolder, EVENT_STATE_FILE_NAME)

    If ContainsControlCharacters(gEventLogPath) Or ContainsControlCharacters(gEventLastPath) Or ContainsControlCharacters(gEventStatePath) Then
        Debug.Print TimeStamp() & " | ERROR | Event logger path contains a control character. Logger disabled."
        Exit Sub
    End If

    gEventLogReady = True

    ' Start each macro run with a fresh event log after the DXF root cleanup has completed.
    WriteTextFileANSI gEventLogPath, _
        "SAVE_ALL_DXF event log" & vbCrLf & _
        "Started: " & TimeStamp() & vbCrLf & _
        "Run label: " & gEventRunLabel & vbCrLf & _
        "DXF root: " & gEventRootFolder & vbCrLf & _
        String(110, "=") & vbCrLf, False

    LogEventRaw String(110, "=")
    LogEvent " | LOGGER | Persistent event logger initialized"
    LogEvent " | LOGGER | Log path  = " & gEventLogPath
    LogEvent " | LOGGER | Last path = " & gEventLastPath
    LogEvent " | LOGGER | State path= " & gEventStatePath
    LogEvent " | LOGGER | Echo to Immediate Window = " & CStr(EVENT_LOG_ECHO_TO_IMMEDIATE)

    FlushPendingEventLines
    Exit Sub

EH:
    On Error Resume Next
    Debug.Print TimeStamp() & " | ERROR | InitializeEventLogger: " & Err.Number & " - " & Err.Description
End Sub

Private Sub LogEvent(ByVal messageText As String)
    On Error GoTo EH

    Dim cleanMessage As String
    cleanMessage = CStr(messageText)

    If Len(cleanMessage) > 0 Then
        If Left$(cleanMessage, 1) = " " Then
            cleanMessage = TimeStamp() & cleanMessage
        Else
            cleanMessage = TimeStamp() & " | " & cleanMessage
        End If
    Else
        cleanMessage = TimeStamp()
    End If

    LogEventLine cleanMessage
    Exit Sub

EH:
    On Error Resume Next
    Debug.Print TimeStamp() & " | ERROR | LogEvent internal failure: " & Err.Number & " - " & Err.Description
End Sub

Private Sub LogEventRaw(ByVal rawText As String)
    On Error GoTo EH
    LogEventLine CStr(rawText)
    Exit Sub

EH:
    On Error Resume Next
    Debug.Print TimeStamp() & " | ERROR | LogEventRaw internal failure: " & Err.Number & " - " & Err.Description
End Sub

Private Sub LogEventLine(ByVal lineText As String)
    On Error GoTo EH

    Dim finalLine As String

    gEventSeq = gEventSeq + 1
    finalLine = Right$("00000000" & CStr(gEventSeq), 8) & " | " & lineText
    gEventLastLine = finalLine

    If EVENT_LOG_ECHO_TO_IMMEDIATE Then
        Debug.Print finalLine
    End If

    If ENABLE_PERSISTENT_EVENT_LOGGER And gEventLogReady And Len(gEventLogPath) > 0 Then
        AppendLineToTextFileANSI gEventLogPath, finalLine
        WriteTextFileANSI gEventLastPath, finalLine & vbCrLf, False
        WriteEventStateFile finalLine
    Else
        BufferEventLine finalLine
    End If

    Exit Sub

EH:
    On Error Resume Next
    If EVENT_LOG_ECHO_TO_IMMEDIATE Then Debug.Print TimeStamp() & " | ERROR | LogEventLine internal failure: " & Err.Number & " - " & Err.Description
End Sub

Private Sub BufferEventLine(ByVal finalLine As String)
    On Error Resume Next

    If gEventPendingLines Is Nothing Then Set gEventPendingLines = New Collection

    If gEventPendingLines.Count < EVENT_LOG_MAX_BUFFER_BEFORE_INIT Then
        gEventPendingLines.Add finalLine
    End If
End Sub

Private Sub FlushPendingEventLines()
    On Error GoTo EH

    If gEventPendingLines Is Nothing Then Exit Sub
    If Not gEventLogReady Then Exit Sub

    Dim i As Long
    For i = 1 To gEventPendingLines.Count
        AppendLineToTextFileANSI gEventLogPath, CStr(gEventPendingLines(i))
    Next i

    Set gEventPendingLines = New Collection
    Exit Sub

EH:
    On Error Resume Next
    Debug.Print TimeStamp() & " | ERROR | FlushPendingEventLines: " & Err.Number & " - " & Err.Description
End Sub

Private Sub WriteEventStateFile(ByVal finalLine As String)
    On Error GoTo EH

    If Not ENABLE_PERSISTENT_EVENT_LOGGER Then Exit Sub
    If Len(gEventStatePath) = 0 Then Exit Sub

    Dim s As String
    s = "{" & vbCrLf & _
        "  ""eventSeq"": " & CStr(gEventSeq) & "," & vbCrLf & _
        "  ""timestamp"": """ & JsonEscape(TimeStamp()) & """," & vbCrLf & _
        "  ""runLabel"": """ & JsonEscape(gEventRunLabel) & """," & vbCrLf & _
        "  ""lastEvent"": """ & JsonEscape(finalLine) & """," & vbCrLf & _
        "  ""totalChecked"": " & CStr(gTotalChecked) & "," & vbCrLf & _
        "  ""totalEligible"": " & CStr(gTotalEligible) & "," & vbCrLf & _
        "  ""totalExported"": " & CStr(gTotalExported) & "," & vbCrLf & _
        "  ""totalSkipped"": " & CStr(gTotalSkipped) & "," & vbCrLf & _
        "  ""totalFailed"": " & CStr(gTotalFailed) & "," & vbCrLf & _
        "  ""totalQtyAccumulated"": " & CStr(gTotalQtyAccumulated) & "," & vbCrLf & _
        "  ""totalImmediateJsonFlushes"": " & CStr(gTotalImmediateJsonFlushes) & "," & vbCrLf & _
        "  ""eventLogPath"": """ & JsonEscape(gEventLogPath) & """" & vbCrLf & _
        "}"

    WriteTextFileANSI gEventStatePath, s, False
    Exit Sub

EH:
    On Error Resume Next
End Sub

Private Sub AppendLineToTextFileANSI(ByVal filePath As String, ByVal lineText As String)
    On Error GoTo EH

    If Len(Trim$(filePath)) = 0 Then Exit Sub

    Dim ff As Integer
    ff = FreeFile

    Open filePath For Append As #ff
    Print #ff, lineText
    Close #ff
    Exit Sub

EH:
    On Error Resume Next
    If ff <> 0 Then Close #ff
End Sub

Private Function WriteTextFileANSI(ByVal filePath As String, ByVal textOut As String, ByVal appendMode As Boolean) As Boolean
    On Error GoTo EH

    WriteTextFileANSI = False
    If Len(Trim$(filePath)) = 0 Then Exit Function

    Dim ff As Integer
    ff = FreeFile

    If appendMode Then
        Open filePath For Append As #ff
    Else
        Open filePath For Output As #ff
    End If

    Print #ff, textOut;
    Close #ff

    WriteTextFileANSI = True
    Exit Function

EH:
    On Error Resume Next
    If ff <> 0 Then Close #ff
End Function

Private Function TimeStamp() As String
    TimeStamp = Format$(Now, "yyyy-mm-dd hh:nn:ss")
End Function

Private Function SafeNowStamp() As String
    SafeNowStamp = Format$(Now, "yyyymmdd_hhnnss")
End Function
Procedure index · 242 declarations
File checksum

SHA-256: 1095df3ab6206913ef2e2a9767db9b379eb20723276a0be2b8242065ff8a3027