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

B站影视 港台电影 2025-11-18 11:14 1

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

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

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

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

- 组内的对象保持独立,可单独编辑。
- 选择组中任意一个对象时,整个组可被选中(取决于系统设置)。
- 每个组有唯一的名称,便于识别和管理。
- 支持嵌套:一个组可以包含另一个组,形成层级结构。
- 组不作为独立实体存储在图形数据库中,仅作为对象的逻辑关联存在。

二、组的核心功能开发

1. 创建组

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

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

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

- 输入 N(名称):进入命名流程,系统提示“输入编组名”。此时可输入 `[查询(A)]` 来查看已存在的组名;若输入 `*` 或直接回车,则列出所有组;否则查询指定组信息。输入名称后,系统检查是否重名,若无冲突则保存名称并返回选择状态。
- 输入 D(说明):进入说明设置,提示“输入编组说明”,用户输入的文本将作为该组的描述信息。

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

- 首先检查所选对象中是否有成员已属于其他组。
- 若存在此类情况,则弹出确认提示:“包含相同对象的组已经存在。仍要创建新的组?”,并提供“是(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

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(`包含相同对象的组已经存在。仍要创建新的组?`);

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`,可进一步输入要查询的组名;
- 输入 `*` 或直接回车,则列出当前图形中所有已定义的组名;
- 输入具体名称,则检查并显示该组是否存在。
- 用户输入组名后,系统查找对应组:
- 若存在,执行分解操作(清空组内对象并从组字典中移除),提示“组 已分解”;
- 若不存在,提示“编组 未定义”,并允许重新输入。

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

- 系统获取该对象,并查询其所属的所有组(一个对象可能属于多个组)。
- 若对象仅属于一个组,则直接选中该组,准备分解。
- 若对象属于多个组,则进入选择流程:
- 提示“对象是多个组的成员接受>”,提供 `[接受(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("输入组的新名称" + ``)

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;

};

}

三、功能演示

来源:CAD梦想画图

相关推荐