Files
SzmediTools/Szmedi.CADkits/ReviewAndMatchWindow.xaml.cs
2026-02-23 11:21:51 +08:00

382 lines
15 KiB
C#
Raw Permalink 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.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<EntityReviewItem> ReviewItems { get; set; }
private readonly string _checkLineLayer;
private bool _isListeningToSelection = true;
private readonly PaletteSet _parentPalette;
private readonly Dictionary<ObjectId, TextWithPosition> _textDataMap;
// 构造函数参数改为 TerrainEntityInfo
public ReviewAndMatchWindow(
List<TerrainEntityInfo> allEntities,
Dictionary<ObjectId, ObjectId> autoPairs,
List<TextWithPosition> allTexts,
string checkLineLayer,
PaletteSet parentPalette)
{
InitializeComponent();
_checkLineLayer = checkLineLayer;
_parentPalette = parentPalette;
_textDataMap = allTexts.ToDictionary(t => t.ObjectId, t => t);
ReviewItems = new ObservableCollection<EntityReviewItem>();
ReviewListView.ItemsSource = ReviewItems;
PopulateList(allEntities, autoPairs);
}
private void PopulateList(List<TerrainEntityInfo> allEntities, Dictionary<ObjectId, ObjectId> 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("列表中没有检测到可转换的多段线实体。", "提示");
}
}
}
}