写了一个一键给分堆成块加框,但是处理速度太慢
using Autodesk.AutoCAD.ApplicationServices;using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.EditorInput;
using System;
namespace MyAutoCADPlugin
{
public class MyCommands
{
public void AddRedFrames()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 选择所有对象
PromptSelectionResult selResult = doc.Editor.GetSelection();
if (selResult.Status != PromptStatus.OK)
{
doc.Editor.WriteMessage("\nSelection failed.");
return;
}
// 获取选择的实体
SelectionSet selSet = selResult.Value;
List<Entity> entities = new List<Entity>();
foreach (SelectedObject selObj in selSet)
{
Entity ent = tr.GetObject(selObj.ObjectId, OpenMode.ForRead) as Entity;
if (ent != null)
{
entities.Add(ent);
}
}
// 计算所有对象的边界框
if (entities.Count == 0)
{
doc.Editor.WriteMessage("\nNo entities selected.");
return;
}
// 过滤掉多行文字
entities = entities.Where(e => !(e is MText)).ToList();
// 计算边界框
Extents3d combinedExtents = new Extents3d();
foreach (Entity ent in entities)
{
combinedExtents.AddExtents(ent.GeometricExtents);
}
// 设置容差
double tolerance = 7.0; // 调整容差值
// 分块
List<List<Entity>> groupedEntities = GroupEntitiesByProximity(entities, tolerance);
// 添加红色外框
foreach (var group in groupedEntities)
{
Extents3d groupExtents = new Extents3d();
foreach (Entity ent in group)
{
groupExtents.AddExtents(ent.GeometricExtents);
}
// 绘制红色外框
AddRedFrame(db, tr, groupExtents);
}
tr.Commit();
}
}
private void AddRedFrame(Database db, Transaction tr, Extents3d extents)
{
using (BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite))
{
Polyline poly = new Polyline();
poly.AddVertexAt(0, new Point2d(extents.MinPoint.X, extents.MinPoint.Y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(extents.MaxPoint.X, extents.MinPoint.Y), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(extents.MaxPoint.X, extents.MaxPoint.Y), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(extents.MinPoint.X, extents.MaxPoint.Y), 0, 0, 0);
poly.Closed = true;
poly.ColorIndex = 1; // Red color
btr.AppendEntity(poly);
tr.AddNewlyCreatedDBObject(poly, true);
}
}
private List<List<Entity>> GroupEntitiesByProximity(List<Entity> entities, double tolerance)
{
List<List<Entity>> groupedEntities = new List<List<Entity>>();
bool[] visited = new bool;
for (int i = 0; i < entities.Count; i++)
{
if (visited) continue;
List<Entity> group = new List<Entity>();
Queue<Entity> queue = new Queue<Entity>();
queue.Enqueue(entities);
while (queue.Count > 0)
{
Entity current = queue.Dequeue();
if (visited) continue;
visited = true;
group.Add(current);
foreach (Entity neighbor in entities)
{
if (!visited && AreEntitiesClose(current, neighbor, tolerance))
{
queue.Enqueue(neighbor);
}
}
}
groupedEntities.Add(group);
}
return groupedEntities;
}
private bool AreEntitiesClose(Entity e1, Entity e2, double tolerance)
{
// 检查两个实体是否相近的逻辑
Extents3d ext1 = e1.GeometricExtents;
Extents3d ext2 = e2.GeometricExtents;
double distX = Math.Abs(ext1.MinPoint.X - ext2.MinPoint.X);
double distY = Math.Abs(ext1.MinPoint.Y - ext2.MinPoint.Y);
return distX < tolerance && distY < tolerance;
}
}
}
写了一个一键给分堆成块加框,但是处理速度太慢 ,求助大佬帮忙修改,怎么样子才能处理速度快一些,自定义容差没写进去,外框外扩%比也没加:(
本帖最后由 你有种再说一遍 于 2024-9-13 05:04 编辑
你的代码风格不是很好,我修改了一下步骤.
因为论坛有问题,数组索引如果是i,需要改成j才能正确显示.
public class MyCommands {
// 设置容差值
public double Tolerance { get; set; } = 1.0;
/// <summary>
/// 添加红色边框到选定对象周围
/// </summary>
public void AddRedFrames() {
// 获取当前活动的文档和数据库
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
// 手选
var selResult = doc.Editor.GetSelection();
if (selResult.Status != PromptStatus.OK) {
doc.Editor.WriteMessage("\n选择失败。");
return;
}
using (Transaction tr = db.TransactionManager.StartTransaction()) {
// 图元
List<Entity> ents = new();
// 最大包围盒
Extents3d combinedExtents = new Extents3d();
// 遍历用户选择的对象
foreach (SelectedObject selObj in selResult.Value) {
Entity ent = (Entity)tr.GetObject(selObj.ObjectId, OpenMode.ForRead);
// 过滤掉多行文字对象
if (ent is MText) continue;
ents.Add(ent);
// 通过并集计算出最大包围盒
combinedExtents.AddExtents(ent.GeometricExtents);
}
// 求邻近距离分组
vat glink = GroupEntitiesByProximity(ents);
// 当前空间的块表记录
using BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
// 为每个分组添加红色外框
foreach (var group in glink) {
Extents3d gExt = new();
foreach (Entity ent in group){
gExt.AddExtents(ent.GeometricExtents);
}
// 绘制红色外框
AddRedFrame(btr, tr, groupExtents);
}
tr.Commit();
}
}
下面是一个坏函数,这个函数三层主循环,时间复杂度平均期望O(n^3),还有两次IndexOf造成,达到O(n^5).
相当于你为了找最近的一个人和全世界每个人都比较,而且是每个人都比较5次.
那么为什么不先分组,然后组内比较呢?
就只和你同省/城/村/建筑内比较而已.
建议改为四叉树或者哈希网格,不要自己写了,去用IFox吧,里面有四叉树调用例子.
/// <summary>
/// 根据接近度将实体分组
/// </summary>
/// <param name="entities">实体列表</param>
/// <returns>分组后的实体列表</returns>
private List<List<Entity>> GroupEntitiesByProximity(List<Entity> entities) {
// 这种变量即使需要也写类字段上面...
List<List<Entity>> groupedEntities = new();
bool[] visited = new bool;
// 对每个的实体进行分组O(n)
for (int j = 0; j < entities.Count; j++) {
if (visited) continue; // 访问过跳过,但是依然遍历问了一次全世界O(1)
List<Entity> group = new();
Queue<Entity> queue = new();
// 入栈后弹栈,以此为基,查找最近
queue.Enqueue(entities);
// O(n)累计O(n^2)
while (queue.Count > 0) {
Entity cEnt = queue.Dequeue();
// 你觉得这个indexof不是遍历吗?它又没有hash,又没有排序后二分,它当然是遍历啦.累计O(n^3)
var x = entities.IndexOf(cEnt);
if (visited) continue;
// 我贴心地帮你提取变量上去,不然此处又加时间复杂度了.
visited = true;
group.Add(cEnt);
// 检查其他实体是否与当前实体接近.累计O(n^4)
foreach (Entity neighbor in entities)
{
if (
//累计O(n^5)
!visited
&& AreEntitiesClose(cEnt, neighbor))
{//出栈
queue.Enqueue(neighbor);
}
}
}
groupedEntities.Add(group);
}
return groupedEntities;
}
/// <summary>
/// 检查两个实体是否在指定的容差范围内相近
/// </summary>
/// <param name="e1">第一个实体</param>
/// <param name="e2">第二个实体</param>
/// <returns>是否相近</returns>
private bool AreEntitiesClose(Entity e1, Entity e2)
{
Extents3d ext1 = e1.GeometricExtents;
Extents3d ext2 = e2.GeometricExtents;
double distX = Math.Abs(ext1.MinPoint.X - ext2.MinPoint.X);
double distY = Math.Abs(ext1.MinPoint.Y - ext2.MinPoint.Y);
return distX < Tolerance && distY < Tolerance;
}
/// <summary>
/// 创建一个多段线对象来表示红色外框
/// </summary>
/// <param name="btr">当前空间的BlockTableRecord对象</param>
/// <param name="tr">当前事务</param>
/// <param name="extents">实体的边界框</param>
private void AddRedFrame(BlockTableRecord btr, Transaction tr, Extents3d extents)
{
Polyline poly = new Polyline();
poly.AddVertexAt(0, new Point2d(extents.MinPoint.X, extents.MinPoint.Y), 0, 0, 0);
poly.AddVertexAt(1, new Point2d(extents.MaxPoint.X, extents.MinPoint.Y), 0, 0, 0);
poly.AddVertexAt(2, new Point2d(extents.MaxPoint.X, extents.MaxPoint.Y), 0, 0, 0);
poly.AddVertexAt(3, new Point2d(extents.MinPoint.X, extents.MaxPoint.Y), 0, 0, 0);
poly.Closed = true;
// 设置多段线颜色为红色
poly.ColorIndex = 1;
// 将多段线添加到当前空间
btr.AppendEntity(poly);
tr.AddNewlyCreatedDBObject(poly, true);
}
} 你有种再说一遍 发表于 2024-9-9 20:45
你的代码风格不是很好,我修改了一下步骤.
因为论坛有问题,数组索引如果是i,需要改成j才能正确显示.
publi ...
真是诲人不倦 提了问题都不露面呢? 你有种再说一遍 发表于 2024-9-9 20:45
你的代码风格不是很好,我修改了一下步骤.
因为论坛有问题,数组索引如果是i,需要改成j才能正确显示.
publi ...
真是诲人不倦,楷模 你有种再说一遍 发表于 2024-9-9 20:45
你的代码风格不是很好,我修改了一下步骤.
因为论坛有问题,数组索引如果是i,需要改成j才能正确显示.
感谢大佬,提供,我试试, 最近一直在忙,没看论坛 你有种再说一遍 发表于 2024-9-9 20:45
你的代码风格不是很好,我修改了一下步骤.
因为论坛有问题,数组索引如果是i,需要改成j才能正确显示.
论坛有点卡,打开好慢
我测试了速度是优化了很多,但是 识别不精准
https://wwui.lanzouj.com/iAED72al984f
这个是项目 如果有时间的话帮我看看,不急的,感谢大佬
页:
[1]