04-选择集过滤器与图元选择教程

第四章:选择集过滤器与图元选择教程

4.1 选择集基础概念

4.1.1 什么是选择集

在AutoCAD中,选择集(Selection Set)是用户选择的一组图元的集合。当用户在CAD中执行命令时,通常需要先选择要操作的对象,这些被选中的对象就组成了选择集。

选择集在CAD二次开发中的作用:

  • 用户交互:让用户选择要处理的图元
  • 批量操作:对多个图元执行相同的操作
  • 数据筛选:从大量图元中筛选出符合条件的对象

4.1.2 CAD原生选择集的使用

使用CAD原生API获取选择集的基本方式:

// 基本选择
Editor ed = doc.Editor;
PromptSelectionResult result = ed.GetSelection();

if (result.Status == PromptStatus.OK)
{
    SelectionSet ss = result.Value;
    foreach (SelectedObject obj in ss)
    {
        ObjectId id = obj.ObjectId;
        // 处理图元...
    }
}

4.1.3 选择集过滤器的重要性

在实际开发中,我们通常不需要选择所有图元,而是需要选择特定类型的图元。这时就需要使用选择集过滤器(Selection Filter)。

原生API的过滤器使用TypedValue数组来定义:

// 原生方式创建过滤器:选择所有直线
TypedValue[] filterList = new TypedValue[]
{
    new TypedValue((int)DxfCode.Start, "LINE")
};
SelectionFilter filter = new SelectionFilter(filterList);
PromptSelectionResult result = ed.GetSelection(filter);

这种方式存在的问题:

  • 代码冗长:创建TypedValue数组繁琐
  • 容易出错:DXF代码需要记忆
  • 可读性差:过滤条件不直观
  • 组合困难:复杂条件需要大量代码

4.2 IFoxCAD的OpFilter体系

4.2.1 OpFilter类设计理念

IFoxCAD设计了一套完整的过滤器类体系,以OpFilter为基类,通过运算符重载和链式调用,提供了优雅的过滤器构建方式。

OpFilter的设计目标:

  • 简洁性:用最少的代码表达过滤条件
  • 可读性:代码即文档,条件一目了然
  • 灵活性:支持复杂的逻辑组合
  • 类型安全:编译时检查,减少运行时错误

4.2.2 OpFilter类体系结构

OpFilter (抽象基类)
├── OpEqual       - 相等条件
├── OpComp        - 比较条件(大于、小于等)
├── OpList        - 列表条件(集合基类)
│   ├── OpAnd     - 逻辑与
│   ├── OpOr      - 逻辑或
│   └── OpXor     - 逻辑异或
├── OpLogi        - 逻辑条件(非)
│   └── OpNot     - 逻辑非
└── Op            - 操作符构建类

4.2.3 OpFilter基类

public abstract class OpFilter
{
    // 过滤器名称
    public abstract string Name { get; }
    
    // 取反操作
    public OpFilter Not => new OpNot(this);
    
    // 获取TypedValue序列
    public abstract IEnumerable<TypedValue> GetValues();
    
    // 非操作符
    public static OpFilter operator !(OpFilter item)
    {
        return item.Not;
    }
    
    // 转换为TypedValue数组
    public TypedValue[] ToArray()
    {
        return GetValues().ToArray();
    }
    
    // 隐式转换为SelectionFilter
    public static implicit operator SelectionFilter(OpFilter item)
    {
        return new SelectionFilter(item.ToArray());
    }
}

关键特性:

  • 抽象设计:定义统一接口,子类实现具体逻辑
  • 隐式转换:可以直接用于需要SelectionFilter的地方
  • 操作符重载:支持!运算符进行取反

4.3 构建过滤器

4.3.1 Build方法

OpFilter提供了Build静态方法,这是构建过滤器最常用的方式:

public static OpFilter Build(Func<Op, Op> func)
{
    return func(new Op()).Filter!;
}

使用示例:

// 构建过滤器:选择所有直线
var filter = OpFilter.Build(e => e.Dxf(0) == "LINE");

// 使用过滤器
using var tr = new DBTrans();
var result = tr.Editor?.GetSelection(filter);

4.3.2 Dxf方法

Dxf方法用于指定要过滤的DXF组码:

// 按实体类型过滤(组码0)
var filter1 = OpFilter.Build(e => e.Dxf(0) == "LINE");

// 按图层过滤(组码8)
var filter2 = OpFilter.Build(e => e.Dxf(8) == "MyLayer");

// 按颜色过滤(组码62)
var filter3 = OpFilter.Build(e => e.Dxf(62) == 1);  // 红色

常用的DXF组码:

组码 说明 示例值
0 实体类型 "LINE", "CIRCLE", "TEXT"
2 块名 "MyBlock"
8 图层名 "0", "MyLayer"
62 颜色索引 1(红), 2(黄), 3(绿)...
6 线型名 "Continuous", "DASHED"
10 起点或中心点 Point3d
11 终点 Point3d
40 半径或高度 double

4.3.3 比较操作符

除了相等判断,还支持各种比较操作:

// 等于
var f1 = OpFilter.Build(e => e.Dxf(0) == "LINE");

// 不等于
var f2 = OpFilter.Build(e => e.Dxf(0) != "CIRCLE");

// 大于(用于数值)
var f3 = OpFilter.Build(e => e.Dxf(40) > 10);  // 半径大于10

// 小于
var f4 = OpFilter.Build(e => e.Dxf(40) < 100);  // 半径小于100

// 大于等于
var f5 = OpFilter.Build(e => e.Dxf(62) >= 1);

// 小于等于
var f6 = OpFilter.Build(e => e.Dxf(62) <= 255);

4.3.4 点的比较

对于点类型的值,可以进行范围比较:

// 选择起点在某个范围内的直线
var minPt = new Point3d(0, 0, 0);
var maxPt = new Point3d(100, 100, 0);

var filter = OpFilter.Build(e => 
    e.Dxf(0) == "LINE" & 
    e.Dxf(10) >= minPt & 
    e.Dxf(10) <= maxPt);

4.3.5 通配符匹配

在字符串比较中可以使用通配符:

// 选择所有以"Temp"开头的图层上的图元
var filter = OpFilter.Build(e => e.Dxf(8) == "Temp*");

// 选择块名包含"Door"的块参照
var filter2 = OpFilter.Build(e => 
    e.Dxf(0) == "INSERT" & e.Dxf(2) == "*Door*");

通配符说明:

  • *:匹配任意数量的字符
  • ?:匹配单个字符
  • #:匹配单个数字
  • @:匹配单个字母
  • [...]:匹配括号内的任一字符
  • [~...]:匹配不在括号内的任一字符

4.4 逻辑组合

4.4.1 逻辑与(And)

使用&运算符或And方法:

// 使用&运算符
var filter1 = OpFilter.Build(e => 
    e.Dxf(0) == "LINE" & e.Dxf(8) == "MyLayer");

// 使用And方法
var filter2 = OpFilter.Build(e => 
    e.And(
        e.Dxf(0) == "LINE",
        e.Dxf(8) == "MyLayer",
        e.Dxf(62) == 1
    ));

4.4.2 逻辑或(Or)

使用|运算符或Or方法:

// 使用|运算符
var filter1 = OpFilter.Build(e => 
    e.Dxf(0) == "LINE" | e.Dxf(0) == "CIRCLE");

// 使用Or方法
var filter2 = OpFilter.Build(e => 
    e.Or(
        e.Dxf(0) == "LINE",
        e.Dxf(0) == "CIRCLE",
        e.Dxf(0) == "ARC"
    ));

4.4.3 逻辑非(Not)

使用!运算符:

// 选择所有非直线的图元
var filter1 = OpFilter.Build(e => !(e.Dxf(0) == "LINE"));

// 选择不在"0"图层上的图元
var filter2 = OpFilter.Build(e => !(e.Dxf(8) == "0"));

4.4.4 逻辑异或(Xor)

使用^运算符:

// 选择直线或圆,但不同时满足其他条件
var filter = OpFilter.Build(e => 
    e.Dxf(0) == "LINE" ^ e.Dxf(0) == "CIRCLE");

4.4.5 复杂条件组合

可以组合多个逻辑操作:

// 复杂条件:选择
// (直线且在Layer1上) 或 (圆且半径大于10) 且不是红色
var filter = OpFilter.Build(e =>
    (e.Dxf(0) == "LINE" & e.Dxf(8) == "Layer1" |
     e.Dxf(0) == "CIRCLE" & e.Dxf(40) > 10) &
    !(e.Dxf(62) == 1));

// 使用方法形式
var filter2 = OpFilter.Build(e =>
    e.And(
        e.Or(
            e.And(e.Dxf(0) == "LINE", e.Dxf(8) == "Layer1"),
            e.And(e.Dxf(0) == "CIRCLE", e.Dxf(40) > 10)
        ),
        !(e.Dxf(62) == 1)
    ));

4.5 获取选择集

4.5.1 GetSelection方法

通过Editor的GetSelection方法获取用户选择:

using var tr = new DBTrans();

// 不带过滤器的选择
var result1 = tr.Editor?.GetSelection();

// 带过滤器的选择
var filter = OpFilter.Build(e => e.Dxf(0) == "LINE");
var result2 = tr.Editor?.GetSelection(filter);

// 处理结果
if (result2?.Status == PromptStatus.OK)
{
    SelectionSet ss = result2.Value;
    tr.Editor?.WriteMessage($"\n选择了 {ss.Count} 个图元");
}

4.5.2 不同的选择方式

让用户框选或点选

using var tr = new DBTrans();

var filter = OpFilter.Build(e => e.Dxf(0) == "CIRCLE");
var result = tr.Editor?.GetSelection(filter);

if (result?.Status == PromptStatus.OK)
{
    foreach (SelectedObject obj in result.Value)
    {
        var circle = tr.GetObject<Circle>(obj.ObjectId);
        if (circle != null)
        {
            tr.Editor?.WriteMessage($"\n圆心:{circle.Center}, 半径:{circle.Radius}");
        }
    }
}

选择全部

using var tr = new DBTrans();

// 选择所有符合条件的图元
var filter = OpFilter.Build(e => e.Dxf(8) == "MyLayer");
var result = tr.Editor?.SelectAll(filter);

if (result?.Status == PromptStatus.OK)
{
    tr.Editor?.WriteMessage($"\n共找到 {result.Value.Count} 个图元");
}

窗口选择

using var tr = new DBTrans();

// 定义选择窗口
Point3d pt1 = new Point3d(0, 0, 0);
Point3d pt2 = new Point3d(100, 100, 0);

var filter = OpFilter.Build(e => e.Dxf(0) == "LINE");

// 窗口选择(完全在窗口内的图元)
var result = tr.Editor?.SelectWindow(pt1, pt2, filter);

// 交叉选择(与窗口相交的图元)
var result2 = tr.Editor?.SelectCrossingWindow(pt1, pt2, filter);

围栏选择

using var tr = new DBTrans();

// 定义围栏点
Point3dCollection fence = new Point3dCollection
{
    new Point3d(0, 0, 0),
    new Point3d(50, 50, 0),
    new Point3d(100, 0, 0)
};

var filter = OpFilter.Build(e => e.Dxf(0) == "LINE");
var result = tr.Editor?.SelectFence(fence, filter);

4.5.3 选择提示选项

可以设置选择提示的各种选项:

using var tr = new DBTrans();

// 创建选择选项
var options = new PromptSelectionOptions();
options.MessageForAdding = "\n请选择直线";
options.MessageForRemoval = "\n请移除直线";
options.AllowDuplicates = false;
options.RejectObjectsOnLockedLayers = true;

// 添加关键字
options.Keywords.Add("All", "全选", "全选(A)");
options.Keywords.Add("Cancel", "取消", "取消(C)");

// 处理关键字事件
options.KeywordInput += (s, e) =>
{
    if (e.Input == "All")
    {
        // 处理全选
    }
};

var filter = OpFilter.Build(e => e.Dxf(0) == "LINE");
var result = tr.Editor?.GetSelection(options, filter);

4.6 处理选择结果

4.6.1 基本处理

using var tr = new DBTrans();

var filter = OpFilter.Build(e => e.Dxf(0) == "CIRCLE");
var result = tr.Editor?.GetSelection(filter);

if (result?.Status != PromptStatus.OK)
{
    tr.Editor?.WriteMessage("\n未选择任何图元");
    return;
}

SelectionSet ss = result.Value;

// 遍历选择集
foreach (SelectedObject obj in ss)
{
    if (obj == null) continue;
    
    var circle = tr.GetObject<Circle>(obj.ObjectId, OpenMode.ForWrite);
    if (circle != null)
    {
        // 修改圆的颜色
        circle.Color = Color.FromColorIndex(ColorMethod.ByAci, 1);
    }
}

tr.Editor?.WriteMessage($"\n已修改 {ss.Count} 个圆的颜色");

4.6.2 使用LINQ处理

using var tr = new DBTrans();

var filter = OpFilter.Build(e => e.Dxf(0) == "CIRCLE");
var result = tr.Editor?.GetSelection(filter);

if (result?.Status != PromptStatus.OK) return;

// 使用LINQ获取所有圆
var circles = result.Value
    .Cast<SelectedObject>()
    .Where(obj => obj != null)
    .Select(obj => tr.GetObject<Circle>(obj.ObjectId))
    .Where(c => c != null);

// 统计信息
double totalArea = circles.Sum(c => Math.PI * c!.Radius * c.Radius);
double avgRadius = circles.Average(c => c!.Radius);

tr.Editor?.WriteMessage($"\n总面积:{totalArea:F2}");
tr.Editor?.WriteMessage($"\n平均半径:{avgRadius:F2}");

4.6.3 使用扩展方法

IFoxCAD提供了选择集的扩展方法:

using var tr = new DBTrans();

var filter = OpFilter.Build(e => e.Dxf(0) == "LINE");
var result = tr.Editor?.GetSelection(filter);

if (result?.Status != PromptStatus.OK) return;

// 获取所有ObjectId
var ids = result.Value.GetObjectIds();

// 获取所有图元
var entities = ids.Select(id => tr.GetObject<Entity>(id)).Where(e => e != null);

// 批量修改
foreach (var ent in entities)
{
    using (ent!.ForWrite())
    {
        ent.Layer = "NewLayer";
    }
}

4.7 高级过滤技巧

4.7.1 扩展数据过滤

可以根据扩展数据(XData)进行过滤:

using var tr = new DBTrans();

// 过滤具有特定应用程序扩展数据的图元
// 组码-3表示扩展数据
var filter = OpFilter.Build(e => 
    e.Dxf(-3) == "MyAppName");

var result = tr.Editor?.GetSelection(filter);

4.7.2 块参照内容过滤

过滤特定块的块参照:

using var tr = new DBTrans();

// 选择特定块的所有参照
var filter = OpFilter.Build(e => 
    e.Dxf(0) == "INSERT" & e.Dxf(2) == "MyBlock");

var result = tr.Editor?.GetSelection(filter);

4.7.3 多类型过滤

同时选择多种类型的图元:

using var tr = new DBTrans();

// 选择直线、圆和圆弧
var filter = OpFilter.Build(e =>
    e.Or(
        e.Dxf(0) == "LINE",
        e.Dxf(0) == "CIRCLE",
        e.Dxf(0) == "ARC"
    ));

var result = tr.Editor?.GetSelection(filter);

4.7.4 嵌套条件

复杂的嵌套条件:

using var tr = new DBTrans();

// (在Layer1上的直线或圆) 或 (在Layer2上且为红色的任何图元)
var filter = OpFilter.Build(e =>
    e.Or(
        e.And(
            e.Dxf(8) == "Layer1",
            e.Or(e.Dxf(0) == "LINE", e.Dxf(0) == "CIRCLE")
        ),
        e.And(
            e.Dxf(8) == "Layer2",
            e.Dxf(62) == 1
        )
    ));

var result = tr.Editor?.GetSelection(filter);

4.8 常用过滤器示例

4.8.1 按图元类型选择

public static class FilterExamples
{
    // 选择所有直线
    public static OpFilter Lines() => 
        OpFilter.Build(e => e.Dxf(0) == "LINE");
    
    // 选择所有圆
    public static OpFilter Circles() => 
        OpFilter.Build(e => e.Dxf(0) == "CIRCLE");
    
    // 选择所有圆弧
    public static OpFilter Arcs() => 
        OpFilter.Build(e => e.Dxf(0) == "ARC");
    
    // 选择所有多段线
    public static OpFilter Polylines() => 
        OpFilter.Build(e => 
            e.Dxf(0) == "LWPOLYLINE" | e.Dxf(0) == "POLYLINE");
    
    // 选择所有文字
    public static OpFilter Texts() => 
        OpFilter.Build(e => 
            e.Dxf(0) == "TEXT" | e.Dxf(0) == "MTEXT");
    
    // 选择所有块参照
    public static OpFilter BlockReferences() => 
        OpFilter.Build(e => e.Dxf(0) == "INSERT");
    
    // 选择所有标注
    public static OpFilter Dimensions() => 
        OpFilter.Build(e => e.Dxf(0) == "DIMENSION");
    
    // 选择所有填充
    public static OpFilter Hatches() => 
        OpFilter.Build(e => e.Dxf(0) == "HATCH");
}

4.8.2 按属性选择

public static class AttributeFilters
{
    // 按图层选择
    public static OpFilter ByLayer(string layerName) => 
        OpFilter.Build(e => e.Dxf(8) == layerName);
    
    // 按颜色选择
    public static OpFilter ByColor(int colorIndex) => 
        OpFilter.Build(e => e.Dxf(62) == colorIndex);
    
    // 按线型选择
    public static OpFilter ByLinetype(string linetypeName) => 
        OpFilter.Build(e => e.Dxf(6) == linetypeName);
    
    // 选择特定块的参照
    public static OpFilter ByBlockName(string blockName) => 
        OpFilter.Build(e => 
            e.Dxf(0) == "INSERT" & e.Dxf(2) == blockName);
    
    // 选择半径大于指定值的圆
    public static OpFilter CirclesWithRadiusGreaterThan(double radius) =>
        OpFilter.Build(e => 
            e.Dxf(0) == "CIRCLE" & e.Dxf(40) > radius);
}

4.8.3 组合过滤器

public static class CombinedFilters
{
    // 选择指定图层上的指定类型图元
    public static OpFilter TypeOnLayer(string entityType, string layerName) =>
        OpFilter.Build(e => 
            e.Dxf(0) == entityType & e.Dxf(8) == layerName);
    
    // 选择多个图层上的图元
    public static OpFilter OnLayers(params string[] layerNames)
    {
        if (layerNames.Length == 0)
            return OpFilter.Build(e => e.Dxf(0) == "*");
        
        if (layerNames.Length == 1)
            return OpFilter.Build(e => e.Dxf(8) == layerNames[0]);
        
        return OpFilter.Build(e =>
        {
            var first = e.Dxf(8) == layerNames[0];
            foreach (var name in layerNames.Skip(1))
            {
                first = first | e.Dxf(8) == name;
            }
            return first;
        });
    }
    
    // 选择除了指定图层外的所有图元
    public static OpFilter NotOnLayer(string layerName) =>
        OpFilter.Build(e => !(e.Dxf(8) == layerName));
}

4.9 实际应用案例

4.9.1 图元统计工具

[CommandMethod("EntityStats")]
public void EntityStatistics()
{
    using var tr = new DBTrans();
    
    // 获取所有图元
    var result = tr.Editor?.SelectAll();
    if (result?.Status != PromptStatus.OK) return;
    
    // 统计各类型图元数量
    var stats = result.Value
        .Cast<SelectedObject>()
        .Where(obj => obj != null)
        .Select(obj => tr.GetObject<Entity>(obj.ObjectId))
        .Where(ent => ent != null)
        .GroupBy(ent => ent!.GetType().Name)
        .Select(g => new { Type = g.Key, Count = g.Count() })
        .OrderByDescending(x => x.Count);
    
    tr.Editor?.WriteMessage("\n\n图元统计:");
    tr.Editor?.WriteMessage("\n" + new string('-', 30));
    foreach (var stat in stats)
    {
        tr.Editor?.WriteMessage($"\n{stat.Type,-20}{stat.Count,10}");
    }
    tr.Editor?.WriteMessage("\n" + new string('-', 30));
    tr.Editor?.WriteMessage($"\n{"总计",-20}{result.Value.Count,10}");
}

4.9.2 批量修改图层

[CommandMethod("BatchChangeLayer")]
public void BatchChangeLayer()
{
    using var tr = new DBTrans();
    
    // 获取源图层名
    var sourceResult = tr.Editor?.GetString("\n请输入源图层名:");
    if (sourceResult?.Status != PromptStatus.OK) return;
    string sourceLayer = sourceResult.StringResult;
    
    // 获取目标图层名
    var targetResult = tr.Editor?.GetString("\n请输入目标图层名:");
    if (targetResult?.Status != PromptStatus.OK) return;
    string targetLayer = targetResult.StringResult;
    
    // 确保目标图层存在
    if (!tr.LayerTable.Has(targetLayer))
    {
        tr.LayerTable.Add(targetLayer);
    }
    
    // 选择源图层上的所有图元
    var filter = OpFilter.Build(e => e.Dxf(8) == sourceLayer);
    var selectResult = tr.Editor?.SelectAll(filter);
    
    if (selectResult?.Status != PromptStatus.OK)
    {
        tr.Editor?.WriteMessage($"\n图层 {sourceLayer} 上没有图元");
        return;
    }
    
    // 修改图层
    int count = 0;
    foreach (SelectedObject obj in selectResult.Value)
    {
        if (obj == null) continue;
        
        var ent = tr.GetObject<Entity>(obj.ObjectId, OpenMode.ForWrite);
        if (ent != null)
        {
            ent.Layer = targetLayer;
            count++;
        }
    }
    
    tr.Editor?.WriteMessage($"\n已将 {count} 个图元从 {sourceLayer} 移动到 {targetLayer}");
}

4.9.3 圆形标注工具

[CommandMethod("AnnotateCircles")]
public void AnnotateCircles()
{
    using var tr = new DBTrans();
    
    // 选择圆
    var filter = OpFilter.Build(e => e.Dxf(0) == "CIRCLE");
    var result = tr.Editor?.GetSelection(filter);
    
    if (result?.Status != PromptStatus.OK)
    {
        tr.Editor?.WriteMessage("\n未选择任何圆");
        return;
    }
    
    // 确保标注图层存在
    if (!tr.LayerTable.Has("标注"))
    {
        tr.LayerTable.Add("标注", layer =>
        {
            layer.Color = Color.FromColorIndex(ColorMethod.ByAci, 3);
        });
    }
    
    // 为每个圆添加标注
    foreach (SelectedObject obj in result.Value)
    {
        if (obj == null) continue;
        
        var circle = tr.GetObject<Circle>(obj.ObjectId);
        if (circle == null) continue;
        
        // 创建标注文字
        var text = new DBText();
        text.Position = circle.Center;
        text.TextString = $"R={circle.Radius:F2}";
        text.Height = circle.Radius / 3;
        text.Layer = "标注";
        text.HorizontalMode = TextHorizontalMode.TextCenter;
        text.VerticalMode = TextVerticalMode.TextVerticalMid;
        text.AlignmentPoint = circle.Center;
        
        tr.CurrentSpace.AddEntity(text);
    }
    
    tr.Editor?.WriteMessage($"\n已为 {result.Value.Count} 个圆添加标注");
}

4.9.4 图元高亮显示

[CommandMethod("HighlightByType")]
public void HighlightByType()
{
    using var tr = new DBTrans();
    
    // 获取要高亮的类型
    var typeResult = tr.Editor?.GetString("\n请输入图元类型(如LINE、CIRCLE):");
    if (typeResult?.Status != PromptStatus.OK) return;
    string entityType = typeResult.StringResult.ToUpper();
    
    // 选择指定类型的图元
    var filter = OpFilter.Build(e => e.Dxf(0) == entityType);
    var result = tr.Editor?.SelectAll(filter);
    
    if (result?.Status != PromptStatus.OK)
    {
        tr.Editor?.WriteMessage($"\n未找到类型为 {entityType} 的图元");
        return;
    }
    
    // 高亮显示
    foreach (SelectedObject obj in result.Value)
    {
        if (obj == null) continue;
        
        var ent = tr.GetObject<Entity>(obj.ObjectId);
        if (ent != null)
        {
            ent.Highlight();
        }
    }
    
    tr.Editor?.WriteMessage($"\n已高亮 {result.Value.Count} 个 {entityType} 图元");
    tr.Editor?.WriteMessage("\n按任意键取消高亮...");
    tr.Editor?.GetString("");
    
    // 取消高亮
    foreach (SelectedObject obj in result.Value)
    {
        if (obj == null) continue;
        
        var ent = tr.GetObject<Entity>(obj.ObjectId);
        if (ent != null)
        {
            ent.Unhighlight();
        }
    }
}

4.10 本章小结

本章我们深入学习了IFoxCAD的选择集过滤器系统:

  1. 选择集基础:理解了选择集的概念和CAD原生过滤器的使用问题
  2. OpFilter体系:学习了OpFilter类的设计和体系结构
  3. 构建过滤器:掌握了Build方法、Dxf方法和各种比较操作
  4. 逻辑组合:学习了And、Or、Not等逻辑操作的使用
  5. 获取选择集:掌握了各种选择方式和选项设置
  6. 处理结果:学习了选择结果的处理方法
  7. 高级技巧:了解了扩展数据过滤、嵌套条件等高级用法
  8. 实际案例:通过多个实际案例巩固所学知识

OpFilter系统极大地简化了选择集过滤器的创建,使代码更加简洁和可读。下一章我们将学习扩展数据与字典操作,这是CAD二次开发中数据存储的重要方式。

posted @ 2025-11-27 12:00  我才是银古  阅读(0)  评论(0)    收藏  举报