CadParamPluging/UI/ParamDrawingPanel.cs

950 lines
36 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using CadParamPluging.Cad;
using CadParamPluging.Common;
using CadParamPluging.Domain;
using CadParamPluging.Domain.Models;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace CadParamPluging.UI
{
public class ParamDrawingPanel : UserControl
{
private readonly ComboBox _cbProjectType;
private readonly ComboBox _cbDrawingType;
private readonly ComboBox _cbSheetSize;
private readonly ComboBox _cbScale;
private Label _lblTemplateInfo;
private TextBox _txtLog;
private TextBox _txtTemplatePath;
private string _selectedFolderPath;
private string[] _cadFilePaths = new string[0];
private TemplateInfo _selectedTemplate;
private Extents3d? _selectedModelWindow;
private string _selectedSheetName;
public ParamDrawingPanel()
{
Dock = DockStyle.Fill;
var dropdownOptions = DropdownOptionsStore.Load();
var layout = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 1,
RowCount = 4,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink,
Padding = new Padding(8)
};
_cbProjectType = CreateComboBox(dropdownOptions.DeliveryStatuses);
_cbDrawingType = CreateComboBox(dropdownOptions.ProcessMethods);
_cbSheetSize = CreateComboBox(dropdownOptions.StructuralFeatures);
_cbScale = CreateComboBox(dropdownOptions.SpecialConditions);
var templateGroup = BuildTemplateGroup();
var drawingGroup = BuildDrawingGroup();
var actionPanel = BuildActionPanel();
var logGroup = BuildLogGroup();
layout.Controls.Add(templateGroup, 0, 0);
layout.Controls.Add(drawingGroup, 0, 1);
layout.Controls.Add(actionPanel, 0, 2);
layout.Controls.Add(logGroup, 0, 3);
Controls.Add(layout);
}
private GroupBox BuildTemplateGroup()
{
var group = new GroupBox
{
Text = "模板参数",
Dock = DockStyle.Top,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink
};
var grid = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = 2,
RowCount = 6,
AutoSize = true
};
grid.Controls.Add(new Label { Text = "交付状态", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 0);
grid.Controls.Add(_cbProjectType, 1, 0);
grid.Controls.Add(new Label { Text = "工艺方法", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 1);
grid.Controls.Add(_cbDrawingType, 1, 1);
grid.Controls.Add(new Label { Text = "结构特征", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 2);
grid.Controls.Add(_cbSheetSize, 1, 2);
grid.Controls.Add(new Label { Text = "特殊条件", AutoSize = true, TextAlign = ContentAlignment.MiddleLeft }, 0, 3);
grid.Controls.Add(_cbScale, 1, 3);
var btnSelect = new Button { Text = "选择路径", AutoSize = true };
btnSelect.Click += (_, __) => OnSelectTemplate();
_txtTemplatePath = new TextBox { Width = 160, ReadOnly = true };
grid.Controls.Add(btnSelect, 0, 4);
grid.Controls.Add(_txtTemplatePath, 1, 4);
var btnMatch = new Button { Text = "匹配模板", AutoSize = true };
btnMatch.Click += (_, __) => OnMatchTemplate();
_lblTemplateInfo = new Label
{
Text = "未匹配模板",
AutoSize = true,
ForeColor = Color.DarkBlue,
TextAlign = ContentAlignment.MiddleLeft
};
grid.Controls.Add(btnMatch, 0, 5);
grid.Controls.Add(_lblTemplateInfo, 1, 5);
group.Controls.Add(grid);
return group;
}
private GroupBox BuildDrawingGroup()
{
var group = new GroupBox
{
Text = "出图参数",
Dock = DockStyle.Top,
AutoSize = true,
AutoSizeMode = AutoSizeMode.GrowAndShrink
};
var label = new Label
{
AutoSize = true,
Padding = new Padding(8),
Text = "出图参数较多,请点击【生成图纸】后在弹窗中填写。"
};
group.Controls.Add(label);
return group;
}
private FlowLayoutPanel BuildActionPanel()
{
var panel = new FlowLayoutPanel
{
Dock = DockStyle.Top,
AutoSize = true
};
var btnGenerate = new Button { Text = "生成图纸", AutoSize = true };
btnGenerate.Click += (_, __) => OnGenerateDrawing();
var btnSaveAs = new Button { Text = "保存当前图纸", AutoSize = true };
btnSaveAs.Click += (_, __) => OnSaveDrawing();
var btnSettings = new Button { Text = "设置", AutoSize = true };
btnSettings.Click += (_, __) => OnOpenSettings();
var btnTestDraw = new Button { Text = "测试绘制", AutoSize = true };
btnTestDraw.Click += (_, __) => OnTestDraw();
panel.Controls.Add(btnGenerate);
panel.Controls.Add(btnSaveAs);
panel.Controls.Add(btnSettings);
panel.Controls.Add(btnTestDraw);
return panel;
}
private GroupBox BuildLogGroup()
{
var group = new GroupBox
{
Text = "日志",
Dock = DockStyle.Fill
};
_txtLog = new TextBox
{
Multiline = true,
ScrollBars = ScrollBars.Vertical,
Dock = DockStyle.Fill,
Height = 140
};
group.Controls.Add(_txtLog);
return group;
}
private void OnMatchTemplate()
{
try
{
if (_cadFilePaths == null || _cadFilePaths.Length == 0)
{
AppendLog("请先选择路径。");
return;
}
AppendLog("开始匹配模板...");
var tplParams = CollectTemplateParams();
foreach (var cadPath in _cadFilePaths)
{
if (string.IsNullOrWhiteSpace(cadPath) || !File.Exists(cadPath))
{
continue;
}
// 1) 优先按 Layout(PaperSpace) 匹配
var layoutCandidates = TemplateLayoutAnnotationExtractor.ExtractPerLayout(cadPath);
var layoutMatch = layoutCandidates.FirstOrDefault(c => LayoutMatches(c, tplParams));
if (layoutMatch != null)
{
_selectedTemplate = new TemplateInfo
{
Name = Path.GetFileName(cadPath),
FilePath = cadPath
};
_selectedTemplate.LayoutName = layoutMatch.LayoutName;
_selectedModelWindow = null;
_selectedSheetName = layoutMatch.LayoutName;
_lblTemplateInfo.Text = $"{cadPath} | {layoutMatch.LayoutName}";
AppendLog($"匹配成功: {Path.GetFileName(cadPath)} | Layout: {layoutMatch.LayoutName}");
return;
}
// 2) Layout 未命中时,尝试按 ModelSpace 窗口候选匹配
var modelCandidates = TemplateModelSheetExtractor.ExtractCandidates(cadPath);
var modelMatch = modelCandidates.FirstOrDefault(c => ModelMatches(c, tplParams));
if (modelMatch != null)
{
_selectedTemplate = new TemplateInfo
{
Name = Path.GetFileName(cadPath),
FilePath = cadPath
};
_selectedTemplate.LayoutName = null;
_selectedModelWindow = modelMatch.Window;
_selectedSheetName = modelMatch.Name;
_lblTemplateInfo.Text = $"{cadPath} | {modelMatch.Name}";
AppendLog($"匹配成功: {Path.GetFileName(cadPath)} | Model: {modelMatch.Name}");
return;
}
}
_selectedTemplate = null;
_selectedModelWindow = null;
_selectedSheetName = null;
_lblTemplateInfo.Text = "未匹配模板";
AppendLog("未找到匹配模板。");
}
catch (BusinessException bex)
{
if (_selectedTemplate != null)
{
_selectedTemplate.LayoutName = null;
}
_selectedModelWindow = null;
_selectedSheetName = null;
_lblTemplateInfo.Text = _selectedTemplate?.FilePath ?? "未匹配图纸";
AppendLog($"图纸匹配错误: {bex.Message}");
}
catch (Exception ex)
{
if (_selectedTemplate != null)
{
_selectedTemplate.LayoutName = null;
}
_selectedModelWindow = null;
_selectedSheetName = null;
_lblTemplateInfo.Text = _selectedTemplate?.FilePath ?? "未匹配图纸";
AppendLog($"匹配失败: {ex.Message}");
Logger.Error("MatchLayout", ex);
}
}
private static bool LayoutMatches(LayoutAnnotation ann, TemplateParams tplParams)
{
if (ann == null || tplParams == null)
{
return false;
}
return ContainsIgnoreCase(ann.DeliveryStatuses, tplParams.ProjectType)
&& ContainsIgnoreCase(ann.ProcessMethods, tplParams.DrawingType)
&& ContainsIgnoreCase(ann.StructuralFeatures, tplParams.SheetSize)
&& ContainsIgnoreCase(ann.SpecialConditions, tplParams.Scale);
}
private static bool ContainsIgnoreCase(System.Collections.Generic.IEnumerable<string> values, string expected)
{
if (string.IsNullOrWhiteSpace(expected))
{
return true;
}
if (values == null)
{
return false;
}
var exp = NormalizeValue(expected);
return values.Any(v => string.Equals(NormalizeValue(v), exp, StringComparison.OrdinalIgnoreCase));
}
private static string NormalizeValue(string s)
{
if (string.IsNullOrWhiteSpace(s))
{
return string.Empty;
}
var trimmed = s.Trim();
var chars = trimmed.Where(c => !char.IsWhiteSpace(c)).ToArray();
return new string(chars);
}
private static string Preview(System.Collections.Generic.IEnumerable<string> values)
{
if (values == null)
{
return "(无)";
}
var arr = values.Where(v => !string.IsNullOrWhiteSpace(v)).Select(v => v.Trim()).ToArray();
return arr.Length == 0 ? "(无)" : string.Join("/", arr);
}
private static bool ModelMatches(ModelSheetCandidate ann, TemplateParams tplParams)
{
if (ann == null || tplParams == null)
{
return false;
}
return ContainsIgnoreCase(ann.DeliveryStatuses, tplParams.ProjectType)
&& ContainsIgnoreCase(ann.ProcessMethods, tplParams.DrawingType)
&& ContainsIgnoreCase(ann.StructuralFeatures, tplParams.SheetSize)
&& ContainsIgnoreCase(ann.SpecialConditions, tplParams.Scale);
}
private void OnSelectTemplate()
{
try
{
using (var dialog = new FolderBrowserDialog())
{
dialog.Description = "选择包含 CAD 文件的文件夹";
if (!string.IsNullOrWhiteSpace(_selectedFolderPath) && Directory.Exists(_selectedFolderPath))
{
dialog.SelectedPath = _selectedFolderPath;
}
if (dialog.ShowDialog(this) == DialogResult.OK)
{
var folderPath = dialog.SelectedPath;
if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
{
AppendLog("选择路径无效。");
return;
}
_selectedFolderPath = folderPath;
_txtTemplatePath.Text = folderPath;
_cadFilePaths = LoadCadFilesFromFolder(folderPath);
AppendLog($"已选择路径: {folderPath}");
AppendLog($"检测到 CAD 文件数量: {_cadFilePaths.Length}");
foreach (var p in _cadFilePaths.Take(10))
{
AppendLog($"- {Path.GetFileName(p)}");
}
if (_cadFilePaths.Length > 10)
{
AppendLog($"... 还有 {_cadFilePaths.Length - 10} 个文件");
}
}
}
}
catch (Exception ex)
{
AppendLog($"选择路径失败: {ex.Message}");
Logger.Error("SelectCadFolder", ex);
}
}
private static string[] LoadCadFilesFromFolder(string folderPath)
{
if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
{
return new string[0];
}
var patterns = new[] { "*.dwg", "*.dwt", "*.dxf" };
return patterns
.SelectMany(p => Directory.EnumerateFiles(folderPath, p, SearchOption.TopDirectoryOnly))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase)
.ToArray();
}
private void TryReplaceDropdownOptionsFromTemplate(string templatePath)
{
try
{
var result = TemplateAnnotationOptionsExtractor.Extract(templatePath);
var options = result?.Options;
if (options == null || !HasAnyOptions(options))
{
AppendLog("未从模板标注解析到参数,下拉列表不变。");
return;
}
AppendLog("已从模板标注解析到参数,询问是否替换下拉设置。");
var preview = BuildOptionsPreview(options, 5);
var confirm = MessageBox.Show(
this,
$"检测到模板参数(去重后):\n\n{preview}\n\n是否用模板参数替换当前下拉列表并保存\n特殊条件不从模板解析将保持当前设置",
"模板参数",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (confirm != DialogResult.Yes)
{
AppendLog("用户取消替换下拉设置。");
return;
}
var current = DropdownOptionsStore.Load();
var updated = (current ?? DropdownOptions.CreateDefault()).Clone();
if (options.DeliveryStatuses != null && options.DeliveryStatuses.Count > 0)
{
updated.DeliveryStatuses = options.DeliveryStatuses.ToList();
}
if (options.ProcessMethods != null && options.ProcessMethods.Count > 0)
{
updated.ProcessMethods = options.ProcessMethods.ToList();
}
if (options.StructuralFeatures != null && options.StructuralFeatures.Count > 0)
{
updated.StructuralFeatures = options.StructuralFeatures.ToList();
}
updated.Normalize();
DropdownOptionsStore.Save(updated);
ReloadDropdownOptions(updated);
AppendLog("已从模板替换下拉设置并保存。");
}
catch (Exception ex)
{
AppendLog($"模板解析/替换失败: {ex.Message}");
Logger.Error("TemplateDropdownOptions", ex);
}
}
private static bool HasAnyOptions(DropdownOptions options)
{
return options != null
&& ((options.DeliveryStatuses != null && options.DeliveryStatuses.Count > 0)
|| (options.ProcessMethods != null && options.ProcessMethods.Count > 0)
|| (options.StructuralFeatures != null && options.StructuralFeatures.Count > 0));
}
private static string BuildOptionsPreview(DropdownOptions options, int maxPerField)
{
return string.Join(
Environment.NewLine,
new[]
{
$"交付状态: {PreviewValues(options?.DeliveryStatuses, maxPerField)}",
$"工艺方法: {PreviewValues(options?.ProcessMethods, maxPerField)}",
$"结构特征: {PreviewValues(options?.StructuralFeatures, maxPerField)}"
});
}
private static string PreviewValues(System.Collections.Generic.IEnumerable<string> values, int max)
{
if (values == null)
{
return "(无)";
}
var arr = values.Where(v => !string.IsNullOrWhiteSpace(v)).Select(v => v.Trim()).ToArray();
if (arr.Length == 0)
{
return "(无)";
}
if (arr.Length <= max)
{
return string.Join(", ", arr);
}
return string.Join(", ", arr.Take(max)) + $" ... (共 {arr.Length} 项)";
}
private void OnGenerateDrawing()
{
try
{
var tplParams = CollectTemplateParams();
if (_selectedTemplate == null || string.IsNullOrWhiteSpace(_selectedTemplate.FilePath))
{
AppendLog("请先选择路径并匹配模板。");
return;
}
if (string.IsNullOrWhiteSpace(_selectedTemplate.LayoutName) && !_selectedModelWindow.HasValue)
{
AppendLog("未匹配图纸,尝试自动匹配...");
OnMatchTemplate();
if (_selectedTemplate == null || (string.IsNullOrWhiteSpace(_selectedTemplate.LayoutName) && !_selectedModelWindow.HasValue))
{
return;
}
}
var templateKey = TemplateKeyBuilder.Build(tplParams);
if (string.IsNullOrWhiteSpace(templateKey))
{
AppendLog("模板参数不完整,无法生成 TemplateKey。");
return;
}
var schemas = TemplateSchemaStore.Load();
var schema = (schemas?.Items ?? Enumerable.Empty<TemplateSchemaDefinition>())
.FirstOrDefault(s => string.Equals(s.TemplateKey, templateKey, StringComparison.OrdinalIgnoreCase));
if (schema == null)
{
AppendLog($"未找到该模板的参数绑定配置TemplateKey={templateKey})。请到【设置→模板参数绑定】中新增/配置。");
return;
}
var catalog = ParamCatalogStore.Load();
CadParamPluging.Common.ParamBag bag;
using (var f = new DrawingParamsForm(catalog, schema))
{
var r = f.ShowDialog(this);
if (r != DialogResult.OK)
{
AppendLog("用户取消填写参数。");
return;
}
bag = f.Result;
}
// Current demo generator uses a rectangle. Size defaults are handled inside DomainFacade.DrawByParams.
// Real templates will use their own generator/parameters.
var drawingParams = new DrawingParams();
DomainFacade.ValidateParameters(tplParams, drawingParams);
var doc = TemplateDrawingService.CreateDocumentFromTemplate(_selectedTemplate);
if (_selectedModelWindow.HasValue)
{
TemplateDrawingService.KeepOnlyModelWindow(doc, _selectedModelWindow.Value);
}
else
{
TemplateDrawingService.KeepOnlyLayout(doc, _selectedTemplate.LayoutName);
}
AppendLog($"已生成图纸窗口,并仅保留图纸: {_selectedSheetName ?? _selectedTemplate.LayoutName}");
using (doc.LockDocument())
using (var ctx = new CadContext(doc))
{
var removed = TemplateDrawingService.RemoveMatchParameterAnnotations(
ctx,
_selectedTemplate.LayoutName,
_selectedModelWindow.HasValue);
if (removed > 0)
{
AppendLog($"已移除模板匹配参数标注文本: {removed} 处");
}
var noteResult = TemplateDrawingService.ApplyNoteTemplate(
ctx,
_selectedTemplate.LayoutName,
_selectedModelWindow.HasValue,
schema,
bag);
if (noteResult != null)
{
if (noteResult.Applied)
{
AppendLog($"附注替换成功(目标={noteResult.TargetKind}, 占位符={noteResult.PlaceholderCountInDwg}");
}
else if (!string.IsNullOrWhiteSpace(noteResult.Message))
{
AppendLog($"附注替换跳过: {noteResult.Message}");
}
}
// 根据模板参数绘制半剖视图
HalfSectionDrawer.Draw(
ctx,
bag,
tplParams.ProjectType, // 交付状态
tplParams.SheetSize // 结构特征
);
ctx.Commit();
}
AppendLog("图纸生成完成。");
}
catch (BusinessException bex)
{
AppendLog($"参数错误: {bex.Message}");
}
catch (Exception ex)
{
AppendLog($"生成失败: {ex.Message}");
Logger.Error("GenerateDrawing", ex);
}
}
private void OnSaveDrawing()
{
try
{
var doc = AcadApp.DocumentManager.MdiActiveDocument;
if (doc == null)
{
AppendLog("未找到活动图纸,无法保存。");
return;
}
using (var dialog = new SaveFileDialog
{
Filter = "AutoCAD Drawing (*.dwg)|*.dwg",
FileName = "新图纸.dwg"
})
{
if (dialog.ShowDialog() == DialogResult.OK)
{
doc.Database.SaveAs(dialog.FileName, true, DwgVersion.Current, doc.Database.SecurityParameters);
AppendLog($"图纸已保存到: {dialog.FileName}");
}
}
}
catch (Exception ex)
{
AppendLog($"保存失败: {ex.Message}");
Logger.Error("SaveDrawing", ex);
}
}
private void OnOpenSettings()
{
try
{
var current = DropdownOptionsStore.Load();
using (var form = new SettingsForm(current))
{
if (form.ShowDialog() == DialogResult.OK)
{
DropdownOptionsStore.Save(form.Result);
ReloadDropdownOptions(form.Result);
AppendLog("设置已保存");
}
}
}
catch (Exception ex)
{
AppendLog($"打开设置失败: {ex.Message}");
Logger.Error("OpenSettings", ex);
}
}
private void ReloadDropdownOptions(DropdownOptions options)
{
if (options == null)
{
return;
}
ResetComboBoxItems(_cbProjectType, options.DeliveryStatuses);
ResetComboBoxItems(_cbDrawingType, options.ProcessMethods);
ResetComboBoxItems(_cbSheetSize, options.StructuralFeatures);
ResetComboBoxItems(_cbScale, options.SpecialConditions);
}
private TemplateParams CollectTemplateParams()
{
var specialCondition = _cbScale.Text?.Trim();
if (string.Equals(specialCondition, "无", StringComparison.OrdinalIgnoreCase))
{
specialCondition = null;
}
return new TemplateParams
{
ProjectType = _cbProjectType.Text?.Trim(),
DrawingType = _cbDrawingType.Text?.Trim(),
SheetSize = _cbSheetSize.Text?.Trim(),
Scale = specialCondition
};
}
private static ComboBox CreateComboBox(System.Collections.Generic.IEnumerable<string> items)
{
var cb = new ComboBox
{
DropDownStyle = ComboBoxStyle.DropDownList,
Width = 160
};
var arr = (items ?? Enumerable.Empty<string>()).Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).ToArray();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
}
if (cb.Items.Count > 0)
{
cb.SelectedIndex = 0;
}
return cb;
}
private static void ResetComboBoxItems(ComboBox cb, System.Collections.Generic.IEnumerable<string> items)
{
if (cb == null)
{
return;
}
var previous = cb.Text;
var arr = (items ?? Enumerable.Empty<string>()).Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).ToArray();
cb.BeginUpdate();
try
{
cb.Items.Clear();
if (arr.Length > 0)
{
cb.Items.AddRange(arr);
var idx = Array.FindIndex(arr, v => string.Equals(v, previous, StringComparison.OrdinalIgnoreCase));
cb.SelectedIndex = idx >= 0 ? idx : 0;
}
}
finally
{
cb.EndUpdate();
}
}
private void OnTestDraw()
{
try
{
// ==========================================
// 参数定义 - 调整比例接近参考图
// ==========================================
// 1. 锻件尺寸参数 (扁平环形件)
double Φ1 = 500.0; // 锻件外径
double a1 = 2.0; // 外径上差
double b1 = -1.0; // 外径下差
double Φ2 = 150.0; // 锻件内径
double a2 = 1.5; // 内径上差
double b2 = -0.5; // 内径下差
double H1 = 100.0; // 锻件高度
double a3 = 1.0; // 高度上差
double b3 = -1.0; // 高度下差
double T = 45.0; // 最小壁厚 (设定值)
// --- 零件尺寸 ---
double Φ_1 = 485.0; // 零件外径 (Φ'1)
double Φ_2 = 165.0; // 零件内径 (Φ'2)
double H_1 = 90.0; // 零件高度 (H'1)
// ==========================================
// 2. 逻辑校验 (使用 T 参数)
// ==========================================
double actualWallThickness = (Φ1 - Φ2) / 2.0;
if (actualWallThickness < T)
{
AppendLog($"[警告] 实际壁厚 ({actualWallThickness}) 小于设定最小壁厚 T ({T})");
}
// ==========================================
// 3. 绘图逻辑 (使用其余几何参数)
// ==========================================
// 仅计算相对位置,不增加额外参数
double partOffsetY = (H1 - H_1) / 2.0;
var doc = AcadApp.DocumentManager.MdiActiveDocument;
if (doc == null)
{
AppendLog("未找到活动图纸。");
return;
}
using (doc.LockDocument())
using (var ctx = new CadContext(doc))
{
var db = ctx.Database;
var tr = ctx.Transaction;
var btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
// --- 半剖视图:只绘制右侧 ---
// 锻件外轮廓 (不闭合,用于显示剖面边界)
var polyForging = new Polyline();
polyForging.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0); // 中心线底部
polyForging.AddVertexAt(1, new Point2d(Φ1 / 2, 0), 0, 0, 0); // 外径底部
polyForging.AddVertexAt(2, new Point2d(Φ1 / 2, H1), 0, 0, 0); // 外径顶部
polyForging.AddVertexAt(3, new Point2d(0, H1), 0, 0, 0); // 中心线顶部
polyForging.Closed = false;
polyForging.ColorIndex = 7; // White
// 锻件内孔轮廓
var polyForgingInner = new Polyline();
polyForgingInner.AddVertexAt(0, new Point2d(Φ2 / 2, 0), 0, 0, 0);
polyForgingInner.AddVertexAt(1, new Point2d(Φ2 / 2, H1), 0, 0, 0);
polyForgingInner.Closed = false;
polyForgingInner.ColorIndex = 7; // White
// 零件轮廓 (闭合,用于填充)
var polyPart = new Polyline();
polyPart.AddVertexAt(0, new Point2d(Φ_2 / 2, partOffsetY), 0, 0, 0);
polyPart.AddVertexAt(1, new Point2d(Φ_1 / 2, partOffsetY), 0, 0, 0);
polyPart.AddVertexAt(2, new Point2d(Φ_1 / 2, partOffsetY + H_1), 0, 0, 0);
polyPart.AddVertexAt(3, new Point2d(Φ_2 / 2, partOffsetY + H_1), 0, 0, 0);
polyPart.Closed = true;
polyPart.ColorIndex = 7; // White
// --- 绘制中心线 (水平,表示轴线) ---
double centerLineExt = 20.0;
var lineCenter = new Line(
new Point3d(-centerLineExt, H1 / 2, 0),
new Point3d(Φ1 / 2 + centerLineExt, H1 / 2, 0));
lineCenter.ColorIndex = 4; // Cyan
// 尝试加载线型
try
{
var linetypeTbl = (LinetypeTable)tr.GetObject(db.LinetypeTableId, OpenMode.ForRead);
if (linetypeTbl.Has("CENTER"))
{
lineCenter.Linetype = "CENTER";
}
else
{
try
{
db.LoadLineTypeFile("CENTER", "acad.lin");
if (linetypeTbl.Has("CENTER"))
{
lineCenter.Linetype = "CENTER";
}
}
catch { /* Ignore */ }
}
}
catch { /* Ignore */ }
// 添加到数据库
btr.AppendEntity(polyForging);
tr.AddNewlyCreatedDBObject(polyForging, true);
btr.AppendEntity(polyForgingInner);
tr.AddNewlyCreatedDBObject(polyForgingInner, true);
btr.AppendEntity(polyPart);
tr.AddNewlyCreatedDBObject(polyPart, true);
btr.AppendEntity(lineCenter);
tr.AddNewlyCreatedDBObject(lineCenter, true);
// --- 剖面填充 ---
try
{
var hatch = new Hatch();
hatch.Normal = new Vector3d(0, 0, 1);
hatch.Elevation = 0.0;
hatch.SetDatabaseDefaults();
btr.AppendEntity(hatch);
tr.AddNewlyCreatedDBObject(hatch, true);
hatch.SetHatchPattern(HatchPatternType.PreDefined, "ANSI31");
hatch.PatternScale = 5.0;
hatch.Associative = true;
hatch.ColorIndex = 4; // Cyan
var ids = new ObjectIdCollection();
ids.Add(polyPart.ObjectId);
hatch.AppendLoop(HatchLoopTypes.External, ids);
hatch.EvaluateHatch(true);
}
catch (Exception ex)
{
AppendLog($"填充失败: {ex.Message}");
}
ctx.Commit();
// --- 日志输出 ---
AppendLog($"半剖视图绘制完成");
AppendLog($"锻件: Φ{Φ1}, 内Φ{Φ2}, H{H1}");
AppendLog($"零件: Φ'{Φ_1}, 内Φ'{Φ_2}, H'{H_1}");
}
// Zoom Extents
doc.SendStringToExecute("._ZOOM _E ", true, false, false);
}
catch (Exception ex)
{
AppendLog($"测试绘制失败: {ex.Message}");
Logger.Error("TestDraw", ex);
}
}
private void AppendLog(string message)
{
var time = DateTime.Now.ToString("HH:mm:ss");
_txtLog.AppendText($"[{time}] {message}{Environment.NewLine}");
}
}
}