fix(mcp): 截图去除 CAD 界面元素(视口控件/ViewCube/滚动条)
- get_viewport_screenshot 改用 acedGetAcadDwgView() 只截图形区(排除滚动条/状态栏) - 截图期间临时置 NAVVCUBEDISPLAY=0、VPCONTROL=0 隐藏 ViewCube 与视口控件, RAII 守卫自动恢复原值,不影响用户 CAD 界面设置;配合 RedrawWindow 同步重绘 - 新增 verify_grounding.py:grounding 实测探针(截整体图 + VLM 定位放大区域)
This commit is contained in:
1 parent
32d552f1f0
commit
f8bd12dcec
2 files changed
+194
-6
No files matched your search
@@ -129,6 +129,42 @@ namespace
|
||||
|
||||
return ::GetForegroundWindow() == hwnd;
|
||||
}
|
||||
|
||||
// 临时把某个整型系统变量置 0,析构时恢复原值(RAII)。
|
||||
// 用于截图期间临时隐藏 ViewCube / 视口控件等叠加 UI,避免污染截图内容。
|
||||
// 若原值本就为 0(或变量不存在/取值失败),则不做任何改动。
|
||||
class TempSysVarOff
|
||||
{
|
||||
public:
|
||||
explicit TempSysVarOff(const ACHAR *name) : m_name(name), m_changed(false), m_old(0)
|
||||
{
|
||||
struct resbuf rb;
|
||||
if (acedGetVar(m_name, &rb) == RTNORM && rb.restype == RTSHORT && rb.resval.rint != 0)
|
||||
{
|
||||
m_old = rb.resval.rint;
|
||||
struct resbuf val;
|
||||
val.restype = RTSHORT;
|
||||
val.resval.rint = 0;
|
||||
m_changed = (acedSetVar(m_name, &val) == RTNORM);
|
||||
}
|
||||
}
|
||||
// 恢复原值;幂等(可显式提前调用,析构时兜底)
|
||||
void restore()
|
||||
{
|
||||
if (!m_changed) return;
|
||||
struct resbuf val;
|
||||
val.restype = RTSHORT;
|
||||
val.resval.rint = m_old;
|
||||
acedSetVar(m_name, &val);
|
||||
m_changed = false;
|
||||
}
|
||||
~TempSysVarOff() { restore(); }
|
||||
|
||||
private:
|
||||
const ACHAR *m_name;
|
||||
bool m_changed;
|
||||
int m_old;
|
||||
};
|
||||
}
|
||||
|
||||
class mcp_Tool_ViewportScreenshot: public mcp_Tool
|
||||
@@ -136,8 +172,14 @@ class mcp_Tool_ViewportScreenshot: public mcp_Tool
|
||||
public:
|
||||
virtual nlohmann::json Execute(const nlohmann::json &args) override
|
||||
{
|
||||
// 1. 获取 AutoCAD 当前文档的绘图区句柄
|
||||
HWND hWnd = adsw_acadDocWnd();
|
||||
// 1. 获取绘图视图窗口句柄(仅图形区,不含滚动条 / 状态栏等窗口边框)。
|
||||
// 优先 acedGetAcadDwgView(),取不到时退回文档窗口 adsw_acadDocWnd()。
|
||||
HWND hWnd = NULL;
|
||||
CView *pDwgView = acedGetAcadDwgView();
|
||||
if (pDwgView)
|
||||
hWnd = pDwgView->m_hWnd;
|
||||
if (!hWnd)
|
||||
hWnd = adsw_acadDocWnd();
|
||||
if (!hWnd)
|
||||
return mcp_Tool_Utility::make_error(-32000, L"无法获取CAD绘图区窗口句柄");
|
||||
|
||||
@@ -152,7 +194,16 @@ public:
|
||||
}
|
||||
bool stillOccluded = IsWindowOccluded(hWnd);
|
||||
|
||||
// 3. 初始化 GDI+
|
||||
// 3. 截图期间临时隐藏叠加 UI:ViewCube(NAVVCUBEDISPLAY) 与视口控件(VPCONTROL)。
|
||||
// 这两个系统变量控制绘图区右上角 / 左上角的浮层控件,会污染截图并误导视觉模型。
|
||||
// 守卫离开作用域时自动恢复原值,不影响用户的 CAD 界面设置。
|
||||
TempSysVarOff hideNavCube(L"NAVVCUBEDISPLAY");
|
||||
TempSysVarOff hideVpControl(L"VPCONTROL");
|
||||
// GDI 抓屏读的是屏幕像素:必须同步重绘,让叠加 UI 的隐藏立即反映到画面。
|
||||
::RedrawWindow(hWnd, NULL, NULL,
|
||||
RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
|
||||
// 4. 初始化 GDI+
|
||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
|
||||
ULONG_PTR gdiplusToken;
|
||||
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
@@ -160,7 +211,7 @@ public:
|
||||
std::string base64Result;
|
||||
bool success = false;
|
||||
|
||||
// 4. 开始 Windows GDI 抓屏逻辑 (使用花括号限定生命周期)
|
||||
// 5. 开始 Windows GDI 抓屏逻辑 (使用花括号限定生命周期)
|
||||
{
|
||||
RECT rc;
|
||||
GetClientRect(hWnd, &rc);
|
||||
@@ -213,10 +264,16 @@ public:
|
||||
ReleaseDC(hWnd, hdcScreen);
|
||||
}
|
||||
|
||||
// 5. 关闭 GDI+
|
||||
// 6. 关闭 GDI+
|
||||
Gdiplus::GdiplusShutdown(gdiplusToken);
|
||||
|
||||
// 6. 按照 MCP 多模态协议返回数据
|
||||
// 7. 恢复叠加 UI(ViewCube / 视口控件)并重绘一次,让界面回到用户设置的样子
|
||||
hideVpControl.restore();
|
||||
hideNavCube.restore();
|
||||
::RedrawWindow(hWnd, NULL, NULL,
|
||||
RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
|
||||
// 8. 按照 MCP 多模态协议返回数据
|
||||
if (success)
|
||||
{
|
||||
std::wstring msg = L"已成功截取 AutoCAD 当前视口画面。";
|
||||
|
||||
Reference in new issue
Block a user