简单2D几何求交点

news2025/7/13 0:52:38

2D图形SVG工具添加了通过选项属性显示交点的功能。

PaladinDu:2D图形SVG化工具0 赞同 · 0 评论文章

在这个工具中,已经定义的数据结构有点,线段,有向线段,射线,直线,多边形,和圆。

其中点不参与交点检测;

线段,有向线段,射线,直线本质都是线段;

多边形由多个线段组成;

所以求交点的问题被减少为:

1.线段与线段;2.圆与圆;3.线段与圆求交点的问题。

线段与线段求交点

两个线段之间的关系可以分为以下几种:

不相交,相交且交点为端点,一般相交,相交且平行

由于工具默认显示线段的端点,对于 相交且平行 和 相交且交点为端点 的情况不在添加交点。

这样就只需要处理完全相交的情况,问题变得简单了许多。

这里用到的算法也比较简单,代码与流程解析如下:

class LineSegment:
    def __init__(self,start:Position,end:Position):
        self.start = start
        self.end = end    

    def is_collision(self,other):  # 通过叉乘检测两个线段是否都满足端点在另一个线段的两侧
        self_dir = self.end.reduce(self.start)
        if self_dir.cross(other.start.reduce(self.start)) * self_dir.cross(other.end.reduce(self.start)) >=0:
            return False 
        other_dir = other.end.reduce(other.start)
        if other_dir.cross(self.start.reduce(other.start))*other_dir.cross(self.end.reduce(other.start)) >= 0:
            return False
        return True

def get_intersection_points_by_line_segments(line_segment1:LineSegment, line_segment2:LineSegment):
    if not line_segment1.check_aabb_by_other_obejct(line_segment2):  # aabb没有碰撞,直接返回
        return []
    if not line_segment1.is_collision(line_segment2):  # 通过叉乘检测线段是否为一般相交
        return []
    # 通过面积比例得出交点所在的位置
    line_segment2_dir = line_segment2.end.reduce(line_segment2.start)
    s1 = abs(line_segment2_dir .cross(line_segment1.start.reduce(line_segment2.start)))
    s2 = abs(line_segment2_dir .cross(line_segment1.end.reduce(line_segment2.end)))
    line_segment1_dir = line_segment1.end.reduce(line_segment1.start)
    return [line_segment1.start.add(line_segment1_dir .multiply(s1 / (s1 + s2)))]

圆与圆求交点

圆与圆之间的关系可以分为以下几种:

外侧不相交,包含不相交,包含一个点交点,包含圆心两个交点,外部一个交点,外部两个交点

不相交的情况可以通过两个圆心的距离与两个半径的和和差的大小比较过滤。

特殊的,对于重叠的圆,可以通过圆心相同排除。

对于一个交点的情况,可以直接通过两个圆的圆心向量信息得到交点:

需要注意的是,如果是内包的情况,选择较小的圆的圆心作为起始的需要将方向反转。

对于两个交点的情况使用了三角形三边求角度,然后旋转圆心向量的方式得到交点

两种情况的逻辑一致

代码与流程解析如下:

def get_intersection_points_by_circles(circle1:Circle,circle2:Circle):
    c1_to_c2_dir = circle2.center_pos.reduce(circle1.center_pos)
    center_pos_dif = c1_to_c2_dir.len()
    if center_pos_dif > circle2.r + circle1.r or center_pos_dif < abs(circle1.r-circle2.r):  # 内包或者距离过远了
        return []
    if center_pos_dif == 0:  # 圆心重叠了
        return []
    if center_pos_dif == circle2.r + circle1.r or center_pos_dif == abs(circle1.r-circle2.r):  # 只有一个交点的情况
        if center_pos_dif == abs(circle1.r-circle2.r) and circle1.r < circle2.r:  # 如果是内包且起始点为更小的圆,反向
            position = circle1.center_pos.reduce(c1_to_c2_dir.to_unit_dir().multiply(circle1.r))
        else:
            position = circle1.center_pos.add(c1_to_c2_dir.to_unit_dir().multiply(circle1.r))  # 通过圆心向量得到交点
        return [position]
    # 一般情况,通过边长求角度
    cos_value = (circle1.r**2+center_pos_dif**2-circle2.r**2)/(2*circle1.r*center_pos_dif)
    angle = math.acos(cos_value)/(2*math.pi)*360
    # 通过角度,转向得到两个交点的坐标
    r_dir = c1_to_c2_dir.to_unit_dir().multiply(circle1.r)
    return [circle1.center_pos.add(r_dir.rotate(angle)), circle1.center_pos.add(r_dir.rotate(-angle))]

圆与线段求交点

求圆与线段的交点可以转换为:

1.求圆与线段所在的直线的交点

2.判断线段所在的直线上的点是否在线段上

求圆与线段所在的直线的交点可以转换为:

1.直线过圆心O的垂直线与直线的交点A

2.判断点A到圆心O的距离H,如果大于半径R直接返回。

3.通过直角3三角形一个变的长度H与斜边的长度R求出点A到目标交点的距离l

其中直线可以等价为很长的线段

代码与流程解析如下:

def get_intersection_points_by_line_segment_and_circle(line_segment:LineSegment,circle:Circle):
    line_dir = line_segment.get_dir()
    len_square = line_dir.len()
    if len_square == 0:
        return []
    line_dir = line_dir.to_unit_dir()
    max_size = 10000
    line = LineSegment(line_segment.start.add(line_dir.multiply(max_size)),
                       line_segment.start.reduce(line_dir.multiply(max_size)))
    circle_line = LineSegment(circle.center_pos.add(line_dir.rotate(90).multiply(max_size)),
                       circle.center_pos.reduce(line_dir.rotate(90).multiply(max_size)))
    points = get_intersection_points_by_line_segments(line,circle_line)  # 求直线过圆心O的垂直线与直线的交点
    if len(points) == 0:  # 预防一下
        return []
    point_a = points[0]
    h = point_a.reduce(circle.center_pos).len()
    if h > circle.r:  # 太远了
        return []

    dif_len = (circle.r**2 - h**2)**0.5
    intersection_points = []
    if dif_len == 0:  # 圆与线段所在的直线相切
        intersection_points = [point_a]
    else:  
        unit_dir = line_dir.to_unit_dir()
        intersection_points = [point_a.add(unit_dir.multiply(dif_len)), point_a.reduce(unit_dir.multiply(dif_len))]
    ret = []
    for position in intersection_points:  # 过滤不在线段上的点
        if line_segment.line_position_in_line_segment(position):
            ret.append(position)
    return ret

工具实际使用下来还是比较麻烦的:

1.没法直观的调整图形的位置。

2.也没有添加文本的功能。

有待后续完善。

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

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

相关文章

【技巧】如何保护PDF文件不被随意修改?

做好的PDF文件&#xff0c;不想被他人随意修改&#xff0c;只要给PDF设置“限制保护”就可以了&#xff0c;设置保护后需要输入密码才能进行编辑。 设置“限制保护”我们需要用到PDF编辑器&#xff0c;以小编使用的编辑器为例&#xff0c;首先通过编辑器打开PDF文件后&#xf…

医学访问学者申请四点规划建议

医学领域一直以来都是人类社会的重要组成部分&#xff0c;而作为一名有志于成为一名医学领域的访问学者&#xff0c;您需要明确自己的目标并做好充分准备。知识人网小编将为您提供四点规划建议&#xff0c;以帮助您成功申请医学访问学者的机会。 第一点&#xff1a;明确研究方向…

input 的 placeholder 样式

::placeholder 伪元素 这个伪元素可以改变 input、textarea 占位文本的样式。 input::placeholder {color: green; }完整的兼容性写法&#xff1a; input {&::-webkit-input-placeholder, /* WebKit browsers*/ &:-moz-input-placeholder, /* Mozilla Firefox 4 to …

2个小时的腾讯面试经历(C++),来看看它终究考察了些什么?

今天分享一位同学实习面试鹅厂 c 岗的面试&#xff0c;全程都是问 C 和计算机基础&#xff08;系统、网络、算法&#xff09;的内容了。难度中规中矩吧&#xff0c;基本都是追问式的问法&#xff0c;一层一层往下问。 C相关 对面向对象的理解 C面向对象编程就是把一切事物都…

Kubernetes 部署应用(nginx)的两种方式,你更喜欢哪一种?

k8s发布应用的两种方式&#xff1a; kubernetes-dashboardkubectl命令行 一、Dashboard方式 配置部署&#xff1a;包含应用名称、容器镒、pod数量、Service非常的方便&#xff0c;不想设置配置yaml的可以很方便的部署。 点击部署就成功了k8s应用的部署了。部署后可以看到相应…

python爬虫经典案例(一)

爬虫&#xff08;Web Scraping&#xff09;是一种自动获取互联网信息的技术&#xff0c;广泛用于数据采集、分析和应用开发。无论你是数据科学家、市场营销专家还是应用程序开发者&#xff0c;都可以通过编写爬虫来获取所需的信息。在本文中&#xff0c;我们将介绍五个实用的爬…

从0开始实现简易版vue2

文章目录 前言原理思路分析实现Observer实现Watcher实现Compile 前言 Vue.js的双向绑定原理是其最重要的特性之一&#xff0c;它使得数据模型和DOM之间的同步变得非常简单和高效。 先上个成果图来吸引各位&#xff1a; new SimpleVue({el: #app,data: {title: SimpleVue,name…

re学习(37)DASCTF 2023_7 controlflow

IDA载入一下 发现flag的长度为40&#xff0c;然后将input[i]的值赋值给str[i]&#xff0c;str[i]又执行一个异或操作&#xff0c;但是上面又有一些函数&#xff0c;导致这个程序的控制流有点奇怪..... 输入40只&#xff0c;检验是否是flag。 F5直接罢工了&#xff0c;暂时先忽…

Java入坑之代理

一、代理模式和静态代理 1.1代理模式 代理模式 - Proxy Pattern, 23个经典模式的一种&#xff0c;又称委托模式 -为目标对象提供(包装)了一个代理&#xff0c;这个代理可以控制对目标对象的访问 外界不用直接访问目标对象&#xff0c;而是访问代理对象&#xff0c;由代理对象再…

软件外包开发bug管理工具

国内有一些常用的Bug管理工具&#xff0c;这些工具旨在帮助团队有效地发现、跟踪和解决软件开发中的缺陷和问题。以下是一些国内的Bug管理工具&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.禅道&…

在openSUSE上开启护眼模式

色温 色温是用来衡量光源色彩时所用到的一个概念&#xff0c;单位为开尔文。热黑体辐射体与光源温度相同时的温度&#xff0c;就是该光源的色温。 显而易见&#xff0c;色温越低时&#xff0c;光源看起来越黄&#xff1b;色温越高时&#xff0c;光源看起来越蓝。下面是一些常见…

【LangChain系列 9】Prompt模版——MessagePromptTemplate

原文地址&#xff1a;【LangChain系列 9】Prompt模版——MessagePromptTemplate 本文速读&#xff1a; MessagePromptTemplate MessagesPlaceholder 在对话模型(chat model) 中&#xff0c; prompt主要是封装在Message中&#xff0c;LangChain提供了一些MessagePromptTemplat…

入门必读:Python try except异常处理详解

Python 中&#xff0c;用try except语句块捕获并处理异常&#xff0c;其基本语法结构如下所示&#xff1a; try: 可能产生异常的代码块 except [ (Error1, Error2, ... ) [as e] ]: 处理异常的代码块1 except [ (Error3, Error4, ... ) [as e] ]: 处理异常的代码块…

CSAPP Bomb Lab

CSAPP Bomb Lab 芜湖&#xff0c;完成实验来记录一下啦~ 这个lab看的我真是眼皮发麻&#xff0c;框框就是反汇编->c语言形式->优化c语言 最后我才能写出来&#xff0c;整的我睡觉都是 mov… lea… 难道适中&#xff0c;感觉只要耐心一点就没问题&#xff0c;好了现在开…

【鸿蒙(HarmonyOS)】List列表、ArkUI资源组数据类型

一、引言 描述&#xff1a;List列表在移动端设备中最为常见。比如&#xff1a;通讯录、短信、聊天软件等都&#xff0c;都拥有他的身影。难度&#xff1a;简单知识点&#xff1a;1、列表组件的使用2、认识ArkUI资源组数据类型 二、列表List 1、发现问题&#xff08;Bug&…

2023-9-14 石子合并

题目链接&#xff1a;石子合并 #include <iostream> #include <algorithm>using namespace std;const int N 310, INF 1e9;int n; // 前缀和 int s[N]; int f[N][N];int main() {cin >> n;for(int i 1; i < n; i ) cin >> s[i];for(int i 1; i …

模式分类与“组件协作模式”

1. GOF-23 模式分类 从目的来看&#xff1a; 创建型&#xff08;Creational&#xff09;模式&#xff1a;将对象的部分创建工作延迟到子类或者其他对象&#xff0c;从而应对需求变化为对象创建时具体类型实现引来的冲击。结构型&#xff08;Structural&#xff09;模式&#…

CS5366 typec转HDMI 4k60拓展坞方案芯片,带PD快充功能

CS5366是一个高性能的USB类型-c/显示端口到HDMI2.0转换器方案芯片&#xff0c;CS5366集成了一个DP1.4兼容的接收器&#xff0c;一个HDMI2.0兼容的发射器。此外&#xff0c;还包括两个CC控 制器&#xff0c;用于CC通信&#xff0c;以实现DP Alt模式和电源传输功能&#xff0c;一…

[设计模式] 浅谈SOLID设计原则

目录 单一职责原则开闭原则里氏替换原则接口隔离原则依赖倒转原则 SOLID是一个缩写词&#xff0c;代表以下五种设计原则 单一职责原则 Single Responsibility Principle, SRP开闭原则 Open-Closed Principle, OCP里氏替换原则 Liskov Substitution Principle, LSP接口隔离原则 …

怎样做一个简易而温馨的原木风居室空间

由 balbek bureau 设计的 Relogged 是一座重新设计的私人住宅&#xff0c;位于乌克兰河岸的绿化区。顾名思义&#xff0c;该项目重新诠释了木屋的概念&#xff0c;并与充满自然气息的环境相呼应&#xff0c;营造出宁静舒适的生活氛围。在探索重新设计的木屋实例时&#xff0c;建…