Files
envi-code/SourceCode/Code2026/cad_mcp_plugins/dwg_annotate_edit.cpp
T
company-desktop c10f5b0083 feat: 补齐 cad_mcp_plugins 的批注/编辑/干涉工具(26 个工具齐了)
现象:mcp_config.json 里配了 40 个工具,但仓库的 cad_mcp_plugins 只有 16 个工厂,
add_line / add_text / add_mtext / add_polyline / add_leader_annotation /
draw_revision_cloud / delete_entities / set_entity_properties / find_collisions /
set_drawing_area 这 10 个在 tools/list 里被静默丢掉(实测只有 30 = 18 + 12)。

来源:d:\new-start\CadProject\src\cad_mcp_plugins(pull 之后新增的
dwg_annotate_*、dwg_review_ui、find_collisions、bvh.h),整体搬到本仓库。

改动:
- 新增 bvh.h、dwg_annotate_common.cpp/h、dwg_annotate_draw.cpp、
  dwg_annotate_edit.cpp、dwg_review_ui.cpp、find_collisions.cpp;
- cad_mcp_plugins/cmakelists.txt 的 SOURCES 补上这 6 个 cpp;
- 移植差异两处(都在本仓库编译/运行才暴露):
  1. `#include "cadsdk.h"` -> `#include "KTCad.h"`(本仓库没有 cadsdk.h);
  2. 上游 cadsdk.h 带 NOMINMAX,本仓库 KTCad.h 没有,`std::min/std::max`
     被 windows.h 的宏顶掉(C2589/C2059)→ 在 dwg_annotate_common.cpp、
     dwg_annotate_draw.cpp、find_collisions.cpp 里 `#undef min / #undef max`。
- 上游的写库工具没有文档锁:MCP 工具跑在主线程消息里、不在命令上下文,
  kForWrite 打开块表记录直接拿到 eLockViolation(0x140),报
  "cannot open target space for write"。补了 `dwg_annotate::DocLock`
  (acDocManager->lockDocument/unlockDocument 的 RAII),并在
  dwg_annotate_draw / dwg_annotate_edit 的 8 个 Execute 开头构造。
  这一条是上游在新环境下的真 bug,不修这批工具在本仓库根本用不了。
- 所有新增文件转 UTF-8 with BOM(仓库红线)。

验证:
- R230 Debug / Z2026 Debug 编译通过并部署;dumpbin 显示
  cad_mcp_plugins.dll 导出 26 个 Create*Tool + 26 个 Destroy_*。
- AutoCAD 2020 实测(部署目录放仓库的 mcp_config.json,frame 优先读它):
  tools/list = **40**,配置里没有一个工具缺失;
  add_line / add_text / add_polyline / add_mtext / add_leader_annotation /
  draw_revision_cloud 全部返回 created[handle](图层 AI_REVIEW);
  set_entity_properties 改图层+颜色、delete_entities 删两个句柄都成功;
  find_collisions / find_zero_length 正常返回结构。
2026-10-29 22:45:14 +08:00

129 lines
4.1 KiB
C++

// ============================================================================
// dwg_annotate_edit.cpp
// 图纸批注 - 编辑类工具(均为 c++_dll 后端)
// delete_entities : 按 handle 列表删除实体
// set_entity_properties : 修改已有实体的图层 / 颜色
//
// 用于审图后清理 AI 自己产生的批注、删除图纸废线,或把问题实体标红/归层。
// ============================================================================
#include "KTCad.h"
#include "dwg_annotate_common.h"
#include "mcp_plugin_api.h"
#include <string>
#include <vector>
using namespace dwg_annotate;
using namespace dwg_review;
namespace
{
// 打开指定句柄的实体(kForWrite);失败返回 false
bool openForWrite(const std::string& hs, AcDbEntity*& out)
{
out = nullptr;
AcDbObjectId id;
if (!objectIdFromHandle(hs, id)) return false;
if (acdbOpenObject(out, id, AcDb::kForWrite) != Acad::eOk) { out = nullptr; return false; }
return out != nullptr;
}
}
// ===========================================================================
// delete_entities
// ===========================================================================
class mcp_Tool_DeleteEntities : public mcp_Tool
{
public:
nlohmann::json Execute(const nlohmann::json& args) override
{
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb) return makeError(kErrNoDocument, "no working database");
DocLock lock; // 写库前先锁文档,见 dwg_annotate_common.h
if (!lock.ok()) return makeError(kErrInternal, "cannot lock drawing document");
const std::vector<std::string> hs = collectHandlesArg(args);
if (hs.empty()) return makeError(kErrBadParam, "handle or handles is required");
int count = 0;
nlohmann::json failed = nlohmann::json::array();
for (size_t i = 0; i < hs.size(); ++i)
{
AcDbEntity* pEnt = nullptr;
if (!openForWrite(hs[i], pEnt)) { failed.push_back(hs[i]); continue; }
const Acad::ErrorStatus es = pEnt->erase();
pEnt->close();
if (es == Acad::eOk) ++count;
else failed.push_back(hs[i]);
}
nlohmann::json r;
r["ok"] = true;
r["count"] = count;
r["failed"] = failed;
return makeJsonResult(r);
}
};
EXPORT_MCP_TOOL(mcp_Tool_DeleteEntities, CreateDeleteEntitiesTool)
// ===========================================================================
// set_entity_properties
// ===========================================================================
class mcp_Tool_SetEntityProperties : public mcp_Tool
{
public:
nlohmann::json Execute(const nlohmann::json& args) override
{
AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase();
if (!pDb) return makeError(kErrNoDocument, "no working database");
DocLock lock; // 写库前先锁文档,见 dwg_annotate_common.h
if (!lock.ok()) return makeError(kErrInternal, "cannot lock drawing document");
const std::vector<std::string> hs = collectHandlesArg(args);
if (hs.empty()) return makeError(kErrBadParam, "handle or handles is required");
const bool hasLayer = args.contains("layer") && args["layer"].is_string();
const bool hasColor = args.contains("color") && args["color"].is_number_integer();
if (!hasLayer && !hasColor)
return makeError(kErrBadParam, "at least one of layer / color is required");
const std::string layer = hasLayer ? args["layer"].get<std::string>() : std::string();
const int color = hasColor ? args["color"].get<int>() : -1;
if (hasLayer) ensureLayer(pDb, layer, 1);
int count = 0;
nlohmann::json failed = nlohmann::json::array();
for (size_t i = 0; i < hs.size(); ++i)
{
AcDbEntity* pEnt = nullptr;
if (!openForWrite(hs[i], pEnt)) { failed.push_back(hs[i]); continue; }
if (hasLayer)
{
const std::wstring wl = utf8ToWStr(layer);
pEnt->setLayer(wl.c_str());
}
if (hasColor)
pEnt->setColorIndex((Adesk::UInt16)color);
pEnt->draw();
pEnt->close();
++count;
}
nlohmann::json r;
r["ok"] = true;
r["count"] = count;
r["failed"] = failed;
return makeJsonResult(r);
}
};
EXPORT_MCP_TOOL(mcp_Tool_SetEntityProperties, CreateSetEntityPropertiesTool)