【Godot4.3】复合路径类myPath

news/2024/12/21 22:26:07/
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">path>

概述

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

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

类实现

# ==================================================
# myPath
# 用方法生成的路径
# 巽星石 v4.3.stable.steam [77dcf97d8]
# 202410413:40:05
# 202410416:53:53
# ==================================================
class_name myPathvar 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:PackedVector2Arrayvar angle =  deg_to_rad(end_angle - start_angle)  # 夹角if edges <= 0:edges = angle * radius  # 要绘制的点的个数 = θ * rvar 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:Vector2if 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.ppmy.cn/news/1535038.html

相关文章

5G NR SSB简介

文章目录 SSB介绍SSB波束扫描 SSB介绍 5G NR 引入了SSB 这个概念&#xff0c;同步信号和PBCH块(Synchronization Signal and PBCH block, 简称SSB) 它由主同步信号(Primary Synchronization Signals, 简称PSS)、辅同步信号(Secondary Synchronization Signals, 简称SSS)、PBCH…

慢病中医药膳养生食疗管理微信小程序、基于微信小程序的慢病中医药膳养生食疗管理系统设计与实现、中医药膳养生食疗管理微信小程序的开发与应用(源码+文档+定制)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

用 Go 和 Redis 构建一个简单的任务管理系统

用 Go 和 Redis 构建一个简单的任务管理系统 在这篇博客中&#xff0c;我们将使用 Go 语言结合 Gin 框架和 Redis&#xff0c;一步步创建一个简单的任务管理系统。本系统可用于执行关键的 CRUD&#xff08;创建、读取、更新、删除&#xff09;操作&#xff0c;我们特别关注如何…

C++【类和对象】(取地址运算符重载与实现Date类)

文章目录 取地址运算符重载const成员函数取地址运算符重载 Date类的实现Date.hDate.cpp1.检查日期合法性2. 构造函数/赋值运算符重载3.得到某月的天数4. Date类 - 天数的操作4.1 日期 天数4.2 日期 天数4.3 日期 - 天数4.4 日期 - 天数 5. Date的前后置/--5.1 前置5.2 后置5.…

杂谈c语言——6.浮点数的存储

1.浮点数在内存中的存储 常⻅的浮点数&#xff1a;3.14159、1E10等&#xff0c;浮点数家族包括&#xff1a; float、double、long double 类型。 浮点数表⽰的范围&#xff1a; float.h 中定义 1.1 练习 #include<stdio.h>int main() {int n 9;float* pFloat (floa…

Vue.js组件开发教程

Vue.js 组件开发教程 Vue.js 是一款流行的前端框架&#xff0c;组件是其核心概念之一。通过将页面拆分为可复用的组件&#xff0c;可以提高代码的可维护性和可重用性。本教程将带您一步步学习如何开发 Vue.js 组件。 目录 什么是组件创建一个简单的组件组件注册 全局注册局部…

计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

如何利用ChatGPT开发一个盈利的AI写作助手网站

3-1 整体介绍写作助手及原型展示说明 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正逐步改变我们的生活方式&#xff0c;特别是在内容创作领域。本文将详细介绍如何利用ChatGPT技术&#xff0c;开发一个能够生成高质量内容的AI写作助手网站&#xff…