写点什么

(WEB 端 CAD)网页 CAD 中的“组”功能开发

作者:WEB CAD SDK
  • 2025-11-14
    四川
  • 本文字数:25630 字

    阅读完需:约 84 分钟

(WEB端CAD)网页CAD中的“组”功能开发

在使用 CAD 工具进行绘图时,面对复杂的图形结构,如何高效地管理多个对象成为提升工作效率的关键。CAD 提供的“组”功能,正是为解决这一问题而设计的实用工具。本文将全面介绍 mxcad 中”组“的概念,以及如何实现组相关的功能开发。

一、什么是“组”(Group)?

在 CAD 中,组(Group) 是指将多个图形对象逻辑地组合在一起,形成一个可被统一操作的集合。组不会创建新的图元实体,也不会改变对象本身的几何属性,仅是一种命名的对象集合,组对象包含特点如下:

  • 组内的对象保持独立,可单独编辑。

  • 选择组中任意一个对象时,整个组可被选中(取决于系统设置)。

  • 每个组有唯一的名称,便于识别和管理。

  • 支持嵌套:一个组可以包含另一个组,形成层级结构。

  • 组不作为独立实体存储在图形数据库中,仅作为对象的逻辑关联存在。

二、组的核心功能开发

1. 创建组

该功能流程是从用户执行“创建组”命令开始。首先,系统初始化相关变量(如组名、描述和对象列表),并获取当前图形数据库中的组管理字典。

随后进入主循环,提示用户“选择对象”。用户可以通过点击或框选方式选择一个或多个图形对象,所选对象的 ID 将被保存到临时列表中。

在选择过程中,用户可随时输入关键字进行设置:

  • 输入 N(名称):进入命名流程,系统提示“输入编组名”。此时可输入 [查询(A)] 来查看已存在的组名;若输入 * 或直接回车,则列出所有组;否则查询指定组信息。输入名称后,系统检查是否重名,若无冲突则保存名称并返回选择状态。

  • 输入 D(说明):进入说明设置,提示“输入编组说明”,用户输入的文本将作为该组的描述信息。


当用户完成选择并按 回车或空格键 确认后,系统开始创建组:


  • 首先检查所选对象中是否有成员已属于其他组。

  • 若存在此类情况,则弹出确认提示:“包含相同对象的组已经存在。仍要创建新的组?<N>”,并提供“是(Y)/否(N)”选项。

  • 若用户选择“否”或取消操作,命令终止。

  • 若用户确认继续或无冲突,则调用底层 API 创建组,并将之前输入的描述信息赋值给新组。


最后,组创建完成,系统退出循环,命令执行结束。整个流程支持 ESC 中断或新命令打断,确保操作的安全性和灵活性。根据上述流程调用 mxcad 内部 API 接口实现方法如下:

import { McDbEntity, McDbGroup, McDbPolyline, McGePoint3d, McObjectId, MxCADSelectionSet, MxCADUiPrKeyWord, MxCADUiPrPoint, MxCADUiPrString, MxCADUtility, MxCpp } from "mxcad";import { DetailedResult, MxFun, MrxDbgUiPrBaseReturn } from "mxdraw";interface GroupObject {    name: string,    group: McDbGroup}// 根据实体查找组const getGroupForEntity = (entity: McDbEntity): GroupObject[] => {    const database = MxCpp.getCurrentDatabase()    const groupDict = database.GetGroupDictionary()    const handle = entity.getHandle()    const groupNames = groupDict.getAllObjectName()    const length = groupNames.length();    let groupArr: GroupObject[] = [];    for (let index = 0; index < length; index++) {        const groupName = groupNames.at(index);        const groupId = groupDict.getAt(groupName)        const group = groupId.getMcDbObject() as McDbGroup        if (!group) continue;        const entityIds = group.getAllEntityId();        entityIds.forEach(entityId => {            if (entityId.getMcDbEntity()?.getHandle() === handle) groupArr.push({ name: groupName, group })        });    };    return groupArr}// 创建组async function Mx_Group() {  let description = ""  let ids: McObjectId[] = [];  const database = MxCpp.getCurrentDatabase();  const groupDict = database.GetGroupDictionary();  const mxcad = MxCpp.getCurrentMxCAD();  // 设定未命名组名  const groupNames = groupDict.getAllObjectName();  let num = 0;  groupNames.forEach(item => {    if (/^\*/.test(item)) {      num += 1;    }  });  let name: string = `*A${num + 1}`;  // 创建组  const createGroup = async () => {    const isPresence = ids.some((id) => {      return database.getEntitiesInTheGroup(id).length !== 0    })    if (isPresence) {      const getKey = new MxCADUiPrKeyWord();      getKey.setMessage(`包含相同对象的组已经存在。仍要创建新的组?<N>`);      getKey.setKeyWords(`[是(Y)/否(N)]`);      const key = await getKey.go();      ids.forEach(id => {        id.getMcDbEntity().highlight(false);      })      mxcad.updateDisplay();      if (key?.toLocaleUpperCase() === "N") {        return      }      if (!key) return    }    if (database.CreateGroup(ids, name)) {      const groupId = groupDict.getAt(name)      const group = groupId.getMcDbObject() as McDbGroup;      if (description) group.description = description;      if (/^\*/.test(name)) {        MxPluginContext.useMessage().success('未命名组已创建');      } else {        MxPluginContext.useMessage().success(`组${name}已创建`);      }      ids.forEach(id => {        id.getMcDbEntity().highlight(false);      })      mxcad.updateDisplay();    };  };  while (true) {    const getEntityPt = new MxCADUiPrPoint();    getEntityPt.setMessage('选择对象');    getEntityPt.setKeyWords(`[名称(N)/说明(D)]`);    getEntityPt.setDisableOsnap(true);    getEntityPt.setDisableDynInput(true);    getEntityPt.disableAllTrace(true);    const hoverSelectEnts: McDbEntity[] = [];    getEntityPt.setUserDraw((pt, pw) => {      if (hoverSelectEnts.length) hoverSelectEnts.forEach(ent => ent.highlight(false));      hoverSelectEnts.length = 0;      const entId = MxCADUtility.findEntAtPoint(pt.x, pt.y, pt.z, -1);      if (entId.isValid() && !ids.map(item => item.id).includes(entId.id)) {        const ent = entId.getMcDbEntity();        const arr = getGroupForEntity(ent);        if (arr.length) {          const group = arr[0].group;          group.getAllEntityId().forEach(id => {            const ent = id.getMcDbEntity();            ent.highlight(true);            hoverSelectEnts.push(ent)          })        } else {          ent.highlight(true);          hoverSelectEnts.push(ent)        }      }    });    const pt = await getEntityPt.go();    hoverSelectEnts.forEach(ent => ent.highlight(false));    // 如果选择关键字,则执行相关操作    if (getEntityPt.getStatus() == MrxDbgUiPrBaseReturn.kKeyWord) {      if (getEntityPt.isKeyWordPicked("N")) {        while (true) {          const getName = new MxCADUiPrString()          getName.setMessage("输入编组名")          getName.setKeyWords(`[查询(A)]`)          const str = await getName.go()          if (getName.getDetailedResult() === DetailedResult.kCodeAbort || getName.getDetailedResult() === DetailedResult.kEcsIn || getName.getDetailedResult() === DetailedResult.kNewCommadIn) return          if (getEntityPt.getDetailedResult() === DetailedResult.kNullEnterIn || getEntityPt.getDetailedResult() === DetailedResult.kNullSpaceIn || getEntityPt.getDetailedResult() === DetailedResult.kMouseRightIn) {            return createGroup()          }          if (getName.isKeyWordPicked("A")) {            getName.setMessage("请输入要列出的编码组名"+ "<*>")            getName.setKeyWords("")            const name = await getName.go();            if (getName.getDetailedResult() === DetailedResult.kCodeAbort || getName.getDetailedResult() === DetailedResult.kEcsIn || getName.getDetailedResult() === DetailedResult.kNewCommadIn) return            if (name && name !== "*") {              const groupId = groupDict.getAt(name)              const group = groupId.getMcDbObject() as McDbGroup              MxFun.acutPrintf(`\n 定义的编组:`)              if (group) {                MxFun.acutPrintf(`\n${group.name}`)              }            }            else if (name === "*" || getName.getDetailedResult() === DetailedResult.kNullEnterIn || getName.getDetailedResult() === DetailedResult.kNullSpaceIn) {              const groupIds = groupDict.getAllObject()              MxFun.acutPrintf(`\n 定义的编组:`)              groupIds.forEach((groupId) => {                const group = groupId.getMcDbObject() as McDbGroup                group && MxFun.acutPrintf(`\n ${group.name}`)              })            }            continue;          }          if (!str) return;          if (/^\*/.test(str)) {            MxFun.acutPrintf(`*无效`);            continue;          }          const groupId = groupDict.getAt(str)          const group = groupId.getMcDbObject() as McDbGroup          if (group && groupId.isValid()) {            MxFun.acutPrintf(`编组${str} 已经存在`);            continue;          }          name = str;          if (ids.length) {            ids.forEach(id => {              const ent = id.getMcDbEntity();              ent.highlight(false);            })            return createGroup();          } else {            break;          }        }      } else if (getEntityPt.isKeyWordPicked('D')) {        const getName = new MxCADUiPrString()        getName.setMessage("输入编组说明")        const str = await getName.go();        if (!str) break;        description = str        continue;      }    } else if (getEntityPt.getStatus() === MrxDbgUiPrBaseReturn.kNone) {      if (!ids.length) {        return MxPluginContext.useMessage().success('未选择对象,未创建编组');      } else {        ids.forEach(id => {          const ent = id.getMcDbEntity();          ent.highlight(false);        })        return createGroup();      }    } else if (getEntityPt.getStatus() === MrxDbgUiPrBaseReturn.kCancel) {      ids.forEach(id => {        const ent = id.getMcDbEntity();        ent.highlight(false);      })      return    } else {      // 判断是否选中实体      if (pt && hoverSelectEnts.length) {        const selectIds = hoverSelectEnts.map(item => {          item.highlight(true);          return item.getObjectID()        })        ids.push(...selectIds);        continue;      } else if (pt && !hoverSelectEnts.length) {        getEntityPt.setUserDraw((point, pw) => {          const pts = [pt, new McGePoint3d(pt.x, point.y), point, new McGePoint3d(point.x, pt.y)]          // 设置范围框颜色即位置          let pl = new McDbPolyline();          pl.isClosed = true;          pts.forEach(pt => pl.addVertexAt(pt));          pw.setColor(0xFFFFFF);          pw.drawMcDbEntity(pl);          // 动态绘制矩形填充框          const geometry = new THREE.BufferGeometry();          geometry.setFromPoints([            new THREE.Vector3(pt.x, pt.y, pt.z),            new THREE.Vector3(pt.x, point.y, point.z),            new THREE.Vector3(point.x, point.y, point.z),            new THREE.Vector3(point.x, pt.y, pt.z)          ]);          geometry.attributes.uv = new THREE.BufferAttribute(new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), 2);          geometry.setIndex([0, 1, 2, 0, 2, 3]);          // 创建材质(半透明的颜色)          const material = new THREE.MeshBasicMaterial({            color: 0x004D00,            transparent: true,            opacity: 0.5,            side: THREE.DoubleSide          });          const mesh = new THREE.Mesh(geometry, material);          pw.drawEntity(mesh);        });        const nextPt = await getEntityPt.go();        if (!nextPt) break;        const ss = new MxCADSelectionSet();        await ss.crossingSelect(pt.x, pt.y, nextPt.x, nextPt.y);        ss.forEach(id => {          if (!ids.map(i => i.id).includes(id.id)) {            const ent = id.getMcDbEntity();            const arr = getGroupForEntity(ent);            if (arr.length) {              const group = arr[0].group;              group.getAllEntityId().forEach(id => {                id.getMcDbEntity().highlight(true)                ids.push(id);              })            } else {              ent.highlight(true);              ids.push(id);            }          }        });        continue;      } else {        continue;      };    }  }}
复制代码

2. 解除组

解除组的功能流程如下:

命令启动后,系统提示用户“选择组”,并支持通过关键字 [名称(N)] 切换为按名称分解模式。在用户操作过程中,系统启用悬停预览功能:当鼠标移动到某个对象上时,会自动查询该对象所属的组,并高亮显示该组内的所有成员对象,便于用户直观判断将要操作的范围。

接下来,根据用户的选择进入不同分支:

  1. 若用户输入 N(名称): 

 - 进入“按名称分解”模式,提示“输入编组名”。

- 支持输入关键字 [查询(A)]

- 若输入 A,可进一步输入要查询的组名; 

- 输入 * 或直接回车,则列出当前图形中所有已定义的组名;   

- 输入具体名称,则检查并显示该组是否存在。   

- 用户输入组名后,系统查找对应组:   

- 若存在,执行分解操作(清空组内对象并从组字典中移除),提示“组 已分解”;   

- 若不存在,提示“编组 未定义”,并允许重新输入。


  1. 若用户点击某个对象:   

- 系统获取该对象,并查询其所属的所有组(一个对象可能属于多个组)。   

- 若对象仅属于一个组,则直接选中该组,准备分解。   

- 若对象属于多个组,则进入选择流程:     

- 提示“对象是多个组的成员<接受>”,提供 [接受(A)/下一个(N)] 选项;     

- 选择 A:接受当前高亮的组;     

- 选择 N:切换到下一个组,并更新高亮显示;     

- 可循环切换,直到用户确认或取消。   - 确定目标组后,记录其名称。


最后,系统根据选定的组名执行分解操作:


  • 从组字典中获取该组对象;

  • 调用 clear() 清空组内成员引用;

  • 调用 remove() 从字典中删除该组;

  • 提示“组 已分解”或“对象不是组成员”(如未选中有效组)。


操作完成后,清除所有高亮显示的对象,确保界面恢复整洁,命令结束。其具体实现代码如下:


import { McDbEntity, McDbGroup, McDbPolyline, McGePoint3d, McObjectId, MxCADSelectionSet, MxCADUiPrKeyWord, MxCADUiPrPoint, MxCADUiPrString, MxCADUtility, MxCpp } from "mxcad";import { DetailedResult, MxFun, MrxDbgUiPrBaseReturn } from "mxdraw";// 解除编组async function Mx_Ungroup() {    const ents: McDbEntity[] = [];    let groupArr: GroupObject[] = [];    let name!: string;    const database = MxCpp.getCurrentDatabase();    const groupDict = database.GetGroupDictionary();    let index: number = 0;    const getEnt = new MxCADUiPrEntity();    getEnt.setMessage('选择组');    getEnt.setKeyWords(`[名称(N)]`);    getEnt.setUserDraw((pt, pw) => {        ents.forEach(ent => ent.highlight(false));        ents.length = 0;        const entId = MxCADUtility.findEntAtPoint(pt.x, pt.y, pt.z, -1);        if (entId.isValid()) {            const ent = entId.getMcDbEntity();            groupArr = getGroupForEntity(ent);//getGroupForEntity参考上述创建组内代码            if (groupArr.length) {                const group = groupArr[index].group;                group.getAllEntityId().forEach(id => {                    const entity = id.getMcDbEntity();                    entity.highlight(true);                    ents.push(entity);                })            }        }    });    const entId = await getEnt.go();    if (getEnt.getStatus() === MrxDbgUiPrBaseReturn.kKeyWord) {        if (getEnt.isKeyWordPicked('N')) {            while (true) {                const getString = new MxCADUiPrString();                getString.setMessage('输入编组名');                getString.setKeyWords(`[查询(A)]`);                const str = await getString.go();                if (getString.getStatus() === MrxDbgUiPrBaseReturn.kOk) {                    // 删除组                    const groupId = groupDict.getAt(str);                    const group = groupId.getMcDbObject() as McDbGroup;                    if (groupId.isValid() && group) {                        group.clear();                        groupDict.remove(str);                        MxPluginContext.useMessage().success('组 ' + str + ' 已分解');                        if (ents.length) ents.forEach(ent => ent.highlight(false));                        return;                    } else {                        MxFun.acutPrintf('编组 ' + str + ' 未定义');                        continue;                    }                } else if (getString.getStatus() === MrxDbgUiPrBaseReturn.kKeyWord) {                    // 查询组                    getString.setMessage("请输入要列出的编码组名" + "<*>")                    getString.setKeyWords("")                    const name = await getString.go();                    if (getString.getStatus() === MrxDbgUiPrBaseReturn.kOk) {                        if (name && name !== "*") {                            const groupId = groupDict.getAt(name)                            const group = groupId.getMcDbObject() as McDbGroup                            MxFun.acutPrintf(`\n 定义的编组:`)                            if (group) {                                MxFun.acutPrintf(`\n${group.name}`)                            }                        } else if (name === "*") {                            const groupIds = groupDict.getAllObject()                            MxFun.acutPrintf(`\n 定义的编组:`)                            groupIds.forEach((groupId) => {                                const group = groupId.getMcDbObject() as McDbGroup                                group && MxFun.acutPrintf(`\n ${group.name}`)                            })                        }                    } else if (getString.getStatus() === MrxDbgUiPrBaseReturn.kNone) {                        const groupIds = groupDict.getAllObject()                        MxFun.acutPrintf(`\n 定义的编组:`)                        groupIds.forEach((groupId) => {                            const group = groupId.getMcDbObject() as McDbGroup                            group && MxFun.acutPrintf(`\n ${group.name}`)                        })                    }                    continue;                }            }        }    } else if (getEnt.getStatus() === MrxDbgUiPrBaseReturn.kOk) {        if (groupArr.length === 1) {            name = groupArr[0].name        } else if (groupArr.length > 1) {            while (true) {                const getKeys = new MxCADUiPrKeyWord();                getKeys.setMessage('对象是多个组的成员<接受>')                getKeys.setKeyWords('[接受(A)/下一个(N)]');                let key = await getKeys.go();                if (key === "A") {                    name = groupArr[index].name;                    break;                } else if (key === "N") {                    ents.forEach(ent => ent.highlight(false));                    ents.length = 0;                    index + 1 > groupArr.length - 1 ? index = 0 : index += 1;                    const res = groupArr[index];                    res.group.getAllEntityId().forEach(id => {                        const ent = id.getMcDbEntity();                        ent.highlight(true);                        ents.push(ent);                    });                    continue;                } else {                    if (ents.length) ents.forEach(ent => ent.highlight(false));                    return;                }            }        }        if (name) {            const groupId = groupDict.getAt(name)            const group = groupId.getMcDbObject() as McDbGroup            if (group) {                group.clear();                groupDict.remove(name);                MxPluginContext.useMessage().success(`组 ${name} 已分解`);            } else {                MxPluginContext.useMessage().success('对象不是组成员');            }        } else {            MxPluginContext.useMessage().success('对象不是组成员');        };        if (ents.length) ents.forEach(ent => ent.highlight(false));    }}
复制代码

3. 编辑组

编辑图形中已有对象组(Group)的交互式功能。其主要功能是允许用户通过选择对象或输入组名的方式,找到目标组,并对其进行添加成员、删除成员或重命名等操作。命令启动后,系统首先提示“选择组”,并支持通过关键字 [名称(N)] 切换为按名称选择模式。在用户移动鼠标时,系统会启用悬停预览功能:自动检测光标下的对象,查询其所属的组,并高亮显示该组内的所有成员,帮助用户直观判断当前将要操作的对象范围。

如果用户点击了一个对象,系统会获取该对象所属的所有组:

  • 若对象不属于任何组,则提示“对象不是组成员”;

  • 若只属于一个组,则直接进入编辑操作;

  • 若属于多个组,则提示“对象是多个组的成员<接受>”,并提供 [接受(A)/下一个(N)] 选项,用户可循环切换高亮不同的组,直到确认目标组。


如果用户选择 [名称(N)] 模式,则进入按名称编辑流程:

  • 提示“输入组的名称”,并支持 [查询(A)] 关键字;

  • 输入 A 后可查看所有组名(输入 *)或查询特定组是否存在;

  • 输入有效组名后,若组存在,则加载并高亮其成员,进入编辑;若不存在,则提示“编组 xxx 不存在”,并允许重新输入。确定目标组后,系统弹出操作菜单:[添加对象(A)/删除对象(R)/重命名(REN)]

  • 添加对象(A):用户可通过单击或框选方式选择要加入的对象。系统会动态高亮预览可添加的对象(不包括已存在于组内的对象),支持窗口和交叉选择,完成后将所选对象追加到组中,并提示“添加对象成功!”。

  • 删除对象(R):用户选择组内对象进行移除。系统仅允许删除当前组中的成员,选择后会从组中剔除这些对象,并通过清空后重新添加剩余对象的方式更新组内容。

  • 重命名(REN):提示用户输入新名称。支持再次使用 [查询(A)] 查看现有组名以避免冲突。若新名称已被其他组使用,则提示“编组 xxx 已经存在”并要求重新输入;否则更新组名,并提示“修改组名成功”。


实现上述流程的具体功能代码如下:

import { McDbEntity, McDbGroup, McDbPolyline, McGePoint3d, McObjectId, MxCADSelectionSet, MxCADUiPrKeyWord, MxCADUiPrPoint, MxCADUiPrString, MxCADUtility, MxCpp } from "mxcad";import { DetailedResult, MxFun, MrxDbgUiPrBaseReturn } from "mxdraw";// 编辑组async function Mx_Groupedit() {    const ents: McDbEntity[] = [];//高亮实体数组    let groupArr: GroupObject[] = [];//实体组集合    let index: number = 0;    let name: string = '';    const database = MxCpp.getCurrentDatabase();    const groupDict = database.GetGroupDictionary();    const mxcad = MxCpp.getCurrentMxCAD();    const editGroup = async () => {        // 选中目标组        if (groupArr.length === 1) {            name = groupArr[0].name        } else if (groupArr.length > 1) {            while (true) {                const getKeys = new MxCADUiPrKeyWord();                getKeys.setMessage('对象是多个组的成员<接受>')                getKeys.setKeyWords(`[接受(A)/下一个(N)]`);                let key = await getKeys.go();                if (key === "A") {                    name = groupArr[index].name;                    break;                } else if (key === "N") {                    ents.forEach(ent => ent.highlight(false));                    ents.length = 0;                    index + 1 > groupArr.length - 1 ? index = 0 : index += 1;                    const res = groupArr[index];                    res.group.getAllEntityId().forEach(id => {                        const ent = id.getMcDbEntity();                        ent.highlight(true);                        ents.push(ent);                    });                    continue;                } else {                    continue;                }            }        } else {            name = '';        }        // 操作目标组        if (name) {            const groupId = groupDict.getAt(name)            const group = groupId.getMcDbObject() as McDbGroup            if (group) {                // 进入编辑组                const getKey = new MxCADUiPrKeyWord();                getKey.setMessage(t('输入选项'));                getKey.setKeyWords(`[添加对象(A)/删除对象(R)/重命名(REN)]`);                const key = await getKey.go();                if (!key) return;                if (key === 'A') {                    const selectIds: McObjectId[] = [];                    // 添加对象                    while (true) {                        const getEntityPt = new MxCADUiPrPoint();                        getEntityPt.setMessage('选择要添加到编组的对象');                        getEntityPt.setDisableOsnap(true);                        getEntityPt.setDisableDynInput(true);                        getEntityPt.disableAllTrace(true);                        const hoverSelectEnts: McDbEntity[] = [];                        getEntityPt.setUserDraw((pt, pw) => {                            if (hoverSelectEnts.length) hoverSelectEnts.forEach(ent => {                                if (!ents.map(i => i.getObjectID().id).includes(ent.getObjectID().id)) ent.highlight(false);                            });                            hoverSelectEnts.length = 0;                            const entId = MxCADUtility.findEntAtPoint(pt.x, pt.y, pt.z, -1);                            if (entId.isValid() && !selectIds.map(item => item.id).includes(entId.id) && !group.has(entId)) {                                const ent = entId.getMcDbEntity();                                const arr = getGroupForEntity(ent);                                if (arr.length) {                                    const group = arr[0].group;                                    group.getAllEntityId().forEach(id => {                                        const ent = id.getMcDbEntity();                                        ent.highlight(true);                                        hoverSelectEnts.push(ent)                                    })                                } else {                                    ent.highlight(true);                                    hoverSelectEnts.push(ent)                                }                            }                        });                        const pt = await getEntityPt.go();                        if (!pt) {                            if (hoverSelectEnts.length) hoverSelectEnts.forEach(item => item.highlight(false));                            break;                        } else {                            // 判断是否选中实体                            if (hoverSelectEnts.length) {                                if (hoverSelectEnts.length) {                                    hoverSelectEnts.forEach(ent => {                                        selectIds.push(ent.getObjectID());                                    })                                };                            } else {                                getEntityPt.setUserDraw((point, pw) => {                                    const pts = [pt, new McGePoint3d(pt.x, point.y), point, new McGePoint3d(point.x, pt.y)]                                    // 设置范围框颜色即位置                                    let pl = new McDbPolyline();                                    pl.isClosed = true;                                    pts.forEach(pt => pl.addVertexAt(pt));                                    pw.setColor(0xFFFFFF);                                    pw.drawMcDbEntity(pl);                                     // 动态绘制矩形填充框                                    const geometry = new THREE.BufferGeometry();                                    geometry.setFromPoints([                                        new THREE.Vector3(pt.x, pt.y, pt.z),                                        new THREE.Vector3(pt.x, point.y, point.z),                                        new THREE.Vector3(point.x, point.y, point.z),                                        new THREE.Vector3(point.x, pt.y, pt.z)                                    ]);                                    geometry.attributes.uv = new THREE.BufferAttribute(new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), 2);                                    geometry.setIndex([0, 1, 2, 0, 2, 3]);                                    // 创建材质(半透明的颜色)                                    const material = new THREE.MeshBasicMaterial({                                        color: 0x004D00,                                        transparent: true,                                        opacity: 0.5,                                        side: THREE.DoubleSide                                    });                                    const mesh = new THREE.Mesh(geometry, material);                                    pw.drawEntity(mesh);                                });                                const nextPt = await getEntityPt.go();                                if (!nextPt) break;                                const ss = new MxCADSelectionSet();                                await ss.crossingSelect(pt.x, pt.y, nextPt.x, nextPt.y);                                ss.forEach(id => {                                    if (!group.has(id) && !selectIds.map(i => i.id).includes(id.id)) {                                        const ent = id.getMcDbEntity();                                        const arr = getGroupForEntity(ent);                                        if (arr.length) {                                            const group = arr[0].group;                                            group.getAllEntityId().forEach(id => {                                                id.getMcDbEntity()?.highlight(true);                                                selectIds.push(id);                                            })                                        } else {                                            id.getMcDbEntity()?.highlight(true);                                            selectIds.push(id);                                        }                                    }                                });                            };                            continue;                        }                    };                    if (selectIds.length) {                        selectIds.forEach(id => {                            id.getMcDbEntity().highlight(false);                            group.append(id);                        });                        MxPluginContext.useMessage().success('添加对象成功!');                    }                } else if (key === 'R') {                    const selectIds: McObjectId[] = [];                    while (true) {                        const getEntityPt = new MxCADUiPrPoint();                        getEntityPt.setMessage('选择要从编组中删除的对象');                        getEntityPt.setDisableOsnap(true);                        getEntityPt.setDisableDynInput(true);                        getEntityPt.disableAllTrace(true);                        const hoverSelectEnts: McDbEntity[] = [];                        getEntityPt.setUserDraw((pt, pw) => {                            const entId = MxCADUtility.findEntAtPoint(pt.x, pt.y, pt.z, -1);                            hoverSelectEnts.forEach(e => {                                if (!group.has(e.getObjectID())) {                                    e.highlight(false)                                }                            });                            hoverSelectEnts.length = 0;                            if (entId.isValid() && !selectIds.map(i => i.id).includes(entId.id)) {                                const ent = entId.getMcDbEntity();                                ent.highlight(true);                                hoverSelectEnts.push(ent)                            }                        });                        const pt = await getEntityPt.go();                        if (!pt) {                            break;                        } else {                            // 判断是否选中实体                            if (hoverSelectEnts.length) {                                hoverSelectEnts.forEach(ent => {                                    ent.highlight(false);                                    if (group.has(ent.getObjectID())) {                                        selectIds.push(ent.getObjectID())                                    } else {                                        MxFun.acutPrintf('对象不是组内元素,无法删除')                                    }                                })                            } else {                                getEntityPt.setUserDraw((point, pw) => {                                    const pts = [pt, new McGePoint3d(pt.x, point.y), point, new McGePoint3d(point.x, pt.y)]                                    // 设置范围框颜色即位置                                    let pl = new McDbPolyline();                                    pl.isClosed = true;                                    pts.forEach(pt => pl.addVertexAt(pt));                                    pw.setColor(0xFFFFFF);                                    pw.drawMcDbEntity(pl);                                     // 动态绘制矩形填充框                                    const geometry = new THREE.BufferGeometry();                                    geometry.setFromPoints([                                        new THREE.Vector3(pt.x, pt.y, pt.z),                                        new THREE.Vector3(pt.x, point.y, point.z),                                        new THREE.Vector3(point.x, point.y, point.z),                                        new THREE.Vector3(point.x, pt.y, pt.z)                                    ]);                                    geometry.attributes.uv = new THREE.BufferAttribute(new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]), 2);                                    geometry.setIndex([0, 1, 2, 0, 2, 3]);                                    // 创建材质(半透明的颜色)                                    const material = new THREE.MeshBasicMaterial({                                        color: 0x004D00,                                        transparent: true,                                        opacity: 0.5,                                        side: THREE.DoubleSide                                    });                                    const mesh = new THREE.Mesh(geometry, material);                                    pw.drawEntity(mesh);                                });                                const nextPt = await getEntityPt.go();                                if (!nextPt) break;                                const ss = new MxCADSelectionSet();                                await ss.crossingSelect(pt.x, pt.y, nextPt.x, nextPt.y);                                ss.forEach(id => {                                    if (group.has(id)) {                                        const ent = id.getMcDbEntity();                                        ent.highlight(false);                                        selectIds.push(ent.getObjectID());                                    }                                });                            };                            continue;                        }                    };                    if (selectIds.length) {                        const newIds = ents.filter(ent => !selectIds.map(i => i.id).includes(ent.getObjectID().id)).map(ent => ent.getObjectID());                        group.clear();                        group.appendArray(newIds);                    }                } else if (key === 'REN') {                    while (true) {                        const getName = new MxCADUiPrString()                        getName.setMessage("输入组的新名称" + `<${group.name}>`)                        getName.setKeyWords('查询(A)]')                        const str = await getName.go();                        if (getName.getStatus() === MrxDbgUiPrBaseReturn.kKeyWord) {                            if (getName.isKeyWordPicked("A")) {                                getName.setMessage("请输入要列出的编码组名" + "<*>")                                const name = await getName.go();                                if (getName.getStatus() === MrxDbgUiPrBaseReturn.kOk) {                                    if (name && name !== "*") {                                        const groupId = groupDict.getAt(name)                                        const group = groupId.getMcDbObject() as McDbGroup                                        MxFun.acutPrintf('定义的编组')                                        if (group) {                                            MxFun.acutPrintf(`\n${group.name}`)                                        }                                    } else if (name === "*") {                                        const groupIds = groupDict.getAllObject()                                        MxFun.acutPrintf(`\n 定义的编组:`)                                        groupIds.forEach((groupId) => {                                            const group = groupId.getMcDbObject() as McDbGroup                                            group && MxFun.acutPrintf(`\n ${group.name}`)                                        })                                    }                                } else {                                    const groupIds = groupDict.getAllObject()                                    MxFun.acutPrintf(`\n 定义的编组:`)                                    groupIds.forEach((groupId) => {                                        const group = groupId.getMcDbObject() as McDbGroup                                        group && MxFun.acutPrintf(`\n ${group.name}`)                                    })                                }                                continue;                            }                        } else if (getName.getStatus() === MrxDbgUiPrBaseReturn.kOk) {                            const groupId = groupDict.getAt(str)                            const _group = groupId.getMcDbObject() as McDbGroup                            if (_group && groupId.isValid()) {                                MxFun.acutPrintf(`编组 ${str} 已经存在}`);                                continue;                            } else {                                group.name = str;                                MxPluginContext.useMessage().success('修改组名成功');                                break;                            }                        } else {                            break;                        }                    }                }            } else {                MxPluginContext.useMessage().success('对象不是组成员');            }        }        if (ents.length) ents.forEach(ent => ent.highlight(false));        mxcad.updateDisplay();    }    const getEnt = new MxCADUiPrEntity();    getEnt.setMessage('选择组');    getEnt.setKeyWords('[名称(N)]');    getEnt.setUserDraw((pt, pw) => {        ents.forEach(ent => ent.highlight(false));        ents.length = 0;        const entId = MxCADUtility.findEntAtPoint(pt.x, pt.y, pt.z, -1);        if (entId.isValid()) {            const ent = entId.getMcDbEntity();            groupArr = getGroupForEntity(ent);            if (groupArr.length) {                const group = groupArr[index].group;                group.getAllEntityId().forEach(id => {                    const entity = id.getMcDbEntity();                    entity.highlight(true);                    ents.push(entity);                })            }        }    });    const entId = await getEnt.go();    if (getEnt.getStatus() === MrxDbgUiPrBaseReturn.kKeyWord) {        if (getEnt.isKeyWordPicked('N')) {            // 选择关键字            while (true) {                const getName = new MxCADUiPrString()                getName.setMessage("输入组的名称")                getName.setKeyWords('[查询(A)]')                const str = await getName.go();                if (getName.getStatus() === MrxDbgUiPrBaseReturn.kKeyWord) {                    if (getName.isKeyWordPicked("A")) {                        getName.setMessage("请输入要列出的编码组名" + "<*>")                        getName.setKeyWords("")                        const name = await getName.go();                        if (getName.getStatus() === MrxDbgUiPrBaseReturn.kOk) {                            if (name && name !== "*") {                                const groupId = groupDict.getAt(name)                                const group = groupId.getMcDbObject() as McDbGroup                                MxFun.acutPrintf('定义的编组')                                if (group) {                                    MxFun.acutPrintf(`\n${group.name}`)                                }                            } else if (name === "*") {                                const groupIds = groupDict.getAllObject()                                MxFun.acutPrintf(`\n 定义的编组:`)                                groupIds.forEach((groupId) => {                                    const group = groupId.getMcDbObject() as McDbGroup                                    group && MxFun.acutPrintf(`\n ${group.name}`)                                })                            }                        } else {                            const groupIds = groupDict.getAllObject()                            MxFun.acutPrintf(`\n 定义的编组:`)                            groupIds.forEach((groupId) => {                                const group = groupId.getMcDbObject() as McDbGroup                                group && MxFun.acutPrintf(`\n ${group.name}`)                            })                        }                        continue;                    }                } else if (getName.getStatus() === MrxDbgUiPrBaseReturn.kOk) {                    const groupId = groupDict.getAt(str)                    const group = groupId.getMcDbObject() as McDbGroup                    if (group && groupId.isValid()) {                        group.getAllEntityId().forEach(id => {                            const ent = id.getMcDbEntity();                            ent.highlight(true);                            ents.push(ent);                        })                        groupArr.push({ name: group.name, group });                        editGroup()                        break;                    } else {                        MxFun.acutPrintf(`编组 ${str} 不存在`);                        continue;                    };                } else {                    break;                }            }        }    } else if (getEnt.getStatus() === MrxDbgUiPrBaseReturn.kOk) {        editGroup();    } else {        if (ents.length) ents.forEach(ent => ent.highlight(false));    }}
复制代码

4. 启用或禁用组选择

启用指定对象组的选择功能其执行过程如下:首先提示用户“请选择目标组”,并在鼠标悬停时自动检测光标下的对象,若该对象属于某个组,则实时高亮显示该组的所有成员,提供可视化反馈。用户点击对象后,系统获取其所属的第一个组,并将该组的 isSelectable 属性设置为 true,从而允许后续通过点击组内任意成员来选中整个组。最后清除高亮并刷新显示,完成设置。该方法提升了组对象的操作便捷性,适用于需要快速选中成组元素的场景。其完整代码如下:

import { MxCADUiPrEntity, MxCADUtility, MxCpp} from "mxcad";// 启用/禁用组选择async function Mx_SetGroupSelection() {    const ents: McDbEntity[] = [];    let groupArr: GroupObject[] = [];    const getEnt = new MxCADUiPrEntity();    getEnt.setMessage('请选择目标组');    getEnt.setUserDraw((pt, pw) => {        ents.forEach(ent => ent.highlight(false));        ents.length = 0;        const entId = MxCADUtility.findEntAtPoint(pt.x, pt.y, pt.z, -1);        if (entId.isValid()) {            const ent = entId.getMcDbEntity();            groupArr = getGroupForEntity(ent);            if (groupArr.length) {                const group = groupArr[0].group;                group.getAllEntityId().forEach(id => {                    const entity = id.getMcDbEntity();                    entity.highlight(true);                    ents.push(entity);                })            }        }    });    const entId = await getEnt.go();    if (groupArr.length) {        const group = groupArr[0].group;        group.isSelectable = true;        ents.forEach(ent => {            ent.highlight(false);        })        MxCpp.getCurrentMxCAD().updateDisplay();    };}
复制代码

三、功能演示


用户头像

WEB CAD SDK

关注

还未添加个人签名 2024-10-16 加入

还未添加个人简介

评论

发布
暂无评论
(WEB端CAD)网页CAD中的“组”功能开发_WEB CAD SDK_InfoQ写作社区