【Godot4.3】复合路径类myPath

概述

之前编写过一个基于指令绘图的类交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

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

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

相关文章

MATLAB|基于多主体主从博弈的区域综合能源系统低碳经济优化调度

目录 主要内容 程序亮点&#xff1a; 模型研究 一、综合能源模型 二、主从博弈框架 部分代码 结果一览 下载链接 主要内容 程序参考文献《基于多主体主从博弈的区域综合能源系统低碳经济优化调度》&#xff0c;采用了区域综合能源系统多主体博弈协同优化方…

【重学 MySQL】五十二、MySQL8 新特性:计算列

【重学 MySQL】五十二、MySQL8 新特性&#xff1a;计算列 定义特性用法应用场景注意事项 在MySQL8中&#xff0c;计算列是一项引入的新特性&#xff0c;它为数据处理和分析提供了更大的灵活性和便捷性。 定义 计算列是指根据数据库中其他列的值通过计算得出的新列&#xff0c…

反调试—1

IsDebuggerPresent() CheckRemoteDebuggerPresent() 其内部实际调用NtQueryInformationProcess() bool _stdcall ThreadCall() {while (true){BOOL pbDebuggerPresent FALSE;CheckRemoteDebuggerPresent(GetCurrentProcess(), &pbDebuggerPresent);if (pbDebuggerPres…

Leetcode: 0011-0020题速览

Leetcode: 0011-0020题速览 本文材料来自于LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer&#xff08;第 2 版&#xff09;》、《程序员面试金典&#xff08;第 6 版&#xff09;》题解 遵从开源协议为知识共享 版权归属-相同方式…

【持续更新中】MMDetection3训练自己的数据集常见报错解决

博主近来跑自己数据集需要对比试验&#xff0c;故选择了MMDetection3这一算法整合详细的框架&#xff0c;遇到了较多问题在此处留作记录&#xff0c;若你也有相应的问题可以在评论区提出与解决方法。会持续更新&#xff0c;同时欢迎批评指正。 0.ModuleNotFoundError: No modu…

微信小程序hbuilderx+uniapp+Android 新农村综合风貌旅游展示平台

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

索尼MDR-M1:超宽频的音频盛宴,打造沉浸式音乐体验

在音乐的世界里&#xff0c;每一次技术的突破都意味着全新的听觉体验。 索尼&#xff0c;作为音频技术的先锋&#xff0c;再次以其最新力作——MDR-M1封闭式监听耳机&#xff0c;引领了音乐界的新潮流。 这款耳机以其超宽频播放和卓越的隔音性能&#xff0c;为音乐爱好者和专…

多模态—图文匹配

可能最近大家已经发现了chatgpt可以根据自己的描述生成图片&#xff0c;其实这就是一个图文匹配的问题&#xff0c;可以理解为这是一个多模态的问题。 在模型训练时我们需要N个图片和N个文本对进行训练&#xff0c;文本通过text encoder形成文本语义向量&#xff0c;text enco…

【Python】Streamlit:为数据科学与机器学习打造的简易应用框架

Streamlit 是一个开源的 Python 库&#xff0c;专为数据科学家和机器学习开发者设计&#xff0c;旨在快速构建数据应用。通过简单的 Python 脚本&#xff0c;开发者无需掌握前端技术&#xff0c;即可将数据分析和模型结果转化为直观、交互式的 Web 应用。其简洁的 API 设计使得…

NVIDIA NVLink-C2C

NVIDIA NVLink-C2C 文章目录 前言一、介绍1. 用于定制芯片集成的超快芯片互连技术2. 构建半定制芯片设计3. 使用 NVLink-C2C 技术的产品 二、NVLink-C2C 技术优势1. 高带宽2. 低延迟3. 低功率和高密度4. 行业标准协议 前言 将 NVLink 扩展至芯片级集成 一、介绍 1. 用于定制芯…

软件设计师——数据结构

本博文所有内容来自于B站up主zst_2001 目录 时间复杂度 常规数据结构 链表 栈与队列 ​编辑 串 数组 树 卡特兰数&#xff1a; 平衡二叉树 哈夫曼 图 AOV 排序 顺序 折半 哈希 时间复杂度 常规数据结构 链表 栈与队列 串 找i位置前面的字符串&#xff0c…

Koa2+mongodb项目实战1(项目搭建)

前言 在正式开始之前&#xff0c;需要先知道用到的东西&#xff1a; koa&#xff1a;Koa 是一个基于 Node.js 的 Web 应用框架&#xff0c;非常适合开发API服务&#xff0c;可以与前端框架&#xff08;如 Vue.js、React.js&#xff09;结合使用&#xff0c;实现前后端分离的开…

【HTTP(3)】(状态码,https)

【认识状态码】 状态码最重要的目的&#xff0c;就是反馈给浏览器:这次请求是否成功&#xff0c;若失败&#xff0c;则出现失败原因 常见状态码: 200:OK&#xff0c;表示成功 404:Not Found&#xff0c;浏览器访问的资源在服务器上没有找到 403:Forbidden&#xff0c;访问被…

使用 Light Chaser 进行大屏数据可视化

引言 在当今数据驱动的世界中&#xff0c;数据可视化变得越来越重要。Light Chaser 是一款基于 React 技术栈的大屏数据可视化设计工具&#xff0c;通过简单的拖拽操作&#xff0c;你可以快速生成漂亮、美观的数据可视化大屏和看板。本文将介绍如何使用 Light Chaser 进行数据…

10款好用的开源 HarmonyOS 工具库

大家好&#xff0c;我是 V 哥&#xff0c;今天给大家分享10款好用的 HarmonyOS的工具库&#xff0c;在开发鸿蒙应用时可以用下&#xff0c;好用的工具可以简化代码&#xff0c;让你写出优雅的应用来。废话不多说&#xff0c;马上开整。 1. efTool efTool是一个功能丰富且易用…

【unity进阶知识6】Resources的使用,如何封装一个Resources资源管理器

文章目录 一、Unity资源加载的几种方式1、Inspector窗口拖拽2、Resources3、AssetBundle4、Addressables&#xff08;可寻址资源系统&#xff09;5、AssetDatabase 二、准备三、同步加载Resources资源1、Resources.Load同步加载单个资源1.1、基本加载1.2、加载指定类型的资源1.…

漆包线称重系统/自动称重/项目合作

万界星空科技漆包线行业称重系统实现自动称重的方式主要依赖于现代数字电子称重技术、计算机网络技术以及相关的软件系统的集成。以下是对该系统如何实现自动称重的详细解释&#xff1a; 一、硬件基础 称重设备&#xff1a; 系统采用高精度的电子秤作为称重设备&#xff0c;这…

Meta推出Movie Gen 旗下迄今最先进的视频生成AI模型

Meta 今天发布了 MovieGen 系列媒体基础AI模型&#xff0c;该模型可根据文本提示生成带声音的逼真视频。 MovieGen 系列包括两个主要模型&#xff1a; MovieGen Video 和 MovieGen Audio。 MovieGen Video 是一个具有 300 亿个参数的变换器模型&#xff0c;可根据单个文本提示生…

方法重载(Overload)

前言 在前面的学习中&#xff0c;我们学到了重写(Override),这里我们主要进行重载(Overload)的介绍&#xff0c;同时对重写和重载的区别进行分析。 1. 重载(Overload) #方法重载 在同一个类中定义多个同名但参数不同的方法。我们称方法与方法之间构成方法重载 在Java中&…

【linux进程】进程优先级命令行参数环境变量

目录 一&#xff0c;进程切换二&#xff0c;进程优先级1. 什么是优先级2. 权限 vs 优先级3. 为什么要有优先级4. 优先级的查看方式 三&#xff0c;命令行参数1. 什么是命令行参数2. 为什么要有命令行参数3. 是谁做的 四&#xff0c;环境变量1. 基本概念2. 常见环境变量3. 查看环…