【Godot4.3】复合路径类myPath

news2024/11/23 15:23:57

概述

之前编写过一个基于指令绘图的类交myPoint,但是只涉及折线段生成。这次我基于SVG的<path>标签路径指令的启发,实现了一个能够获得连续绘制的直线段、圆弧和贝塞尔复合路径的类型myPath

可以使用绘图指令方法或字符串形式的绘图指令解析来创建符合路径。
通过points属性可以获取路径的点集,并用于CanvasItem绘图函数绘制。

类实现

# ==================================================
# myPath
# 用方法生成的路径
# 巽星石 v4.3.stable.steam [77dcf97d8]
# 202410413:40:05
# 202410416:53:53
# ==================================================
class_name myPath

var points:PackedVector2Array

# 通过指令创建
static func by_order_string(order_string:String) -> myPath:
	var path = myPath.new()
	var orders = order_string.split(" ",false)
	for order in orders:
		var od = order.split("_",false)
		match od[0]:
			"M":
				var pos = od[1].split(",",false)
				path.move_to(float(pos[0]),float(pos[1]))
			"Mpv":
				var pos = od[1].split(",",false)
				path.move_to_pv(float(pos[0]),float(pos[1]))
			"L":
				var pos = od[1].split(",",false)
				path.line_to(float(pos[0]),float(pos[1]))
			"Lpv":
				var pos = od[1].split(",",false)
				path.line_to_pv(float(pos[0]),float(pos[1]))
			"Ld":
				var pos = od[1].split(",",false)
				path.line_to_d(float(pos[0]),float(pos[1]))
			"Ldpv":
				var pos = od[1].split(",",false)
				path.line_to_d_pv(float(pos[0]),float(pos[1]))
			"A":
				var pos = od[1].split(",",false)
				path.arc(float(pos[0]),float(pos[1]),float(pos[2]),float(pos[3]))
			"Q":
			
				var pos = od[1].split(",",false)
				var p2 = Vector2(float(pos[0]),float(pos[1]))
				pos = od[2].split(",",false)
				var ctl_1:=pVector2(float(pos[0]),float(pos[1]))
				pos =od[3].split(",",false)
				var ctl_2:=pVector2(float(pos[0]),float(pos[1]))
				var points_count:=float(od[4])
				path.bezier_curve_to(p2,ctl_1,ctl_2,points_count)
		if order == "Z":
			path.close()
	return path

# ========================= 移动指令 =============================
# 绝对移动
func move_to(x:float,y:float)-> void:
	if points.size() == 0:
		points.append(Vector2(x,y))

# 绝对移动 - 极坐标位置
func move_to_pv(ang:float,len:float) -> void:
	if points.size() == 0:
		points.append(pVector2(ang,len))
# ========================= 直线指令 =============================
# 绝对移动
func line_to(x:float,y:float)-> void:
	if points.size() > 0:
		points.append(Vector2(x,y))

# 相对移动
func line_to_d(dx:float,dy:float)-> void:
	if points.size() > 0:
		points.append(get_last_point() + Vector2(dx,dy))

# 绝对移动 - 极坐标位置
func line_to_pv(ang:float,len:float) -> void:
	if points.size() > 0:
		points.append(pVector2(ang,len))

# 相对移动 - 极坐标位置
func line_to_d_pv(d_ang:float,d_len:float)-> void:
	if points.size() > 0:
		points.append(get_last_point() + pVector2(d_ang,d_len))

# ========================= 弧线指令 ==========================
func arc(
	radius:float,         # 所在圆的半径
	start_angle:float,    # 起始角度()
	end_angle:float,      # 结束角度()
	edges:int,            # 分段数,默认为0,则表示采用 夹角θ * radius
) -> void:
	if points.size() > 0:
		var arc_pots:PackedVector2Array
		var angle =  deg_to_rad(end_angle - start_angle)  # 夹角
		if edges <= 0:
			edges = angle * radius  # 要绘制的点的个数 = θ * r
		var ang = angle/float(edges) # 每次旋转角度
		for i in range(edges+1):
			arc_pots.append(Vector2.RIGHT.rotated(i * ang + deg_to_rad(start_angle)) * radius)
		print(get_last_point())
		points.append_array(Transform2D(0,get_last_point() - arc_pots[0]) * arc_pots)

# ========================= 贝塞尔曲线指令 ==========================
func bezier_curve_to(
		p2:Vector2,                     # 目标位置
		ctl_1:=Vector2(),ctl_2:=Vector2(),    # 控制点
		points_count:=10,                     # 顶点数目(插值次数),值越大,曲线越平滑
	) -> void:
	var pots:PackedVector2Array = []
	var p1:Vector2
	if points.size() > 0:
		p1 = get_last_point()
		# 求曲线点集
		for i in range(points_count+1):
			var p = p1.bezier_interpolate(p1+ctl_1,p2+ctl_2,p2,i/float(points_count))
			pots.append(p)
	points.append_array(pots)

# ========================= 闭合指令 ==========================

# 闭合曲线
func close() -> void:
	if points.size() > 2 and points[points.size()-1] != points[0]:
		points.append(points[0])


# 获取上一个点坐标
func get_last_point():
	return points[points.size()-1] if points.size() > 0 else null

# 获取第一个点坐标
func get_first_point():
	return points[0] if points.size() > 0 else null

# 极坐标点函数 - 通过角度和长度定义一个点
static func pVector2(angle:float = 0.0,length:float =0.0) -> Vector2:
	var dir = Vector2.RIGHT.rotated(deg_to_rad(angle))
	return dir * length

测试

首先实现的是各种绘图指令方法。以下是基于这些绘图指令方法绘制路径的测试。

extends Node2D
var path = myPath.new()  # 创建实例

func _ready() -> void:
    # 使用指令创建路径
	path.move_to(100,100)
	path.line_to_d(100,0)
	path.line_to_d(0,100)
	path.line_to_d(-100,0)
	path.close()

func _draw() -> void:
	draw_polyline(path.points,Color.AQUAMARINE,1)   # 绘制路径

extends Node2D
var path = myPath.new()  # 创建实例

func _ready() -> void:
	# 使用指令创建路径
	path.move_to(300,300)
	path.line_to_d_pv(90,100)
	path.line_to_d_pv(180,50)
	path.arc(50,180,270,5)
	path.close()  # 闭合路径
	
func _draw() -> void:
	draw_polyline(path.points,Color.AQUAMARINE,1)   # 绘制路径

extends Node2D
var path = myPath.new()  # 创建实例

func _ready() -> void:
	# 使用指令创建路径
	path.move_to(300,300)
	path.line_to_d_pv(90,100)
	path.line_to_d_pv(180,50)
	path.arc(50,180,270,5)
	path.bezier_curve_to(path.get_first_point(),path.pVector2(180,50),path.pVector2(-180,50))
	
	#path.close()
	
func _draw() -> void:
	draw_polyline(path.points,Color.AQUAMARINE,1)   # 绘制路径

绘图指令设计

  • M_x,y
  • Mpv_ang,len:
  • L_x,y:
  • Ld_dx,dy:
  • Lpv_ang,len:
  • Ldpv_ang,len:
  • A_radius,start_angle,end_angle,edges:
  • Q_x,y_ang1,len1_ang2,len2_10:
  • Z:闭合曲线

实现解析

# 通过指令创建
static func by_order_string(order_string:String) -> myPath:
	var path = myPath.new()
	var orders = order_string.split(" ",false)
	for order in orders:
		var od = order.split("_",false)
		match od[0]:
			"M":
				var pos = od[1].split(",",false)
				path.move_to(float(pos[0]),float(pos[1]))
			"Mpv":
				var pos = od[1].split(",",false)
				path.move_to_pv(float(pos[0]),float(pos[1]))
			"L":
				var pos = od[1].split(",",false)
				path.line_to(float(pos[0]),float(pos[1]))
			"Lpv":
				var pos = od[1].split(",",false)
				path.line_to_pv(float(pos[0]),float(pos[1]))
			"Ld":
				var pos = od[1].split(",",false)
				path.line_to_d(float(pos[0]),float(pos[1]))
			"Ldpv":
				var pos = od[1].split(",",false)
				path.line_to_d_pv(float(pos[0]),float(pos[1]))
			"A":
				var pos = od[1].split(",",false)
				path.arc(float(pos[0]),float(pos[1]),float(pos[2]),float(pos[3]))
			"Q":
			
				var pos = od[1].split(",",false)
				var p2 = Vector2(float(pos[0]),float(pos[1]))
				pos = od[2].split(",",false)
				var ctl_1:=pVector2(float(pos[0]),float(pos[1]))
				pos =od[3].split(",",false)
				var ctl_2:=pVector2(float(pos[0]),float(pos[1]))
				var points_count:=float(od[4])
				path.bezier_curve_to(p2,ctl_1,ctl_2,points_count)
		if order == "Z":
			path.close()
	return path

测试:

extends Node2D
var path = myPath.by_order_string("M_45,100 L_200,200 L_120,40 Z")  # 创建实例
	
func _draw() -> void:
	draw_polyline(path.points,Color.AQUAMARINE,1)   # 绘制路径

M_45,100 Ld_100,0 Ld_0,100 Z

M_45,100 Ldpv_45,100 Ldpv_0,100

M_100,100 A_50,0,90,10 A_100,180,90,10

M_100,100 Q_300,300_-45,100_-45,100_10

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

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

相关文章

hbuilderx+uniapp+Android宠物用品商城领养服务系统的设计与实现 微信小程序沙箱支付

目录 项目介绍支持以下技术栈&#xff1a;具体实现截图HBuilderXuniappmysql数据库与主流编程语言java类核心代码部分展示登录的业务流程的顺序是&#xff1a;数据库设计性能分析操作可行性技术可行性系统安全性数据完整性软件测试详细视频演示源码获取方式 项目介绍 顾客 领养…

OpenCAEPoro优化(1)

核心目的&#xff1a;减少运行时的 object time 方法一&#xff1a;改变运行的进程数 进入OpenCAEPoro目录下运行下述代码&#xff08;进程数为4&#xff09; mpirun -np 4 ./testOpenCAEPoro ./data/case1/case1.data verbose1结果如下 可以看到&#xff0c;object time是…

日常工作记录:服务器被攻击导致chattr: command not found

在深夜的寂静中&#xff0c;公司的服务器突然遭遇了一场突如其来的攻击。特别是nginx配置文件无法修改&#xff0c;仿佛预示着不祥的预兆&#xff0c;面对这突如其来的灾难&#xff0c;技术人员迅速响应。 这时候需要chattr&#xff0c;但是执行的chattr -i xxx的时候&#xf…

神经网络激活函数之前的加权求和 | 矩阵相乘运算法则(清晰版)

1. 神经网络中进行加权求和为什么要将w矩阵进行转置&#xff1f; 下面以一个简单的神经网络作为举例&#xff1a; 我们要将输入特征与W进行加权求和&#xff0c;想要的是下面这种结果&#xff1a; 但是根据矩阵相乘的运算法则&#xff1a; 矩阵A的列数&#xff08;column&am…

SysML案例-风力发电

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>>

攻防世界---->Newbie_calculations

学习笔记。 前言&#xff1a;试过od动态分析&#xff0c; 然后发现&#xff0c;那些函数不完全是混淆&#xff0c;怎么剥离 - - 不会 现在学会了。 参考&#xff1a; xctf-Newbie_calculations - jane_315 - 博客园 (cnblogs.com)https://www.cnblogs.com/jane315/p/1376964…

111.WEB渗透测试-信息收集-ARL(2)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;110.WEB渗透测试-信息收集-ARL&#xff08;1&#xff09; 2、安装ARL 1、最好先“apt-g…

创建django项目时,不同的编译类型有什么区别

这里主要提及的是 project venv 和 Custom environment 两种类型。 简单来说&#xff0c;project venv 是Python 3.3及以上版本中自带的虚拟环境管理工具&#xff0c;使用venv可以为每个项目创建一个独立的环境&#xff1a;python -m venv myprojectenv &#xff08;项目名后e…

电梯,建模的常见话题

以下是最近一则"女婿开电梯门导致岳父惨死"的新闻&#xff0c;可惜生命的同时&#xff0c;也引发了一系列联想。 不少人不了解或者了解但经常下意识忽略&#xff1a;电梯的门和轿厢是分离的部件。部件之间的协作如果有失误&#xff0c;系统就会出问题。电梯可以看作是…

JVM 基础、GC 算法与 JProfiler 监控工具详解

目录 1、引言 1.1 JVM内存与本地内存 1.2 JVM与JDK的关系 2、JVM基础 2.1 JVM&#xff08;Java Virtual Machine&#xff09; 2.2 Java与JVM的关系 2.3 JVM的内存结构 2.3.1 堆内存 2.3.2 栈内存 2.3.3 方法区 2.3.4 本地方法栈 2.3.5 程序计数器&#xff08;PC寄存…

Python+Matplotlib创建y=sinx、y=cosx、y=sinx+cosx可视化

y sin x (奇函数)&#xff1a; 图像关于原点对称。 对于任何 x&#xff0c;sin(-x) -sin(x)&#xff0c;符合奇函数定义。 y cos x (偶函数)&#xff1a; 图像关于 y 轴对称。 对于任何 x&#xff0c;cos(-x) cos(x)&#xff0c;符合偶函数定义。 y sin x cos x (既…

jQuery——对象的查找(查找孩子-父母-兄弟标签)

在已经匹配出的元素集合中根据选择器查找孩子/父母/兄弟标签&#xff0c;并封装为新的 jQuery 对象返回 children&#xff08;&#xff09; 子标签中找 find&#xff08;&#xff09; 后代标签中找 parent&#xff08;&#xff09; 父标签 prevAll&#xff08;&#xff0…

【内存池】——Nginx 内存池结构设计

目录 实现思路——分而治之 Nginx 的内存池结构图 结构体设计 内存池设计&#xff1a; 数据区属性设计&#xff1a; 大块内存区设计&#xff1a; 伪代码解释&#xff1a; 数据结构实现 实现思路——分而治之 算法结构&#xff1a;链表顺序表 1、对于每个请求或者连接都会建…

通信工程学习:什么是IGMP因特网组管理协议

IGMP&#xff1a;因特网组管理协议 IGMP&#xff08;Internet Group Management Protocol&#xff0c;因特网组管理协议&#xff09;是TCP/IP协议簇中负责组播成员管理的协议。它主要用于在用户主机和与其直接相连的组播路由器之间建立和维护组播组成员关系。以下是关于IGMP协议…

浙江工业大学《2019年+2023年828自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《浙江工业大学828自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2019年真题 2023年真题 Part1&#xff1a;2019年2023年完整版真题 2019年真题 2023年…

NVIDIA H100 GPU 上的机密计算可实现安全且值得信赖的 AI

NVIDIA H100 GPU 上的机密计算,实现安全可信的 AI 文章目录 前言1. 使用硬件虚拟化的 NVIDIA 机密计算2. 跨硬件、固件和软件保护 AI3. NVIDIA H100 GPU 的硬件安全性4. 在机密计算模式下运行 NVIDIA H100 GPU5. NVIDIA Hopper H100 机密计算为可信 AI 带来的优势6. 虚拟机上基…

68.【C语言】动态内存管理(重点)(1)

本文为数据结构打下基础 备注:数据结构需要掌握指针,结构体和动态内存管理 目录 1.内存开辟的方式 2.malloc函数 cplusplus网翻译 提炼要点 操作内存空间 01.开辟内存空间成功 02.开辟内存空间失败 如果是x64debug环境下,可能会成功 1.内存开辟的方式 01.创建变量 i…

从0到1酒店民宿管理系统

最近几天放假没事做&#xff0c;在家里就像把学过的winform技术整合下&#xff0c;一些用的技术点整理整理。想着做个什么软件那&#xff1f;无意中看到的酒店管理系统给了我思路。为啥不自己做一个那&#xff1f;说做就做。首先技术确定了使用winform为啥不用wpf那&#xff1f…

Linux环境基础开发工具使用(2)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Linux环境基础开发工具使用(2) 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. Li…

微服务_3.微服务保护

文章目录 一、微服务雪崩及解决方法1.1、超时处理1.2、仓壁模式1.3、断路器1.4、限流 二、Sentinel2.1、流量控制2.1.1、普通限流2.1.2、热点参数限流 2.2、线程隔离2.3、熔断降级2.3.1、断路器状态机2.3.2、断路器熔断策略2.3.2.1、慢调用2.3.2.2、异常比例&#xff0c;异常数…