python之二维几何学习笔记

news2025/1/18 14:37:21

一、概要

资料来源《机械工程师Python编程:入门、实战与进阶》安琪儿·索拉·奥尔巴塞塔 2024年6月

  • 点和向量:向量的缩放、范数、点乘、叉乘、旋转、平行、垂直、夹角
  • 直线和线段:线段中点、离线段最近的点、线段的交点、直线交点、线段的垂直平分线
  • 多边形:一般多边形、圆、矩形
  • 仿射变换

书中强调了单元测试的重要性。

二、点和向量

数字比较

# geom2d/nums.py

import math

def are_close_enough(a,b,tolerance=1e-10):
    return math.fabs(a-b)<tolerance

def is_close_to_zero(a,tolerance=1e-10):
    return are_close_enough(a,0.0,tolerance)

def is_close_to_one(a,tolerance=1e-10):
    return are_close_enough(a,1.0,tolerance)

# geom2d/point.py

import math

from geom2d import nums
from geom2d.vector import Vector


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # 计算两点间的距离
    def distance_to(self, other):
        delta_x = other.x - self.x
        delta_y = other.y - self.y
        return math.sqrt(delta_x ** 2 + delta_y ** 2)

    # 对点进行加操作
    def __add__(self, other):
        return Point(
            self.x + other.x,
            self.y + other.y
        )

    # 对点进行减操作
    def __sub__(self, other):
        return Vector(
            self.x - other.x,
            self.y - other.y
        )

    # 用向量移动点
    def displaced(self, vector: Vector, times=1):
        scaled_vec = vector.scaled_by(times)
        return Point(
            self.x + scaled_vec.u,
            self.y + scaled_vec.v
        )

    # 比较点是否相等
    def __eq__(self, other):
        if self is other:
            return True

        if not isinstance(other, Point):
            return False

        return nums.are_close_enough(self.x, other.x) and \
            nums.are_close_enough(self.y, other.y)

    def __str__(self):
        return f'({self.x},{self.y})'

向量

# geom2d/vector.py

import math

from geom2d import nums


class Vector:
    def __init__(self, u, v):
        self.u = u
        self.v = v

    # 向量的加法
    def __add__(self, other):
        return Vector(
            self.u+other.u,
            self.v+other.v
        )

    # 向量的减法
    def __sub__(self, other):
        return Vector(
            self.u-other.u,
            self.v-other.v
        )

    # 向量的缩放
    def scaled_by(self,factor):
        return Vector(factor*self.u,factor*self.v)

    # 计算向量的范数
    @property
    def norm(self):
        return math.sqrt(self.u**2+self.v**2)

   # 验证向量是否为单位向量
    @property
    def is_normal(self):
        return nums.is_close_to_one(self.norm)

    # 计算单位长度的向量
    def normalized(self):
        return self.scaled_by(1.0/self.norm)

   # 计算指定长度的向量
    def with_length(self,length):
        return self.normalized().scaled_by(length)

    # 向量的投影
    def projection_over(self,direction):
        return self.dot(direction.normalized())

    # 向量点乘
    def dot(self,other):
        return (self.u*other.u)+(self.v*other.v)

    # 向量叉乘
    def cross(self,other):
        return (self.u*other.v)-(self.v*other.u)

    # 检验两向量是否平行,即叉乘是否为0
    def is_parallel_to(self,other):
        return nums.is_close_to_zero(self.cross(other))

    # 检验两向量是否垂直,即点乘是否为0
    def is_perpendicular_to(self,other):
        return nums.is_close_to_zero(self.dot(other))

    # 向量的夹角(角度值)
    def angle_value_to(self,other):
        dot_product=self.dot(other)  # 计算点乘值
        norm_product=self.norm*other.norm # 范数的乘积
        return math.acos(dot_product/norm_product) # (点乘值/范数乘积)取反余弦,即角度值

    # 向量的夹角(带叉乘符号的角度值)
    def angle_to(self,other):
        value=self.angle_value_to(other)
        cross_product=self.cross(other)
        return math.copysign(value,cross_product) #math.copysign(x, y)函数返回x的大小和y的符号

    # 向量的旋转,旋转一定角度
    def rotated_radians(self,radians):
        cos=math.cos(radians)
        sin=math.sin(radians)
        return Vector(
            self.u*cos-self.v*sin,
            self.u*sin+self.v*cos
        )

    # 垂直向量,旋转90度
    def perpendicular(self):
        return Vector(-self.v,self.u)

    # 相反向量,旋转180度
    def opposite(self):
        return Vector(-self.u,-self.v)

    # 向量的正旋和余弦
    @property
    def sine(self):
        return self.v/self.norm

    @property
    def cosine(self):
        return self.u/self.norm

    # 比较向量是否相等
    def __eq__(self, other):
        # 检查是否在比较相同的实例
        if self is other:
            return True

        # other不是Vector类的实例
        if not isinstance(other,Vector):
            return False

        return nums.are_close_enough(self.u,other.u) and \
            nums.are_close_enough(self.v,other.v)

    def __str__(self):
        return f'({self.u},{self.v}) with norm {self.norm}'
#geom2d/vectors.py
# 向量工厂

from geom2d.point import Point
from geom2d.vector import Vector

# 创建一个从点p到点q的向量
def make_vector_between(p:Point,q:Point):
    return q-p

# 创建单位方向向量
def make_versor(u:float,v:float):
    return Vector(u,v).normalized()

# 在两点之间创建一个单位方向向量
def make_versor_between(p:Point,q:Point):
    return make_vector_between(p,q).normalized()

向量范数

向量的范数(norm)是指它的长度。单位范数的长度为一个单位。拥有单位范数的向量在确认向量方向时非常有用,因此,我们经常会想知道一个向量的范数是否为单位范数(它是否是单位向量)​。我们也经常需要归一化(normalize)一个向量:方向不变,长度变为1。

向量点乘

点乘(dot product)会得到一个标量,它可以反映两个向量方向的差异

图上有一个参考向量\vec{v}和另外三个向量:\vec{a}\vec{b}\vec{c}。一条垂直于\vec{v}的直线将空间分成两个半平面。向量\vec{b}在直线上,因此\vec{v}\vec{b}的夹角θ等于90°。而cos(90°)=0,因此\vec{v}\cdot\vec{b}=0。垂直向量的点乘为零。向量\vec{a}所在的半平面和\vec{v}相同,因此,\vec{v}\cdot\vec{a}> 0。最后,\vec{c}在与\vec{v}相对的半平面上,因此,\vec{v}\cdot\vec{c}< 0

向量叉乘

向量叉乘(cross product)会得到一个垂直于这两个向量所在平面的新向量。向量的顺序很重要,它决定了结果向量的方向。可以使用右手法则得到叉乘的方向。

叉乘不满足交换律:\vec{u}\times \vec{v}= - \vec{v}\times \vec{u}

二维向量叉乘的一个重要应用是确定角度的旋转方向\vec{u}\times \vec{v}> 0,因为从\vec{u}\vec{v}的角度为正(逆时针)​。相反,从\vec{v}\vec{u}的角度为负,因此叉乘\vec{v}\times \vec{u}< 0。最后,平行向量的叉乘为0,这很显然,因为sin 0=0。

向量旋转

cos(π/2)=0, sin(π/2)=1,cos(π)=-1, sin(π)=0

向量的正弦和余弦

三、直线和线段 

线段

# geom2d/segment.py

from geom2d.point import Point
from geom2d.vectors import make_vector_between,make_versor_between
from geom2d import tparam

class Segment:
    def __init__(self,start:Point,end:Point):
        self.start=start
        self.end=end

    # 线段的方向向量
    @property
    def direction_vector(self):
        return make_vector_between(self.start,self.end)

    # 线段的单位方向向量
    @property
    def direction_versor(self):
        return make_versor_between(self.start,self.end)

    # 垂直于线段方向的向量,法向量
    # 调用self的direction_versor来得到线段的方向向量,同时也是Vector类的实例
    # 调用perpendicular方法,返回垂直于线段方向的向量
    def normal_versor(self):
        return self.direction_versor.perpendicular()

    # 线段的长度
    @property
    def length(self):
        return self.start.distance_to(self.end)

    # 使用参数t获取线段上的任意一点
    def point_at(self,t:float):
        tparam.ensure_valid(t)  # 验证t值
        return self.start.displaced(self.direction_vector,t)

    # 线段的中点
    @property
    def middle(self):
        return self.point_at(tparam.MIDDLE)

    # 线段上的最近点
    # 计算从线段的端点S到外部点P的向量v
    # 计算在线段方向上投影的单位向量d
    # 将投影的长度设为vs
    def closest_point_to(self,p:Point):
        v=make_vector_between(self.start,p)
        d=self.direction_versor
        vs=v.projection_over(d)

        if vs<0:
            return self.start

        if vs>self.length:
            return self.end

        return self.start.displaced(d,vs)



线段的方向向量

方向(direction)是线段的一个重要性质,定义为从起点S到终点E的向量。用\vec{d}来表示该向量。

方向向量(direction vector)是一个与线段平行且长度相同的向量,其方向是从起点到终点。

单位方向(direction versor)是方向向量的归一化版本,即与方向向量的方向相同,但长度为一个单位。

垂直于线段的方向也同样重要。将单位方向向量\hat{d}旋转方向π/4 rad(90°),就可以得到线段的单位法向量(normalversor)。

线段上最接近外部点的点

如果外部点没有与线段对齐,穿过该点且垂直于线段的直线不与线段相交,那么最近的点必然是两个端点S或E中的一个。

如果该点与该段对齐,则垂直线与线段的交点就是最近的点。

如图:点S≡A'是离A最近的点,点E≡B'是最接近B的点,C'是最接近C的点。

线段的交点

四、多边形

一般多边形——用它们的顶点来定义;

圆是平面内与指定点(圆心)的距离(半径)相同的所有点的集合。因此,圆由圆心C的位置和半径R的值定义

矩形——由原点、宽度和高度定义

多边形中一个重要性质是质心(centroid),即所有顶点坐标的算术平均值。

五、仿射变换

仿射变换:它使我们能够通过缩放、旋转、平移和剪切来改变几何形状。

六、单元测试

断言方法

断言方法描述
assertAlmostEqual定义在我们引用的类unittest.TestCase中,用指定的公差来检查浮点数是否相等,公差用小数点后的位数表示,默认是7。请记住,在比较浮点数时,必须有公差,或者像上述例子,给定小数点后的位数
assertEqual使用==操作符来比较这两个参数
assertTrue检验给定表达式的计算结果是否为True
assertFalse检验给定表达式的计算结果是否为False
assertRaises向其传入三个参数。首先是预期要触发的异常(TParamError)。其次,传入了期望触发异常的方法。最后,传入需要传递给前面的方法(在本例中为point_at)的实参。
assertIsNone检查传入的值是否是None(无)​

单元测试的三个规则

1、失败原因须唯一

单元测试应该有且仅有一个失败的原因。如果测试失败只有一个原因,那么很容易找到代码中的错误。如果一个测试失败可能有五个不同的原因。当测试失败时,你会发现自己花费太多时间去阅读错误消息和调试代码。

2、受控环境

测试的输入和输出应该是已知的。发生在测试中的一切都应该是确定的(deterministic),也就是说,不应该出现随机性或依赖任何你无法控制的东西:日期或时间、操作系统、未在测试中设置的机器环境变量,等等。

3、测试独立性

测试不应依赖于其他测试。每个测试都应该独立运行,绝不能依赖于其他测试所设置的运行测试的环境。这至少有三个原因。首先,你需要独立地运行或调试测试。其次,许多测试框架并不能保证测试的执行顺序。最后,不依赖于其他测试的测试要易读得多。

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

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

相关文章

RabbitMQ---消息确认和持久化

&#xff08;一&#xff09;消息确认 1.概念 生产者发送消息后&#xff0c;到达消费端会有以下情况&#xff1a; 1.消息处理成功 2.消息处理异常 如果RabbitMQ把消息发送给消费者后就把消息删除&#xff0c;那么就可能会导致&#xff0c;消息处理异常想要再获取这条消息的时…

map和set c++

关联式容器也是⽤来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;关联式容器逻辑结构通常是⾮线性结构&#xff0c;两个位置有紧密的关联关系&#xff0c;交换⼀下&#xff0c;他的存储结构就被破坏了。顺序容器中的元素是按关键字来保存和访问的。关联式容器有map/…

turtle教学课程课堂学习考试在线网站

完整源码项目包获取→点击文章末尾名片&#xff01;

Digital Document System (DDS)

Digital Document System (DDS&#xff09; 数字档案平台 信息注入

Springer Nature——Applied Intelligence 投稿指南

投稿系统&#xff1a;Editorial Manager (Manuscript and Peer Review) : 使用Editorial Manager 投稿系统的期刊列表&#xff1a;期刊列表 期刊主页&#xff1a;Spring Nature 主页 投稿主页&#xff1a;Spring Nature Submit SystemSubmission Guidelines: Official Submissi…

如何在前端给视频进行去除绿幕并替换背景?-----Vue3!!

最近在做这个这项目奇店桶装水小程序V1.3.9安装包骑手端V2.0.1小程序前端 最近&#xff0c;我在进行前端开发时&#xff0c;遇到了一个难题“如何给前端的视频进行去除绿幕并替换背景”。这是一个“数字人项目”所需&#xff0c;我一直在冥思苦想。终于有了一个解决方法…

使用python+pytest+requests完成自动化接口测试(包括html报告的生成和日志记录以及层级的封装(包括调用Json文件))

一、API的选择 我们进行接口测试需要API文档和系统&#xff0c;我们选择JSONPlaceholder免费API&#xff0c;因为它是一个非常适合进行接口测试、API 测试和学习的工具。它免费、易于使用、无需认证&#xff0c;能够快速帮助开发者模拟常见的接口操作&#xff08;增、删、改、…

UE4原生的增量Cook原理

设置Cook的步骤后&#xff0c;断点进入到如下堆栈&#xff1a; UCookOnTheFlyServer::StartCookByTheBook(const UCookOnTheFlyServer::FCookByTheBookStartupOptions &) CookOnTheFlyServer.cpp:7723 UCookCommandlet::CookByTheBook(const TArray<…> &, TArr…

C#表达式和运算符

本文我们将学习C#的两个重要知识点&#xff1a;表达式和运算符。本章内容会理论性稍微强些&#xff0c;我们会尽量多举例进行说明。建议大家边阅读边思考&#xff0c;如果还能边实践就更好了。 1. 表达式 说到表达式&#xff0c;大家可能感觉有些陌生&#xff0c;我们先来举个…

蓝桥杯 Python 组知识点容斥原理

容斥原理 这张图初中或者高中数学课应该画过 也就是通过这个简单的例子引出容斥原理的公式 这张图的面积&#xff1a;s1 s3 s7 - 2 * s2 - 2 * s4 - 2 * s6 3 * s5 通过此引导出容斥原理公式 那么下面来一起看看题目 题目描述 给定 n,m 请求出所有 n 位十进制整数中有多…

PDF文件提取开源工具调研总结

概述 PDF是一种日常工作中广泛使用的跨平台文档格式&#xff0c;常常包含丰富的内容&#xff1a;包括文本、图表、表格、公式、图像。在现代信息处理工作流中发挥了重要的作用&#xff0c;尤其是RAG项目中&#xff0c;通过将非结构化数据转化为结构化和可访问的信息&#xff0…

PDF编辑 PDF-XChange Editor Plus 免装优化版

PDF编辑器很多打工人都需要用到&#xff0c;也分享过好几款口碑不错的&#xff0c;这次这款PDF依旧值得你的期待。 PDF-XChange Editor&#xff0c;号称打开速度最快最强大的PDF编辑器/PDF阅读器&#xff0c;专注于PDF文档的编辑&#xff0c;可以自定义制作PDF电子文档&#xf…

IP属地会随着人的移动而改变吗

在当今数字化时代&#xff0c;互联网已成为人们生活中不可或缺的一部分。无论是社交媒体的日常互动&#xff0c;还是在线购物、远程工作&#xff0c;IP地址作为网络身份的重要标识&#xff0c;扮演着举足轻重的角色。随着移动互联网技术的飞速发展&#xff0c;人们越来越多地在…

我的世界-与门、或门、非门等基本门电路实现

一、红石比较器 (1) 红石比较器结构 红石比较器有前端单火把、后端双火把以及两个侧端 其中后端和侧端是输入信号,前端是输出信号 (2) 红石比较器的两种模式 比较模式 前端火把未点亮时处于比较模式 侧端>后端 → 0 当任一侧端强度大于后端强度时,输出…

【大数据】机器学习------支持向量机(SVM)

支持向量机的基本概念和数学公式&#xff1a; 1. 线性可分的支持向量机 对于线性可分的数据集 &#xff0c;其中(x_i \in R^d) 是特征向量 是类别标签&#xff0c;目标是找到一个超平面 &#xff0c;使得对于所有 的样本 &#xff0c;对于所有(y_i -1) 的样本&#xff0c;…

RDD和DataFrame两种数据结构的对比

文章目录 1. 实战概述2. RDD&#xff08;弹性分布式数据集&#xff09;2.1 RDD概念2.2 RDD特点2.3 实战操作 3. DataFrame&#xff08;数据帧&#xff09;3.1 DataFrame概念3.2 DataFrame优点3.3 实战操作 4. 实战小结 1. 实战概述 今天我们将深入探讨 Apache Spark 中的两种核…

中职网络建设与运维ansible服务

ansible服务 填写hosts指定主机范围和控制节点后创建一个脚本&#xff0c;可以利用简化脚本 1. 在linux1上安装系统自带的ansible-core,作为ansible控制节点,linux2-linux7作为ansible的受控节点 Linux1 Linux1-7 Yum install ansible-core -y Vi /etc/ansible/hosts 添加…

Kibana 控制台中提供语义、向量和混合搜索

作者&#xff1a;来自 Elastic Mark_Laney 想要将常规 Elasticsearch 查询与新的 AI 搜索功能结合起来吗&#xff1f;那么&#xff0c;你不需要连接到某个第三方的大型语言模型&#xff08;LLM&#xff09;吗&#xff1f;不。你可以使用 Elastic 的 ELSER 模型来改进现有搜索&a…

多种 Docker 镜像拉取解决方案与实践

最近国内 Docker 镜像拉取不太通畅&#xff0c;尝试了几种镜像拉取的方式&#xff0c;写篇博客分享一下。 原以为只是 docker hub 被毙了&#xff0c;上机器一操作&#xff0c;官方的下载地址也被毙了&#xff0c;真是从源头解决问题。 不过还好目前还有其他源能用&#xff0…

2025边缘计算新年沙龙成功举办,共话边缘AI未来

1月11日下午&#xff0c;北京市海淀区中关村创业大街热闹非凡&#xff0c;以“云边腾跃&#xff0c;蛇启新航”为主题的 2025边缘计算新年沙龙 盛大举行。本次活动汇聚了边缘计算、人工智能以及云边协同领域的顶尖专家、学者和从业者&#xff0c;共同探讨技术前沿与实际应用场景…