solidworks 装配体用bom信息处理每个零件 c#

csharp 复制代码
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace tools
{
    public class asm2do
    {
        static private Dictionary<string, int> docnameCount = new Dictionary<string, int>();
        static private Dictionary<string, int> dwgExportCount = new Dictionary<string, int>();
        static private readonly object _swApiLock = new object();
        static private string[] currentFilterKeywords = null;

        public delegate int SolidWorksAction( ModelDoc2 swModel,SldWorks swApp=null);

        static public string[]? run(SldWorks swApp, ModelDoc2 swModel, SolidWorksAction action, string[] filterKeywords = null)
        {
            try
            {
                // 清空上次的统计结果
                docnameCount.Clear();
                dwgExportCount.Clear();

                if (swModel == null)
                {
                    Console.WriteLine("错误:没有打开任何文档。");
                    return null;
                }

                // 确保是装配体
                if (swModel.GetType() != (int)swDocumentTypes_e.swDocASSEMBLY)
                {
                    Console.WriteLine("错误:当前文档不是装配体。");
                    return null;
                }

                Console.WriteLine("=== 从BOM缓存清单获取零件信息 ===");

                if (!asm2bom.HasGeneratedPartList())
                {
                    Console.WriteLine("BOM清单未生成,先执行一次 asm2bom 生成清单...");
                    int bomResult = asm2bom.run(swApp, swModel, "零件", false).GetAwaiter().GetResult();
                    if (bomResult != 0)
                    {
                        Console.WriteLine("错误:无法通过 asm2bom 生成零件清单。");
                        return null;
                    }
                }

                List<BomPartExportInfo> bomParts = asm2bom.GetLastBomParts();
                Console.WriteLine($"BOM缓存共 {bomParts.Count} 个零件");

                // 存储需要处理的零件信息:零件路径 -> 零件名称
                Dictionary<string, string> partsToProcess = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
                foreach (BomPartExportInfo bomPart in bomParts)
                {
                    if (bomPart == null || string.IsNullOrEmpty(bomPart.PartPath))
                    {
                        continue;
                    }

                    string partName = bomPart.PartName ?? Path.GetFileNameWithoutExtension(bomPart.PartPath);
                    if (string.IsNullOrEmpty(partName))
                    {
                        partName = Path.GetFileNameWithoutExtension(bomPart.PartPath);
                    }

                    // 如果有关键字筛选,检查是否匹配
                    if (filterKeywords != null && filterKeywords.Length > 0)
                    {
                        bool shouldProcess = false;
                        foreach (string keyword in filterKeywords)
                        {
                            if (!string.IsNullOrEmpty(keyword) && partName.Contains(keyword))
                            {
                                shouldProcess = true;
                                break;
                            }
                        }

                        if (!shouldProcess)
                        {
                            continue;
                        }
                    }

                    string resolvedPath = ResolvePartPath(bomPart.PartPath);
                    if (!partsToProcess.ContainsKey(resolvedPath))
                    {
                        partsToProcess[resolvedPath] = partName;
                        Debug.WriteLine($"[BOM缓存] 找到零件: {partName}, 路径: {resolvedPath}");
                    }
                }
                
                Console.WriteLine($"筛选后共需处理 {partsToProcess.Count} 个零件");
                
                if (partsToProcess.Count == 0)
                {
                    Console.WriteLine("没有找到需要处理的零件。");
                    return new string[0];
                }
                
                int processedCount = 0;
                int totalCount = partsToProcess.Count;
                
                // 处理每个零件
                foreach (var kvp in partsToProcess)
                {
                    string partPath = kvp.Key;
                    string partName = kvp.Value;
                    
                    processedCount++;
                    Console.WriteLine($"[{processedCount}/{totalCount}] 正在处理: {partName}");
                    
                    // 打开零件文档
                    int openErrors = 0;
                    int openWarnings = 0;
                    ModelDoc2 partDoc = (ModelDoc2)swApp.OpenDoc6(
                        partPath, 
                        (int)swDocumentTypes_e.swDocPART, 
                        (int)swOpenDocOptions_e.swOpenDocOptions_Silent, 
                        "", 
                        ref openErrors, 
                        ref openWarnings
                    );
                    
                    if (partDoc != null)
                    {
                        partDoc.Visible = true;
                        
                        // 执行操作
                        int exportedCount = action.Invoke(partDoc, swApp);
                        
                        // 记录统计信息
                        if (!docnameCount.ContainsKey(partPath))
                        {
                            docnameCount[partPath] = 0;
                        }
                        docnameCount[partPath]++;
                        
                        if (!dwgExportCount.ContainsKey(partPath))
                        {
                            dwgExportCount[partPath] = 0;
                        }
                        dwgExportCount[partPath] = exportedCount;
                        
                        // 关闭文档
                        swApp.CloseDoc(partPath);
                        
                        Console.WriteLine($"进度: {processedCount}/{totalCount} ({(processedCount * 100.0 / totalCount):F1}%)");
                    }
                    else
                    {
                        Console.WriteLine($"警告:无法打开零件 {partName},路径: {partPath},errors={openErrors}, warnings={openWarnings}");
                    }
                }

                Console.WriteLine("\n========== 零件统计信息 ==========");
                foreach (var kvp in docnameCount.OrderBy(x => x.Key))
                {
                    string partName = Path.GetFileName(kvp.Key);
                    int refCount = kvp.Value;
                    int exportCount = dwgExportCount.ContainsKey(kvp.Key) ? dwgExportCount[kvp.Key] : 0;
                    Console.WriteLine($"{partName}: 引用 {refCount} 次,导出 {exportCount} 个文件");
                }
                Console.WriteLine($"\n总计:{docnameCount.Count} 个零件,共导出 {dwgExportCount.Values.Sum()} 个文件");
                Console.WriteLine("====================================\n");

                List<string> resultList = new List<string>(docnameCount.Keys);
                return resultList.ToArray();

            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
                Console.WriteLine(ex.StackTrace);
            }

            return null;
        }

        /// <summary>
        /// 清理文件路径:去掉末尾的"-数字"后缀
        /// </summary>
        static private string ResolvePartPath(string pathName)
        {
            if (string.IsNullOrWhiteSpace(pathName))
            {
                return string.Empty;
            }

            string originalPath = pathName.Trim().Replace(@"\\", "/");
            if (File.Exists(originalPath))
            {
                return originalPath;
            }

            // 兼容历史逻辑:仅在原始路径不存在时,尝试去掉末尾 "-数字" 后缀
            string fileName = Path.GetFileName(originalPath);
            string directory = Path.GetDirectoryName(originalPath);
            string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
            string extension = Path.GetExtension(fileName);

            int lastDashIndex = fileNameWithoutExt.LastIndexOf('-');
            if (lastDashIndex > 0 && lastDashIndex < fileNameWithoutExt.Length - 1)
            {
                string suffix = fileNameWithoutExt.Substring(lastDashIndex + 1);
                if (int.TryParse(suffix, out _))
                {
                    string compatName = fileNameWithoutExt.Substring(0, lastDashIndex) + extension;
                    string compatPath = Path.Combine(directory ?? string.Empty, compatName).Replace(@"\\", "/");
                    if (File.Exists(compatPath))
                    {
                        return compatPath;
                    }
                }
            }

            // 文件都不存在时,返回原始路径,便于上层输出准确错误定位
            return originalPath;
        }
        
        /// <summary>
        /// 根据零件名称查找对应的组件
        /// </summary>
        static private Component2 FindComponentByName(AssemblyDoc swAssembly, string partName)
        {
            object[] allComponents = (object[])swAssembly.GetComponents(false);
            
            foreach (object compObj in allComponents)
            {
                Component2 component = (Component2)compObj;
                string componentName = component.Name2;
                
                // 去掉"/"号及之前的文字
                int slashIndex = componentName.LastIndexOf('/');
                if (slashIndex >= 0 && slashIndex < componentName.Length - 1)
                {
                    componentName = componentName.Substring(slashIndex + 1);
                }
                
                // 去掉末尾的"-数字"部分
                int lastDashIndex = componentName.LastIndexOf('-');
                if (lastDashIndex > 0 && lastDashIndex < componentName.Length - 1)
                {
                    string suffix = componentName.Substring(lastDashIndex + 1);
                    if (int.TryParse(suffix, out _))
                    {
                        componentName = componentName.Substring(0, lastDashIndex);
                    }
                }
                
                // 比较名称
                if (componentName.Equals(partName, StringComparison.OrdinalIgnoreCase))
                {
                    return component;
                }
            }
            
            return null;
        }
    }
}
相关推荐
njsgcs2 天前
导出glb可视化让vlm看图找面 自己配合
智能制造·solidworks
花开月满西楼3 天前
零基础速学SolidWorks2026【曲面】曲面缝合
3d建模·solidworks·机械设计·机械绘图绘制
花开月满西楼3 天前
零基础速学SolidWorks2026【曲面】删除面
3d建模·solidworks·机械设计·机械绘图绘制
花开月满西楼3 天前
零基础速学SolidWorks2026【曲面】加厚曲面
3d建模·solidworks·机械设计·机械绘图绘制
花开月满西楼6 天前
零基础速学SolidWorks2026【曲面】边界曲面和等距曲面
3d建模·solidworks·机械设计·机械绘图绘制
花开月满西楼6 天前
零基础速学SolidWorks2026【曲面】平面区域和填充曲面
3d建模·solidworks·机械设计·机械绘图绘制
蓝悦无人机7 天前
SOLIDWORKS高级应用之方程
solidworks·参数化建模·if 判断语句
花开月满西楼7 天前
零基础速学SolidWorks2026【曲面】分割线
3d建模·solidworks·机械设计·机械绘图绘制
花开月满西楼9 天前
零基础速学SolidWorks2026【曲面】建模核心基础
solidworks·机械设计·机械绘图绘制
花开月满西楼10 天前
零基础速学SolidWorks2026【草图】绘制、编辑命令和约束
solidworks·机械设计