solidworks c# 打标草图面和平板型式固定面不一致时自动翻转视图

csharp 复制代码
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using View = SolidWorks.Interop.sldworks.View;

namespace tools
{
    public class New_drw
    {
        private const string BendNoteFontName = "宋体";

        static public void run(SldWorks swApp, ModelDoc2 swModel, string? assemblyPath = null)
        {
            try
            {
                // 出图前始终执行 K 检查并修正折弯 K(与 exportdwg 一致;无论工程图是否已存在)
                checkk_factor.run(swApp, swModel);
                fix_bends_kcheck.Run(swApp, swModel);
                // 1058 圆弧折弯距:出图前对零件模型执行一次(仅违规弹窗)
                selected_view_arc_bend_clearance.runForPart(swApp, swModel);

                var partdoc = swModel;
                string fullpath = swModel.GetPathName();
                string partname = Path.GetFileNameWithoutExtension(fullpath);
                clear_thread_hole_near_countersink.Run(swModel, partname, "new_drw");

                // 与 BOM 一致:识别钣金厚度后写入零件「材料」自定义属性(SPPC/SUS + 厚度)
                var bomCat = asm2bom.ComputeBomStylePartCategory(partdoc, null, allowMaterialPropertyWrite: true, partname);
                checkk_factor.AlertNonStainlessIntegerPlateThicknessForNewDrw(swApp, partdoc);

                string drwpath = Path.ChangeExtension(fullpath, ".slddrw");
                 
                 // 检查工程图文件是否已存在
                 if (File.Exists(drwpath))
                 {
                     Console.WriteLine($"工程图已存在,直接打开:{drwpath}");
                     swApp.OpenDoc(drwpath, (int)swDocumentTypes_e.swDocDRAWING);
                     var existingDrawing = (ModelDoc2)swApp.ActiveDoc;
                     FixPanelBendDimIfNeeded(swApp, existingDrawing);
                     // 1060 折弯线端点检查:对已有工程图内全部平板型式视图各执行一次
                     if (existingDrawing != null)
                     {
                         selected_view_bend_line_endpoint_check.runForDrawingSheetMetalViews(
                             swApp, existingDrawing, appendAbortHint: false);
                     }

                     ReportPanelBendDimCheck(swApp, existingDrawing);
                     PartDrawingDimensionRecorder.Record(swApp, partdoc, bomCat, drwpath, "new_drw", assemblyPath);
                     return;
                 }
                 
                // SolidWorks 宿主下 AppContext.BaseDirectory 往往是 SW 安装目录,应用 share.dll 所在目录
                string? dllDir = Path.GetDirectoryName(typeof(New_drw).Assembly.Location);
                if (string.IsNullOrEmpty(dllDir))
                    dllDir = AppContext.BaseDirectory;
                string templatePath = Path.Combine(dllDir, "my_a4.drwdot");
                if (!File.Exists(templatePath))
                    templatePath = Path.Combine(dllDir, "my_a4.DRWDOT");
                Console.WriteLine($"工程图模板 DLL 目录: {dllDir}");
                Console.WriteLine($"工程图模板路径: {templatePath}");
                Console.WriteLine($"工程图模板文件存在: {File.Exists(templatePath)}");
                swApp.NewDocument(templatePath, 0, 0, 0);
               
               swModel = (ModelDoc2)swApp.ActiveDoc;
               swModel.Extension.SetUserPreferenceInteger((int)swUserPreferenceIntegerValue_e.swDetailingLinearDimPrecision,
                   (int)swUserPreferenceOption_e.swDetailingDimension, 1);
                  if (swModel.GetType() != (int)swDocumentTypes_e.swDocDRAWING)
                {
                    Console.WriteLine("错误:无法创建工程图");
                    return;
                }
                else
                {
                    ApplyDrawingDocumentFont(swModel, BendNoteFontName);
                    if (flat_pattern_export_sketch_filter.HasMarkingSketch(partdoc))
                    {
                        EnableDrawingDocumentShowSketches(swModel);
                    }
                    else
                    {
                        Console.WriteLine("零件无「打标」草图特征,跳过工程图显示草图设置");
                    }
         
                    
                        DrawingDoc drawingDoc = (DrawingDoc)swModel;
                      

                drawingDoc.GenerateViewPaletteViews(fullpath);
              
               var view1 = CreateLargestAreaModelView(swModel, drawingDoc, fullpath, 0.08, 0.10);
                if (view1 == null)
                {
                    Console.WriteLine("自动选主视图失败,回退到 *上视/*Top");
                    view1 = drawingDoc.CreateDrawViewFromModelView3(fullpath, "*上视", 0.08, 0.10, 0);
                    if (view1 == null) view1 = drawingDoc.CreateDrawViewFromModelView3(fullpath, "*Top", 0.08, 0.10, 0);
                }
                if (view1 == null)
                {
                    Console.WriteLine("主视图创建失败,终止当前工程图流程");
                    return;
                }
                 swModel.Extension.SelectByID2(view1.Name, "DRAWINGVIEW", 0, 0, 0, false, 0, null, 0);
                var view2 = drawingDoc.CreateUnfoldedViewAt3(0.20, 0.10, 0, false);
                            swModel.Extension.SelectByID2(view1.Name, "DRAWINGVIEW", 0, 0, 0, false, 0, null, 0);
                var view3 = drawingDoc.CreateUnfoldedViewAt3(0.08, 0.15, 0, false);

               ApplyDrawingViewDisplaySettings(swModel, drawingDoc, view1, "主视图");
               ApplyDrawingViewDisplaySettings(swModel, drawingDoc, view2, "展开视图1");
               ApplyDrawingViewDisplaySettings(swModel, drawingDoc, view3, "展开视图2");

               swModel.Extension.SelectByID2(view1.Name, "DRAWINGVIEW", 0, 0, 0, false, 0, null, 0);
              // 创建平板视图(view4),后续仅对这个视图内的注解改字体高度
              var view4 = drawingDoc.CreateFlatPatternViewFromModelView3(partdoc.GetPathName(), "", 0.20, 0.15, 0, false, false);
              Console.WriteLine(view4 == null ? "view4 创建失败" : $"view4 创建成功,名称:{view4.Name}");

              if (view4 != null)
              {
                  ApplyDrawingViewDisplaySettings(swModel, drawingDoc, view4, "平板型式");
                  drawingDoc.ActivateView(view4.Name);
                  swModel.ClearSelection2(true);
                  // 须在改折弯注释字号前 FlipView,否则 useDoc=false 会锁住「上」不随翻转更新
                  FixFlatPatternViewOrientationIfNeeded(swApp, swModel, partdoc);
                  FixPanelBendDimIfNeeded(swApp, swModel);
                  threadhol_dim.OnlyPrintFeatureTypeNames = false;
                  threadhol_dim.DimensionThreadHolesForDrawingView(swApp, view4);
                  selected_view_note_text_size.runForView(swApp, swModel, view4);
              }

              // 1040 选中视图标总长宽:对钣金视图(展开视图 + 平板型式)各执行一次
              if (view2 != null)
                  AddSizeDimensionForDrawing.runForView(swApp, swModel, view2);
              if (view3 != null)
                  AddSizeDimensionForDrawing.runForView(swApp, swModel, view3);
              if (view4 != null)
                  AddSizeDimensionForDrawing.runForView(swApp, swModel, view4);

              // 1060 折弯线端点检查:对全部平板型式视图各执行一次
              if (!selected_view_bend_line_endpoint_check.runForDrawingSheetMetalViews(
                      swApp, swModel, appendAbortHint: true))
              {
                  Console.WriteLine("折弯线端点检查未通过,跳过后续保存(工程图保持打开)。");
                  return;
              }
        
                     var boolstatus =
                swModel.Extension.SetUserPreferenceDouble((int)swUserPreferenceDoubleValue_e.swDetailingArrowWidth, 0,
                    0.002);
            boolstatus =
                swModel.Extension.SetUserPreferenceDouble((int)swUserPreferenceDoubleValue_e.swDetailingArrowHeight,
                    0, 0.0005);
            boolstatus =
                swModel.Extension.SetUserPreferenceDouble((int)swUserPreferenceDoubleValue_e.swDetailingArrowLength,
                    0, 0.0031);
            boolstatus =
                swModel.Extension.SetUserPreferenceToggle((int)swUserPreferenceToggle_e.swDetailingAutoInsertCenterMarksForHoles,
                    0, false);
            boolstatus =
                swModel.Extension.SetUserPreferenceToggle((int)swUserPreferenceToggle_e.swDetailingAutoInsertDowelSymbols,
                    0, false);
           swApp.SetUserPreferenceIntegerValue((int)swUserPreferenceIntegerValue_e.swDxfVersion, (int)swDxfFormat_e.swDxfFormat_R2000);
              Console.WriteLine("swDxfVersion:R2000");
               swModel.EditRebuild3();
              swModel.SaveAs3(drwpath, 0, 0);
  Console.WriteLine($"成功,已创建工程图{drwpath}");
              PartDrawingDimensionRecorder.Record(swApp, partdoc, bomCat, drwpath, "new_drw", assemblyPath);
              ReportPanelBendDimCheck(swApp, swModel);

                }
            
            
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误:{ex.Message}");
                Console.WriteLine("提示:请确保 SolidWorks 正在运行。");
            }
        }

        /// <summary>仅新建工程图流程:打标基准面与 FixedFace2 不一致时 FlipView 平板型式视图。</summary>
        static void FixFlatPatternViewOrientationIfNeeded(
            SldWorks swApp,
            ModelDoc2? drawingModel,
            ModelDoc2 partModel)
        {
            if (drawingModel == null)
            {
                return;
            }

            int flipped = flat_pattern_marking_view_flip.TryFixFlatPatternViewsForMarkingSketch(
                swApp, drawingModel, partModel);
            if (flipped > 0)
            {
                Console.WriteLine(
                    $"打标草图基准面与固定面不一致:已自动 FlipView 翻转 {flipped} 个平板型式视图");
            }
        }

        static void FixPanelBendDimIfNeeded(SldWorks swApp, ModelDoc2? drawingModel)
        {
            if (drawingModel == null)
            {
                return;
            }

            int flipped = panel_bend_dim_check.TryFixPanelBendShangByFlippingViews(swApp, drawingModel);
            if (flipped > 0)
            {
                Console.WriteLine($"面板折弯含「上」:已自动翻转 {flipped} 个工程图视图");
            }
        }

        static void ReportPanelBendDimCheck(SldWorks swApp, ModelDoc2? drawingModel)
        {
            if (drawingModel == null)
            {
                return;
            }

            if (panel_bend_dim_check.TryGetPanelBendDimShangError(drawingModel, out string errorMessage))
            {
                panel_bend_dim_check.ReportError(swApp, errorMessage);
            }
        }

        /// <summary>
        /// 仅修改指定视图中注解的文字高度,不影响全局文档偏好。
        /// </summary>
        private static void SetViewTextCharHeight(ModelDoc2 swModel, View? swView, double charHeight)
        {
            if (swView == null)
            {
                Console.WriteLine("SetViewTextCharHeight 终止:视图为空");
                return;
            }

            object[]? annotations = swView.GetAnnotations() as object[];
            if (annotations == null || annotations.Length == 0)
            {
                Console.WriteLine($"视图[{swView.Name}]没有可处理的注解");
                return;
            }

            Console.WriteLine($"开始处理视图[{swView.Name}]注解,数量:{annotations.Length},目标字高:{charHeight}");
            int successCount = 0;
            int skipCount = 0;
            int failCount = 0;

            foreach (object item in annotations)
            {
                if (item == null)
                {
                    skipCount++;
                    continue;
                }
                Annotation? annotation = item as Annotation;
                if (annotation == null)
                {
                    skipCount++;
                    continue;
                }

                try
                {
                    int annotationType = annotation.GetType();
                    string annotationTypeName = Enum.GetName(typeof(swAnnotationType_e), annotationType) ?? $"Unknown({annotationType})";
                    string annotationName = annotation.GetName();
                    string annotationText = GetAnnotationText(annotation);
                    Console.WriteLine($"注解信息 => 名称:[{annotationName}] 类型:[{annotationTypeName}] 文本:[{annotationText}]");

                    TextFormat? textFormat = annotation.GetTextFormat(0) as TextFormat;
                    if (textFormat == null)
                    {
                        skipCount++;
                        Console.WriteLine($"跳过注解[{annotation.GetName()}]:无法获取 TextFormat");
                        continue;
                    }

                    double oldHeight = textFormat.CharHeight;
                    int oldHeightPts = textFormat.CharHeightInPts;
                    string oldFontName = textFormat.TypeFaceName;
                    int targetPts = (int)Math.Round(charHeight * 1000.0 / 25.4 * 72.0); // 米 -> pt

                    textFormat.CharHeight = charHeight;
                    textFormat.CharHeightInPts = targetPts;
                    textFormat.TypeFaceName = BendNoteFontName;

                    bool useDocBefore = annotation.GetUseDocTextFormat(0);

                    // 严格按 API 说明:先 useDoc=true 且 TextFormat=null,再切回 useDoc=false
                    bool setDocOn = annotation.ISetTextFormat(0, true, null);
                    if (!setDocOn)
                    {
                        setDocOn = annotation.SetTextFormat(-1, true, null);
                    }

                    bool rewriteNoteOk = false;
                    if (annotationType == (int)swAnnotationType_e.swNote)
                    {
                        Note? note = annotation.GetSpecificAnnotation() as Note;
                        if (note != null)
                        {
                            string noteText = note.GetText() ?? string.Empty;
                            rewriteNoteOk = note.SetText(noteText);
                        }
                    }

                    bool setAllOk = annotation.ISetTextFormat(0, false, textFormat);
                    if (!setAllOk)
                    {
                        setAllOk = annotation.SetTextFormat(-1, false, textFormat);
                    }

                    bool setFirstOk = annotation.SetTextFormat(0, false, textFormat);
                    bool setOk = setAllOk || setFirstOk;
                    bool useDocAfter = annotation.GetUseDocTextFormat(0);
                    Console.WriteLine(
                        $"SetTextFormat结果[{annotationTypeName}]:useDoc[{useDocBefore}->{useDocAfter}] doc=true[{setDocOn}] -> doc=false[-1:{setAllOk},0:{setFirstOk}] rewriteNote[{rewriteNoteOk}],字体:{oldFontName}->{BendNoteFontName}");

                    if (annotationType == (int)swAnnotationType_e.swDisplayDimension)
                    {
                        DisplayDimension? displayDimension = annotation.GetSpecificAnnotation() as DisplayDimension;
                        if (displayDimension != null)
                        {
                            // 关闭尺寸引出线"使用文档设置",避免仍然继承文档线型
                            bool setExtLineStyleOk = displayDimension.SetLineFontExtensionStyle(false, 0);
                            Console.WriteLine($"DisplayDimension 引出线样式设置:useDoc=false, style=0, 结果={setExtLineStyleOk}");
                        }
                    }

                    Console.WriteLine(
                        $"应用字高[{annotationName}] SetTextFormat={setOk}, CharHeight:{oldHeight:F6}->{charHeight:F6}, CharHeightInPts:{oldHeightPts}->{targetPts}");
                    successCount++;
                }
                catch (Exception ex)
                {
                    failCount++;
                    Console.WriteLine($"设置视图注解文字高度失败:{ex.Message}");
                }
            }

            Console.WriteLine($"视图[{swView.Name}]文字高度处理完成:成功 {successCount},跳过 {skipCount},失败 {failCount}");
        }

        /// <summary>
        /// 尽可能提取注解文本,便于在输出窗排查目标注解。
        /// </summary>
        private static string GetAnnotationText(Annotation annotation)
        {
            if (annotation == null) return "<null>";

            try
            {
                int annotationType = annotation.GetType();
                if (annotationType == (int)swAnnotationType_e.swDisplayDimension)
                {
                    DisplayDimension? displayDimension = annotation.GetSpecificAnnotation() as DisplayDimension;
                    if (displayDimension == null) return "<displayDimension:null>";

                    string prefix = displayDimension.GetText((int)swDimensionTextParts_e.swDimensionTextPrefix) ?? "";
                    string calloutAbove = displayDimension.GetText((int)swDimensionTextParts_e.swDimensionTextCalloutAbove) ?? "";
                    string calloutBelow = displayDimension.GetText((int)swDimensionTextParts_e.swDimensionTextCalloutBelow) ?? "";
                    string suffix = displayDimension.GetText((int)swDimensionTextParts_e.swDimensionTextSuffix) ?? "";

                    string dimText = $"{prefix} {calloutAbove} {calloutBelow} {suffix}".Trim();
                    return string.IsNullOrWhiteSpace(dimText) ? "<displayDimension:empty>" : dimText;
                }

                Note? note = annotation.GetSpecificAnnotation() as Note;
                if (note != null)
                {
                    string noteText = note.GetText() ?? "";
                    return string.IsNullOrWhiteSpace(noteText) ? "<note:empty>" : noteText;
                }

                return "<该类型暂不支持直接读取文本>";
            }
            catch (Exception ex)
            {
                return $"<读取文本失败:{ex.Message}>";
            }
        }

        private static void ApplyDrawingDocumentFont(ModelDoc2 swModel, string fontName)
        {
            try
            {
                TextFormat? noteFormat = swModel.GetUserPreferenceTextFormat((int)swUserPreferenceTextFormat_e.swDetailingNoteTextFormat) as TextFormat;
                if (noteFormat != null)
                {
                    noteFormat.TypeFaceName = fontName;
                    bool noteOk = swModel.SetUserPreferenceTextFormat((int)swUserPreferenceTextFormat_e.swDetailingNoteTextFormat, noteFormat);
                    Console.WriteLine($"文档Note字体设置:{fontName},结果={noteOk}");
                }

                TextFormat? dimFormat = swModel.GetUserPreferenceTextFormat((int)swUserPreferenceTextFormat_e.swDetailingDimensionTextFormat) as TextFormat;
                if (dimFormat != null)
                {
                    dimFormat.TypeFaceName = fontName;
                    bool dimOk = swModel.SetUserPreferenceTextFormat((int)swUserPreferenceTextFormat_e.swDetailingDimensionTextFormat, dimFormat);
                    Console.WriteLine($"文档Dimension字体设置:{fontName},结果={dimOk}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"设置文档字体失败:{ex.Message}");
            }
        }

        /// <summary>工程图文档级:显示草图(与零件中可见草图一致,供各视图 ResetSketchVisibility 同步)。</summary>
        private static void EnableDrawingDocumentShowSketches(ModelDoc2 drwModel)
        {
            try
            {
                bool docToggle = drwModel.SetUserPreferenceToggle((int)swUserPreferenceToggle_e.swDisplaySketches, true);
                bool extToggle = drwModel.Extension.SetUserPreferenceToggle(
                    (int)swUserPreferenceToggle_e.swDisplaySketches, 0, true);
                Console.WriteLine($"工程图文档显示草图:SetUserPreferenceToggle={docToggle}, Extension={extToggle}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"工程图文档显示草图设置失败:{ex.Message}");
            }
        }

        /// <summary>为单个工程图视图设置隐藏线可见(HLV)显示模式,并重置草图可见性以反映模型。</summary>
        private static void ApplyDrawingViewDisplaySettings(
            ModelDoc2 drwModel,
            DrawingDoc drawingDoc,
            View? view,
            string logTag)
        {
            if (view == null)
            {
                return;
            }

            try
            {
                drawingDoc.ActivateView(view.Name);
                drwModel.ClearSelection2(true);
                drwModel.Extension.SelectByID2(view.Name, "DRAWINGVIEW", 0, 0, 0, false, 0, null, 0);

                int modeBefore = view.GetDisplayMode();
                if (modeBefore != 3)
                {
                    view.SetDisplayMode3(false, (int)swDisplayMode_e.swFACETED_HIDDEN_GREYED, false, true);
                }

                view.ResetSketchVisibility();
                Console.WriteLine(
                    $"[{logTag}] 视图 {view.Name}:DisplayMode {modeBefore}->{view.GetDisplayMode()},已 ResetSketchVisibility");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[{logTag}] 视图 {view.Name} 显示设置失败:{ex.Message}");
            }
        }

        /// <summary>
        /// 在若干候选方向中创建并比较视图外框面积,保留面积最大的视图作为主视图。
        /// 机加工程图 <see cref="New_drw_cnc"/> 与钣金共用同一套主视图选取逻辑。
        /// </summary>
        internal static View? CreateLargestAreaModelView(ModelDoc2 swModel, DrawingDoc drawingDoc, string modelPath, double x, double y)
        {
            // 常规只在三个主方向中选主视图,兼顾速度与稳定性
            string[] candidateNames = new[]
            {
                "*前视", "*Front",
                "*上视", "*Top",
                "*右视", "*Right"
            }.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();

            View? bestView = null;
            double bestArea = -1.0;

            foreach (string viewName in candidateNames)
            {
                View? currentView = drawingDoc.CreateDrawViewFromModelView3(modelPath, viewName, x, y, 0);
                if (currentView == null) continue;

                double currentArea = GetViewOutlineArea(currentView);
                Console.WriteLine($"候选视图[{viewName}] 面积={currentArea:F6}");

                if (currentArea > bestArea)
                {
                    if (bestView != null)
                    {
                        DeleteDrawingView(swModel, bestView);
                    }
                    bestView = currentView;
                    bestArea = currentArea;
                }
                else
                {
                    DeleteDrawingView(swModel, currentView);
                }
            }

            if (bestView != null)
            {
                Console.WriteLine($"主视图选择结果:{bestView.Name},面积={bestArea:F6}");
            }

            return bestView;
        }

        private static double GetViewOutlineArea(View view)
        {
            try
            {
                double[]? outline = view.GetOutline() as double[];
                if (outline == null || outline.Length < 4) return 0.0;

                double width = Math.Abs(outline[2] - outline[0]);
                double height = Math.Abs(outline[3] - outline[1]);
                return width * height;
            }
            catch
            {
                return 0.0;
            }
        }

        private static void DeleteDrawingView(ModelDoc2 swModel, View view)
        {
            try
            {
                bool selected = swModel.Extension.SelectByID2(view.Name, "DRAWINGVIEW", 0, 0, 0, false, 0, null, 0);
                if (selected)
                {
                    swModel.EditDelete();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"删除视图[{view.Name}]失败:{ex.Message}");
            }
        }

    }
}