PDF文档中表格以及形状解析-后续处理(长线段根据交点打断成短线段)

问题描述
给定n条线段,要求根据它们的交点将线段打断,生成新的线段集合。
定义结构:
代码如下:

typedef struct tagStruVertex
{
    double x;
    double y;
    tagStruVertex(double x = 0, double y = 0) : x(x), y(y) {}
    // 重载运算符,用于排序和去重
    bool operator<(const tagStruVertex& other) const {
        if (x != other.x) return x < other.x;
        return y < other.y;
    }
    bool operator==(const tagStruVertex& other) const 
    {
        return fabs(x - other.x) < 1e-9 && fabs(y - other.y) < 1e-9;
    }
    bool operator!=(const tagStruVertex& other) const {
        if (x != other.x || y != other.y) 
            return true;
        return false;
    }
    double distanceTo(
const tagStruVertex& point) const
    {
        double disX = x - point.x;
        double disY = y - point.y;
        return sqrt(disX * disX + disY * disY);
    }
}Vertex;
typedef struct tagStruSegment
{
    Vertex start, end;
    tagStruSegment(Vertex p1, Vertex p2) : start(p1), end(p2) {}
    tagStruSegment() {}
    // 重载运算符,用于 set 去重
    bool operator<(const tagStruSegment& other) const {
        if (start == other.start) return end < other.end;
        return start < other.start;
    }
    bool operator==(const tagStruSegment& other) const {
        if ((start == other.start && end == other.end) || (start == other.end && end == other.start))
            return true;
        else
            return false;
    }
}Segment;

判断交点
使用线段相交的几何算法来检测两条线段是否相交。计算交点坐标,如果相交,则返回交点。
代码如下:

// 计算叉积
double cross(const Vertex& o, const Vertex& a, const Vertex& b) {
    return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
}

//判断点是否在线段上
bool IsPointOnSegment(const Vertex& p, const Segment& seg) {
    double crossProd = cross(seg.start, seg.end, p);
    if (fabs(crossProd) > 1e-9) return false; // 不在直线上
    double minX = min(seg.start.x, seg.end.x);
    double maxX = max(seg.start.x, seg.end.x);
    double minY = min(seg.start.y, seg.end.y);
    double maxY = max(seg.start.y, seg.end.y);
    return (p.x >= minX - 1e-9 && p.x <= maxX + 1e-9) &&
(p.y >= minY - 1e-9 && p.y <= maxY + 1e-9);
}

//判断两条线段是否相交:
bool IsCross(const Segment& seg1, const Segment& seg2, Vertex& intersect) {
    Vertex a = seg1.start, b = seg1.end;
    Vertex c = seg2.start, d = seg2.end;

    double cross1 = cross(a, b, c);
    double cross2 = cross(a, b, d);
    double cross3 = cross(c, d, a);
    double cross4 = cross(c, d, b);

    // 判断是否相交
    if (((cross1 * cross2) < 0) && ((cross3 * cross4) < 0)) {
        // 计算交点
        double t = cross3 / (cross3 - cross4);
        intersect.x = a.x + t * (b.x - a.x);
        intersect.y = a.y + t * (b.y - a.y);
        return true;
    }

    // 处理共线情况
    if (fabs(cross1) < 1e-9 && IsPointOnSegment(c, seg1)) { intersect = c; return true; }
    if (fabs(cross2) < 1e-9 && IsPointOnSegment(d, seg1)) { intersect = d; return true; }
    if (fabs(cross3) < 1e-9 && IsPointOnSegment(a, seg2)) { intersect = a; return true; }
    if (fabs(cross4) < 1e-9 && IsPointOnSegment(b, seg2)) { intersect = b; return true; }

    return false;
}

线段根据交点打断后生成新的线段
代码如下:

// 打断线段
vector<Segment> AdjustSegment(const Segment& seg, const set<Vertex>& intersections) {
    vector<Segment> vecSegments;
    vector<Vertex> points;
    // 将起点和终点加入
    points.push_back(seg.start);
    for (const auto& p : intersections) {
        if (IsPointOnSegment(p, seg)) {
            points.push_back(p);
        }
    }
    points.push_back(seg.end);
    // 按x坐标排序(或按y坐标,取决于线段方向)
    sort(points.begin(), points.end());
    // 生成小线段
    for (size_t i = 1; i < points.size(); ++i) {
        vecSegments.push_back(Segment(points[i - 1], points[i]));
    }
    return vecSegments;
}

vector<Segment> AdjustSegments(const vector<Segment>& segments) {
    vector<Segment> vecSegments;
    for (size_t i = 0; i < segments.size(); ++i) {
        set<Vertex> intersections;
        // 查找当前线段与其他线段的交点
        for (size_t j = 0; j < segments.size(); ++j) {
            if (i == j) continue;
            Vertex intersect;
            if (IsCross(segments[i], segments[j], intersect)) {
                intersections.insert(intersect);
            }
        }
        // 打断当前线段
        vector<Segment> lines = AdjustSegment(segments[i], intersections);
        vecSegments.insert(vecSegments.end(), lines.begin(), lines.end());
    }
    // 使用 set 去重
    set<Segment> uniqueSegments(vecSegments.begin(), vecSegments.end());
    return vector<Segment>(uniqueSegments.begin(), uniqueSegments.end());
}

调用测试
代码如下:

vector<Segment> segments = {
    Segment(Vertex(0, 0), Vertex(30, 0)),
    Segment(Vertex(0, 10), Vertex(30, 10)),
    Segment(Vertex(0, 20), Vertex(30, 20)),
    Segment(Vertex(0, 30), Vertex(30, 30)),
    Segment(Vertex(0, 0), Vertex(0, 30)),
    Segment(Vertex(10, 0), Vertex(10, 30)),
    Segment(Vertex(20, 0), Vertex(20, 30)),
    Segment(Vertex(30, 0), Vertex(30, 30))
};
vector<Segment> vecSegments = AdjustSegments(segments);
//过滤掉长度为0的线段
for (auto it = vecSegments.begin(); it != vecSegments.end(); ) {
    if (it->start.distanceTo(it->end) == 0)
    
        it = vecSegments.erase(it);  // 如果匹配,删除元素并更新迭代器
    
    else 
        ++it;  // 如果不匹配,继续遍历
    
}
//处理完成最终vecSegments里边的结果即为打断后的所有小线段

处理完得到小线段的数量为24条小线段。结果与预期一致。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WSL + 4050 部署 Deepseek-7B 蒸馏模型

操作环境&#xff1a;WSL - Oracle Linux RTX 4050 Laptop edition 渣渣笔记本实在是跑不了更大模型了&#x1f602; 整体架构 WSL 配置显卡加速环境 总体流程 安装教程&#xff1a;https://zhuanlan.zhihu.com/p/681092042 总体流程&#xff1a; 优化 WSL 系统配置&#x…

C++入门——输入输出、缺省参数

C入门——输入输出、缺省参数 一、C标准库——命名空间 std C标准库std是一个命名空间&#xff0c;全称为"standard"&#xff0c;其中包括标准模板库&#xff08;STL&#xff09;&#xff0c;输入输出系统&#xff0c;文件系统库&#xff0c;智能指针与内存管理&am…

简单的二元语言模型bigram实现

内容总结归纳自视频&#xff1a;【珍藏】从头开始用代码构建GPT - 大神Andrej Karpathy 的“神经网络从Zero到Hero 系列”之七_哔哩哔哩_bilibili 项目&#xff1a;https://github.com/karpathy/ng-video-lecture Bigram模型是基于当前Token预测下一个Token的模型。例如&#x…

用Deepseek写一个五子棋微信小程序

在当今快节奏的生活中&#xff0c;休闲小游戏成为了许多人放松心情的好选择。五子棋作为一款经典的策略游戏&#xff0c;不仅规则简单&#xff0c;还能锻炼思维。最近&#xff0c;我借助 DeepSeek 的帮助&#xff0c;开发了一款五子棋微信小程序。在这篇文章中&#xff0c;我将…

【Raspberry Pi 5 测评】无显示器上手指南

【Raspberry Pi 5 测评】无显示器上手指南 一、硬件开箱二、系统安装2.1 安装 Raspberry Pi Imager2.2 安装 Rasberry Pi OS 三、系统登录3.1 ping测试3.2 SSH登录 四、远程桌面4.1 启用VNC服务4.2 使用VNC客户端 五、软件安装5.1 替换软件源5.2 安装常用软件 六、参考链接 摘要…

图像标注与OCR工具分析

图像标注和OCR&#xff08;光学字符识别&#xff09;工具的代码进行详细分析。该工具允许用户在图像上进行矩形标注&#xff0c;使用 OCR 对标注区域进行文本识别&#xff0c;并将结果保存为 Excel 文件。同时&#xff0c;用户可以保存和加载标注&#xff0c;清除标注&#xff…

使用Node.js从零搭建DeepSeek本地部署(Express框架、Ollama)

目录 1.安装Node.js和npm2.初始化项目3.安装Ollama4.下载DeepSeek模型5.创建Node.js服务器6.运行服务器7.Web UI对话-Chrome插件-Page Assist 1.安装Node.js和npm 首先确保我们机器上已经安装了Node.js和npm。如果未安装&#xff0c;可以通过以下链接下载并安装适合我们操作系…

基于粒子群算法的配电网重构

一、配电网重构原理 定义&#xff1a; 配电网重构是指在满足运行约束的前提下&#xff0c;通过改变开关状态优化配电网性能&#xff0c;提高系统的经济效益和运行效率。 拓扑约束&#xff1a; 配电网必须保持径向拓扑&#xff0c;避免环网或孤岛。采用算法控制开关状态的选择&…

下载Hugging Face模型的几种方式

1.网页下载 直接访问Hugging Face模型页面&#xff0c;点击“File and versions”选项卡&#xff0c;选择所需的文件进行下载。 2.使用huggingface-cli 首先&#xff0c;安装huggingface_hub: pip install huggingface_hub 然后&#xff0c;使用以下命令下载模型&#xff1…

【Dubbo+Zookeeper】——SpringBoot+Dubbo+Zookeeper知识整合

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

DeepSeek R1 学习笔记

DeepSeek为了方便大众的使用&#xff0c;同时提供了6个蒸馏版本 DeekSeek使用方式 1.大众方式&#xff1a; 网页版&#xff1a;DeepSeek App版&#xff1a;手机各大应用商店下载安装DeepSeek-AI智能对话助手 2.专业用户 开发者&#xff1a;调用API DeepSeek服务器 网址&a…

《从零构建企业级容器镜像生态:Harbor与Registry双星架构实战手记》

目录 一、企业级镜像中枢&#xff1a;Harbor架构深度解析 1.Harbor介绍 环境准备 2. Harbor战略部署 下载安装Harbor 关键配置文件 报错一 添加本地解析 登录测试Harbor 报错二 登录成功 测试 成功显示 二、轻量化镜像驿站&#xff1a;Registry闪电战部署 简单介…

FPGA之USB通信实战:基于FX2芯片的Slave FIFO回环测试详解

FPGA之Usb数据传输 Usb 通信 你也许会有疑问&#xff0c;明明有这么多通信方式和数据传输&#xff08;SPI、I2C、UART、以太网&#xff09;为什么偏偏使用USB呢? 原因有很多&#xff0c;如下&#xff1a; 1. 高速数据传输能力 高带宽&#xff1a;USB接口提供了较高的数据传…

mysql中in和exists的区别?

大家好&#xff0c;我是锋哥。今天分享关于【mysql中in和exists的区别?】面试题。希望对大家有帮助&#xff1b; mysql中in和exists的区别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中&#xff0c;IN 和 EXISTS 都用于进行子查询&#xff0c;但它…

Unity摄像机跟随物体

功能描述 实现摄像机跟随物体&#xff0c;并使物体始终保持在画面中心位置。 实现步骤 创建脚本&#xff1a;在Unity中创建一个新的C#脚本&#xff0c;命名为CameraFollow。 代码如下&#xff1a; using UnityEngine;public class CameraFollow : MonoBehaviour {public Tran…

springcloud sentinel教程

‌QPS&#xff08;Queries Per Second&#xff09;即每秒查询率 TPS&#xff0c;每秒处理的事务数目 PV&#xff08;page view&#xff09;即页面浏览量 UV 访问数&#xff08;Unique Visitor&#xff09;指独立访客访问数 一、初识Sentinel 什么是雪崩问题? 微服务之间相…

【Tools】Windows下Git 2.48安装教程详解

00. 目录 文章目录 00. 目录01. Git简介02. Git参考资料03. Git安装04. Git测试05. 附录 01. Git简介 Git(读音为/gɪt/。)是一个开源的分布式版本控制系统&#xff0c;可以有效、高速的处理从很小到非常大的项目版本管理。 [1] Git 是 Linus Torvalds 为了帮助管理 Linux 内核…

【Linux系统编程】初识系统编程

目录 一、什么是系统编程1. 系统编程的定义2. 系统编程的特点3. 系统编程的应用领域4. 系统编程的核心概念5. 系统编程的工具和技术 二、操作系统四大基本功能1. 进程管理&#xff08;Process Management&#xff09;2. 内存管理&#xff08;Memory Management&#xff09;3. 文…

神经网络|(十四)|霍普菲尔德神经网络-Hebbian训练

【1】引言 前序学习进程中&#xff0c;除了对基本的神经网络知识进行了学习&#xff0c;还掌握了SOM神经网络原理&#xff0c;文章链接包括且不限于&#xff1a; 神经网络|(十一)|神经元和神经网络-CSDN博客 神经网络|(十二)|常见激活函数-CSDN博客 神经网络|(十三)|SOM神经…

Hive八股

Hive八股 说一下GC模型遇到过gc调优吗yarn有哪些了解讲讲hqI转化为MR源码hbase读写流程hive数据倾斜page cache和buffer的区别和相同近来你关注了大数据生态哪些领域的发展&#xff0c;比如新的feature&#xff0c;新的领域等 Hive1Hive1hive简介2hive架构3hive与Hadoop的关系4…