当前位置: 首页 > news >正文

DXFViewer进行中 : ->封装OpenGL -> 解析DXF直线

DXFViewer进行中,目标造一个dxf看图工具。.

目标1:封装OpenGL,实现正交相机及平移缩放功能

Application.h

#pragma once
#include <string>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "../Core/TimeStamp.h"
#include "../Core/OrthoCamera.h"
class Application
{
public:Application();virtual ~Application();virtual void  Initialize(int width, int height, const char* title);  // 1.初始化virtual void  Run();	  virtual void  Startup();        // 1.准备数据virtual void  Render();         // 2.渲染数据virtual void  Shutdown();       // 3.关闭private:// 系统回调函数static void  ErrorCallback(int error, const char* description);static void  KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);static void  MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);static void  CursorPositionCallback(GLFWwindow* window, double xpos, double ypos);static void  WindowSizeCallback(GLFWwindow* window, int width, int height);static void  ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);static Application* GetWindow(GLFWwindow* window); protected:int           m_winWidth = 0;int	          m_winHeight = 0;GLFWwindow* m_pWindow = nullptr;OrthoCamera   m_camera;        // 相机 double m_LastCursorX = 0.0;double m_LastCursorY = 0.0;bool m_MiddleButtonPressed = false;};

 Application.cpp

#include "Application.h"
#include <algorithm>
#include <iostream>Application::Application() {}Application::~Application()
{glfwDestroyWindow(m_pWindow);glfwTerminate();exit(EXIT_SUCCESS);
}void Application::ErrorCallback(int error, const char* description)
{std::cerr << "Error: " << description << std::endl;
}void Application::KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{// 键盘事件处理逻辑
}void Application::MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{Application* app = GetWindow(window);if (button == GLFW_MOUSE_BUTTON_MIDDLE){if (action == GLFW_PRESS){app->m_MiddleButtonPressed = true;glfwGetCursorPos(window, &app->m_LastCursorX, &app->m_LastCursorY);// 设置抓手光标// glfwSetCursor(window, glfwCreateStandardCursor(GLFW_HAND_CURSOR));}else if (action == GLFW_RELEASE){app->m_MiddleButtonPressed = false;// 恢复默认箭头光标// glfwSetCursor(window, glfwCreateStandardCursor(GLFW_ARROW_CURSOR));}}
}void Application::CursorPositionCallback(GLFWwindow* window, double xpos, double ypos)
{Application* app = GetWindow(window);if (app->m_MiddleButtonPressed){double dx = xpos - app->m_LastCursorX;double dy = ypos - app->m_LastCursorY;app->m_LastCursorX = xpos;app->m_LastCursorY = ypos;glm::vec3 pos = app->m_camera.GetPosition();pos.x -= (dx / app->m_camera.GetZoom() * 0.5);pos.y += (dy / app->m_camera.GetZoom() * 0.5);//printf("pos.x = %f, pos.y = %f  \r\n", pos.x, pos.y);app->m_camera.SetPosition(pos);}
}void Application::WindowSizeCallback(GLFWwindow* window, int width, int height)
{Application* app = GetWindow(window);app->m_winWidth = width;app->m_winHeight = height;   app->m_camera.SetView(width, height);
}void Application::ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{Application* app = GetWindow(window);// 1. 获取鼠标在窗口中的位置double mouseX, mouseY;glfwGetCursorPos(window, &mouseX, &mouseY);// 2. 将鼠标屏幕坐标转换为世界坐标float ndcX = (2.0f * static_cast<float>(mouseX)) / app->m_winWidth - 1.0f;float ndcY = 1.0f - (2.0f * static_cast<float>(mouseY)) / app->m_winHeight;glm::vec4 ndcPos = glm::vec4(ndcX, ndcY, 0.0f, 1.0f);glm::mat4 invVP = glm::inverse(app->m_camera.GetViewProjectionMatrix());glm::vec4 worldPosBeforeZoom = invVP * ndcPos;// 3. 执行缩放float zoom = app->m_camera.GetZoom();if (yoffset > 0)zoom *= 1.15f;elsezoom *= 0.85f;app->m_camera.SetZoom(zoom);// 4. 重新计算世界坐标invVP = glm::inverse(app->m_camera.GetViewProjectionMatrix());glm::vec4 worldPosAfterZoom = invVP * ndcPos;// 5. 保持鼠标位置不变:调整相机位置glm::vec3 camPos = app->m_camera.GetPosition();glm::vec3 offset = glm::vec3(worldPosBeforeZoom - worldPosAfterZoom); app->m_camera.SetPosition(camPos + glm::vec3(offset.x*0.5,offset.y*0.5,offset.z*0.5));}
// 获取窗口的用户数据
Application* Application::GetWindow(GLFWwindow* window)
{void* userdata = glfwGetWindowUserPointer(window);return reinterpret_cast<Application*>(userdata);
}void Application::Initialize(int width, int height, const char* title)
{if (!glfwInit()){exit(EXIT_FAILURE);}glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);m_pWindow = glfwCreateWindow(width, height, title, NULL, NULL);m_winWidth = width;m_winHeight = height;if (!m_pWindow){glfwTerminate();exit(EXIT_FAILURE);}glfwDefaultWindowHints();GLFWmonitor* primary = glfwGetPrimaryMonitor();const GLFWvidmode* mode = glfwGetVideoMode(primary);    // 设置窗口位置为屏幕中心glfwSetWindowPos(m_pWindow, (mode->width- width)/2, (mode->height - height) / 2);// 窗口的物理尺寸int widthMM, heightMM;glfwGetMonitorPhysicalSize(primary, &widthMM, &heightMM);// 计算 DPIfloat dpiX = static_cast<float>(mode->width) / (static_cast<float>(widthMM) );    float dpiY = static_cast<float>(mode->height) / (static_cast<float>(heightMM));glfwShowWindow(m_pWindow);// 设置 glfw 回调函数glfwSetKeyCallback(m_pWindow, KeyCallback);glfwSetMouseButtonCallback(m_pWindow, MouseButtonCallback);glfwSetCursorPosCallback(m_pWindow, CursorPositionCallback);glfwSetWindowSizeCallback(m_pWindow, WindowSizeCallback);glfwSetScrollCallback(m_pWindow, ScrollCallback);glfwMakeContextCurrent(m_pWindow);gladLoadGL();glfwSwapInterval(1); // 垂直同步glEnable(GL_DEPTH_TEST); // 开启深度测试// 设置相机m_camera.SetView(width, height);   glfwSetWindowUserPointer(m_pWindow, this);
}void Application::Run()
{Startup(); // 准备工作while (!glfwWindowShouldClose(m_pWindow)){glfwGetFramebufferSize(m_pWindow, &m_winWidth, &m_winHeight);glViewport(0, 0, m_winWidth, m_winHeight);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);glClearColor(0.0f, 0.0f, 0.0f, 1.0f);Render(); // 渲染数据glfwSwapBuffers(m_pWindow);glfwWaitEvents(); // 等待事件}Shutdown(); // 关闭程序
}void Application::Startup()
{// 初始化数据
}void Application::Render()
{}void Application::Shutdown()
{// 清理资源
}

OrthoCamera.h

#pragma once#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>/// <summary>
/// 实现一个用于 2D 渲染的正交相机类。
/// 提供相机的位置、旋转、投影矩阵和视图矩阵等基本功能。
/// </summary>
class OrthoCamera
{
public:OrthoCamera();~OrthoCamera();public: void SetView(int windowWidth, int windowHeight);void SetView(float fixedHeight, int windowWidth, int windowHeight);void SetPosition(const glm::vec3& pos);void SetZoom(float zoom);const double& GetZoom() const { return m_Zoom ;} const glm::vec3& GetPosition() const { return m_Position; } const glm::mat4& GetViewProjectionMatrix() const { return m_ViewProjectionMatrix; };private:void RecalculateMatrix();glm::vec3 m_Position = { 0.0f, 0.0f, 0.0f };double m_Zoom = 200.0f;double m_FixedHeight = 1000.0f;int m_WindowWidth = 1280;int m_WindowHeight = 720;glm::mat4 m_ProjectionMatrix = glm::mat4(1.0f);glm::mat4 m_ViewMatrix = glm::mat4(1.0f);glm::mat4 m_ViewProjectionMatrix = glm::mat4(1.0f);
};

OrthoCamera.cpp

#include "OrthoCamera.h"OrthoCamera::OrthoCamera()
{
}OrthoCamera::~OrthoCamera()
{
}void OrthoCamera::SetView(int windowWidth, int windowHeight)
{m_FixedHeight = windowHeight;m_WindowWidth = windowWidth;m_WindowHeight = windowHeight;RecalculateMatrix();
}void OrthoCamera::SetView(float fixedHeight, int windowWidth, int windowHeight)
{m_FixedHeight = fixedHeight;m_WindowWidth = windowWidth;m_WindowHeight = windowHeight;RecalculateMatrix();
}void OrthoCamera::SetPosition(const glm::vec3& pos)
{m_Position = pos;RecalculateMatrix();
}void OrthoCamera::SetZoom(float zoom)
{m_Zoom = zoom;RecalculateMatrix();
}void OrthoCamera::RecalculateMatrix()
{float aspect = static_cast<float>(m_WindowWidth) / m_WindowHeight;float halfHeight = (m_FixedHeight * 0.5f) / m_Zoom;float halfWidth = halfHeight * aspect;float left = m_Position.x - halfWidth;float right = m_Position.x + halfWidth;float bottom = m_Position.y - halfHeight;float top = m_Position.y + halfHeight;m_ProjectionMatrix = glm::ortho(left, right, bottom, top, -1000.0f, 1000.0f); // 扩展 zNear/zFar 范围// 这里是关键:m_ViewMatrix = glm::translate(glm::mat4(1.0f), -m_Position); // x/y/z 都考虑进去m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}

Triangle.h

#pragma once
#include "Entity.h"
#include "glm/glm.hpp"
#include "../Shader/Shader_P2_C3.h"
#include "../Core/OrthoCamera.h"class Triangle // : public Entity
{
public:Triangle(){m_vao = -1;m_vbo = -1;};~Triangle(){		glDeleteVertexArrays(1, &m_vao);glDeleteBuffers(1, &m_vbo);		};virtual void Init()  // 数据准备{	// 1.准备Shaderm_shader.Initialize();// 2.准备数据typedef struct Vertex{float x, y;float r, g, b;} Vertex;Vertex vertices[3] ={{  -1.0f, -1.0f  , 1.f, 0.f, 0.f},{   1.0f, -1.0f  , 0.f, 1.f, 0.f},{    0.f,  1.0f  , 0.f, 0.f, 1.f}};// Shader应用绑定顶点缓冲区数据glGenVertexArrays(1, &m_vao);glBindVertexArray(m_vao);// 创建显存并向顶点缓冲填充数据glGenBuffers(1, &m_vbo);glBindBuffer(GL_ARRAY_BUFFER, m_vbo);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);glVertexAttribPointer(m_shader.m_position, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);glEnableVertexAttribArray(m_shader.m_position);glVertexAttribPointer(m_shader.m_color, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(2 * sizeof(float)));glEnableVertexAttribArray(m_shader.m_color);}virtual void Render(const OrthoCamera &camera) // 绘制{ m_shader.Begin();glBindVertexArray(m_vao);glUniformMatrix4fv(m_shader.m_mvp, 1, GL_FALSE, (const GLfloat*)&camera.GetViewProjectionMatrix());glDrawArrays(GL_TRIANGLES, 0, 3);m_shader.End();}public:unsigned        m_vao;unsigned        m_vbo;Shader_P2_C3    m_shader;};

Shader_P2_C3.h

#pragma once
#include "Shader.h"
class Shader_P2_C3:public Shader
{public:Shader_P2_C3(){m_mvp      = -1;m_position = -1;m_color    = -1;};~Shader_P2_C3(){};virtual bool  Initialize(){const char* vs = R"(#version 330uniform mat4 MVP;in vec2 vPos;in vec3 vCol;out vec3 color;void main(){gl_Position = MVP * vec4(vPos, 0.0, 1.0);color = vCol;})";const char* ps = R"(#version 330in vec3 color;out vec4 fragment;void main(){fragment = vec4(color, 1.0);//fragment = vec4(1.0,1,0,0);})";bool    res = CreateShader(vs, ps);if (res){m_mvp      = glGetUniformLocation(m_shaderId, "MVP");m_position = glGetAttribLocation(m_shaderId,  "vPos");m_color    = glGetAttribLocation(m_shaderId,  "vCol");;}	return true;}public:int m_mvp;int m_position;int m_color;
};

 Shader.h

#pragma once
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <assert.h>
#include <map>
#include <glm/gtc/type_ptr.hpp>
#include <string>class Shader
{
public:Shader();~Shader();public:bool CreateShader(const char* vertex, const char* fragment);virtual void Begin();virtual void End();void SetVec3(const std::string& name, const float x, const float y, const float z)const{auto cit = uniform.find(name);glUniform3f(cit->second, x, y, z);}void SetVec3(const std::string& name, const glm::vec3& vec) const{auto cit = uniform.find(name);glUniform3f(cit->second, vec.x, vec.y, vec.z);}void SetMat4(const std::string& name, const glm::mat4& mat) const{auto cit = uniform.find(name);glUniformMatrix4fv(cit->second, 1, GL_FALSE, glm::value_ptr(mat));}void SetFloat(const std::string& name, const float x) const{auto cit = uniform.find(name);glUniform1f(cit->second, x);}void SetInt(const std::string& name, const int d)const{auto cit = uniform.find(name);glUniform1i(cit->second, d);        }
public:int  m_shaderId;std::map <std::string, unsigned> uniform;
};

Shader.cpp

#include "Shader.h"Shader::Shader():m_shaderId(0)
{
}Shader::~Shader()
{// 删除shaderglDeleteProgram(m_shaderId);
}bool Shader::CreateShader(const char* vertex, const char* fragment)
{bool error = false;int  vertexShader = 0;int  fragmentShader = 0;do{if (vertex){vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertex, 0);glCompileShader(vertexShader);GLint   compileStatus;glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &compileStatus);error = compileStatus == GL_FALSE;if (error){GLchar messages[256];glGetShaderInfoLog(vertexShader, sizeof(messages), 0, messages);assert(messages && 0 != 0);break;}}if (fragment){fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragment, 0);glCompileShader(fragmentShader);GLint   compileStatus;glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &compileStatus);error = compileStatus == GL_FALSE;if (error){GLchar messages[256];glGetShaderInfoLog(fragmentShader, sizeof(messages), 0, messages);assert(messages && 0 != 0);break;}}m_shaderId = glCreateProgram();if (vertexShader){glAttachShader(m_shaderId, vertexShader);}if (fragmentShader){glAttachShader(m_shaderId, fragmentShader);}glLinkProgram(m_shaderId);GLint linkStatus;glGetProgramiv(m_shaderId, GL_LINK_STATUS, &linkStatus);if (linkStatus == GL_FALSE){GLchar messages[256];glGetProgramInfoLog(m_shaderId, sizeof(messages), 0, messages);break;}glUseProgram(m_shaderId);} while (false);if (error){if (fragmentShader){glDeleteShader(fragmentShader);fragmentShader = 0;}if (vertexShader){glDeleteShader(vertexShader);vertexShader = 0;}if (m_shaderId){glDeleteProgram(m_shaderId);m_shaderId = 0;}}return true;
}void Shader::Begin()
{glUseProgram(m_shaderId);}void Shader::End()
{glUseProgram(0);}

目标2:先解析DXF基础图元(直线) 

dxf选用格式为utf-8明文编码,一下是图层组码信息:100  AcDbLine (直线) 。

AutoCAD 2025 Developer and ObjectARX 帮助 | LINE (DXF) | Autodesk

根据官方文档解析直线->以下组码适用于直线图元。

LINE 组码

组码

说明

100

子类标记 (AcDbLine)

39

厚度(可选;默认值 = 0)

10

起点(在 WCS 中)

DXF:X 值;APP:三维点

20, 30

DXF:起点的 Y 值和 Z 值(在 WCS 中)

11

端点(在 WCS 中)

DXF:X 值;APP:三维点

21, 31

DXF:端点的 Y 值和 Z 值(在 WCS 中)

210

拉伸方向(可选;默认值 = 0, 0, 1)

DXF:X 值;APP:三维矢量

220, 230

DXF:拉伸方向的 Y 值和 Z 值(可选)

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <Windows.h>using Entity = std::map<std::string, std::string>;
/// <summary>
/// ifstream和getline获取中文乱码解决方案
/// </summary> 
std::string UTF8ToGB(const char* str)
{std::string result;WCHAR* strSrc;LPSTR szRes;//获得临时变量的大小int i = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);strSrc = new WCHAR[i + 1];MultiByteToWideChar(CP_UTF8, 0, str, -1, strSrc, i);//获得临时变量的大小i = WideCharToMultiByte(CP_ACP, 0, strSrc, -1, NULL, 0, NULL, NULL);szRes = new CHAR[i + 1];WideCharToMultiByte(CP_ACP, 0, strSrc, -1, szRes, i, NULL, NULL);result = szRes;delete[]strSrc;delete[]szRes;return result;
}// 去除前后空格
std::string trim(const std::string& str) {auto first = str.find_first_not_of(" \t\r\n");auto last = str.find_last_not_of(" \t\r\n");return (first == std::string::npos) ? "" : str.substr(first, last - first + 1);
}// 读取组码-值对
bool ReadCodes(std::ifstream& file, std::string& code, std::string& value) {if (!std::getline(file, code)) return false;if (!std::getline(file, value)) return false; std::string strCode = UTF8ToGB(code.c_str()).c_str();std::string strValue = UTF8ToGB(value.c_str()).c_str();code = trim(strCode);value = trim(strValue);return true;
}// 解析 DXF 中所有 LINE 实体的图层和坐标
std::vector<Entity> ParseDXFLines(const std::string& filename) {std::ifstream file(filename, std::ios::binary);if (!file.is_open()) {std::cerr << "无法打开文件: " << filename << std::endl;return {};}std::vector<Entity> lineEntities;Entity currentEntity;std::string code, value;std::string currentLayer;while (ReadCodes(file, code, value)) {// 处理每个 AcDbEntity 实体if (code == "100" && value == "AcDbEntity") {// 获取图层信息while (ReadCodes(file, code, value)) {if (code == "8") {currentLayer = value;  // 保存图层名break;}}}// 处理 AcDbLine 实体if (code == "100" && value == "AcDbLine") {Entity lineEntity;lineEntity["Layer"] = currentLayer; // 设置图层信息// 获取起点 (10, 20, 30)while (ReadCodes(file, code, value)) {if (code == "10") lineEntity["StartX"] = value;if (code == "20") lineEntity["StartY"] = value;if (code == "30") lineEntity["StartZ"] = value;// 获取终点 (11, 21, 31)if (code == "11") lineEntity["EndX"] = value;if (code == "21") lineEntity["EndY"] = value;if (code == "31") lineEntity["EndZ"] = value;// 检查是否处理完一个线段(可根据需要继续读取更多信息)if (lineEntity.size() == 6) {lineEntities.push_back(lineEntity);break;}}}}file.close();return lineEntities;
}int main()
{ std::string filename = R"(C:\Users\Desktop\Drawing1.dxf)";// 解析文件auto lines = ParseDXFLines(filename);// 输出解析的直线信息for (const auto& entity : lines) {std::string layer = entity.count("Layer") ? entity.at("Layer") : "(未知图层)";std::string x1 = entity.count("StartX") ? entity.at("StartX") : "?";std::string y1 = entity.count("StartY") ? entity.at("StartY") : "?";std::string x2 = entity.count("EndX") ? entity.at("EndX") : "?";std::string y2 = entity.count("EndY") ? entity.at("EndY") : "?";std::cout << "图层: " << layer<< ",起点: (" << x1 << ", " << y1 << ")"<< ",终点: (" << x2 << ", " << y2 << ")"<< std::endl;}return 0;
} 

相关文章:

  • Compose 中使用 WebView
  • Unity:输入系统(Input System)与持续检测键盘按键(Input.GetKey)
  • win10开了移动热点,手机无法连接,解决办法(chatgpt版)
  • socket,http
  • 基于python的哈希查表搜索特定文件
  • 查看Ubuntu版本
  • (41)VTK C++开发示例 ---qt使用vtk最小示例
  • 科创大赛——知识点复习【c++】——第一篇
  • Flink流水线任务在线演示
  • 《类和对象(上)》
  • Python 整理3种查看神经网络结构的方法
  • 虚幻引擎作者采访
  • 什么是原码、反码与补码?
  • 2025流感疫苗指南+卫健委诊疗方案|高危人群防护+并发症处理 慢性肾脏病饮食指南2025卫健委版|低盐低磷食谱+中医调理+PDF 网盘下载 pdf下载
  • 牛客1018逆序数-归并排序
  • 金融的本质是智融、融资的实质是融智、投资的关键是投智,颠覆传统金融学的物质资本中心论,构建了以智力资本为核心的新范式
  • PyTorch 张量与自动微分操作
  • 全球化电商平台Azure云架构设计
  • 期末代码Python
  • iptables的基本选项及概念
  • 美国内政部长:今年夏天美国可能发生西班牙式大停电,全怪拜登
  • 无畏契约新王诞生:属于电竞世界的凯泽斯劳滕奇迹
  • 华尔兹转岗与鲁比奥集权:特朗普政府人事震荡背后的深层危机
  • 商务部新闻发言人就中美经贸对话磋商情况答记者问
  • 奥斯卡新规:评委必须看完影片再投票;网友:以前不是啊?
  • 杨轶群任莆田市荔城区人民政府副区长