拆分多实体到装配体 solidworks c#

参考https://blog.csdn.net/zengqh0314/article/details/103560570

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

namespace tools
{
    public class Create_new_assembly
    {
        public const int Ok = 0;
        public const int ErrTemplate = 1;
        public const int ErrCreateDoc = 2;
        public const int ErrSave = 3;
        public const int ErrInsert = 4;
        public const int ErrSplit = 5;
        public static string LastSplitErrorSummary { get; private set; } = string.Empty;

        public static int run(SldWorks swApp, string assemblyName, List<string> partNames)
        {
            if (swApp == null || string.IsNullOrWhiteSpace(assemblyName) || partNames == null || partNames.Count == 0)
            {
                return ErrInsert;
            }

            try
            {
                assemblyName = NormalizePathSafe(assemblyName);
                string templateFolder = @"C:\ProgramData\SolidWorks\SOLIDWORKS 2025\templates";
                string templatePath = ResolveTemplatePath(templateFolder, "*.asmdot");

                if (string.IsNullOrWhiteSpace(templatePath))
                {
                    templatePath = swApp.GetDocumentTemplate((int)swDocumentTypes_e.swDocASSEMBLY, "", 0, 0, 0);
                }

                if (string.IsNullOrWhiteSpace(templatePath) || !File.Exists(templatePath))
                {
                    Debug.WriteLine("Create assembly failed: assembly template not found.");
                    return ErrTemplate;
                }

                string outputDir = Path.GetDirectoryName(assemblyName) ?? string.Empty;
                if (!string.IsNullOrWhiteSpace(outputDir))
                {
                    Directory.CreateDirectory(outputDir);
                }

                ModelDoc2 asmModel = swApp.NewDocument(templatePath, 0, 0, 0) as ModelDoc2;
                if (asmModel == null || asmModel.GetType() != (int)swDocumentTypes_e.swDocASSEMBLY)
                {
                    Debug.WriteLine("Create assembly failed: cannot create assembly document.");
                    return ErrCreateDoc;
                }

                int errors = 0;
                int warnings = 0;
                int saveResult = asmModel.SaveAs3(assemblyName, (int)swSaveAsOptions_e.swSaveAsOptions_Silent, 0);
                if (saveResult == 0)
                {
                    Debug.WriteLine($"Create assembly failed: cannot save file {assemblyName}.");
                    return ErrSave;
                }

                AssemblyDoc assemblyDoc = asmModel as AssemblyDoc;
                if (assemblyDoc == null)
                {
                    Debug.WriteLine("Create assembly failed: cast to AssemblyDoc failed.");
                    return ErrCreateDoc;
                }

                int insertedCount = 0;
                foreach (string partPath in partNames)
                {
                    if (string.IsNullOrWhiteSpace(partPath) || !File.Exists(partPath))
                    {
                        continue;
                    }

                    Component2 component = assemblyDoc.AddComponent5(partPath, 0, "", false, "", 0, 0, 0);
                    if (component == null)
                    {
                        Debug.WriteLine($"Create assembly warning: failed to insert part {partPath}");
                        continue;
                    }

                    insertedCount++;
                }

                if (insertedCount == 0)
                {
                    Debug.WriteLine("Create assembly failed: no parts inserted.");
                    return ErrInsert;
                }

                asmModel.ClearSelection2(true);
                asmModel.ShowNamedView2("*Isometric", (int)swStandardViews_e.swIsometricView);
                asmModel.ViewZoomtofit2();
                asmModel.EditRebuild3();
                asmModel.Save3((int)swSaveAsOptions_e.swSaveAsOptions_Silent, ref errors, ref warnings);

                return Ok;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Create_new_assembly.run failed: {ex.Message}");
                return ErrInsert;
            }
        }

        public static List<string> SplitBodiesToPartFiles(SldWorks swApp, ModelDoc2 sourcePartModel)
        {
            LastSplitErrorSummary = string.Empty;
            var result = new List<string>();
            if (swApp == null || sourcePartModel == null || sourcePartModel.GetType() != (int)swDocumentTypes_e.swDocPART)
            {
                LastSplitErrorSummary = "输入无效:当前文档不是零件或SolidWorks未初始化。";
                return result;
            }

            string sourcePath = sourcePartModel.GetPathName();
            if (string.IsNullOrWhiteSpace(sourcePath) || !File.Exists(sourcePath))
            {
                LastSplitErrorSummary = "源零件未保存或文件不存在。";
                return result;
            }

            PartDoc sourcePartDoc = sourcePartModel as PartDoc;
            if (sourcePartDoc == null)
            {
                LastSplitErrorSummary = "当前活动文档无法转换为 PartDoc。";
                return result;
            }

            object[] bodies = sourcePartDoc.GetBodies2((int)swBodyType_e.swSolidBody, true) as object[];
            if (bodies == null || bodies.Length == 0)
            {
                LastSplitErrorSummary = "未检测到可导出的实体(solid body)。";
                return result;
            }

            // ??????????????????
            if (bodies.Length == 1)
            {
                result.Add(sourcePath);
                return result;
            }

            string sourceTitle = sourcePartModel.GetTitle();
            string sourceName = SanitizeFileName(Path.GetFileNameWithoutExtension(sourcePath));
            string sourceDir = Path.GetDirectoryName(sourcePath) ?? string.Empty;
            string splitDir = Path.Combine(sourceDir, sourceName + "_split");
            Directory.CreateDirectory(splitDir);

            string partTemplate = ResolvePartTemplatePath(swApp);
            if (string.IsNullOrWhiteSpace(partTemplate) || !File.Exists(partTemplate))
            {
                Debug.WriteLine("Split body failed: part template not found.");
                LastSplitErrorSummary = "未找到零件模板(swDocPART)。";
                return result;
            }

            swApp.ActivateDoc3(sourceTitle, true, 0, 0);
            sourcePartModel = swApp.ActiveDoc as ModelDoc2 ?? sourcePartModel;
            sourcePartDoc = sourcePartModel as PartDoc ?? sourcePartDoc;

            int successCount = 0;
            int selectFailCount = 0;
            int exportFailCount = 0;
            string firstFailedBody = string.Empty;
            string firstFailedReason = string.Empty;

            foreach (object obj in bodies)
            {
                Body2 body = obj as Body2;
                if (body == null)
                {
                    continue;
                }

                string bodyName = string.IsNullOrWhiteSpace(body.Name) ? "Body" : body.Name;
                string safeBodyName = SanitizeFileName(bodyName);
                string targetPartPath = NormalizePathSafe(Path.Combine(splitDir, $"{sourceName}_{safeBodyName}.sldprt"));

                int suffix = 2;
                while (File.Exists(targetPartPath))
                {
                    targetPartPath = NormalizePathSafe(Path.Combine(splitDir, $"{sourceName}_{safeBodyName}_{suffix}.sldprt"));
                    suffix++;
                }

                swApp.ActivateDoc3(sourceTitle, true, 0, 0);
                sourcePartModel = swApp.ActiveDoc as ModelDoc2 ?? sourcePartModel;
                sourcePartDoc = sourcePartModel as PartDoc ?? sourcePartDoc;
                sourcePartModel.ClearSelection2(true);
                bool selected = sourcePartModel.Extension.SelectByID2(bodyName, "SOLIDBODY", 0, 0, 0, false, 0, null, 0);
                if (!selected)
                {
                    Entity bodyEntity = body as Entity;
                    selected = bodyEntity != null && bodyEntity.Select4(false, null);
                }
                if (!selected)
                {
                    object[] selectObjs = { body };
                    selected = sourcePartModel.Extension.MultiSelect2(selectObjs, false, null) == 1;
                }
                if (!selected)
                {
                    Debug.WriteLine($"Split body warning: cannot select body {bodyName}");
                    selectFailCount++;
                    if (string.IsNullOrWhiteSpace(firstFailedBody))
                    {
                        firstFailedBody = bodyName;
                        firstFailedReason = "实体选择失败";
                    }
                    continue;
                }

                bool inserted = ExportBodyToPartFile(swApp, sourcePartDoc, body, targetPartPath, partTemplate);
                sourcePartModel.ClearSelection2(true);
                swApp.ActivateDoc3(sourceTitle, true, 0, 0);

                if (inserted && File.Exists(targetPartPath))
                {
                    result.Add(targetPartPath);
                    successCount++;
                }
                else
                {
                    Debug.WriteLine($"Split body warning: failed to export body {bodyName} to {targetPartPath}");
                    exportFailCount++;
                    if (string.IsNullOrWhiteSpace(firstFailedBody))
                    {
                        firstFailedBody = bodyName;
                        firstFailedReason = "实体导出失败";
                    }
                }
            }

            if (result.Count == 0 && bodies.Length > 1)
            {
                LastSplitErrorSummary = string.IsNullOrWhiteSpace(firstFailedBody)
                    ? $"拆分失败:共 {bodies.Length} 个实体,全部导出失败。"
                    : $"拆分失败:共 {bodies.Length} 个实体,成功 0;首个失败实体={firstFailedBody},原因={firstFailedReason};选择失败={selectFailCount},导出失败={exportFailCount}。";
            }
            else
            {
                LastSplitErrorSummary = $"拆分统计:总实体={bodies.Length},成功={successCount},选择失败={selectFailCount},导出失败={exportFailCount}。";
            }

            return result;
        }

        private static string ResolveTemplatePath(string folderPath, string searchPattern)
        {
            if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
            {
                return string.Empty;
            }

            string[] files = Directory.GetFiles(folderPath, searchPattern, SearchOption.TopDirectoryOnly);
            if (files == null || files.Length == 0)
            {
                return string.Empty;
            }

            return files[0];
        }

        private static string ResolvePartTemplatePath(SldWorks swApp)
        {
            string[] candidatePaths =
            {
                @"C:\ProgramData\SolidWorks\SOLIDWORKS 2025\templates\零件.prtdot",
                @"C:\ProgramData\SOLIDWORKS\SOLIDWORKS 2025\templates\零件.prtdot",
                @"C:\ProgramData\SolidWorks\SOLIDWORKS 2025\templates\Part.prtdot",
                @"C:\ProgramData\SOLIDWORKS\SOLIDWORKS 2025\templates\Part.prtdot"
            };

            foreach (string candidate in candidatePaths)
            {
                if (File.Exists(candidate))
                {
                    return candidate;
                }
            }

            string[] candidateFolders =
            {
                @"C:\ProgramData\SolidWorks\SOLIDWORKS 2025\templates",
                @"C:\ProgramData\SOLIDWORKS\SOLIDWORKS 2025\templates"
            };

            foreach (string folder in candidateFolders)
            {
                if (!Directory.Exists(folder))
                {
                    continue;
                }

                string[] files = Directory.GetFiles(folder, "*.prtdot", SearchOption.TopDirectoryOnly);
                if (files == null || files.Length == 0)
                {
                    continue;
                }

                string zhPart = files.FirstOrDefault(f => Path.GetFileName(f).Contains("零件"));
                if (!string.IsNullOrWhiteSpace(zhPart))
                {
                    return zhPart;
                }

                string enPart = files.FirstOrDefault(f => Path.GetFileName(f).IndexOf("part", StringComparison.OrdinalIgnoreCase) >= 0);
                if (!string.IsNullOrWhiteSpace(enPart))
                {
                    return enPart;
                }

                return files[0];
            }

            string fromSw = swApp?.GetDocumentTemplate((int)swDocumentTypes_e.swDocPART, "", 0, 0, 0);
            if (!string.IsNullOrWhiteSpace(fromSw) && File.Exists(fromSw))
            {
                return fromSw;
            }

            return string.Empty;
        }

        private static bool ExportBodyToPartFile(SldWorks swApp, PartDoc sourcePartDoc, Body2 sourceBody, string targetPartPath, string partTemplate)
        {
            try
            {
                if (swApp == null || sourcePartDoc == null || sourceBody == null || string.IsNullOrWhiteSpace(targetPartPath) || string.IsNullOrWhiteSpace(partTemplate))
                {
                    return false;
                }

                if (!File.Exists(partTemplate))
                {
                    Debug.WriteLine("Split body failed: part template not found.");
                    return false;
                }

                int errors;
                int warnings;
                bool exported = sourcePartDoc.SaveToFile3(targetPartPath, 1, 1, false, partTemplate, out errors, out warnings);
                if (!exported)
                {
                    Debug.WriteLine($"Split body warning: SaveToFile3 failed. errors={errors}, warnings={warnings}, target={targetPartPath}, fallback=CreateFeatureFromBody3");
                    return ExportBodyByFeature(swApp, sourceBody, targetPartPath, partTemplate);
                }

                return File.Exists(targetPartPath);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"ExportBodyToPartFile failed: {ex.Message}");
                return false;
            }
        }

        private static bool ExportBodyByFeature(SldWorks swApp, Body2 sourceBody, string targetPartPath, string partTemplate)
        {
            try
            {
                ModelDoc2 newPartModel = swApp.NewDocument(partTemplate, 0, 0, 0) as ModelDoc2;
                if (newPartModel == null || newPartModel.GetType() != (int)swDocumentTypes_e.swDocPART)
                {
                    return false;
                }

                PartDoc newPartDoc = newPartModel as PartDoc;
                if (newPartDoc == null)
                {
                    return false;
                }

                object copiedObj = null;
                try
                {
                    copiedObj = sourceBody.Copy();
                }
                catch
                {
                    copiedObj = sourceBody;
                }

                if (copiedObj == null)
                {
                    return false;
                }

                Feature importedFeature = newPartDoc.CreateFeatureFromBody3(copiedObj, false, 0) as Feature;
                if (importedFeature == null)
                {
                    return false;
                }

                int saveResult = newPartModel.SaveAs3(targetPartPath, (int)swSaveAsOptions_e.swSaveAsOptions_Silent, 0);
                bool ok = saveResult != 0 && File.Exists(targetPartPath);

                string title = newPartModel.GetTitle();
                if (!string.IsNullOrWhiteSpace(title))
                {
                    swApp.CloseDoc(title);
                }

                return ok;
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"ExportBodyByFeature failed: {ex.Message}");
                return false;
            }
        }

        private static string SanitizeFileName(string rawName)
        {
            if (string.IsNullOrWhiteSpace(rawName))
            {
                return "Body";
            }

            string safe = rawName.Trim();
            foreach (char c in Path.GetInvalidFileNameChars())
            {
                safe = safe.Replace(c, '_');
            }
            safe = new string(safe.Where(ch => !char.IsControl(ch)).ToArray());

            return string.IsNullOrWhiteSpace(safe) ? "Body" : safe;
        }

        private static string NormalizePathSafe(string path)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                return path;
            }

            string root = Path.GetPathRoot(path) ?? string.Empty;
            string left = path.Substring(root.Length);
            string[] parts = left.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < parts.Length; i++)
            {
                parts[i] = SanitizeFileName(parts[i]);
            }

            string rebuilt = root;
            foreach (string p in parts)
            {
                rebuilt = string.IsNullOrWhiteSpace(rebuilt) ? p : Path.Combine(rebuilt, p);
            }

            return rebuilt;
        }
    }
}
相关推荐
何以解忧唯有撸码3 小时前
C# 视频录制监控系统
c#·winform
xiaoshuaishuai88 小时前
C# modbustcp的ack包通信延迟原因
网络·tcp/ip·c#
hixiong1239 小时前
使用C#自制一个截屏工具
c#
少控科技12 小时前
小数典应用:小诗典
windows·c#
wuyoula13 小时前
尹之盾企业版网络验证
服务器·开发语言·javascript·c++·人工智能·ui·c#
zdr尽职尽责13 小时前
Untiy 处理Aseprite 资产 解决偏移问题
学习·unity·c#·游戏引擎
步步为营DotNet14 小时前
.NET 11 与 C# 14 助力云原生应用安全架构升级
云原生·c#·.net
少控科技14 小时前
小数典应用:农场环境数据采集监控
开发语言·windows·c#
¥-oriented15 小时前
记录使用C#编程中遇到的一个小bug
c#·bug