CAD实体对象智能识别
CAD实体对象智能识别
概述
实体对象智能识别能够在CAD图纸中智能识别和匹配相似的实体对象。该系统采用模式匹配算法,支持几何变换(缩放、旋转),并提供了丰富的配置选项和可视化界面。
系统提供两种主要的识别方式:
1. 块参照实体识别
针对CAD图纸中以块(Block)形式存在的对象,系统能够:
- 批量获取所有块参照:自动检索图纸中的所有块参照实体,支持从元数据或表达式查询获取
- 块信息管理:显示块名称、对象ID、图层名称、边界范围、位置坐标、旋转角度、缩放比例等详细信息
- 可视化展示:通过动画线框和高亮显示所有块的位置和边界
- 交互式操作:支持点击表格行定位到对应块,支持显示/隐藏所有块的可视化效果
- 悬浮提示:鼠标悬停时显示块的详细属性信息,包括属性数据
2. 智能对象识别
针对不是块形式的普通CAD实体对象,系统提供:
- 模式匹配识别:基于用户选择的参考实体,在图纸中智能匹配相似的对象
- 几何变换支持:支持缩放、旋转等几何变换的容差匹配
- 多条件筛选:支持颜色、图层、文本内容等多种匹配条件
- 配置化管理:支持保存和加载识别配置,提高识别效率
核心功能特性
1. 智能实体选择
- 多种选择模式:支持框选、点选、多边形选择三种实体选择方式
- 实时预览:选择后立即显示所选实体数量
- 边界计算:自动计算所选实体的边界范围
2. 几何变换支持
- 缩放变换:支持设置缩放比例范围(0.1-10倍)
- 旋转变换:支持设置旋转角度范围(0-360度)
- 变换容差:可配置变换匹配的容差值
3. 匹配条件配置
- 颜色匹配:可设置是否要求实体颜色相同
- 图层匹配:可设置是否要求实体在同一图层
- 文本内容匹配:可设置文本类实体是否要求内容相同
- 自定义匹配规则:支持针对不同实体类型配置匹配属性
4. 配置管理系统
- 配置保存:支持将识别配置保存到服务器
- 配置加载:支持从服务器加载已保存的配置
- 配置覆盖:支持覆盖同名配置
- 配置删除:支持删除不需要的配置
5. 缩略图生成
- 自动生成:选择实体后自动生成120x80像素的缩略图
- 配置关联:缩略图与配置一起保存,便于快速识别
- 实时更新:选择实体变化时自动更新缩略图
使用场景
1. 块参照实体管理
- 块实体统计:快速统计图纸中所有块参照的数量和类型分布
- 块位置定位:通过表格快速定位到指定块的位置,便于查看和编辑
- 块属性查看:查看块的详细属性信息,包括位置、旋转角度、缩放比例等
- 块重复性分析:识别相同块名的多个实例,分析设计重复性
2. CAD图纸标准化检查
- 检查图纸中相似元素的一致性
- 发现不规范的设计元素
3. 重复元素检测
- 识别图纸中的重复设计
- 优化图纸存储和传输
4. 设计模式分析
- 分析图纸中的设计模式
- 提取可复用的设计元素
5. 智能对象匹配
- 基于参考实体智能匹配相似对象
- 支持几何变换的模糊匹配
- 提高CAD图纸处理的自动化程度
技术实现架构
1. 核心数据结构
模式配置数据
let patternConfig: any = {"name": "","sameColor": true,"sameLayer": false,"global": {"match": {"all": {"equalMatchProperty": ["color"]},"AcDbCircle": {"scaleMatchProperty": ["radius"]},"AcDbArc": {"scaleMatchProperty": ["radius"]},"AcDbLine": {"scaleMatchProperty": ["length"]},"AcDbText": {"scaleMatchProperty": ["height"]}}},"rules": [{"tolerance": 0.00001,"translateTolerance": 0.015,"transform": {"scale": {"min": 0.5,"max": 2.0},"rotation": {"min": 0,"max": 360}},"referenceObjectIds": []}]
}
2. 关键算法实现
块参照实体检索算法
const detectAllBlockRefsObjects = async () => {try {removeAntPathAnimateLine();let svc = map.getService();let metadata = await svc.metadata();let blockReferences = []if("blockReferences" in metadata) {// 从元数据中获取块参照信息(新版本)let blockRefs = metadata.blockReferences;if (blockRefs) {blockReferences = JSON.parse(blockRefs);}} else {// 通过表达式查询获取块参照信息(旧版本兼容)if (map.logInfo) map.logInfo("正在获取所有块数据,请稍候...", "success", 2000);let query = await svc.exprQueryFeature({expr: `gOutReturn := if((gInFeatureType == 'AcDbBlockReference'), 1, 0);`,fields: "", // 查询所有字段geom: false, // 内存模式useCache: true,limit: 1000000 // 查找所有块参照});if (query.error) {ElMessage({type: 'error',message: query.error,});return;}blockReferences = query.result.map((r: any) => {return {objectId: r.objectid,blockName: r.blockname,layerName: r.layername,bounds: r.bounds,position: r.positon,...r};});}// 保存数据并创建可视化效果blockRefsData.value = blockReferences;let data = getData();createAntPathAnimateLine(data);createHighlightBlocks(data);ElMessage({type: 'success',message: `共找到 ${blockReferences.length} 个块参照实体。`,});} catch (error) {showError("获取块参照实体失败:" + (error as any).message);}
}
块可视化高亮算法
const createHighlightBlocks = (data: any) => {let polygons = datalet polygon = new vjmap.Polygon({data: polygons,fillColor: ['case', ['to-boolean', ['feature-state', 'hover']], '#0ff', '#f00'],// 默认透明,鼠标悬停时显示高亮fillOpacity: ['case', ['to-boolean', ['feature-state', 'hover']], 0.1, 0.0],fillOutlineColor: ['get', 'color'],isHoverPointer: true,isHoverFeatureState: true});polygon.addTo(map);// 悬浮提示功能polygon.hoverPopup((f: any, popup: any) => {let bounds = vjmap.GeoBounds.fromDataExtent(f);popup.setLngLat([bounds.center().x, bounds.max.y]);return `<h3>块名称: ${f.properties.blockName}</h3>图层名称: ${f.properties.layerName}<br>对象ID: ${f.properties.objectId}${f.properties.attributeDef ? '<br>属性数据: ' + f.properties.attributeDef : ''}`}, { anchor: 'bottom' });polygonOverlay = polygon;
}
实体选择算法
const select = async () => {removeAntPathAnimateLine()let result = await selectFeatures(map, null, btnCtx, false)if (!result || !result.features) return;currentFeatures.value = result.featurespatternConfig.rules[patternConfig.rules.length - 1].referenceObjectIds = result.features// 选择后生成缩略图await generateThumbnail()
}
缩略图生成算法
const generateThumbnail = async () => {if (currentFeatures.value.length === 0) {thumbnailImage.value = ''return}try {isGeneratingThumbnail.value = true// 获取所有选中对象的边界let allBounds = nullfor (const feature of currentFeatures.value) {const bounds = vjmap.GeoBounds.fromString(feature.properties.bounds)if (!allBounds) {allBounds = bounds} else {allBounds.updateByBounds(bounds)}}if (allBounds) {// 生成 120x80 的缩略图let objectIds = currentFeatures.value.map((item: any) => item.properties.objectid)const base64Image = await getObjectsThumbnail(map, objectIds, allBounds, 120, 80)thumbnailImage.value = base64Image}} catch (error) {console.error('Generate thumbnail failed:', error)thumbnailImage.value = ''} finally {isGeneratingThumbnail.value = false}
}
智能识别算法
const detectAllObjects = async () => {try {if (!formData.value.keepLastResult) {removeAntPathAnimateLine();}if (currentFeatures.value.length == 0) {ElMessage({type: 'error',message: '请先选择要识别的实体',})return;}let svc = map.getService();ElMessage({type: 'success',message: '正在执行智能识别,请稍候...',})// 调用后端识别服务let res = await svc.execCommand("objectDetection", {mapid: svc.currentMapParam()?.mapid,version: svc.currentMapParam()?.version,layer: svc.currentMapParam()?.layer,pattern: JSON.stringify(patternConfig),detailedLog: formData.value.detailedLog,bounds: formData.value.bounds}, "_null", "v1");// 处理识别结果if (res && res.result && res.result.length > 0) {// 在地图上显示识别结果let geoDatas = [];for (let i = 0; i < res.result.length; i++) {const bounds = vjmap.GeoBounds.fromString(res.result[i].bounds)const pts = bounds.toPointArray();pts.push(pts[0])geoDatas.push({points: map.toLngLat(pts.map(p => vjmap.geoPoint(p))),properties: {color: "#ff0000"}})}// 创建动画线图层let antPathAnimateLine = vjmap.createAntPathAnimateLineLayer(map, geoDatas, {fillColor1: "#f00",fillColor2: formData.value.keepLastResult ? vjmap.randomColor() : "#0ff",canvasWidth: 128,canvasHeight: 32,frameCount: 4,lineWidth: 2,lineOpacity: 0.8});map._dectionAntPathAnimateLines = map._dectionAntPathAnimateLines || [];map._dectionAntPathAnimateLines.push(antPathAnimateLine);ElMessage({type: 'success',message: `共找到 ${geoDatas.length} 个匹配的对象。`,})}} catch (error) {showError("识别失败:" + (error as any).message);}
}
4. 配置管理实现
配置保存
const saveConfig = async () => {try {// 确保配置列表已加载,用于检查重复名称if (configList.value.length === 0) {await loadConfigList()}// 获取配置名称const name = await getInput('保存配置', '请输入配置名称', patternConfig.name || '')if (!name || typeof name !== 'string') {ElMessage.warning('配置名称不能为空')return}// 检查名称是否重复const exists = checkConfigExists(name)let shouldOverwrite = falseif (exists) {try {const action = await ElMessageBox.confirm(`配置名称 "${name}" 已存在,请选择操作`,'名称重复',{confirmButtonText: '覆盖',cancelButtonText: '新增',distinguishCancelAndClose: true,type: 'warning'})shouldOverwrite = truepatternConfig.name = name} catch (error: any) {if (error === 'cancel') {patternConfig.name = name} else {return}}} else {patternConfig.name = name}// 如果是覆盖操作,先删除旧配置if (shouldOverwrite) {const existingConfig = configList.value.find((c: any) => c.name === name)if (existingConfig) {const svc = map.getService()const deleteUrl = svc.serviceUrl(`recognizer/delete?filename=${existingConfig.filePrefix}`)await svc.httpDel(deleteUrl)}}// 添加缩略图到配置中if (thumbnailImage.value) {patternConfig.thumbnail = thumbnailImage.value}const svc = map.getService()const url = svc.serviceUrl("recognizer/add")const response = await svc.httpPost(url, patternConfig)const result = response.dataif (result.code === 0) {ElMessage.success(shouldOverwrite ? '配置覆盖成功' : '配置保存成功')await loadConfigList()} else {ElMessage.error('配置保存失败')}} catch (error) {console.error('Save config failed:', error)ElMessage.error('配置保存失败')}
}
配置加载
const selectConfig = async (config: any) => {try {selectedConfigId.value = config.filePrefix// 获取配置详细数据const svc = map.getService()const url = svc.serviceUrl(`recognizer/detail?filenames=${config.filePrefix}`)const response = await svc.httpGet(url)const result = response.dataif (result.code === 0 && result.data && result.data.length > 0) {const configData = result.data[0]// 加载配置数据patternConfig = configData// 同步表单数据if (configData.rules && configData.rules.length > 0) {const rule = configData.rules[0]if (rule.transform) {if (rule.transform.scale) {formData.value.allowScale = trueformData.value.scaleMin = rule.transform.scale.min || 0.5formData.value.scaleMax = rule.transform.scale.max || 2} else {formData.value.allowScale = false}if (rule.transform.rotation) {formData.value.allowRotation = trueformData.value.rotationMin = rule.transform.rotation.min || 0formData.value.rotationMax = rule.transform.rotation.max || 360} else {formData.value.allowRotation = false}}}// 同步其他配置项formData.value.sameColor = configData.sameColor || falseformData.value.sameLayer = configData.sameLayer || false// 更新缩略图if (configData.thumbnail) {thumbnailImage.value = configData.thumbnail} else {thumbnailImage.value = ''}currentFeatures.value = patternConfig.rules[patternConfig.rules.length - 1].referenceObjectIdsElMessage.success(`已加载配置: ${config.name}`)}} catch (error) {console.error('Load config failed:', error)ElMessage.error('选择配置失败')}
}
在线体验地址 https://vjmap.com/app/cloud/#/
相关文章:

CAD实体对象智能识别
CAD实体对象智能识别 概述 实体对象智能识别能够在CAD图纸中智能识别和匹配相似的实体对象。该系统采用模式匹配算法,支持几何变换(缩放、旋转),并提供了丰富的配置选项和可视化界面。 系统提供两种主要的识别方式:…...
MySQL中的部分问题(2)
索引失效 运算或函数影响列的使用 当查询条件中对索引列用了函数或运算,索引会失效。 例:假设有索引:index idx_name (name) select * from users where upper(name) ALICE; -- 索引失效因为upper(name)会对列内容进行函数处理…...
【从前端到后端导入excel文件实现批量导入-笔记模仿芋道源码的《系统管理-用户管理-导入-批量导入》】
批量导入预约数据-笔记 前端场馆列表后端 前端 场馆列表 该列表进入出现的是这样的,这儿是列表操作 <el-table-column label"操作" align"center" width"220px"><template #default"scope"><el-buttonlinktype"…...

LabVIEW音频测试分析
LabVIEW通过读取指定WAV 文件,实现对音频信号的播放、多维度测量分析功能,为音频设备研发、声学研究及质量检测提供专业工具支持。 主要功能 文件读取与播放:支持持续读取示例数据文件夹内的 WAV 文件,可实时播放音频以监听被测信…...
MySQL 8.0 绿色版安装和配置过程
MySQL作为云计算时代,被广泛使用的一款数据库,他的安装方式有很多种,有yum安装、rpm安装、二进制文件安装,当然也有本文提到的绿色版安装,因绿色版与系统无关,且可快速复制生成,具有较强的优势。…...

RoseMirrorHA 双机热备全解析
在数字化时代,企业核心业务系统一旦瘫痪,每分钟可能造成数万甚至数十万的损失。想象一下,如果银行的交易系统突然中断,或者医院的挂号系统无法访问,会引发怎样的连锁反应?为了守护这些关键业务,…...

day 18进行聚类,进而推断出每个簇的实际含义
浙大疏锦行 对聚类的结果根据具体的特征进行解释,进而推断出每个簇的实际含义 两种思路: 你最开始聚类的时候,就选择了你想最后用来确定簇含义的特征, 最开始用全部特征来聚类,把其余特征作为 x,聚类得到…...
pandas 字符串存储技术演进:从 object 到 PyArrow 的十年历程
文章目录 1. 引言2. 阶段1:原始时代(pandas 1.0前)3. 阶段2:Python-backed StringDtype(pandas 1.0 - 1.3)4. 阶段3:PyArrow初次尝试(pandas 1.3 - 2.1)5. 阶段4…...

LLMs 系列科普文(6)
截止到目前,我们从模型预训练阶段的数据准备讲起,谈到了 Tokenizer、模型的结构、模型的训练,基础模型、预训练阶段、后训练阶段等,这里存在大量的术语或名词,也有一些奇奇怪怪或者说是看起来乱七八糟的内容。这期间跳…...
exp1_code
#include <iostream> using namespace std; // 链栈节点结构 struct StackNode { int data; StackNode* next; StackNode(int val) : data(val), next(nullptr) {} }; // 顺序栈实现 class SeqStack { private: int* data; int top; int capac…...

serv00 ssh登录保活脚本-邮件通知版
适用于自己有服务器情况,ssh定时登录到serv00,并在登录成功后发送邮件通知 msmtp 和 mutt安装 需要安装msmtp 和 mutt这两个邮件客户端并配置,参考如下文章前几步是讲配置这俩客户端的,很简单,不再赘述 用Shell脚本实…...

意识上传伦理前夜:我们是否在创造数字奴隶?
当韩国财阀将“数字永生”标价1亿美元准入权时,联合国预警的“神经种姓制度”正从科幻步入现实。某脑机接口公司用户协议中“上传意识衍生算法归公司所有”的隐藏条款,恰似德里达预言的当代印证:“当意识沦为可交易数据流,主体性便…...

【AIGC】RAGAS评估原理及实践
【AIGC】RAGAS评估原理及实践 (1)准备评估数据集(2)开始评估2.1 加载数据集2.2 评估忠实性2.3 评估答案相关性2.4 上下文精度2.5 上下文召回率2.6 计算上下文实体召回率 RAGas(RAG Assessment)RAG 评估的缩写ÿ…...

ESP12E/F 参数对比
模式GPIO0GPIO2GPIO15描述正常启动高高低从闪存运行固件闪光模式低高低启用固件刷写 PinNameFunction1RSTReset (Active Low)2ADC (A0)Analog Input (0–1V)3EN (CH_PD)Chip Enable (Pull High for Normal Operation)4GPIO16Wake from Deep Sleep, General Purpose I/O5GPIO14S…...

第二十八章 字符串与数字
第二十八章 字符串与数字 计算机程序完全就是和数据打交道。很多编程问题需要使用字符串和数字这种更小的数据来解决。 参数扩展 第七章,已经接触过参数扩展,但未进行详细说明,大多数参数扩展并不用于命令行,而是出现在脚本文件中。 如果没有什么特殊原因,把参数扩展放…...

[RDK X5] MJPG编解码开发实战:从官方API到OpenWanderary库的C++/Python实现
业余时间一直在基于RDK X5搞一些小研究,需要基于高分辨率图像检测目标。实际落地时,在图像采集上遇到了个大坑。首先,考虑到可行性,我挑选了一个性价比最高的百元内摄像头,已确定可以在X5上使用,接下来就开…...
java复习 05
我的天啊一天又要过去了,没事的还有时间!!! 不要焦虑不要焦虑,事实证明只要我认真地投入进去一切都还是来得及的,代码多实操多复盘,别叽叽喳喳胡思乱想多多思考,有迷茫前害怕后的功…...

aardio 简单网页自动化
WebView自动化,以前每次重复做网页登录、搜索这些操作时都觉得好麻烦,现在终于能让程序替我干活了,赶紧记录下这个超实用的技能! 一、初次接触WebView WebView自动化就像给程序装了个"网页浏览器",第一步得…...

打卡第39天:Dataset 和 Dataloader类
知识点回顾: 1.Dataset类的__getitem__和__len__方法(本质是python的特殊方法) 2.Dataloader类 3.minist手写数据集的了解 作业:了解下cifar数据集,尝试获取其中一张图片 import torch import torch.nn as nn import…...
【评测】Qwen3-Embedding模型初体验
每一篇文章前后都增加返回目录 回到目录 【评测】Qwen3-Embedding模型初体验 模型的介绍页面 本机配置:八代i5-8265U,16G内存,无GPU核显运行,win10操作系统 ollama可以通过下面命令拉取模型: ollama pull modelscope…...
BeanFactory 和 FactoryBean 有何区别与联系?
导语: Spring 是后端面试中的“常青树”,而 BeanFactory 与 FactoryBean 的关系更是高频卡人点。很多候选人混淆两者概念,答非所问,轻则失分,重则直接被“pass”。本文将从面试官视角,深入剖析这一经典问题…...

如何做好一份优秀的技术文档:专业指南与最佳实践
如何做好一份优秀的技术文档:专业指南与最佳实践 技术文档是产品开发、用户支持和团队协作的核心工具。高质量的技术文档能够提升开发效率、降低维护成本并改善用户体验。本文将从实践出发,详细讲解如何编写专业、清晰且实用的技术文档。 🌟…...
C语言内存管理和编译优化实战
参考: C语言内存管理“玄学”:从崩溃到精通的避坑指南C语言编译优化实战:从入门到进阶的高效代码优化技巧...

TCP相关问题 第一篇
TCP相关问题1 1.TCP主动断开连接方为什么需要等待2MSL 如上图所示:在被动链接方调用close,发送FIN时进入LAST_ACK状态,但未收到主动连接方的ack确认,需要被动连接方重新发送一个FIN,而为什么是2MSL,一般认为丢失ack在…...

6.Pandas 数据可视化图-1
第三章 数据可视化 文章目录 目录 第三章 数据可视化 文章目录 前言 一、数据可视化 二、使用步骤 1.pyplot 1.1引入库 1.2 设置汉字字体 1.3 数据准备 1.4 设置索引列 编辑 1.5 调用绘图函数 2.使用seaborn绘图 2.1 安装导入seaborn 2.2 设置背景风格 2.3 调用绘图方法 2.…...

软件功能测试报告都包含哪些内容?
软件功能测试报告是软件开发生命周期中的重要文档,主要涵盖以下关键内容: 1.测试概况:概述测试目标、范围和方法,确保读者对测试背景有清晰了解。 2.测试环境:详细描述测试所用的硬件、软件环境,确保…...

在Vue或React项目中使用Tailwind CSS实现暗黑模式切换:从系统适配到手动控制
在现代Web开发中,暗黑模式(Dark Mode)已成为提升用户体验的重要功能。本文将带你使用Tailwind CSS在React项目(Vue项目类似)中实现两种暗黑模式控制方式: 系统自动适配 - 根据用户设备偏好自动切换手动切换 - 通过按钮让用户自由选择 一、项目准备 使…...

Linux--命令行参数和环境变量
1.命令行参数 Linux 命令行参数基础 1.1参数格式 位置参数:无符号,按顺序传递(如 ls /home/user 中 /home/user 是位置参数) 选项参数: 短选项:以 - 开头,单个字母(如 -l 表示长格…...
Android 集成 Firebase 指南
Firebase 是 Google 提供的一套移动开发平台,包含分析、认证、数据库、消息推送等多种服务。以下是在 Android 应用中集成 Firebase 的详细步骤: 1. 准备工作 安装 Android Studio - 确保使用最新版本 创建或打开 Android 项目 - 项目需要配置正确的包…...

springboot线上教学平台
摘要:在社会快速发展的影响下,使线上教学平台的管理和运营比过去十年更加理性化。依照这一现实为基础,设计一个快捷而又方便的网上线上教学平台系统是一项十分重要并且有价值的事情。对于传统的线上教学平台控制模型来说,网上线上…...