diff --git a/Cad/TemplateDrawingService.cs b/Cad/TemplateDrawingService.cs index 0612246..f966326 100644 --- a/Cad/TemplateDrawingService.cs +++ b/Cad/TemplateDrawingService.cs @@ -897,6 +897,167 @@ namespace CadParamPluging.Cad return string.Join(" ", parts); } + public static int ApplyFeatureCategory(CadContext ctx, string layoutName, bool scanModelSpace, ParamBag bag) + { + if (ctx == null || bag == null) + { + return 0; + } + + var category = bag.GetString("FeatureCategory"); + + // Logic: Is "一般件" -> show blank. + // Is "关键件"/"重要件" -> show text. + + var textToShow = category; + if (string.IsNullOrWhiteSpace(textToShow) || string.Equals(textToShow, "一般件", StringComparison.OrdinalIgnoreCase)) + { + textToShow = string.Empty; // Show blank + } + + var db = ctx.Database; + var tr = ctx.Transaction; + var space = GetTargetSpace(tr, db, layoutName, scanModelSpace); + + if (space == null) return 0; + + int count = 0; + foreach (ObjectId id in space) + { + var ent = tr.GetObject(id, OpenMode.ForWrite, false) as Entity; + if (ent == null) continue; + + if (ent is DBText t) + { + if (t.TextString.Contains("******")) + { + t.TextString = t.TextString.Replace("******", textToShow); + count++; + } + } + else if (ent is MText mt) + { + if (mt.Contents.Contains("******")) + { + mt.Contents = mt.Contents.Replace("******", textToShow); + count++; + } + } + else if (ent is BlockReference br) + { + foreach (ObjectId attId in br.AttributeCollection) + { + var att = tr.GetObject(attId, OpenMode.ForWrite, false) as AttributeReference; + if (att != null && att.TextString.Contains("******")) + { + att.TextString = att.TextString.Replace("******", textToShow); + count++; + } + } + } + } + + // Fallback: If no placeholder found AND we have text to show (e.g. "关键件"), create it manually. + if (count == 0 && !string.IsNullOrWhiteSpace(textToShow)) + { + // Try to find white frame to determine position + var spaceEntList = space.Cast() + .Select(id => + { + try { return tr.GetObject(id, OpenMode.ForRead, false) as Entity; } + catch { return null; } + }) + .Where(e => e != null && !e.IsErased) + .ToList(); + + var frame = ComputeWhiteFrameExtentsFromEntities(tr, spaceEntList); + if (frame.HasValue) + { + var f = frame.Value; + + // Strategy: + // 1. Align Right: Use f.MaxX as the right boundary anchor. + // 2. Find Table Top: Look for horizontal lines in the bottom-right quadrant to find the top of the title block. + // If found, place text above that line. If not, use a safe default from bottom. + + var searchRegionMinX = f.MaxPoint.X - 200.0; // Assume title block width < 200 + var searchRegionMinY = f.MinPoint.Y; + var searchRegionMaxY = f.MinPoint.Y + 150.0; // Assume title block height < 150 + + double tableTopY = f.MinPoint.Y + 60.0; // Default fallback (e.g. 60mm from bottom) + + // Scan lines to find the highest horizontal line in this region which represents the table top + var candidatesY = new List(); + foreach (var ent in spaceEntList) + { + if (ent is Line ln) + { + if (ln.StartPoint.X > searchRegionMinX && ln.EndPoint.X > searchRegionMinX && + ln.StartPoint.Y > searchRegionMinY && ln.StartPoint.Y < searchRegionMaxY && + Math.Abs(ln.StartPoint.Y - ln.EndPoint.Y) < 1.0) // Horizontal + { + candidatesY.Add(ln.StartPoint.Y); + } + } + else if (ent is Polyline pl) + { + for (int i = 0; i < pl.NumberOfVertices; i++) + { + var pt = pl.GetPoint3dAt(i); + if (pt.X > searchRegionMinX && pt.Y > searchRegionMinY && pt.Y < searchRegionMaxY) + { + candidatesY.Add(pt.Y); + } + } + } + } + + if (candidatesY.Count > 0) + { + // The "Title Block" usually consists of many lines. + // We want the top-most line of the block, but "below" the drawing area. + // Let's take the max Y found in that bottom-right corner zone. + tableTopY = candidatesY.Max(); + } + + // Position: + // X: f.MaxX - 5 (margin) - (TextWidth/2 treated by Attachment) => Let's use TopRight or MiddleRight alignment + // Anchor at f.MaxX - 2.0 (small margin from right border line) + // Y: tableTopY + 2.0 (small gap above the table line) + // Anchor BottomRight or BottomLeft? + // User image shows text centered in a box-like area ABOVE the table rows. + // Let's align BottomRight to (MaxX - margin, TableTop + margin) + + var insertX = f.MaxPoint.X - 5.0; + var insertY = tableTopY + 2.0; + var insertPoint = new Point3d(insertX, insertY, 0); + + var mt = new MText(); + mt.Contents = ToMTextContents(textToShow); + mt.Location = insertPoint; + mt.TextHeight = 5.0; + mt.Attachment = AttachmentPoint.BottomRight; // Anchor at bottom-right, grows up and left + mt.Width = 0; // No wrap width, auto + mt.ColorIndex = 7; + + try + { + var layerTbl = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead); + if (layerTbl.Has("TEXT")) mt.Layer = "TEXT"; + else if (layerTbl.Has("文字")) mt.Layer = "文字"; + else mt.Layer = "0"; + } + catch { mt.Layer = "0"; } + + space.AppendEntity(mt); + tr.AddNewlyCreatedDBObject(mt, true); + count++; + } + } + + return count; + } + public static void KeepOnlyLayout(Document doc, string layoutName) { if (doc == null) diff --git a/Common/ParamCatalog.cs b/Common/ParamCatalog.cs index 85f2e9a..14e38c2 100644 --- a/Common/ParamCatalog.cs +++ b/Common/ParamCatalog.cs @@ -76,12 +76,12 @@ namespace CadParamPluging.Common Key = "FeatureCategory", Label = "特性分类", Type = ParamValueType.Enum, - Required = false, + Required = true, DefaultValue = "一般件", EnumOptions = new List { "一般件", "关键件", "重要件" }, Hint = "下拉列表(一般件/关键件/重要件),点选;关键件/重要件需加方框标注", Order = 110, - Group = "备注参数" + Group = "模板参数" }, new ParamDefinition { diff --git a/UI/ParamDrawingPanel.cs b/UI/ParamDrawingPanel.cs index a1e73c7..35d18e4 100644 --- a/UI/ParamDrawingPanel.cs +++ b/UI/ParamDrawingPanel.cs @@ -608,6 +608,16 @@ namespace CadParamPluging.UI AppendLog($"已移除模板匹配参数标注文本: {removed} 处"); } + var featureCategoryCount = TemplateDrawingService.ApplyFeatureCategory( + ctx, + _selectedTemplate.LayoutName, + _selectedModelWindow.HasValue, + bag); + if (featureCategoryCount > 0) + { + AppendLog($"已更新特性分类(******): {featureCategoryCount} 处"); + } + var noteResult = TemplateDrawingService.ApplyNoteTemplate( ctx, _selectedTemplate.LayoutName,