chili3d笔记23 正交投影3d重建笔记4 点到线2

从俯视图到主视图就这两条线有问题,比想象的效果好

原图

两条斜线变成了4条横线

经典少一根线

好了但是不知道为什么好了

import { Logger, PubSub } from "chili-core";
import DxfParser, { ILineEntity } from 'dxf-parser';
class Cluster {lines: [number, number, number, number][];min_x: number;max_x: number;min_y: number;max_y: number;constructor(lines: [number, number, number, number][] = []) {this.lines = [...lines];this.min_x = Infinity;this.max_x = -Infinity;this.min_y = Infinity;this.max_y = -Infinity;if (lines.length > 0) {this.updateBounds();}}updateBounds(): void {this.min_x = Math.min(...this.lines.flatMap(line => [line[0], line[2]]));this.max_x = Math.max(...this.lines.flatMap(line => [line[0], line[2]]));this.min_y = Math.min(...this.lines.flatMap(line => [line[1], line[3]]));this.max_y = Math.max(...this.lines.flatMap(line => [line[1], line[3]]));}get lengthX(): number {return parseFloat((this.max_x - this.min_x).toFixed(1));}get lengthY(): number {return parseFloat((this.max_y - this.min_y).toFixed(1));}
}
function clusterLines(lines: [number, number, number, number][], expandDistance: number = 5): Cluster[] {const clusters: Cluster[] = [];const remainingLines = [...lines];while (remainingLines.length > 0) {const seed = remainingLines.shift()!;const currentCluster = new Cluster([seed]);currentCluster.updateBounds();let changed = true;while (changed) {changed = false;const expandedMinX = currentCluster.min_x - expandDistance;const expandedMaxX = currentCluster.max_x + expandDistance;const expandedMinY = currentCluster.min_y - expandDistance;const expandedMaxY = currentCluster.max_y + expandDistance;const toAdd: [number, number, number, number][] = [];for (const line of [...remainingLines]) {const [x1, y1, x2, y2] = line;const inBound =(x1 >= expandedMinX && x1 <= expandedMaxX && y1 >= expandedMinY && y1 <= expandedMaxY) ||(x2 >= expandedMinX && x2 <= expandedMaxX && y2 >= expandedMinY && y2 <= expandedMaxY);if (inBound) {toAdd.push(line);changed = true;}}for (const line of toAdd) {currentCluster.lines.push(line);remainingLines.splice(remainingLines.indexOf(line), 1);}currentCluster.updateBounds();}// 合并完全覆盖的聚类for (let i = 0; i < clusters.length; i++) {const cluster = clusters[i];if (currentCluster.min_x <= cluster.min_x &&currentCluster.min_y <= cluster.min_y &&currentCluster.max_x >= cluster.max_x &&currentCluster.max_y >= cluster.max_y) {currentCluster.lines.push(...cluster.lines);clusters.splice(i, 1);break;}}clusters.push(currentCluster);}return clusters;
}
export function rebuild3D(document: Document) {const fileInput = document.createElement("input");fileInput.type = "file";fileInput.accept = ".dxf";fileInput.style.display = "none";fileInput.addEventListener("change", async (event) => {const target = event.target as HTMLInputElement;if (!target.files || target.files.length === 0) return;const file = target.files[0];Logger.info(`Selected file: ${file.name}`);try {const reader = new FileReader();reader.onload = () => {const dxfText = reader.result as string;const parser = new DxfParser();const dxf = parser.parseSync(dxfText);const inputlines: [number, number, number, number][] = [];if (dxf && dxf.entities) {dxf.entities.forEach(entity => {if (entity.type === 'LINE') {const lineEntity = entity as ILineEntity;const start = lineEntity.vertices[0];const end = lineEntity.vertices[1];if (start && end) {inputlines.push([start.x, start.y, end.x, end.y]);}}});}// 执行聚类const clusters = clusterLines(inputlines, 5);const lines3d:[number,number,number,number,number,number,number][]=[]const { mostMinX, mostMinY } = getMostFrequentMinXY(clusters);const mostFrequentClusters = clusters.filter(cluster => {return cluster.min_x === mostMinX.value && cluster.min_y === mostMinY.value;
});
const topclusters = clusters.filter(cluster => {return cluster.min_x === mostMinX.value && cluster.min_y > mostMinY.value;
});
;
const rightclusters = clusters.filter(cluster => {return cluster.min_x > mostMinX.value && cluster.min_y === mostMinY.value;
});
const bottomclusters = clusters.filter(cluster => {return cluster.min_x === mostMinX.value && cluster.min_y < mostMinY.value;
});
const leftclusters = clusters.filter(cluster => {return cluster.min_x < mostMinX.value && cluster.min_y === mostMinY.value;
});const mostFrequentCluster= mostFrequentClusters[0];const topcluauster= topclusters[0];const rightcluster= rightclusters[0];const bottomcluster= bottomclusters[0];const leftcluster= leftclusters[0];const seen = new Set<string>(); // 用于记录已经添加过的线段function addUniqueLine(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number,color:number) {const key = `${x1},${y1},${z1},${x2},${y2},${z2}`;if (!seen.has(key)) {seen.add(key);lines3d.push([x1, y1, z1, x2, y2, z2,color]);}
} 
const clusterMinY = topcluauster.min_y;// 构建点存在性查询的 Map
const pointToLinesMap = new Map<string, boolean>();
topcluauster.lines.forEach(([tx1, ty1, tx2, ty2]) => {pointToLinesMap.set(`${tx1},${ty1}`, true);pointToLinesMap.set(`${tx2},${ty2}`, true);
});// 判断某点是否存在于 topcluauster 中
function isPointInTopCluster(x: number, y: number): boolean {return pointToLinesMap.has(`${x},${y}`);
}// 主处理逻辑
for (const [x1, y1, x2, y2] of mostFrequentCluster.lines) {for (const [tx1, ty1, tx2, ty2] of topcluauster.lines) {// 判断 (x1, ty1) 和 (x2, ty2) 是否在 topcluauster 的线段中const p1Exists = isPointInTopCluster(x1, ty1);const p2Exists = isPointInTopCluster(x2, ty2);const offset1 = ty1 - clusterMinY;const offset2 = ty2 - clusterMinY;if (p1Exists && p2Exists) {if(x1==x2&&x1==tx1){addUniqueLine(x1, y1, offset1, x2, y2, offset1, 1);}else if(x1==x2&&x1==tx2){addUniqueLine(x1, y1, offset2, x2, y2, offset2, 1);}else if(x1==tx1&&x2==tx2){ addUniqueLine(x1, y1, offset1, x2, y2, offset2, 1);}}if (ty1 !== ty2 && (x1 === tx1 && tx1 === tx2 )) {addUniqueLine(x1, y1, offset1, x1, y1, offset2, 1);}if (ty1 !== ty2 && ( x2 === tx1 && tx1 === tx2)) {addUniqueLine(x2, y2, offset1, x2, y2, offset2, 1);}}
}
Logger.info(`lines3d completed with ${lines3d.length} lines3d`);lines3d.forEach(line => {PubSub.default.pub("njsgcs_makeline", line[0], line[1],  line[2], line[3], line[4], line[5],1); })///// let i =0;// // 发送每个线段给 njsgcs_makeline// clusters.forEach(cluster => {//     i++;//     cluster.lines.forEach(line => {//         const [x1, y1, x2, y2] = line;//         PubSub.default.pub("njsgcs_makeline", x1, y1, 0, x2, y2, 0,i); // z=0 假设为俯视图//     });// });///Logger.info(`Clustering completed with ${clusters.length} clusters`);};reader.readAsText(file);} catch (error) {Logger.error("Error reading file:", error);}});fileInput.click();
}
function getMostFrequentMinXY(clusters: Cluster[]) {const minXCounts: Record<number, number> = {};const minYCounts: Record<number, number> = {};let maxXCount = 0, mostX = clusters[0]?.min_x;let maxYCount = 0, mostY = clusters[0]?.min_y;for (const cluster of clusters) {const x = cluster.min_x;const y = cluster.min_y;minXCounts[x] = (minXCounts[x] || 0) + 1;if (minXCounts[x] > maxXCount) {maxXCount = minXCounts[x];mostX = x;}minYCounts[y] = (minYCounts[y] || 0) + 1;if (minYCounts[y] > maxYCount) {maxYCount = minYCounts[y];mostY = y;}}return {mostMinX: { value: mostX, count: maxXCount },mostMinY: { value: mostY, count: maxYCount }};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86518.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86518.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LDO的自放电功能

LDO&#xff08;低压差线性稳压器&#xff09;的自放电功能&#xff08;Discharge Function 或 Active Discharge&#xff09;是一种在关闭输出时主动释放输出端残留电荷的机制。以下是其关键点&#xff1a; 1. 自放电功能的作用 快速放电&#xff1a;当LDO被禁用&#xff08;如…

Ingress-Nginx简介和配置样例

Ingress-Nginx 是 Kubernetes 中一个基于 Nginx 的 Ingress 控制器&#xff0c;用于管理对集群内服务的 HTTP/HTTPS 访问。它是 Kubernetes Ingress 资源的实现之一&#xff0c;通过配置 Nginx 反向代理和负载均衡器&#xff0c;提供路由规则、SSL/TLS 终止、路径重写等高级功能…

Java+LangChain实战入门:深度剖析开发大语言模型应用!

在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;如GPT系列&#xff09;正改变着我们构建应用的方式。但如何将这些先进模型无缝集成到企业级Java应用中&#xff1f;这正是LangChain框架的强项——它简化了语言模型的调用、链式处理和上下文管理&#xff0c;让开发…

论文笔记:Large language model augmented narrative driven recommendations

RecSys 2023 代码&#xff1a;iesl/narrative-driven-rec-mint: Mint: A data augmentation method for narrative driven recommendation. 1 intro 尽管基于历史交互的数据能够有效地提供推荐&#xff0c;但用户在请求推荐时&#xff0c;往往只是对目标物品有一个模糊的概念…

兴达易控Modbus TCP转Profibus DP网关与安科瑞多功能电表的快速通讯

兴达易控Modbus TCP转Profibus DP网关与安科瑞多功能电表的快速通讯 在工业自动化领域&#xff0c;不同设备之间的通信连接至关重要。兴达易控Modbus TCP转Profibus DP网关接APM810/MCE安科瑞多功能电表与300plc通讯&#xff0c;这一过程涉及到多个关键技术和环节&#xff0c;…

epoll实现理解

根据前文高性能网络设计推演中&#xff0c;epoll作为一个“大杀器”为网络开发提供强大的支持。Linux系统上IO多路复用方案有select、poll、epoll。其中epoll的性能表现最优&#xff0c;且支持的并发量最大。本文大概介绍epoll的底层实现。 一、示例引入 了解epoll开发&#…

协议转换赋能光伏制造:DeviceNET转PROFINET网关的通信质检实践

协议转换赋能光伏制造&#xff1a;DeviceNET转PROFINET网关的通信质检实践 某光伏电池片生产线创新性地将网关作为计算节点&#xff0c;通过搭载DeviceNET-PROFINET智能网关-稳联技术WL-PN-DVNM&#xff0c;在协议转换层直接运行AI质检模型。DeviceNET端采集的高清图像数据经网…

学习永无止境

已掌握以下每个&#xff0c;有属于自己的一套架构方式&#xff1a; vue.element-ui&#xff1a;后台管理 vue.uni-app&#xff1a;H5&#xff0c;小程序&#xff0c;Android&#xff0c;IOS php&#xff1a;​​RESTful&#xff0c;服务&#xff0c;业务逻辑&#xff08;如电商…

永磁无刷电机旋转原理

目录 1. 磁场的基本知识 2. 角速度&#xff0c;线速度&#xff0c;工程转速 3.力和力矩 4. 惯量&#xff0c;转动惯量 5. 电机的四种状态 5.1 空载 5.2 带载 5.3 满载 5.4 堵转 6. 功和功率 1. 磁场的基本知识 无头无尾&#xff0c;转了一圈&#xff0c;就叫有旋…

Ubuntu 物理桌面远程访问教程(基于 RealVNC / mstsc)

Ubuntu 物理桌面远程访问教程&#xff08;基于 RealVNC / mstsc&#xff09; 适用对象&#xff1a;任意安装了 GNOME GDM 的 Ubuntu 系统 目标&#xff1a;远程连接系统默认物理桌面 :0&#xff0c;无虚拟桌面、无 Xfce&#xff0c;真实 GNOME 桌面环境 1. 准备条件 Ubuntu 系…

Vue3 工程化实战

Vue3 工程化实战 引言&#xff1a;构建工具的演进与选择 在前端工程化领域&#xff0c;构建工具的选择直接影响开发效率与项目性能。随着Vue3的普及&#xff0c;构建工具生态也发生了显著变化&#xff1a;传统vue-cli逐渐进入维护模式&#xff0c;而新一代构建工具Vite凭借其…

调用phantomjs(前端)插件生成ECharts图片

package com.demo.common.utils; //json格式化工具,可以其他工具类 import cn.hutool.json.JSONUtil; import lombok.extern. public class FileUtil { /** * 调用phantomjs(前端)插件生成ECharts图片 * @param path 根路径 * @param option ECharts配置J…

React Hooks详解

React Hooks 常考内容 React Hooks 是 React 16.8 引入的重要特性&#xff0c;用于在函数组件中使用状态和其他 React 特性。以下是面试中常考的核心内容&#xff1a; 基础 Hook useState: 用于管理组件内部状态&#xff0c;返回状态变量和更新状态的函数。useEffect: 处理副…

c++17标准std::filesystem常用函数

std::filesystem 是 C17 引入的标准库&#xff0c;用于处理文件系统操作&#xff0c;提供了跨平台的文件和目录操作能力。以下是一些常用的函数和类&#xff1a; 一、路径操作&#xff08;std::filesystem::path&#xff09; cpp 运行 #include <filesystem> namespa…

非结构化文档的自动化敏感标识方法技术解析

在数字化时代&#xff0c;企业与组织面临的数据形态正发生深刻变革。据统计&#xff0c;非结构化数据占企业数据总量的 80% 以上&#xff0c;涵盖文本、邮件、PDF、日志、社交媒体内容等多种形式。这些数据中往往蕴含着大量敏感信息&#xff0c;如个人身份信息、商业机密、医疗…

c语言中的字符类型

字符类型 char char是一种整数&#xff0c;也是一种特殊的类型&#xff1a;字符。 #include <stdio.h> int main(){char c,d;c 1; //把整数1赋值给变量cd 1; //把字符‘1’赋值给变量dif (c d){printf("相等");}else{printf("不相等\n");…

Cribl stream 管道对时间的改变时区

先说一下时区的重要性&#xff0c;要是cribl 时区是UTC&#xff0c;但是过来数据是GTM8 就是中国时区&#xff0c;那么数据过来&#xff0c;就可能在后端的Splunk 没有显示&#xff0c;那么解决这个问题&#xff0c;cribl 管道引入了auto timestamp 的功能&#xff1a; 注意到&…

深度学习:PyTorch卷积神经网络(1)

本文目录&#xff1a; 一、CNN概述二、CNN日常应用三、CNN的卷积层&#xff08;一 &#xff09;基本介绍&#xff08;二&#xff09;卷积层计算1.对输入数据的要求2.卷积核核心参数3.计算过程4.特征图尺寸计算5.1、多通道卷积计算5.2、多卷积核计算6.PyTorch卷积层API 前言&…

linux网络编程socket套接字

套接字概念 Socket本身有“插座”的意思&#xff0c;在Linux环境下&#xff0c;用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。 既然是文件&#xff0c;那么理所当然的&#xff0c;我们可以使用文件描述符引用套接字。与管道类似的&#xff0c;L…

Python 数据分析与可视化 Day 5 - 数据可视化入门(Matplotlib Seaborn)

&#x1f3af; 今日目标 掌握 Matplotlib 的基本绘图方法&#xff08;折线图、柱状图、饼图&#xff09;掌握 Seaborn 的高级绘图方法&#xff08;分类图、分布图、箱线图&#xff09;熟悉图像美化&#xff08;标题、标签、颜色、风格&#xff09;完成一组学生成绩数据的可视化…