SetViewportOrgEx-Windows API

本文详细介绍了SetViewportOrgEx函数,该函数用于说明哪个设备点映射到窗口原点(0,0)。文中给出了函数原型、各参数含义,包括设备内容HANDLE、新Viewport坐标等,还说明了返回值情况,以及该函数在逻辑坐标到设备坐标映射中的作用。

SetViewportOrgEx说明哪个设备点映射到窗口原点(0,0)
BOOL SetViewportOrgEx(
  HDC hdc,        // 设备内容HANDLE
  int X,          // 新Viewport的x坐标
  int Y,          // 新Viewport的y坐标
  LPPOINT lpPoint // 原来的Viewport的坐标
);
参数:
hdc:[输入]设备内容的HANDLE
X:[输入]新的viewport原点的设备单位的x坐标
Y:[输入]新的viewport原点的设备单位的y坐标
lpPoint:
[输出]指向一个POINT结构用来接收原先的viewport原点坐标,坐标是设备单位的。如果lpPoint是NULL,这个参数不使用。
返回值:
如果返回成功返回非0,如果失败,返回0。
备注:
这个函数(连同SetViewportExtEx和SetWindowExtEx)帮助定义逻辑坐标空间(也就是一个窗口)到设备坐标空间映射(viewport)。SetViewPortOrgEx指定哪个设备点映射到逻辑点(0,0).它有移动坐标轴的功能,从而使逻辑点(0,0)不再指向左上角了。
//映射逻辑点 (0,0) 到设备点 (xViewOrg, yViewOrg)
SetViewportOrgEx ( hdc, xViewOrg, yViewOrg, NULL)
这就是SetViewportOrgEx的作用。总的来说,你使用一个函数或另一个函数,但不能都使用,而不管你使用SetWindowOrgEx还是SetViewportOrgEx,设备点(0,0)总是在左上角。

要使用 **C 语言 + Windows API** 完整地读取 DXF 文件中的图形实体(如 LINE、CIRCLE、ARC 等),并将其在窗口中显示出来,需要完成以下关键步骤: 1. **解析 DXF 文件结构** 2. **提取图形实体数据** 3. **使用 GDI 在 Win32 窗口中绘制** 下面是一个 **完整可运行的 C 程序示例**,支持解析 `LINE`、`CIRCLE` 和 `ARC` 实体,并用 Windows GDI 显示。 --- ### ✅ 完整代码:读取 DXF 实体并在窗口中显示 ```c #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define MAX_ENTITIES 1000 #define BUFFER_SIZE 256 // 实体类型枚举 typedef enum { ENTITY_LINE, ENTITY_CIRCLE, ENTITY_ARC } EntityType; // 统一存储所有图形实体 typedef struct { EntityType type; union { struct { double x1, y1, x2, y2; } line; struct { double cx, cy, r; } circle; struct { double cx, cy, r, startAngle, endAngle; } arc; } data; } GraphicEntity; GraphicEntity entities[MAX_ENTITIES]; int entityCount = 0; // 解析 DXF 文件(ASCII 格式) void ParseDXF(const char* filename) { FILE* file = fopen(filename, "r"); if (!file) { MessageBoxA(NULL, "无法打开 DXF 文件!", "错误", MB_OK | MB_ICONERROR); return; } char buffer[BUFFER_SIZE]; char groupCode[2] = {0}; char currentEntity[10] = {0}; // 临时变量 double cx = 0, cy = 0, r = 0, startAngle = 0, endAngle = 0; double x1 = 0, y1 = 0, x2 = 0, y2 = 0; int inEntities = 0; while (fgets(buffer, sizeof(buffer), file)) { buffer[strcspn(buffer, "\r\n")] = 0; if (strlen(buffer) == 0) continue; // 判断是否为组码行(单个数字) if (strlen(buffer) == 1 && isdigit(buffer[0])) { strcpy_s(groupCode, sizeof(groupCode), buffer); continue; } char* value = buffer; // 节处理 if (strcmp(value, "SECTION") == 0) { inEntities = 0; continue; } else if (strcmp(value, "ENTITIES") == 0) { inEntities = 1; continue; } else if (strcmp(value, "ENDSEC") == 0 && inEntities) { inEntities = 0; continue; } else if (strcmp(value, "EOF") == 0) { break; } if (!inEntities) continue; // 实体类型识别 if (strcmp(groupCode, "0") == 0) { if (strcmp(value, "LINE") == 0) { strcpy_s(currentEntity, sizeof(currentEntity), "LINE"); x1 = y1 = x2 = y2 = 0; } else if (strcmp(value, "CIRCLE") == 0) { strcpy_s(currentEntity, sizeof(currentEntity), "CIRCLE"); cx = cy = r = 0; } else if (strcmp(value, "ARC") == 0) { strcpy_s(currentEntity, sizeof(currentEntity), "ARC"); cx = cy = r = startAngle = endAngle = 0; } else { currentEntity[0] = '\0'; } } // 提取数据 if (strcmp(currentEntity, "LINE") == 0) { if (strcmp(groupCode, "10") == 0) x1 = atof(value); else if (strcmp(groupCode, "20") == 0) y1 = atof(value); else if (strcmp(groupCode, "11") == 0) x2 = atof(value); else if (strcmp(groupCode, "21") == 0) y2 = atof(value); if (strcmp(groupCode, "21") == 0 && entityCount < MAX_ENTITIES) { entities[entityCount].type = ENTITY_LINE; entities[entityCount].data.line.x1 = x1; entities[entityCount].data.line.y1 = y1; entities[entityCount].data.line.x2 = x2; entities[entityCount].data.line.y2 = y2; entityCount++; } } else if (strcmp(currentEntity, "CIRCLE") == 0) { if (strcmp(groupCode, "10") == 0) cx = atof(value); else if (strcmp(groupCode, "20") == 0) cy = atof(value); else if (strcmp(groupCode, "40") == 0) r = atof(value); if (strcmp(groupCode, "40") == 0 && entityCount < MAX_ENTITIES) { entities[entityCount].type = ENTITY_CIRCLE; entities[entityCount].data.circle.cx = cx; entities[entityCount].data.circle.cy = cy; entities[entityCount].data.circle.r = r; entityCount++; } } else if (strcmp(currentEntity, "ARC") == 0) { if (strcmp(groupCode, "10") == 0) cx = atof(value); else if (strcmp(groupCode, "20") == 0) cy = atof(value); else if (strcmp(groupCode, "40") == 0) r = atof(value); else if (strcmp(groupCode, "50") == 0) startAngle = atof(value); else if (strcmp(groupCode, "51") == 0) endAngle = atof(value); if (strcmp(groupCode, "51") == 0 && entityCount < MAX_ENTITIES) { entities[entityCount].type = ENTITY_ARC; entities[entityCount].data.arc.cx = cx; entities[entityCount].data.arc.cy = cy; entities[entityCount].data.arc.r = r; entities[entityCount].data.arc.startAngle = startAngle; entities[entityCount].data.arc.endAngle = endAngle; entityCount++; } } } fclose(file); } // 窗口过程函数 LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static HWND hButton; HDC hdc; PAINTSTRUCT ps; RECT rect; switch (uMsg) { case WM_CREATE: hButton = CreateWindow( "BUTTON", "加载 DXF 文件", WS_VISIBLE | WS_CHILD, 50, 50, 150, 30, hwnd, (HMENU)1, NULL, NULL ); break; case WM_COMMAND: if (LOWORD(wParam) == 1) { ParseDXF("test.dxf"); // 放置你的 DXF 文件 InvalidateRect(hwnd, NULL, TRUE); } break; case WM_PAINT: hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rect); // 设置坐标映射,适应绘图范围 SetMapMode(hdc, MM_ANISOTROPIC); SetWindowExtEx(hdc, 1000, -1000, NULL); // Y向下为正 SetViewportExtEx(hdc, rect.right, rect.bottom, NULL); SetViewportOrgEx(hdc, 0, 0, NULL); // 绘制所有实体 for (int i = 0; i < entityCount; i++) { switch (entities[i].type) { case ENTITY_LINE: MoveToEx(hdc, (int)entities[i].data.line.x1, (int)entities[i].data.line.y1, NULL); LineTo(hdc, (int)entities[i].data.line.x2, (int)entities[i].data.line.y2); break; case ENTITY_CIRCLE: { int cx = (int)entities[i].data.circle.cx; int cy = (int)entities[i].data.circle.cy; int r = (int)entities[i].data.circle.r; Ellipse(hdc, cx - r, cy - r, cx + r, cy + r); break; } case ENTITY_ARC: { int cx = (int)entities[i].data.arc.cx; int cy = (int)entities[i].data.arc.cy; int r = (int)entities[i].data.arc.r; double sa = entities[i].data.arc.startAngle; double ea = entities[i].data.arc.endAngle; // 转换角度为笛卡尔坐标点(GDI Arc 需要物理坐标) int x1 = cx + (int)(r * cos(sa * M_PI / 180.0)); int y1 = cy - (int)(r * sin(sa * M_PI / 180.0)); // Y轴反向 int x2 = cx + (int)(r * cos(ea * M_PI / 180.0)); int y2 = cy - (int)(r * sin(ea * M_PI / 180.0)); Arc(hdc, cx - r, cy - r, cx + r, cy + r, x1, y1, x2, y2); break; } } } EndPaint(hwnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } // WinMain int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { const char CLASS_NAME[] = "DXF_Viewer"; WNDCLASS wc = {0}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = CLASS_NAME; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); if (!RegisterClass(&wc)) { MessageBox(NULL, "注册窗口类失败!", "错误", MB_OK); return 0; } HWND hwnd = CreateWindowEx( 0, CLASS_NAME, "DXF 图形查看器", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBox(NULL, "创建窗口失败!", "错误", MB_OK); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } ``` --- ### 🔍 解释 #### ✅ 功能说明: - 支持从 ASCII DXF 文件中解析 `LINE`、`CIRCLE`、`ARC`。 - 使用标准 Win32 API 创建窗口和按钮。 - 点击按钮加载 `test.dxf` 文件并绘制图形。 - 使用 `SetMapMode(MM_ANISOTROPIC)` 实现逻辑坐标到屏幕坐标的缩放适配。 - 所有实体统一管理,便于扩展。 #### 📁 使用方法: 1. 将上述代码保存为 `.c` 文件(如 `dxf_viewer.c`)。 2. 编译环境:Visual Studio 或 MinGW(需链接 `user32.lib`, `gdi32.lib`)。 3. 准备一个简单的 ASCII DXF 文件(例如 AutoCAD 导出为“AutoCAD R12/LT2 DXF”格式)。 4. 把文件命名为 `test.dxf` 并放在程序同目录下。 5. 运行程序,点击按钮即可看到图形。 #### ⚠️ 注意事项: - 本程序仅处理基本实体,未考虑图层、颜色、多段线(POLYLINE)、块(BLOCK)等复杂结构。 - 坐标系假设是二维 XY 平面,Z=0。 - GDI 的 `Arc` 函数按顺时针方向绘制,角度单位为度。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值