Compare commits

...

5 Commits

Author SHA1 Message Date
AJ
c9a8442a29 Refactored ExportContext 2025-10-01 09:44:07 -04:00
AJ
a2b89318e1 Changed mm to inches in sheet metal properties 2025-10-01 09:42:22 -04:00
AJ
f1fc105a1b Set minimum width for BOM description column 2025-10-01 09:42:01 -04:00
AJ
58269f9761 Changed BomExcelSettings defaults 2025-10-01 09:40:54 -04:00
AJ
4053038632 Fixed unit scales 2025-10-01 09:40:16 -04:00
9 changed files with 268 additions and 166 deletions

View File

@@ -26,7 +26,7 @@
<PublisherName>Rogers Engineering</PublisherName>
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
<WebPage>publish.htm</WebPage>
<ApplicationRevision>6</ApplicationRevision>
<ApplicationRevision>7</ApplicationRevision>
<ApplicationVersion>1.6.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
@@ -99,6 +99,12 @@
<Compile Include="Extensions\TimeSpanExtensions.cs" />
<Compile Include="Extensions\UIExtensions.cs" />
<Compile Include="Extensions\UnitConversionExtensions.cs" />
<Compile Include="Forms\MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="ItemExtractors\AssemblyItemExtractor.cs" />
<Compile Include="ItemExtractors\BomColumnIndices.cs" />
<Compile Include="ItemExtractors\BomItemExtractor.cs" />
@@ -122,12 +128,6 @@
<Compile Include="ViewFlipDeciders\AskViewFlipDecider.cs" />
<Compile Include="ViewFlipDeciders\AutoViewFlipDecider.cs" />
<Compile Include="ViewFlipDeciders\IViewFlipDecider.cs" />
<Compile Include="Forms\MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewFlipDeciders\PreferUpViewFlipDecider.cs" />

View File

@@ -5,8 +5,8 @@
/// </summary>
public static class UnitConversionExtensions
{
private const double METERS_TO_MM = .0001;
private const double METERS_TO_INCHES = 0.0254;
private const double METERS_TO_MM = 1000;
private const double METERS_TO_INCHES = 39.37007874;
/// <summary>
/// Converts a SolidWorks dimension (in meters) to millimeters.

View File

@@ -1,7 +1,11 @@
using ExportDXF.ViewFlipDeciders;
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace ExportDXF.Services
{
@@ -10,6 +14,9 @@ namespace ExportDXF.Services
/// </summary>
public class ExportContext
{
private const string DRAWING_TEMPLATE_FOLDER = "Templates";
private const string DRAWING_TEMPLATE_FILE = "Blank.drwdot";
/// <summary>
/// The document to be exported.
/// </summary>
@@ -34,5 +41,90 @@ namespace ExportDXF.Services
/// Callback for reporting progress and status messages.
/// </summary>
public Action<string, Color?> ProgressCallback { get; set; }
public void LogProgress(string message, Color? color = null)
{
ProgressCallback?.Invoke(message, color);
}
public SldWorks SolidWorksApp { get; set; }
public DrawingDoc TemplateDrawing { get; set; }
private string DrawingTemplatePath
{
get
{
return Path.Combine(
Application.StartupPath,
DRAWING_TEMPLATE_FOLDER,
DRAWING_TEMPLATE_FILE);
}
}
public DrawingDoc GetOrCreateTemplateDrawing()
{
if (TemplateDrawing != null)
return TemplateDrawing;
TemplateDrawing = SolidWorksApp.NewDocument(
DrawingTemplatePath,
(int)swDwgPaperSizes_e.swDwgPaperDsize,
1,
1) as DrawingDoc;
return TemplateDrawing;
}
public void CleanupTemplateDrawing()
{
try
{
if (TemplateDrawing == null)
return;
if (SolidWorksApp == null)
{
ProgressCallback?.Invoke("Warning: Cannot cleanup template drawing - SolidWorks app not available", Color.DarkBlue);
TemplateDrawing = null;
return;
}
var model = TemplateDrawing as ModelDoc2;
if (model != null)
{
var title = model.GetTitle();
if (!string.IsNullOrEmpty(title))
{
// Close the document without saving
SolidWorksApp.CloseDoc(title);
ProgressCallback?.Invoke("Closed template drawing", null);
}
}
// Clear the reference regardless of success/failure
TemplateDrawing = null;
}
catch (Exception ex)
{
ProgressCallback?.Invoke($"Failed to close template drawing: {ex.Message}", Color.Red);
// Still clear the reference to prevent further issues
TemplateDrawing = null;
// Don't throw here as this is cleanup code - log the error but continue
}
}
public void CloseDocument(string title)
{
SolidWorksApp?.CloseDoc(title);
}
public ModelDoc2 CreateDocument(string templatePath, int paperSize, double width, double height)
{
return SolidWorksApp?.NewDocument(templatePath, paperSize, width, height) as ModelDoc2;
}
}
}

View File

@@ -285,10 +285,22 @@ namespace ExportDXF.Services
{
worksheet.Column(col).AutoFit();
if (worksheet.Column(col).Width > MAX_COLUMN_WIDTH)
// Special handling for Description column (assuming it's column 4)
if (col == 4) // Description column
{
worksheet.Column(col).Width = Math.Max(worksheet.Column(col).Width, 30); // Minimum 30 units
if (worksheet.Column(col).Width > 50) // Maximum 50 units
worksheet.Column(col).Width = 50;
}
else if (worksheet.Column(col).Width > MAX_COLUMN_WIDTH)
{
worksheet.Column(col).Width = MAX_COLUMN_WIDTH;
}
else
{
worksheet.Column(col).Width += COLUMN_PADDING;
}
}
// Add borders if enabled

View File

@@ -19,17 +19,17 @@
/// <summary>
/// Add summary section with totals and statistics.
/// </summary>
public bool AddSummary { get; set; } = true;
public bool AddSummary { get; set; } = false;
/// <summary>
/// Format header row with bold text and background color.
/// </summary>
public bool FormatHeaders { get; set; } = true;
public bool FormatHeaders { get; set; } = false;
/// <summary>
/// Add borders around all cells.
/// </summary>
public bool AddBorders { get; set; } = true;
public bool AddBorders { get; set; } = false;
/// <summary>
/// Freeze the header row for easier scrolling.
@@ -44,7 +44,7 @@
/// <summary>
/// Number of decimal places for thickness values.
/// </summary>
public int ThicknessDecimalPlaces { get; set; } = 2;
public int ThicknessDecimalPlaces { get; set; } = 4;
/// <summary>
/// Number of decimal places for K-Factor values.
@@ -54,7 +54,7 @@
/// <summary>
/// Number of decimal places for bend radius values.
/// </summary>
public int BendRadiusDecimalPlaces { get; set; } = 2;
public int BendRadiusDecimalPlaces { get; set; } = 3;
/// <summary>
/// Minimum number of digits for item numbers (pad with zeros).

View File

@@ -16,14 +16,13 @@ namespace ExportDXF.Services
/// </summary>
/// <param name="drawing">The drawing document to export.</param>
/// <param name="saveDirectory">The directory where the PDF file will be saved.</param>
/// <param name="progressCallback">Optional callback for progress updates.</param>
void ExportToPdf(DrawingDoc drawing, string saveDirectory, Action<string, Color?> progressCallback);
/// <param name="context">The export context containing SolidWorks app and callbacks.</param>
void ExportToPdf(DrawingDoc drawing, string saveDirectory, ExportContext context);
}
public class DrawingExporter : IDrawingExporter
{
public void ExportToPdf(DrawingDoc drawing, string saveDirectory, Action<string, Color?> progressCallback)
public void ExportToPdf(DrawingDoc drawing, string saveDirectory, ExportContext context)
{
if (drawing == null)
throw new ArgumentNullException(nameof(drawing));
@@ -31,27 +30,40 @@ namespace ExportDXF.Services
if (string.IsNullOrWhiteSpace(saveDirectory))
throw new ArgumentException("Save directory cannot be null or empty.", nameof(saveDirectory));
if (context == null)
throw new ArgumentNullException(nameof(context));
if (context.SolidWorksApp == null)
throw new ArgumentException("SolidWorksApp cannot be null in context.", nameof(context));
try
{
var pdfFileName = GetPdfFileName(drawing);
var pdfPath = Path.Combine(saveDirectory, pdfFileName);
var model = drawing as ModelDoc2;
var sldWorks = (SldWorks)Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application"));
var sldWorks = context.SolidWorksApp;
var exportData = sldWorks.GetExportFileData(
(int)swExportDataFileType_e.swExportPdfData) as ExportPdfData;
if (exportData == null)
{
throw new InvalidOperationException("Failed to get PDF export data from SolidWorks.");
}
exportData.ViewPdfAfterSaving = false;
exportData.SetSheets(
(int)swExportDataSheetsToExport_e.swExportData_ExportAllSheets,
drawing);
context.ProgressCallback?.Invoke($"Exporting drawing to PDF: \"{pdfFileName}\"", null);
int errors = 0;
int warnings = 0;
var modelExtension = model.Extension;
modelExtension.SaveAs(
var success = modelExtension.SaveAs(
pdfPath,
(int)swSaveAsVersion_e.swSaveAsCurrentVersion,
(int)swSaveAsOptions_e.swSaveAsOptions_Silent,
@@ -59,19 +71,29 @@ namespace ExportDXF.Services
ref errors,
ref warnings);
if (errors == 0)
if (success && errors == 0)
{
progressCallback?.Invoke($"Saved drawing to PDF: \"{pdfFileName}\"", Color.Green);
context.ProgressCallback?.Invoke($"Saved drawing to PDF: \"{pdfFileName}\"", Color.Green);
}
else if (success && warnings > 0)
{
context.ProgressCallback?.Invoke(
$"PDF export completed with warnings: {warnings}",
Color.DarkBlue);
}
else
{
progressCallback?.Invoke($"PDF export completed with errors: {errors}", Color.Yellow);
context.ProgressCallback?.Invoke(
$"PDF export failed. Errors: {errors}, Warnings: {warnings}",
Color.Red);
throw new InvalidOperationException($"PDF export failed with {errors} errors and {warnings} warnings.");
}
}
catch (Exception ex)
{
progressCallback?.Invoke($"Failed to export PDF: {ex.Message}", Color.Red);
throw;
var errorMessage = $"Failed to export PDF: {ex.Message}";
context.ProgressCallback?.Invoke(errorMessage, Color.Red);
throw new InvalidOperationException(errorMessage, ex);
}
}
@@ -79,6 +101,14 @@ namespace ExportDXF.Services
{
var model = drawing as ModelDoc2;
var modelFilePath = model.GetPathName();
if (string.IsNullOrEmpty(modelFilePath))
{
// Handle unsaved documents
var title = model.GetTitle();
return string.IsNullOrEmpty(title) ? "Untitled.pdf" : Path.GetFileNameWithoutExtension(title) + ".pdf";
}
return Path.GetFileNameWithoutExtension(modelFilePath) + ".pdf";
}
}

View File

@@ -25,9 +25,6 @@ namespace ExportDXF.Services
/// </summary>
public class DxfExportService : IDxfExportService
{
private const string DRAWING_TEMPLATE_FOLDER = "Templates";
private const string DRAWING_TEMPLATE_FILE = "Blank.drwdot";
private readonly ISolidWorksService _solidWorksService;
private readonly IBomExtractor _bomExtractor;
private readonly IPartExporter _partExporter;
@@ -57,6 +54,7 @@ namespace ExportDXF.Services
throw new ArgumentNullException(nameof(context));
ValidateContext(context);
SetupExportContext(context);
var startTime = DateTime.Now;
@@ -85,6 +83,7 @@ namespace ExportDXF.Services
}
finally
{
CleanupExportContext(context);
_solidWorksService.EnableUserControl(true);
var duration = DateTime.Now - startTime;
@@ -131,7 +130,7 @@ namespace ExportDXF.Services
if (items == null || items.Count == 0)
{
LogProgress(context, "No items found in assembly.", Color.Yellow);
LogProgress(context, "No items found in assembly.", Color.DarkBlue);
return;
}
@@ -177,7 +176,7 @@ namespace ExportDXF.Services
}
// Export drawing to PDF first
_drawingExporter.ExportToPdf(drawing, saveDirectory, context.ProgressCallback);
_drawingExporter.ExportToPdf(drawing, saveDirectory, context);
// Then export parts to DXF
ExportItems(items, saveDirectory, context);
@@ -185,6 +184,40 @@ namespace ExportDXF.Services
#endregion
#region Context Management
private void SetupExportContext(ExportContext context)
{
// Set up SolidWorks application reference
context.SolidWorksApp = _solidWorksService.GetNativeSldWorks();
if (context.SolidWorksApp == null)
{
throw new InvalidOperationException("SolidWorks service is not connected.");
}
// Set up drawing template path
context.TemplateDrawing = null;
LogProgress(context, "Export context initialized", null);
}
private void CleanupExportContext(ExportContext context)
{
try
{
// Clean up template drawing if it was created
context.CleanupTemplateDrawing();
}
catch (Exception ex)
{
LogProgress(context, $"Warning: Failed to cleanup template drawing: {ex.Message}", Color.DarkBlue);
// Don't throw - this is cleanup code
}
}
#endregion
#region Item Processing
private List<Item> ExtractItemsFromAssembly(AssemblyDoc assembly, ExportContext context)
@@ -207,117 +240,43 @@ namespace ExportDXF.Services
private void ExportItems(List<Item> items, string saveDirectory, ExportContext context)
{
DrawingDoc templateDrawing = null;
LogProgress(context, "", null);
try
int successCount = 0;
int failureCount = 0;
foreach (var item in items)
{
templateDrawing = CreateTemplateDrawing();
if (context.CancellationToken.IsCancellationRequested)
{
LogProgress(context, "Export canceled by user.", Color.DarkBlue);
return;
}
try
{
// PartExporter will handle template drawing creation through context
_partExporter.ExportItem(item, saveDirectory, context);
if (!string.IsNullOrEmpty(item.FileName))
successCount++;
else
failureCount++;
}
catch (Exception ex)
{
LogProgress(context, $"Error exporting item {item.ItemNo}: {ex.Message}", Color.Red);
failureCount++;
}
LogProgress(context, "", null);
int successCount = 0;
int failureCount = 0;
foreach (var item in items)
{
if (context.CancellationToken.IsCancellationRequested)
{
LogProgress(context, "Export canceled by user.", Color.Yellow);
return;
}
try
{
_partExporter.ExportItem(item, templateDrawing, saveDirectory, context);
if (!string.IsNullOrEmpty(item.FileName))
successCount++;
else
failureCount++;
}
catch (Exception ex)
{
LogProgress(context, $"Error exporting item {item.ItemNo}: {ex.Message}", Color.Red);
failureCount++;
}
LogProgress(context, "", null);
}
LogProgress(context, $"Export complete: {successCount} succeeded, {failureCount} failed",
failureCount > 0 ? Color.Yellow : Color.Green);
// Create BOM Excel file
CreateBomExcelFile(items, saveDirectory, context);
}
finally
{
CloseTemplateDrawing(templateDrawing);
}
}
#endregion
#region Template Drawing Management
private DrawingDoc CreateTemplateDrawing()
{
var sldWorks = _solidWorksService.GetNativeSldWorks();
if (sldWorks == null)
throw new InvalidOperationException("SolidWorks service is not connected.");
var templatePath = GetDrawingTemplatePath();
if (!File.Exists(templatePath))
{
throw new FileNotFoundException(
$"Drawing template not found at: {templatePath}",
templatePath);
}
var drawing = sldWorks.NewDocument(
templatePath,
(int)swDwgPaperSizes_e.swDwgPaperDsize,
1,
1) as DrawingDoc;
LogProgress(context, $"Export complete: {successCount} succeeded, {failureCount} failed",
failureCount > 0 ? Color.DarkBlue : Color.Green);
if (drawing == null)
{
throw new InvalidOperationException(
"Failed to create drawing from template. Please check the template file.");
}
return drawing;
}
private void CloseTemplateDrawing(DrawingDoc drawing)
{
if (drawing == null)
return;
try
{
var model = drawing as ModelDoc2;
var title = model?.GetTitle();
if (!string.IsNullOrEmpty(title))
{
_solidWorksService.CloseDocument(title);
}
}
catch
{
// Ignore errors during cleanup
}
}
private string GetDrawingTemplatePath()
{
return Path.Combine(
Application.StartupPath,
DRAWING_TEMPLATE_FOLDER,
DRAWING_TEMPLATE_FILE);
// Create BOM Excel file
CreateBomExcelFile(items, saveDirectory, context);
}
#endregion
@@ -408,6 +367,8 @@ namespace ExportDXF.Services
context.ProgressCallback?.Invoke(message, color);
}
#endregion
}
}

View File

@@ -25,10 +25,9 @@ namespace ExportDXF.Services
/// Exports an item (component from BOM or assembly) to DXF.
/// </summary>
/// <param name="item">The item to export.</param>
/// <param name="templateDrawing">The template drawing to use for creating flat patterns.</param>
/// <param name="saveDirectory">The directory where the DXF file will be saved.</param>
/// <param name="context">The export context.</param>
void ExportItem(Item item, DrawingDoc templateDrawing, string saveDirectory, ExportContext context);
void ExportItem(Item item, string saveDirectory, ExportContext context);
}
public class PartExporter : IPartExporter
@@ -38,6 +37,12 @@ namespace ExportDXF.Services
if (part == null)
throw new ArgumentNullException(nameof(part));
if (string.IsNullOrWhiteSpace(saveDirectory))
throw new ArgumentException("Save directory cannot be null or empty.", nameof(saveDirectory));
if (context == null)
throw new ArgumentNullException(nameof(context));
var model = part as ModelDoc2;
var activeConfig = model.GetActiveConfiguration() as SolidWorks.Interop.sldworks.Configuration;
var originalConfigName = activeConfig?.Name;
@@ -47,16 +52,9 @@ namespace ExportDXF.Services
var fileName = GetSinglePartFileName(model, context.FilePrefix);
var savePath = Path.Combine(saveDirectory, fileName + ".dxf");
var templateDrawing = CreateTemplateDrawing(context);
context.GetOrCreateTemplateDrawing();
try
{
ExportPartToDxf(part, originalConfigName, templateDrawing, savePath, context);
}
finally
{
CloseTemplateDrawing(templateDrawing, context);
}
ExportPartToDxf(part, originalConfigName, savePath, context);
}
finally
{
@@ -67,8 +65,14 @@ namespace ExportDXF.Services
}
}
public void ExportItem(Item item, DrawingDoc templateDrawing, string saveDirectory, ExportContext context)
public void ExportItem(Item item, string saveDirectory, ExportContext context)
{
if (string.IsNullOrWhiteSpace(saveDirectory))
throw new ArgumentException("Save directory cannot be null or empty.", nameof(saveDirectory));
if (context == null)
throw new ArgumentNullException(nameof(context));
if (item?.Component == null)
{
context.ProgressCallback?.Invoke($"Item {item?.ItemNo} - skipped, no component", Color.Yellow);
@@ -93,7 +97,9 @@ namespace ExportDXF.Services
var fileName = GetItemFileName(item, context.FilePrefix);
var savePath = Path.Combine(saveDirectory, fileName + ".dxf");
if (ExportPartToDxf(part, item.Component.ReferencedConfiguration, templateDrawing, savePath, context))
var templateDrawing = context.GetOrCreateTemplateDrawing();
if (ExportPartToDxf(part, item.Component.ReferencedConfiguration, savePath, context))
{
item.FileName = Path.GetFileNameWithoutExtension(savePath);
}
@@ -116,8 +122,18 @@ namespace ExportDXF.Services
// Get description from custom properties
var config = item.Component.ReferencedConfiguration;
item.Description = model.Extension.CustomPropertyManager[config].Get("Description");
item.Description = model.Extension.CustomPropertyManager[""].Get("Description");
// Try configuration-specific properties first
var configPropertyManager = model.Extension.CustomPropertyManager[config];
item.Description = configPropertyManager?.Get("Description");
// Fall back to document-level properties if no config-specific description
if (string.IsNullOrEmpty(item.Description))
{
var docPropertyManager = model.Extension.CustomPropertyManager[""];
item.Description = docPropertyManager?.Get("Description");
}
item.Description = TextHelper.RemoveXmlTags(item.Description);
// Get material
@@ -127,7 +143,6 @@ namespace ExportDXF.Services
private bool ExportPartToDxf(
PartDoc part,
string configName,
DrawingDoc templateDrawing,
string savePath,
ExportContext context)
{
@@ -141,6 +156,8 @@ namespace ExportDXF.Services
return false;
}
var templateDrawing = context.GetOrCreateTemplateDrawing();
SolidWorksHelper.ConfigureFlatPatternSettings(model);
var sheet = templateDrawing.IGetCurrentSheet();
@@ -286,15 +303,5 @@ namespace ExportDXF.Services
Color.Red);
}
}
private DrawingDoc CreateTemplateDrawing(ExportContext context)
{
throw new NotImplementedException("Template drawing creation not implemented.");
}
private void CloseTemplateDrawing(DrawingDoc drawing, ExportContext context)
{
throw new NotImplementedException("Template drawing creation not implemented.");
}
}
}

View File

@@ -6,7 +6,7 @@
public class SheetMetalProperties
{
/// <summary>
/// Material thickness in millimeters.
/// Material thickness
/// </summary>
public double Thickness { get; set; }
@@ -16,12 +16,12 @@
public double KFactor { get; set; }
/// <summary>
/// Bend radius in millimeters.
/// Inside bend radius
/// </summary>
public double BendRadius { get; set; }
/// <summary>
/// Bend allowance in millimeters.
/// Bend allowance
/// </summary>
public double BendAllowance { get; set; }
@@ -37,7 +37,7 @@
public override string ToString()
{
return $"Thickness: {Thickness:F2}mm, K-Factor: {KFactor:F3}, Bend Radius: {BendRadius:F2}mm";
return $"Thickness: {Thickness:F2}\", K-Factor: {KFactor:F3}, Bend Radius: {BendRadius:F2}\"";
}
}
}