// ============================================================================ // dwg_review_overview.cpp // 图纸审查 - 概览层工具(均为 c++_dll 后端) // get_drawing_info : 图纸元数据(文件名/单位/布局数/各空间实体数) // get_layers : 图层清单(开关/冻结/锁定/颜色/线型/可选实体计数) // get_layouts : 布局清单(模型空间 + 图纸空间布局 + 视口) // ============================================================================ #include "KTCad.h" #include "dwg_review_common.h" #include "mcp_plugin_api.h" #include "dbcolor.h" // AcCmColor(图层颜色);AcDbViewport 在 dbents.h(已由 cadsdk 引入) #include using namespace dwg_review; namespace { // 图纸单位代码 -> 名称 std::string insUnitsName(int u) { switch (u) { case 0: return "Unitless"; case 1: return "Inches"; case 2: return "Feet"; case 3: return "Miles"; case 4: return "Millimeters"; case 5: return "Centimeters"; case 6: return "Meters"; case 7: return "Kilometers"; case 8: return "Microinches"; case 9: return "Mils"; case 10: return "Yards"; case 11: return "Angstroms"; case 12: return "Nanometers"; case 13: return "Microns"; case 14: return "Decimeters"; case 15: return "Decameters"; case 16: return "Hectometers"; case 17: return "Gigameters"; case 18: return "AstronomicalUnits"; case 19: return "LightYears"; case 20: return "Parsecs"; default: return "Unknown"; } } // 取块表记录名 std::string recordName(AcDbBlockTableRecord* pRec) { const ACHAR* nm = NULL; if (pRec && pRec->getName(nm) == Acad::eOk && nm) return acharToUtf8(nm); return std::string(); } // 统计某空间内的实体总数 int countEntitiesIn(AcDbBlockTableRecord* pRec) { if (!pRec) return 0; int n = 0; AcDbBlockTableRecordIterator* it = nullptr; if (pRec->newIterator(it) != Acad::eOk || !it) return 0; for (it->start(); !it->done(); it->step()) ++n; delete it; return n; } // 取线型名 std::string linetypeName(AcDbObjectId id) { AcDbLinetypeTableRecord* pRec = nullptr; if (acdbOpenObject(pRec, id, AcDb::kForRead) == Acad::eOk && pRec) { const ACHAR* nm = NULL; std::string s; if (pRec->getName(nm) == Acad::eOk && nm) s = acharToUtf8(nm); pRec->close(); return s; } return std::string(); } // 统计各图层实体数(遍历模型空间 + 所有图纸布局) void countByLayer(AcDbDatabase* pDb, std::map& out) { AcDbBlockTable* pBT = nullptr; if (pDb->getBlockTable(pBT, AcDb::kForRead) != Acad::eOk || !pBT) return; AcDbBlockTableIterator* it = nullptr; if (pBT->newIterator(it) == Acad::eOk && it) { for (it->start(); !it->done(); it->step()) { AcDbBlockTableRecord* pRec = nullptr; if (it->getRecord(pRec, AcDb::kForRead) != Acad::eOk || !pRec) continue; const std::string nm = recordName(pRec); static const std::string kModelSpace = acharToUtf8(ACDB_MODEL_SPACE); const bool isModel = (nm == kModelSpace); if (isModel || pRec->isLayout()) { AcDbBlockTableRecordIterator* eit = nullptr; if (pRec->newIterator(eit) == Acad::eOk && eit) { for (eit->start(); !eit->done(); eit->step()) { AcDbEntity* pEnt = nullptr; if (eit->getEntity(pEnt, AcDb::kForRead) == Acad::eOk && pEnt) { out[layerOf(pEnt)]++; pEnt->close(); } } delete eit; } } pRec->close(); } delete it; } pBT->close(); } // 收集某布局内的视口 nlohmann::json collectViewports(AcDbBlockTableRecord* pRec) { nlohmann::json arr = nlohmann::json::array(); if (!pRec) return arr; AcDbBlockTableRecordIterator* it = nullptr; if (pRec->newIterator(it) != Acad::eOk || !it) return arr; for (it->start(); !it->done(); it->step()) { AcDbEntity* pEnt = nullptr; if (it->getEntity(pEnt, AcDb::kForRead) != Acad::eOk || !pEnt) continue; AcDbViewport* pVp = AcDbViewport::cast(pEnt); if (pVp) { nlohmann::json v; v["handle"] = handleOf(pEnt); v["center"] = point2Json(pVp->centerPoint().x, pVp->centerPoint().y); v["width"] = pVp->width(); v["height"] = pVp->height(); v["scale"] = pVp->customScale(); arr.push_back(v); } pEnt->close(); } delete it; return arr; } } // =========================================================================== // get_drawing_info // =========================================================================== class mcp_Tool_GetDrawingInfo : public mcp_Tool { public: nlohmann::json Execute(const nlohmann::json&) override { AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase(); if (!pDb) return makeError(kErrNoDocument, "no active document"); nlohmann::json r; const ACHAR* fn = NULL; pDb->getFilename(fn); r["file_name"] = acharToUtf8(fn); r["insunits"] = (int)pDb->insunits(); r["insunits_name"] = insUnitsName((int)pDb->insunits()); nlohmann::json counts = nlohmann::json::object(); int layoutCount = 0; int total = 0; AcDbBlockTable* pBT = nullptr; if (pDb->getBlockTable(pBT, AcDb::kForRead) == Acad::eOk && pBT) { AcDbBlockTableRecord* pModel = nullptr; if (pBT->getAt(ACDB_MODEL_SPACE, pModel, AcDb::kForRead) == Acad::eOk && pModel) { int c = countEntitiesIn(pModel); counts["Model"] = c; total += c; pModel->close(); } AcDbBlockTableIterator* it = nullptr; if (pBT->newIterator(it) == Acad::eOk && it) { for (it->start(); !it->done(); it->step()) { AcDbBlockTableRecord* pRec = nullptr; if (it->getRecord(pRec, AcDb::kForRead) != Acad::eOk || !pRec) continue; if (pRec->isLayout()) { ++layoutCount; int c = countEntitiesIn(pRec); counts[recordName(pRec)] = c; total += c; } pRec->close(); } delete it; } pBT->close(); } r["layout_count"] = layoutCount + 1; // 含 Model r["entity_count"] = counts; r["entity_count_total"] = total; return makeJsonResult(r); } }; EXPORT_MCP_TOOL(mcp_Tool_GetDrawingInfo, CreateGetDrawingInfoTool) // =========================================================================== // get_layers // =========================================================================== class mcp_Tool_GetLayers : public mcp_Tool { public: nlohmann::json Execute(const nlohmann::json& args) override { AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase(); if (!pDb) return makeError(kErrNoDocument, "no active document"); const std::string nameFilter = args.value("name_filter", std::string()); const bool includeEmpty = args.value("include_empty", false); const bool needCount = args.value("count_entities", false); std::map layerCounts; if (needCount) countByLayer(pDb, layerCounts); nlohmann::json items = nlohmann::json::array(); AcDbLayerTable* pLT = nullptr; if (pDb->getLayerTable(pLT, AcDb::kForRead) == Acad::eOk && pLT) { AcDbLayerTableIterator* it = nullptr; if (pLT->newIterator(it) == Acad::eOk && it) { for (it->start(); !it->done(); it->step()) { AcDbLayerTableRecord* pRec = nullptr; if (it->getRecord(pRec, AcDb::kForRead) != Acad::eOk || !pRec) continue; const ACHAR* nm = NULL; pRec->getName(nm); const std::string name = acharToUtf8(nm); const int cnt = needCount ? (layerCounts.count(name) ? layerCounts[name] : 0) : -1; if (!wildcardMatch(name, nameFilter) || (needCount && !includeEmpty && cnt == 0)) { pRec->close(); continue; } nlohmann::json o; o["name"] = name; o["on"] = !pRec->isOff(); o["frozen"] = pRec->isFrozen(); o["locked"] = pRec->isLocked(); o["plot"] = pRec->isPlottable(); AcCmColor col = pRec->color(); o["color_index"] = (int)col.colorIndex(); o["linetype"] = linetypeName(pRec->linetypeObjectId()); if (cnt >= 0) o["entity_count"] = cnt; items.push_back(o); pRec->close(); } delete it; } pLT->close(); } nlohmann::json r; r["count"] = (int)items.size(); r["items"] = items; return makeJsonResult(r); } }; EXPORT_MCP_TOOL(mcp_Tool_GetLayers, CreateGetLayersTool) // =========================================================================== // get_layouts // =========================================================================== class mcp_Tool_GetLayouts : public mcp_Tool { public: nlohmann::json Execute(const nlohmann::json&) override { AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase(); if (!pDb) return makeError(kErrNoDocument, "no active document"); nlohmann::json items = nlohmann::json::array(); AcDbBlockTable* pBT = nullptr; if (pDb->getBlockTable(pBT, AcDb::kForRead) == Acad::eOk && pBT) { // 模型空间 AcDbBlockTableRecord* pModel = nullptr; if (pBT->getAt(ACDB_MODEL_SPACE, pModel, AcDb::kForRead) == Acad::eOk && pModel) { nlohmann::json o; o["name"] = "Model"; o["is_model"] = true; o["entity_count"] = countEntitiesIn(pModel); o["viewports"] = nlohmann::json::array(); items.push_back(o); pModel->close(); } // 图纸空间布局 AcDbBlockTableIterator* it = nullptr; if (pBT->newIterator(it) == Acad::eOk && it) { for (it->start(); !it->done(); it->step()) { AcDbBlockTableRecord* pRec = nullptr; if (it->getRecord(pRec, AcDb::kForRead) != Acad::eOk || !pRec) continue; if (pRec->isLayout()) { nlohmann::json o; o["name"] = recordName(pRec); o["is_model"] = false; o["entity_count"] = countEntitiesIn(pRec); o["viewports"] = collectViewports(pRec); items.push_back(o); } pRec->close(); } delete it; } pBT->close(); } nlohmann::json r; r["count"] = (int)items.size(); r["items"] = items; return makeJsonResult(r); } }; EXPORT_MCP_TOOL(mcp_Tool_GetLayouts, CreateGetLayoutsTool)