using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Controls; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Windows; using Application = Autodesk.AutoCAD.ApplicationServices.Application; namespace Szmedi.CADkits { // 定义视图模型,对应列表中的一行 public class EntityReviewItem { public ObjectId EntityId { get; set; } public string Handle { get; set; } public string Position { get; set; } // 支持属性通知可使用 INotifyPropertyChanged,这里为了简化直接使用属性 public string Status { get; set; } } public partial class ReviewAndMatchWindow : UserControl { public ObservableCollection ReviewItems { get; set; } private readonly string _checkLineLayer; private bool _isListeningToSelection = true; private readonly PaletteSet _parentPalette; private readonly Dictionary _textDataMap; // 构造函数参数改为 TerrainEntityInfo public ReviewAndMatchWindow( List allEntities, Dictionary autoPairs, List allTexts, string checkLineLayer, PaletteSet parentPalette) { InitializeComponent(); _checkLineLayer = checkLineLayer; _parentPalette = parentPalette; _textDataMap = allTexts.ToDictionary(t => t.ObjectId, t => t); ReviewItems = new ObservableCollection(); ReviewListView.ItemsSource = ReviewItems; PopulateList(allEntities, autoPairs); } private void PopulateList(List allEntities, Dictionary autoPairs) { foreach (var entData in allEntities) { var item = new EntityReviewItem { EntityId = entData.ObjectId, Handle = entData.Handle, Position = $"{entData.Position.X:F2}, {entData.Position.Y:F2}" }; if (autoPairs.TryGetValue(entData.ObjectId, out ObjectId textId)) { item.Status = _textDataMap[textId].TextContent; } else { item.Status = "--- 未匹配 ---"; } ReviewItems.Add(item); } } private void MatchButton_Click(object sender, RoutedEventArgs e) { if (!(ReviewListView.SelectedItem is EntityReviewItem selected)) { MessageBox.Show("请先在列表中选择一个要匹配的实体。", "提示"); return; } Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; if (_parentPalette.Dock == DockSides.None) _parentPalette.Visible = false; MatchButton.IsEnabled = false; try { PromptEntityOptions peo = new PromptEntityOptions("\n请点选此实体对应的标高文字: "); peo.SetRejectMessage("\n选择的不是文字对象。"); peo.AddAllowedClass(typeof(DBText), true); peo.AddAllowedClass(typeof(MText), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status == PromptStatus.OK) { UpdateEntityWithSelectedText(selected, per.ObjectId); } } catch (System.Exception ex) { MessageBox.Show($"发生错误: {ex.Message}"); } finally { if (_parentPalette.Dock == DockSides.None) _parentPalette.Visible = true; MatchButton.IsEnabled = true; } } private void UpdateEntityWithSelectedText(EntityReviewItem itemToUpdate, ObjectId textId) { Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; using (DocumentLock docLock = doc.LockDocument()) { using (Transaction tr = db.TransactionManager.StartTransaction()) { Entity textEnt = (Entity)tr.GetObject(textId, OpenMode.ForRead); string textContent = ""; if (textEnt is MText mtext) textContent = mtext.Contents; else if (textEnt is DBText dbtext) textContent = dbtext.TextString; if (!double.TryParse(textContent, NumberStyles.Float, CultureInfo.InvariantCulture, out double elevationZ)) { MessageBox.Show($"文字内容 '{textContent}' 不是有效的数字。", "匹配失败"); tr.Abort(); return; } // --- 更新逻辑:区分 BlockReference 和 DBPoint --- Entity targetEnt = (Entity)tr.GetObject(itemToUpdate.EntityId, OpenMode.ForWrite); Point3d currentPos; if (targetEnt is BlockReference blockRef) { blockRef.Position = new Point3d(blockRef.Position.X, blockRef.Position.Y, elevationZ); currentPos = blockRef.Position; } else if (targetEnt is DBPoint dbPoint) { dbPoint.Position = new Point3d(dbPoint.Position.X, dbPoint.Position.Y, elevationZ); currentPos = dbPoint.Position; } else if (targetEnt is Polyline polyline) { //// 修改多段线的整体标高 //polyline.Elevation = elevationZ; //currentPos = polyline.GetPoint3dAt(0); polyline.Elevation = elevationZ; // 重新计算中心点用于校对线绘制 Extents3d ext = polyline.GeometricExtents; currentPos = ext.MinPoint + (ext.MaxPoint - ext.MinPoint) * 0.5; } else { MessageBox.Show("未知的实体类型,无法更新。"); tr.Abort(); return; } // 创建连线 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); Extents3d textExtents = textEnt.GeometricExtents; Point3d textCenter = textExtents.MinPoint + (textExtents.MaxPoint - textExtents.MinPoint) * 0.5; Line checkLine = new Line(currentPos, textCenter); checkLine.Layer = _checkLineLayer; checkLine.ColorIndex = 256; btr.AppendEntity(checkLine); tr.AddNewlyCreatedDBObject(checkLine, true); // 更新UI itemToUpdate.Status = $"手动: {elevationZ}"; // 强制刷新列表显示 (如果需要) ReviewListView.Items.Refresh(); tr.Commit(); } } } private void ZoomToEntity(ObjectId entId) { if (!entId.IsValid) return; Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Editor ed = doc.Editor; Database db = doc.Database; using (Transaction tr = db.TransactionManager.StartTransaction()) { if (entId.IsErased) return; Entity ent = tr.GetObject(entId, OpenMode.ForRead) as Entity; if (ent != null) { Extents3d extents = ent.GeometricExtents; // 如果是点,包围盒可能很小,稍微扩大一点显示范围 if (ent is DBPoint) { extents = new Extents3d(extents.MinPoint - new Vector3d(1, 1, 0), extents.MaxPoint + new Vector3d(1, 1, 0)); } Matrix3d ucs = ed.CurrentUserCoordinateSystem; double viewSize = Math.Max(extents.MaxPoint.X - extents.MinPoint.X, extents.MaxPoint.Y - extents.MinPoint.Y) * 10.0; if (viewSize < 1.0) viewSize = 20.0; // 最小视野 extents.TransformBy(ucs.Inverse()); ViewTableRecord view = new ViewTableRecord { CenterPoint = new Point2d( (extents.MinPoint.X + extents.MaxPoint.X) / 2.0, (extents.MinPoint.Y + extents.MaxPoint.Y) / 2.0), Height = viewSize, Width = viewSize }; ed.SetCurrentView(view); ed.SetImpliedSelection(new ObjectId[] { entId }); } tr.Commit(); } } private void ListView_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (ReviewListView.SelectedItem is EntityReviewItem selected) { ZoomToEntity(selected.EntityId); } } private void SelectAndScrollToItem(ObjectId entId) { var itemToSelect = ReviewItems.FirstOrDefault(item => item.EntityId == entId); if (itemToSelect != null) { ReviewListView.SelectedItem = itemToSelect; ReviewListView.ScrollIntoView(itemToSelect); } } private void CleanLinesButton_Click(object sender, RoutedEventArgs e) { MessageBoxResult result = MessageBox.Show( "确定要删除所有由本工具创建的校对线吗?\n此操作不可撤销。", "确认清理", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) { TerrainTools.CleanAllCheckLines(); } } private void LocateInListButton_Click(object sender, RoutedEventArgs e) { Document doc = Application.DocumentManager.MdiActiveDocument; Editor ed = doc.Editor; ObjectId targetId = ObjectId.Null; _isListeningToSelection = false; LocateInListButton.IsEnabled = false; try { PromptSelectionResult psr = ed.GetSelection(); if (psr.Status == PromptStatus.OK && psr.Value.Count > 0) { targetId = psr.Value.GetObjectIds()[0]; } else { if (_parentPalette.Dock == DockSides.None) _parentPalette.Visible = false; // 允许选择块或点 PromptEntityOptions peo = new PromptEntityOptions("\n请在图中选择一个地形点(块或点)进行定位: "); peo.SetRejectMessage("\n选择的不是块参照或点。"); peo.AddAllowedClass(typeof(BlockReference), true); peo.AddAllowedClass(typeof(DBPoint), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status == PromptStatus.OK) { targetId = per.ObjectId; } } if (!targetId.IsNull) { SelectAndScrollToItem(targetId); } } finally { _isListeningToSelection = true; if (_parentPalette.Dock == DockSides.None) _parentPalette.Visible = true; LocateInListButton.IsEnabled = true; this.Focus(); } } private void ConvertToPointsButton_Click(object sender, RoutedEventArgs e) { Document doc = Application.DocumentManager.MdiActiveDocument; if (doc == null) return; Database db = doc.Database; Editor ed = doc.Editor; int convertCount = 0; using (DocumentLock docLock = doc.LockDocument()) { using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); // 遍历列表中所有的项 foreach (var item in ReviewItems) { // 获取实体对象,判断是否为多段线 if (item.EntityId.IsErased) continue; Entity ent = tr.GetObject(item.EntityId, OpenMode.ForRead) as Entity; if (ent is Polyline pl) { try { // 1. 计算几何中心 Extents3d ext = pl.GeometricExtents; Point3d center = ext.MinPoint + (ext.MaxPoint - ext.MinPoint) * 0.5; // 2. 创建新点 (继承图层和当前的高程) DBPoint newPoint = new DBPoint(center); newPoint.Layer = pl.Layer; newPoint.Color = pl.Color; btr.AppendEntity(newPoint); tr.AddNewlyCreatedDBObject(newPoint, true); // 3. 更新列表中的数据源 (核心步骤) item.EntityId = newPoint.ObjectId; item.Handle = newPoint.ObjectId.Handle.Value.ToString(); // 坐标显示也更新一下 item.Position = $"{center.X:F2}, {center.Y:F2}"; // 4. 删除原多段线 pl.UpgradeOpen(); pl.Erase(); convertCount++; } catch (System.Exception ex) { ed.WriteMessage($"\n转换句柄为 {item.Handle} 的对象时失败: {ex.Message}"); } } } tr.Commit(); } } if (convertCount > 0) { // 强制刷新 UI 列表显示 ReviewListView.Items.Refresh(); MessageBox.Show($"成功将 {convertCount} 个多段线符号转换为中心点。", "转换完成"); } else { MessageBox.Show("列表中没有检测到可转换的多段线实体。", "提示"); } } } }