
1. NX二次开发里屏幕取点为什么总踩坑做 NX 二次开发的朋友大概率遇到过这种需求让用户在图形窗口里点一下程序拿到这个点的屏幕坐标和所在视图然后基于这个位置做后续建模或者标注。听起来简单但真动手写的时候很多人第一反应是去翻 UF_UI_specify_screen_position 这个函数结果发现文档写得云里雾里回调函数一挂上去光标就卡顿返回值还分不清是绝对坐标还是绘图坐标。这个函数的核心作用就一句话在图形窗口中通过按鼠标左键MB1指示一个屏幕位置返回该位置的屏幕坐标和所在视图的 tag。它适合谁适合需要在 NX 交互式环境里做“点选定位”的二次开发场景比如自定义标注工具、快速定位特征创建点、交互式测量起点等。调用时会弹出一个只有“返回”和“取消”按钮的空对话框用户点一下图形窗口函数就把坐标和视图信息回传给你。但这里有几个容易翻车的点。第一调用这个函数时必须有一个已加载的 part否则直接报错。第二它返回的 screen_pos 是“工作部件绝对坐标中通过屏幕投影到 WCS XY 平面”的位置不是屏幕像素坐标很多人第一次拿到值以为是像素结果算出来完全不对。第三如果你挂了 motion 回调每次鼠标移动都会触发回调里做太多计算或者定义太多 Overlay Graphics 原语光标就会“断断续续”跟不上鼠标。第四UF_UI_set_cursor_view 会影响返回的 view_tag 和 screen_pos特别是绘图视图下“Any View”和“Work View”两种设置返回的坐标系完全不同。我试过在一个标注工具里直接拿返回值去创建点结果在绘图视图下坐标偏得离谱后来才发现是 cursor_view 设置的问题。所以这篇内容我会把函数签名、参数含义、回调写法、坐标系统差异、以及怎么在统一 API 通道下做验证请求一步步拆开讲清楚。你跟着操作应该能少走不少弯路。2. TaoToken 统一 API 通道的前置准备在讲具体配置之前先说一下为什么 NX 二次开发场景里会用到 TaoToken。NX Open 的调试过程经常需要反复验证接口行为、查文档、对比不同版本的函数差异尤其是像 UF_UI_specify_screen_position 这种带回调的交互函数光看头文件很难判断实际运行效果。TaoToken 提供的是一个统一的大模型 API 通道你可以把它理解成一个“接口聚合层”同一个 Base URL、同一个 Key就能调用多种模型来完成代码解释、报错分析、文档摘要这些辅助工作。它的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 请求地址统一走 https://taotoken.net/api 。对于 NX 二次开发者来说比较实用的场景是把 UFUN 头文件里的函数声明贴给模型让它帮你生成调用骨架或者把编译报错贴进去快速定位是参数类型不对还是链接库没加。这比翻几百页 PDF 文档快得多。前置准备其实就三件事。第一注册并拿到 API Key入口在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。第二确认你要用的模型 ID不同模型在代码生成和长上下文理解上差异挺大建议选支持长上下文的。第三准备好你的 NX 开发环境Visual Studio 版本和 NX 版本要匹配这个后面排障会细说。这里要强调一点TaoToken 是合法的 API 服务通道不是那种来路不明的转发。你拿到的 Key 就是正常调用凭证配置方式和主流 API 服务一致。对于 NX 二次开发这种需要频繁查文档、验证接口的场景有一个稳定的统一通道能省很多切换成本。接下来我会给出可直接复制的配置片段包括 JSON 和 TOML 两种格式你按自己用的工具选就行。3. 可复制的配置片段与函数调用骨架这一节是重点我会把 TaoToken 的配置和 UF_UI_specify_screen_position 的调用代码分开给你直接复制改改就能用。3.1 TaoToken 客户端配置JSON / TOML如果你用的是支持 OpenAI 兼容接口的客户端或者自己写的调试脚本JSON 配置大概长这样{ base_url: https://taotoken.net/api, api_key: sk-你的实际Key, model: claude-3-5-sonnet, timeout: 60, max_tokens: 4096 }如果你用的是 Codex 或者类似支持 TOML 配置的工具auth.json 和 config.toml 要分开写。auth.json 放凭证{ api_key: sk-你的实际Key, base_url: https://taotoken.net/api }config.toml 放模型和参数model claude-3-5-sonnet base_url https://taotoken.net/api timeout 60 [params] max_tokens 4096 temperature 0.2注意 Base URL 后面不要多加/v1或者斜杠统一用https://taotoken.net/api就行。Model ID 要写全别只写个 “claude” 或者 “gpt”不然请求会返回模型不存在的错误。3.2 UF_UI_specify_screen_position 调用骨架下面是一个完整的 C 调用示例包含回调函数定义和主调用逻辑。你可以直接贴到自己的 ufusr 入口里测试。#include uf.h #include uf_ui.h #include uf_disp.h #include uf_modl_primitives.h #include stdio.h // 运动回调每次鼠标移动都会触发 static void motion_callback(double screen_pos[3], UF_UI_motion_cb_data_p_t motion_cb_data, void* user_data) { // screen_pos 是当前十字光标在工作部件绝对坐标中的位置 // motion_cb_data-view_tag 是当前视图 tag // 这里只做简单打印避免回调里做重计算导致光标卡顿 char msg[256]; sprintf_s(msg, X%.3f Y%.3f Z%.3f\n, screen_pos[0], screen_pos[1], screen_pos[2]); // 实际项目中可以用 UF_DISP_display_ogp_ 系列函数画临时反馈 } extern DllExport void ufusr(char* param, int* returnCode, int rlen) { UF_initialize(); char message[] 请在图形窗口中选择一个屏幕位置; double screen_pos[3] {0.0, 0.0, 0.0}; tag_t view_tag NULL_TAG; int response 0; // 调用核心函数 UF_UI_specify_screen_position( message, // 提示行消息最大132字符可传 NULL motion_callback, // 运动回调可传 NULL NULL, // 客户端数据指针会原样传给回调 screen_pos, // 输出屏幕位置 view_tag, // 输出视图 tag response // 输出用户响应 ); if (response UF_UI_PICK_RESPONSE) { // 用户成功点选screen_pos 和 view_tag 有效 char buf[256]; sprintf_s(buf, 选中位置: %.3f, %.3f, %.3f\n视图 tag: %d\n, screen_pos[0], screen_pos[1], screen_pos[2], view_tag); UF_UI_open_listing_window(); UF_UI_write_listing_window(buf); } else if (response UF_UI_BACK) { // 用户点了返回 } else if (response UF_UI_CANCEL) { // 用户点了取消 } UF_terminate(); } extern int ufusr_ask_unload(void) { return (UF_UNLOAD_IMMEDIATELY); }几个关键点再强调一下。message 参数最大 132 个字符超了会被截断传 NULL 就不显示提示。motion_cb 传 NULL 的话就没有实时反馈用户只能盲点。motion_cb_data 是你自己的数据指针回调里通过第三个参数拿到。screen_pos 和 view_tag 只有在 response 等于 UF_UI_PICK_RESPONSE 时才有意义其他情况别去读。3.3 坐标系统差异对照UF_UI_set_cursor_view 的设置会直接影响返回值这个表你存一下cursor_view 设置光标位置view_tag 返回screen_pos 坐标系Any View绘图成员视图内成员视图 tag该成员视图绝对坐标Any View非成员视图当前视图 tag工作部件绝对坐标Work View任意位置绘图 tag绘图坐标如果你发现拿到的坐标和预期对不上先检查 UF_UI_set_cursor_view 当前是什么状态。Grid Snap 开启时返回的坐标会自动吸附到网格这个也会影响精度。4. 验证请求与成功结果确认配置写好了代码也编译通过了接下来要验证两件事TaoToken 通道是否通以及 UF_UI_specify_screen_position 是否按预期返回。4.1 验证 TaoToken 通道用 curl 发一个最小请求确认 Key 和 Base URL 没问题curl -X POST https://taotoken.net/api/v1/messages \ -H Content-Type: application/json \ -H x-api-key: sk-你的实际Key \ -H anthropic-version: 2023-06-01 \ -d { model: claude-3-5-sonnet, max_tokens: 128, messages: [ {role: user, content: 用一句话解释 UF_UI_specify_screen_position 的作用} ] }如果返回里包含正常的文本内容说明通道没问题。如果返回 401检查 Key 是否复制完整如果返回 model not found检查 Model ID 拼写。你也可以直接在模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 里手动问一句确认账号状态正常。4.2 验证 NX 函数返回编译好 DLL 后在 NX 里通过“文件-执行-用户函数”或者你习惯的方式加载。调用后应该看到第一图形窗口顶部提示行显示你传入的 message。第二鼠标在图形窗口移动时如果挂了回调会触发 motion_callback你可以在 listing window 看到实时坐标打印。第三按 MB1 点选后弹出对话框关闭listing window 输出选中位置和视图 tag。第四点“取消”或“返回”时response 分别是 UF_UI_CANCEL 和 UF_UI_BACK不会输出坐标。一个常见的验证技巧先在 WCS 原点附近点一下看输出的坐标是不是接近 (0,0,0)。如果偏差很大检查是不是在绘图视图下且 cursor_view 设成了 Work View。另一个技巧开启 Grid Snap 后点选看坐标是否吸附到整数网格确认吸附逻辑生效。如果你在验证过程中遇到编译报错或者运行时报错可以把错误信息贴到 TaoToken 的对话里让它帮你分析。比一个人对着头文件猜快很多。5. 本篇常见错误排查这一节列几个真实会遇到的报错和现象对照着查。401 Unauthorized / invalid api keyTaoToken 的 Key 没填对或者 Base URL 写成了https://taotoken.net/api/v1导致路径重复。正确写法是 Base URL 只到/api具体端点由客户端拼接。检查 auth.json 里的 api_key 字段有没有多余空格。local proxy failed / connection refused客户端配置了本地代理但代理没启动。如果你用的是 Codex 或类似工具检查 config.toml 里有没有误加 proxy 配置。TaoToken 直连即可不需要额外代理设置。reading choices field error请求体格式和模型不匹配。比如用 Anthropic 格式的 messages 去请求 OpenAI 兼容端点或者反过来。确认你用的模型对应的请求格式Claude 系列走/v1/messagesGPT 系列走/v1/chat/completions。OAuth token expired如果你用的是 OAuth 方式登录而不是 API Keytoken 过期了。重新走一遍授权流程或者直接改用 API Key 方式更稳定。NX 编译报错 LNK2019 unresolved external symbol没链接 libufun.lib 和 libugopenint.lib。在 Visual Studio 的项目属性里链接器-输入-附加依赖项加上这两个库。注意 Debug 和 Release 配置要分别设置。运行时提示 “There must be a part loaded”调用 UF_UI_specify_screen_position 时没有加载任何 part。在 ufusr 入口里先判断 UF_PART_ask_display_part() 是否返回 NULL_TAG如果是就先打开一个 part 或者提示用户新建。光标移动卡顿 / 回调不跟手motion_callback 里做了太多计算或者定义了太多 Overlay Graphics 原语。把重计算移到点选完成之后回调里只做最轻量的反馈。如果不需要实时反馈直接把 motion_cb 传 NULL。返回坐标和预期不符检查 UF_UI_set_cursor_view 的设置以及当前是否在绘图视图下。参考第 3.3 节的对照表。另外确认 Grid Snap 状态开启时会自动吸附。CC Switch / Cline MCP 配置不生效如果你用这类工具接入 TaoToken三件套必须写全Base URL 填https://taotoken.net/apiAPI Key 填你的实际 KeyModel ID 填完整模型名。缺任何一个都会导致请求失败。配置路径通常在工具的 settings 或 config 目录下改完记得重启工具。Codex auth.json 读取失败auth.json 的路径不对或者 JSON 格式有语法错误。用在线 JSON 校验工具过一遍确认没有多余逗号或引号不匹配。文件权限也要确认可读。6. 继续深入的方向与实用建议UF_UI_specify_screen_position 只是 NX 二次开发里交互定位的入口之一。实际项目中你往往需要把它和 UF_DISP_display_ogp_ 系列函数配合在回调里画临时线框或者标记让用户直观看到当前光标位置对应的几何含义。Overlay Graphics 原语的生命周期很短回调触发后立即显示下一次回调前自动擦除函数结束时全部清除所以不用担心残留。另一个实用建议是把 screen_pos 拿到之后如果需要转换成其他坐标系先确认当前 WCS 和 ABS 的关系。UF_UI_specify_screen_position 返回的是工作部件绝对坐标投影到 WCS XY 平面的位置如果你要的是屏幕像素坐标需要另外用 UF_DISP_ask_screen_pos 之类的函数做转换别直接拿这个值当像素用。对于需要长期做 NX 二次开发、频繁调试 UFUN 接口的朋友可以考虑用 Coding Plan 把常用的代码骨架和排障流程固化下来减少重复劳动。入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言的调用示例和错误码说明遇到问题先翻文档比到处搜快。最后说一个我踩过的坑回调函数里千万不要调用 UF_UI_open_listing_window 或者弹窗因为回调触发频率很高频繁操作 UI 会导致 NX 界面卡死。需要输出调试信息的话先存到内存变量里等点选完成后再统一打印。这个细节文档里不会写但实际开发中很容易中招。