直线首尾相连-CAD选择版
本帖最后由 wang2006zhi 于 2024-8-27 13:17 编辑[CommandMethod("tt222")]
public void Tt222()
{
using var tr = new DBTrans();
var tol = new Tolerance(5, 50);
while (true)
{
var sw = Stopwatch.StartNew();
if (!Env.Editor.SelEnt(out Line line))
return;
var queue = new Queue<Line>();
queue.Enqueue(line);
var sellines = new List<Line>();
while (queue.Any())
{
var temp = queue.Dequeue();
var ptc = temp.GeometricExtents.GetPointCollection();
if (!Env.Editor.SelEnts(out List<Line> sel, ptc, fil: fil))
return;
foreach (var item in sel)
{
if (temp.Equals(item))
continue;
if (sellines.Contains(item))
continue;
if (IsLink(temp, item))
{
sellines.Add(item);
queue.Enqueue(item);
}
}
}
if (!sellines.Any())
continue;
sellines.ForEach(ent =>
{
using (ent.ForWrite())
{
ent!.ColorIndex = ent.ColorIndex == 1 ? 2 : 1;
ent.Draw();
}
});
sw.Stop();
Env.Editor.WriteMessage("\n TT10用时{0}毫秒", sw.Elapsed.TotalMilliseconds);
}
//链接条件
bool IsLink(Line lineA, Line lineB)
{
if (lineA.StartPoint.IsEqualTo(lineB.StartPoint, tol)
|| lineA.StartPoint.IsEqualTo(lineB.EndPoint, tol)
|| lineA.EndPoint.IsEqualTo(lineB.StartPoint, tol)
|| lineA.EndPoint.IsEqualTo(lineB.EndPoint, tol)
)
return true;
return false;
}
}
https://gitee.com/inspirefunction/ifoxcad/blob/v0.7/tests/TestShared/TestCurve.cs
IFOX 封裝了時間監測器,在此測試文件的 57 -61 行里可以看到。
另:
一、 if (!Env.Editor.SelEnt(out Line line)) 中 SelEnt 0.7.1版本的麼看到這個封裝函數,是用的更高版本的 IFOX嗎?
二、temp.StartPoint..GetPointCollection(); 原始APII也麼有這個方法,是自己封裝的嗎?
三、 bool IsLink(Line lineA, Line lineB) 函數的方法建議輸入形參加一個tol,做SDK形式更通用一些。 很好,学习了,要是加上注释就更好了 本帖最后由 你有种再说一遍 于 2024-8-7 02:42 编辑
还得接着优化,考虑使用线程安全邻接表和多线程并行,
因为这样才可以把每次识别一条改为多条,提高吞吐量.
写c#重点是一次性完成全部并且尽可能在一秒内,
而不是像lisp一点一点的处理.
本次的优化建议:
public void Tt222() {
using var tr = new DBTrans();
while (true) {
var sw = Stopwatch.StartNew();
// 链式选择,选择图元对象作为起点种子.
if (!Env.Editor.SelEnt(out ObjectId lineId)) return;
// 创建一个队列用于存储待处理的线段...
此处储存line有问题,应该改为id,
一是储存图元的信息熵巨大,Entity和Entity比较会进入内部逻辑而不是id这样的数值比较.
二是不利于后续删除,
三是改为多事务的话,Entity跨事务会错乱,甚至有人不小心在跨事务进行写模式.
// 创建一个列表用于存储符合条件的线段
var sellines = new HashSet<LineType>();
var line = lineId.ToEntity();
var lineType=new LineType(
line.ObjectId,line.StartPoint,line.EndPoint);
var queue = new Queue<LineType>();
queue.Enqueue(lineType);
// 只要队列不为空就继续循环
while (queue.Any()){
// 不要做无畏的转换,Hash容器可以保证唯一,选择与起点和终点相关的实体加入...按理来说这里用一个ssget就够了...
HashSet<ObjectId> ids=[];
var a=Env.Editor.SelEnts(ids);
if (!a) return;
var b=Env.Editor.SelEnts(ids);
if (!b) return;
// 取出种子线段
var t = queue.Dequeue();
foreach (var id in ids) {
// 当前线段与遍历线段相同则跳过
if (t.ObjectId==id) continue;
// 已经添加过该线段则跳过
var iLine = id.ToEntity();
var iType=new LineType(
iLine.ObjectId,iLine.StartPoint,iLine.EndPoint);
if (sellines.Contains(iType)) continue;
// 有链接关系
if (t.IsLink(iType)) {
sellines.Add(iType);
queue.Enqueue(iType);
}
}
}
// 结果列表为空则跳过
if (!sellines.Any()) continue;
// 对结果列表中的每个线段执行操作
sellines.ForEach(id => {
var ent = id.ToEntity();
using (ent.ForWrite()){
// 切换线段的颜色索引
ent!.ColorIndex = ent.ColorIndex == 1 ? 2 : 1;
// 绘制线段
ent.Draw();
}
});
// 停止计时
sw.Stop();
// 输出操作所用的时间
Env.Editor.WriteMessage($"\n {nameof(Tt222)}用时{sw.Elapsed.TotalMilliseconds}毫秒");
}
}
public class LineType {
public ObjectId ObjectId;
public Point3d StartPoint;
public Point3d EndPoint;
// 构造函数
public LineType(ObjectId objectId, Point3d startPoint, Point3d endPoint) {
ObjectId = objectId;
StartPoint = startPoint;
EndPoint = endPoint;
}
// IsLink方法
public bool IsLink(LineType lineB, Tolerance? tol = null) {
if (tol == null) {
tol = new Tolerance(1, 1); // 默认容差值
}
return
StartPoint.IsEqualTo(lineB.StartPoint, tol) ||
StartPoint.IsEqualTo(lineB.EndPoint, tol) ||
EndPoint.IsEqualTo(lineB.StartPoint, tol) ||
EndPoint.IsEqualTo(lineB.EndPoint, tol);
}
// 使用hashset或者dictionary重写下面
// GetHashCode方法
public override int GetHashCode() {
unchecked { // 允许溢出,避免不必要的异常处理
return ObjectId.GetHashCode()
^= StartPoint.GetHashCode()
^= EndPoint.GetHashCode();
}
}
// Equals方法
public override bool Equals(object obj) {
return obj is LineType other
&& ObjectId.Equals(other.ObjectId)
&& StartPoint.Equals(other.StartPoint)
&& EndPoint.Equals(other.EndPoint);
}
}
}
好東西,謝謝分享,感謝!!! 本帖最后由 wang2006zhi 于 2024-8-7 14:07 编辑
你有种再说一遍 发表于 2024-8-6 17:46
还得接着优化,考虑使用线程安全邻接表和多线程并行,
因为这样才可以把每次识别一条改为多条,提高吞吐量.
...
非常好的建议,通过构造一个新的类(LineType)用以减少原LINE数据量;但在新建类的时候是否有消耗。。TT21中原直线修改新的类(LineType)测试中用时较之前长。
个人意见:通过直线起终点(如10范围)构造选择集,可以快速过滤掉需要的可能数据,减少循环判断。
var ptcS = temp.StartPoint.GetPointCollection();
var ptcE = temp.EndPoint.GetPointCollection();
if (!Env.Editor.SelEnts(out List<Line> selS, ptcS) & !Env.Editor.SelEnts(out List<Line> selE, ptcE))
return;
经过实际测试。10万条乱线。你代码用时较多。。。【T2原四叉树】【TT21原CAD选择】【TT22你优化的代码】
TT2用时2478.1483毫秒
请选择对象:
TT2用时977.6429毫秒
请选择对象:
TT2用时1928.7176毫秒
请选择对象:
命令: tt21
请选择对象:
TT21用时1437.1039毫秒
请选择对象:
TT21用时711.9279毫秒
请选择对象:
TT21用时821.3567毫秒
请选择对象:
TT21用时645.9824毫秒
请选择对象:
命令: tt22
请选择对象:
Tt22用时1531.449毫秒
请选择对象:
Tt22用时1604.1684毫秒
请选择对象:
Tt22用时1427.732毫秒
请选择对象:
优化修改后的
[CommandMethod(nameof(Tt22))]
public void Tt22()
{
using var tr = new DBTrans();
while (true)
{
var sw = Stopwatch.StartNew();
// 链式选择,选择图元对象作为起点种子.
if (!Env.Editor.SelEnt(out Line line))
return;
// 此处储存line有问题,应该改为id,一是储存图元的信息熵巨大,Entity和Entity比较会进入内部逻辑而不是id这样的数值比较.
// 二是不利于后续删除,
// 三是改为多事务的话,Entity跨事务会错乱,甚至有人不小心在跨事务进行写模式.
// 创建一个队列用于存储待处理的线段...
// 创建一个列表用于存储符合条件的线段
var sellines = new HashSet<LineType>();
var lineType=new LineType(line.ObjectId,line.StartPoint,line.EndPoint);
var queue = new Queue<LineType>();
queue.Enqueue(lineType);
// 只要队列不为空就继续循环
while (queue.Any())
{
// 不要做无畏的转换,Hash容器可以保证唯一,选择与起点和终点相关的实体加入...按理来说这里用一个ssget就够了...
var temp = queue.Dequeue();
var ptcS = temp.StartPoint.GetPointCollection();
var ptcE = temp.EndPoint.GetPointCollection();
if (!Env.Editor.SelEnts(out HashSet<ObjectId> selS, ptcS) & !Env.Editor.SelEnts(out HashSet<ObjectId> selE, ptcE))
return;
var ids = selS.Union(selE);
// 取出种子线段
foreach (var id in ids)
{ // 当前线段与遍历线段相同则跳过
if (temp.ObjectId==id)
continue;
// 已经添加过该线段则跳过
var iLine = id.ToEntity<Line>();
var iType=new LineType(iLine.ObjectId,iLine.StartPoint,iLine.EndPoint);
if (sellines.Contains(iType))
continue;
// 有链接关系
if (temp.IsLink(iType))
{
sellines.Add(iType);
queue.Enqueue(iType);
}
}
}
// 结果列表为空则跳过
if (!sellines.Any())
continue;
// 对结果列表中的每个线段执行操作
sellines.ForEach(id =>
{
var ent = id.ObjectId.ToEntity();
using (ent.ForWrite())
{// 切换线段的颜色索引
ent!.ColorIndex = ent.ColorIndex == 1 ? 2 : 1;
// 绘制线段
ent.Draw(); }});
// 停止计时
sw.Stop();
// 输出操作所用的时间
Env.Editor.WriteMessage($"\n {nameof(Tt22)}用时{sw.Elapsed.TotalMilliseconds}毫秒");
}
}
本帖最后由 wang2006zhi 于 2024-8-7 14:10 编辑
箭头_Row 发表于 2024-8-6 14:52
https://gitee.com/inspirefunction/ifoxcad/blob/v0.7/tests/TestShared/TestCurve.cs
IFOX 封裝了時間 ...
/// <summary>
/// 交互模式获取单个实体
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
/// <param name="ed">命令行</param>
/// <param name="t">实体</param>
/// <param name="pt">交互点</param>
/// <param name="msg">提示</param>
/// <returns>bool</returns>
public static bool SelEnt<T>(this Editor ed,
out T t,
out Point3d pt,
string msg = "请选择对象:") where T : Entity
{
var per = ed.GetEntity("\n " + msg);
t = null!;
pt = per.PickedPoint;
if (per.Status != PromptStatus.OK)
return false;
var tr = DBTrans.Top;
if (tr.GetObject(per.ObjectId) is T result)
{
t = result;
return true;
}
return false;
}
/// <summary>
/// 以单点(中心点)构造选择点集
/// </summary>
/// <param name="cenpt">中心单点3D</param>
/// <param name="ex">偏移量</param>
/// <returns>点集合</returns>
public static Point3dCollection GetPointCollection(this Point3d cenpt, double ex = 50)
{
var pt2d = new Point2d(cenpt.X, cenpt.Y);
return GetPointCollection(pt2d, ex);
}
public static Point3dCollection GetPointCollection(this Point2d cenpt, double ex = 50)
{
return new Point3dCollection()
{
new Point3d(cenpt.X - 0.5 * ex, cenpt.Y - 0.5 * ex, 0),
new Point3d(cenpt.X + 0.5 * ex, cenpt.Y - 0.5 * ex, 0),
new Point3d(cenpt.X + 0.5 * ex, cenpt.Y + 0.5 * ex, 0),
new Point3d(cenpt.X - 0.5 * ex, cenpt.Y + 0.5 * ex, 0),
};
}
此为一个私有函数bool IsLink(Line lineA, Line lineB),并不通用,并且形参中var tol = new Tolerance(5, 50);无法设置默认值。。
还能优化的,最起码你现在没有用并行,继续努力 #region 精细选取
// var ptcS = dimtemp.DimLinePoint.GetPointCollection(fuz);
// var ptcE = dimtemp.DimLinePointN.GetPointCollection(fuz);
// if (!Env.Editor.SelEnts(out List<Dimension> selS, ptcS, fil) &
// !Env.Editor.SelEnts(out List<Dimension> selE, ptcE, fil))
// return dimInfos;
// var sel = selS.Union(selE);
#endregion
var ptColl = temp.GetRect().GetPointCollection(fuz);
if (!Env.Editor.SelEnts(out List<Dimension> sel, ptColl, fil))
return dimInfos;
页:
[1]