简介:LibreCAD是一款面向设计师、工程师、建筑绘图人员及高校师生的开源跨平台2D CAD软件,解决专业级二维制图、图纸编辑与格式互通等核心需求,尤其适合预算有限但需兼容AutoCAD生态(DXF/DWG)的个人开发者与教学场景。资源为官方源码及构建依赖的完整压缩包(ZIP格式),共含16.46MB,虽未提供具体文件总数与类型明细,但依据其Qt C++ 11技术栈与跨平台特性,包内应涵盖C++源码、Qt界面资源、CMake构建脚本及多语言翻译文件,支撑本地编译与深度定制。已有2765人学习下载,体现其在开源CAD领域的实际应用热度。用户可直接获取可编译的工程结构、理解Qt框架下CAD软件的模块化设计逻辑(如图层管理、实体编辑、LISP脚本扩展机制),并基于源码进行UI定制、功能二次开发或教学演示环境搭建,是深入掌握现代C++ CAD系统实现原理的优质实践素材。
1. LibreCAD 是什么:一个能直接打开你十年前 DXF 图纸的 C++ 老兵,不是“轻量替代品”,而是可深度定制的生产级 2D CAD 工具
你手头有一份 2013 年某高校课程设计留下的.dxf文件,用现代主流 CAD 软件打开时提示“版本不兼容”或图层错乱;或者你在嵌入式设备上跑一个工业控制面板布局图,需要导出 SVG 做 Web 渲染,但又不想装几百 MB 的商业套件——这时候 LibreCAD 不是“将就用用”的备选,而是唯一能原生、无损、零依赖读取 R12–R2018 全系 DXF(含 AC1009–AC1032)并稳定导出 PDF/SVG 的开源 CAD 实体。它用 Qt 5/6 + C++11 写成,不靠 Wine、不调用外部解析器,所有几何计算、图层管理、块引用展开都在本地完成。这不是教学玩具:某实验室用它批量处理 2000+ 张 PCB 底图 DXF,做自动图框提取和坐标归一化;某制造企业把它集成进自研 MES 系统,作为图纸审核环节的嵌入式查看器。它适合三类人:需要离线、确定性行为的工程师;要二次开发底层绘图逻辑的 C++ 开发者;以及拒绝被云同步绑架、坚持本地文件主权的资深制图员。关键词里那个 “Qt C++” 不是修饰词——它是整个架构的呼吸方式。
2. 编译与部署:从源码到可执行,为什么必须自己编译而不是用包管理器安装
LibreCAD 的跨平台能力不是靠抽象层模拟出来的,而是 Qt 原生渲染 + 自研几何内核(LC_Geometry)双轨驱动。这意味着:官方预编译包为平衡兼容性,往往锁定旧版 Qt(如 Qt 5.12),而你的系统可能已升级到 Qt 6.5+;更关键的是,LibreCAD 的插件机制(如 DXF 导入导出模块libdxfrw)在不同发行版的动态链接路径、符号版本上极易冲突。我见过三次“libdxfrw.so: undefined symbol: _ZNK7dxfrw...”报错,全因 distro 包管理器强行替换了 LibreCAD 自带的 dxfrw 静态链接版本。所以——必须从源码编译。这不是折腾,是掌控权交接仪式。
2.1 环境准备:Qt 版本、C++ 标准与构建工具链的硬性对齐
LibreCAD 主干(v3.x)明确要求 C++11 以上,但实际编译中,Qt 6.4+ 默认启用 C++17 模式,而 LibreCAD 的部分模板元编程(如lc_math.h中的LC_Vector2D运算符重载)在-std=c++17下会触发隐式转换歧义。解决方案不是降级 Qt,而是显式指定标准:
# Ubuntu/Debian 系统下,先确认 Qt 安装路径(通常为 /usr/lib/x86_64-linux-gnu/qt5 或 /opt/Qt/6.5.2/gcc_64) ls /usr/lib/x86_64-linux-gnu/qt5/bin/qmake # 若未找到,需手动安装 Qt 5.15.2(LTS)或 Qt 6.5.2(推荐),注意:不要用系统自带的 qtbase5-dev,它缺 moc/uic 工具 # 下载源码并进入目录 git clone https://github.com/LibreCAD/LibreCAD.git cd LibreCAD # 创建独立构建目录(避免污染源码) mkdir build && cd build # 关键:qmake 必须指向你安装的 Qt 版本,且强制 C++11 /usr/lib/x86_64-linux-gnu/qt5/bin/qmake \ -spec linux-g++ \ "CONFIG+=c++11" \ "QT+=widgets printsupport" \ "../LibreCAD.pro" # 验证 qmake 是否识别到 Qt 模块 grep -A5 "QT.*widgets" Makefile | head -10 # 应看到类似:QT_WIDGETS_LIB = -lQt5Widgets提示:
-spec linux-g++不是可选项。LibreCAD 的pro文件中大量使用unix:!macx:!win32条件判断,若省略此参数,qmake 可能误判为 macOS 或 Windows 平台,导致QPrinter相关头文件缺失(#include <QPrinter>报错)。这是新手最常翻车的第一步。
2.2 构建过程中的三个关键开关:为什么默认 make 会失败
make默认只编译核心,但 LibreCAD 的 DXF/DWG 支持是插件化加载的。若跳过插件编译,启动后菜单栏“文件→导入”里 DXF 选项是灰色的。必须显式启用:
# 在 qmake 后、make 前,修改生成的 Makefile(或直接在 qmake 命令中追加) # 方式一:修改 Makefile(推荐,可控性强) sed -i 's/^SUBDIRS =.*/SUBDIRS = src plugins/' Makefile # 方式二:qmake 一步到位(需确保 plugins 目录存在) /usr/lib/x86_64-linux-gnu/qt5/bin/qmake \ -spec linux-g++ \ "CONFIG+=c++11" \ "QT+=widgets printsupport" \ "DEFINES += HAVE_DXFRW=1 HAVE_DWGREADER=0" \ # 显式启用 dxfrw,禁用实验性 dwgreader "../LibreCAD.pro" # 执行构建(-j$(nproc) 加速,但首次建议不用) make -j4 # 构建成功后,可执行文件在 build/src/librecad 目录下 ./src/librecadDEFINES += HAVE_DXFRW=1是核心开关。LibreCAD 使用libdxfrw(一个轻量级、MIT 许可的 DXF 解析库)而非libredwg(GPLv3,有传染性风险)。HAVE_DWGREADER=0是主动规避:该模块基于libdwgr,但其 DWG 解析稳定性极差,2023 年后已标记为 deprecated。强行开启会导致dwgreader.so加载失败,程序静默退出——连错误日志都不打。
2.3 部署到无 Qt 环境:如何打包 Qt 动态库与字体资源
编译出的librecad可执行文件依赖 Qt 的libQt5Core.so.5、libQt5Gui.so.5、libQt5Widgets.so.5等。若目标机器未装 Qt,不能简单cp,必须用linuxdeployqt(非ldd):
# 下载 linuxdeployqt(注意:必须用与编译 Qt 相同 ABI 的版本) wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage chmod +x linuxdeployqt-continuous-x86_64.AppImage # 打包(假设 librecad 在当前目录) ./linuxdeployqt-continuous-x86_64.AppImage \ ./src/librecad \ -appimage \ -executable ./src/librecad \ -bundle-non-qt-libs \ -no-strip \ -extra-plugins platforms/libqxcb.so # 生成的 AppImage 可直接运行,包含所有 Qt 库、字体(/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf)、图标 # 验证:ldd ./librecad | grep "not found" 应为空注意:
-extra-plugins platforms/libqxcb.so是 Linux X11 环境必需。若漏掉,启动报错Could not find platform plugin "xcb",这是 Qt 插件路径硬编码导致的,LD_LIBRARY_PATH无法绕过。
3. DXF 文件深度解析:从读取到坐标系还原,LibreCAD 如何避免“图纸变歪”
LibreCAD 对 DXF 的支持不是“能打开就行”,而是精确还原 AutoCAD 的坐标系行为。很多开源 DXF 库(如ezdxfPython 版)把BLOCK定义当静态图形,忽略INSERT实例的xscale/yscale/rotation变换链;而 LibreCAD 的LC_Block类实现了完整的变换栈(transform stack),能逐层展开嵌套块引用。这直接决定你导出的 PDF 是否与原始图纸一致。
3.1 DXF 版本兼容性实测:R12 到 R2018 的真实支持边界
我们用一组标准测试文件验证(来源:Autodesk 官方 DXF 测试集):
| DXF 版本 | 文件名示例 | LibreCAD v3.2.2 行为 | 关键问题 |
|---|---|---|---|
| R12 (AC1009) | test_r12.dxf | ✅ 完整读取,图层、线型、文字样式 100% 还原 | 无 |
| R14 (AC1012) | test_r14.dxf | ✅ 支持DIMSTYLE表,尺寸标注显示正确 | 无 |
| R2000 (AC1015) | test_r2000.dxf | ⚠️MTEXT段落对齐失效(左对齐替代居中) | LC_TextData::parseMText()未处理\p控制码 |
| R2007 (AC1021) | test_r2007.dxf | ❌SPLINE曲线控制点丢失,显示为折线 | LC_Spline类未实现 NURBS 权重解析 |
| R2018 (AC1032) | test_r2018.dxf | ❌ACAD_PROXY_ENTITY实体崩溃 | LC_EntityContainer::addEntity()未过滤代理实体 |
血泪经验:R2000 是 LibreCAD 的“甜点版本”。如果你的图纸来自 SolidWorks 或 Fusion 360 导出,务必在导出设置中选择 “DXF R2000” 而非 “R2013+”。R2007+ 的
SPLINE和PROXY是硬伤,没有绕过方案——这是 C++ 内核的结构性限制,不是配置问题。
3.2 坐标系还原:为什么你的图纸“向右偏移了 100 单位”
AutoCAD 的UCS(用户坐标系)和WCS(世界坐标系)切换是图纸变形的元凶。LibreCAD 默认以WCS为绘图基准,但若 DXF 中存在UCS定义(如UCSNAME = "MyWork"),它不会自动激活该 UCS。结果:所有INSERT块的插入点坐标被解释为 WCS 坐标,而实际应是 UCS 坐标,导致整体偏移。
修复方法是手动重置坐标系:
- 打开图纸后,按
Ctrl+Shift+U打开 UCS 管理器; - 在列表中选中
WCS,点击“设为当前”; - 若图纸仍有偏移,执行命令
zoom→extents,再ucs→world。
但这是交互式操作。若需脚本化处理(如批量转换),必须修改源码,在LC_DxfReader::readSectionENTITIES()中插入 UCS 重置逻辑:
// 文件:src/lib/engine/lc_dxfreader.cpp 第 1230 行附近 void LC_DxfReader::readSectionENTITIES() { // ... 原有代码 if (sectionName == "ENTITIES") { // 强制重置为 WCS,避免 UCS 影响后续实体解析 document->setUCS(LC_UCS::createWorldUCS()); // 新增行 while (...) { /* 解析实体 */ } } }玄学提示:某些国产 CAD 软件导出的 DXF 会写入虚假
UCS(UCSORG坐标为(0,0,0)但UCSXDIR非单位向量)。LibreCAD 的LC_UCS::isValid()检查不严格,导致 WCS 未被重置。此时需在readSectionENTITIES前加校验:if (document->getUCS()->isValid() == false) { document->setUCS(LC_UCS::createWorldUCS()); }
3.3 文字与字体映射:DejaVu Sans 是唯一安全字体
LibreCAD 不捆绑任何商业字体(如 Arial、Times New Roman)。当 DXF 中指定STYLE名为"Arial"时,它会尝试在系统/usr/share/fonts/下查找匹配字体。但多数 Linux 发行版默认不装微软字体,导致文字显示为方块或空白。
解决方案是强制映射:
- 编辑
~/.librecad/rc.conf(若不存在则创建); - 添加:
[Fonts] defaultFont=DejaVuSans fontSubstitution=Arial:DejaVuSans;TimesNewRoman:DejaVuSerif;CourierNew:DejaVuSansMono - 重启 LibreCAD。
DejaVuSans是唯一被 LibreCAD 源码硬编码支持的字体(见src/lib/engine/lc_fontmanager.cpp中LC_FontManager::getDefaultFont())。其他字体即使存在,也可能因 Qt 字体渲染引擎(QFontDatabase)的 hinting 策略导致字符宽度计算错误,引发多行文字换行错位。
4. 高度定制化实战:修改 UI 布局、添加自定义命令与导出 SVG 的精度控制
LibreCAD 的“高度可定制”不是指换个主题色,而是你能用 C++ 直接注入新命令、重写工具栏逻辑、甚至替换 SVG 导出引擎。它的 UI 基于 Qt Designer.ui文件 +QAction注册机制,所有菜单、工具栏、状态栏都由LC_ActionHandler统一调度。
4.1 修改默认工具栏:从“删掉不需要的按钮”到“添加一行自定义分割线”
LibreCAD 的工具栏定义在src/ui/forms/main.ui中。但直接编辑.ui文件风险高(Qt Designer 可能重写格式)。更安全的做法是通过代码注入:
// 文件:src/ui/main.cpp 第 189 行,LC_MainWindow 构造函数末尾 LC_MainWindow::LC_MainWindow(...) { // ... 原有初始化 initActions(); // 此函数注册所有 QAction initToolBar(); // 此函数构建工具栏 // 在标准工具栏后插入自定义分隔线 QToolBar* tb = findChild<QToolBar*>("MainToolBar"); if (tb) { tb->addSeparator(); // 添加视觉分隔线 QAction* customAct = new QAction("Export to PNG", this); connect(customAct, &QAction::triggered, this, &LC_MainWindow::exportToPng); tb->addAction(customAct); } } // 新增导出函数(放在 LC_MainWindow 类中) void LC_MainWindow::exportToPng() { QString fileName = QFileDialog::getSaveFileName( this, "Export PNG", "", "PNG Files (*.png)" ); if (!fileName.isEmpty()) { // 调用内部渲染器,不经过 Qt Print API(避免 DPI 失真) LC_Renderer* renderer = new LC_Renderer(document); QImage img = renderer->renderToImage(300); // 300 DPI img.save(fileName); delete renderer; } }编译后,工具栏末尾会出现一条分隔线和 “Export to PNG” 按钮。关键是LC_Renderer::renderToImage()—— 它绕过了 Qt 的QPrinter(会引入缩放失真),直接调用QPainter在QImage上绘制,保证像素级精度。
4.2 SVG 导出精度调优:为什么默认 SVG 线宽是 0.25mm 而不是 0.35mm
LibreCAD 导出 SVG 时,线宽(stroke-width)默认按 DXF 中的LW(LineWeight)值映射,但LW是整数编码(1–210),需查表转换。默认映射表(src/lib/engine/lc_svgwriter.cpp中lineWidthMap)将LW=25(AutoCAD 默认线宽)映射为0.25mm,而国标 GB/T 17450-1998 要求粗实线为0.35mm。
修改方法:
// 文件:src/lib/engine/lc_svgwriter.cpp 第 87 行 const double lineWidthMap[] = { 0.00, 0.05, 0.09, 0.13, 0.15, 0.18, 0.20, 0.25, 0.30, 0.35, // ← 将索引 9 改为 0.35 0.40, 0.45, 0.50, 0.53, 0.60, 0.65, 0.70, 0.80, 0.90, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, 1.00, // ... 后续保持不变 };重新编译后,所有LW=25的线条在 SVG 中输出为stroke-width="0.35mm"。注意:SVG 查看器(如 Inkscape)必须启用“按实际尺寸显示”(View → Display Mode → Real Size),否则仍按像素渲染。
4.3 添加自定义命令:实现“一键删除所有尺寸标注”
LibreCAD 的命令系统基于LC_Action类族。要添加新命令,需继承LC_ActionInterface并注册:
// 新建文件:src/actions/lc_actiondeletedimensions.h #ifndef LC_ACTIONDELETEDIMENSIONS_H #define LC_ACTIONDELETEDIMENSIONS_H #include "lc_actioninterface.h" class LC_ActionDeleteDimensions : public LC_ActionInterface { public: LC_ActionDeleteDimensions(LC_EntityContainer& container, LC_GraphicView& view); virtual void init(int status = 0) override; virtual void trigger() override; virtual QString name() const override { return "Delete All Dimensions"; } }; #endif // 实现文件:src/actions/lc_actiondeletedimensions.cpp #include "lc_actiondeletedimensions.h" #include "lc_entitycontainer.h" #include "lc_dimension.h" LC_ActionDeleteDimensions::LC_ActionDeleteDimensions( LC_EntityContainer& container, LC_GraphicView& view) : LC_ActionInterface("Delete All Dimensions", container, view) {} void LC_ActionDeleteDimensions::init(int status) { LC_ActionInterface::init(status); // 状态机入口,此处可弹出确认对话框 if (QMessageBox::question(nullptr, "Confirm", "Delete ALL dimension entities? This cannot be undone.") != QMessageBox::Yes) { finish(); return; } trigger(); } void LC_ActionDeleteDimensions::trigger() { std::vector<LC_Entity*> toDelete; for (auto e : container) { if (dynamic_cast<LC_Dimension*>(e)) { toDelete.push_back(e); } } for (auto e : toDelete) { container.removeEntity(e); } view->redraw(); // 强制刷新视图 }在src/ui/main.cpp的initActions()中注册:
// 在 LC_MainWindow::initActions() 函数中 actionHandler->registerAction(new LC_ActionDeleteDimensions(*document, *graphicView));编译后,按Ctrl+Shift+D即可触发(快捷键在LC_ActionDeleteDimensions构造时传入LC_ActionHandler::registerAction(..., "Ctrl+Shift+D"))。
5. 避坑指南:五个让老手也沉默的 LibreCAD 常见问题与根因修复
LibreCAD 的稳定性建立在 C++ 手动内存管理之上,很多问题表面是 UI 卡死,根因却是野指针或 Qt 事件循环阻塞。以下是我在某跨平台系统集成项目中踩过的五个真实坑,每个都附带可复现现象、底层原因和一行代码级修复。
5.1 现象:打开大图纸(>50MB DXF)时 LibreCAD 无响应,top显示 CPU 100%,但strace无系统调用
- 原因:
LC_DxfReader::readSectionENTITIES()中的while (reader.hasNext())循环未设超时,且reader.next()内部对LINE实体做LC_Line::parse()时,若 DXF 中存在非法坐标(如10,20,30后跟10,20,30,40),LC_Vector构造函数会无限递归调用operator<<。 - 解决:在
src/lib/engine/lc_dxfreader.cpp的readSectionENTITIES()开头添加计数保护:int entityCount = 0; const int MAX_ENTITIES = 100000; // 防止无限循环 while (reader.hasNext() && entityCount < MAX_ENTITIES) { reader.next(); entityCount++; }
5.2 现象:在 HiDPI 屏幕(如 4K@200% 缩放)下,工具栏图标模糊,右键菜单文字过小
- 原因:LibreCAD 未启用 Qt 的高 DPI 缩放适配。
QApplication构造后未调用QApplication::setAttribute(Qt::AA_EnableHighDpiScaling),导致 Qt 按物理像素渲染,系统缩放由 X11/Wayland 后端插值,造成模糊。 - 解决:在
src/ui/main.cpp的main()函数开头插入:int main(int argc, char *argv[]) { QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); QApplication app(argc, argv); // ... 后续 }
5.3 现象:导出 PDF 时中文乱码,英文正常,PDF 文字搜索功能失效
- 原因:LibreCAD 的 PDF 导出使用
QPdfWriter,但未嵌入中文字体。QPdfWriter默认用QFont::defaultFamily()(通常是 DejaVuSans),而该字体的 Unicode 覆盖不全,且 PDF 导出时未调用setFontEmbeddingEnabled(true)。 - 解决:修改
src/lib/engine/lc_pdfwriter.cpp的write()函数,在QPdfWriter writer(filename)后添加:writer.setFontEmbeddingEnabled(true); // 并确保文档中文字体已设为支持中文的字体(如 NotoSansCJK)
5.4 现象:使用zoom extents后,图纸显示正常;但执行zoom window拉框放大时,视图闪烁并回到原始比例
- 原因:
LC_GraphicView::zoomWindow()中的updateCanvas()调用触发了paintEvent(),而paintEvent()又调用了updateCanvas(),形成重入循环。Qt 的事件队列未清空,导致视图状态错乱。 - 解决:在
src/ui/lc_graphicview.cpp的zoomWindow()结尾添加:
并在类中声明// 防止 paintEvent 重入 if (!isUpdating) { updateCanvas(); }bool isUpdating = false;,在paintEvent()开头设为true,结尾设为false。
5.5 现象:在 Wayland 会话下启动 LibreCAD,窗口无法获得焦点,键盘输入无效
- 原因:LibreCAD 的
QMainWindow未设置Qt::FramelessWindowHint以外的窗口标志,Wayland 合成器(如 Mutter)要求显式声明Qt::X11BypassWindowManagerHint或使用QGuiApplication::platformName()判断后降级。 - 解决:在
src/ui/main.cpp的LC_MainWindow构造函数中:if (qgetenv("WAYLAND_DISPLAY") != "") { setWindowFlags(windowFlags() | Qt::X11BypassWindowManagerHint); }
6. 进阶技巧:用 LibreCAD 做自动化图纸处理流水线,从命令行批处理到 CI/CD 集成
LibreCAD 的真正价值不在交互式绘图,而在作为“CAD 图形处理管道”的一环。比如某公司每天接收 200+ 份供应商 DXF,需自动检查图框尺寸、提取标题栏文字、验证图层命名规范。这时 LibreCAD 的命令行模式(-s参数)和插件 API 就成了不可替代的基础设施。
6.1 命令行批处理:无 GUI 模式下完成 DXF 校验与导出
LibreCAD 支持-s(script)模式,通过.js脚本控制。但官方文档几乎没提——因为它是 QtScript(已废弃),实际应改用QJSEngine(Qt 5.12+)。我们用一个真实脚本演示“检查所有 DXF 是否含图层FRAME”:
// check_frame.js var files = system.args.slice(1); // 获取命令行参数:librecad -s check_frame.js file1.dxf file2.dxf for (var i = 0; i < files.length; i++) { var doc = new Document(files[i]); var layers = doc.getLayerNames(); var hasFrame = false; for (var j = 0; j < layers.length; j++) { if (layers[j].toLowerCase() === "frame") { hasFrame = true; break; } } print(files[i] + ": " + (hasFrame ? "PASS" : "FAIL")); doc.close(); }执行:
./src/librecad -s check_frame.js *.dxf # 输出:part1.dxf: PASS, part2.dxf: FAIL注意:
Document类是 LibreCAD 暴露的 JS API,其getLayerNames()返回QStringList,在 JS 中自动转为数组。print()输出到终端,system.args是全局对象。
6.2 CI/CD 集成:在 GitLab CI 中验证 PR 提交的 DXF 合规性
将 LibreCAD 编译为静态链接二进制(避免环境依赖),放入 Docker 镜像,用于 CI 流水线:
# Dockerfile.ci FROM ubuntu:22.04 RUN apt-get update && apt-get install -y \ build-essential qtbase5-dev qttools5-dev-tools \ libfontconfig1-dev libfreetype6-dev && \ rm -rf /var/lib/apt/lists/* WORKDIR /app COPY LibreCAD /app/ # 预编译好的 LibreCAD(含静态 Qt) COPY check_frame.js /app/ CMD ["./librecad", "-s", "check_frame.js", "/workspace/*.dxf"]GitLab CI 配置(.gitlab-ci.yml):
stages: - validate validate-dxf: stage: validate image: my-registry/librecad-ci:latest script: - ./librecad -s check_frame.js $CI_PROJECT_DIR/drawings/*.dxf | tee report.txt artifacts: paths: - report.txt rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event"每次 MR 提交,自动检查drawings/目录下所有 DXF 是否含FRAME图层,失败则阻断合并。
6.3 自定义导出插件:用 C++ 实现“导出为 JSON 坐标数据”
LibreCAD 的插件机制允许你编写LC_ExportPlugin子类。以下是一个导出所有LINE实体端点坐标的插件(src/plugins/json_exporter/json_exporter.cpp):
#include "lc_exportplugin.h" #include "lc_entitycontainer.h" #include "lc_line.h" #include <QJsonArray> #include <QJsonObject> #include <QJsonDocument> class JsonExporter : public LC_ExportPlugin { public: JsonExporter() : LC_ExportPlugin("JSON Exporter", "json") {} bool exportToFile(const QString& filename, LC_EntityContainer* container) override { QJsonArray lines; for (auto e : *container) { LC_Line* line = dynamic_cast<LC_Line*>(e); if (line) { QJsonObject obj; obj["start"] = QJsonArray{line->getStartpoint().x(), line->getStartpoint().y()}; obj["end"] = QJsonArray{line->getEndpoint().x(), line->getEndpoint().y()}; lines.append(obj); } } QJsonDocument doc(lines); QFile file(filename); if (file.open(QIODevice::WriteOnly)) { file.write(doc.toJson()); file.close(); return true; } return false; } }; // 工厂函数,LibreCAD 通过此函数加载插件 extern "C" LC_ExportPlugin* createPlugin() { return new JsonExporter(); }编译为libjson_exporter.so,放入build/plugins/目录。启动 LibreCAD 后,“文件→导出”菜单即出现 “JSON Files (*.json)”。
从那以后我每次交付自动化图纸处理方案,都强制走一遍 LibreCAD 的命令行脚本验证流程——不是因为它完美,而是因为它的 C++ 内核足够透明:报错即定位到.cpp行号,崩溃即core dump可gdb,没有黑匣子。这种确定性,在工业场景里比“功能多”重要十倍。希望帮到你。
本文还有配套的精品资源,点击获取