概述
用于生成常见二维几何图形顶点数据(PackedVector2Array
)的静态函数库。
生成的数据可用于_draw
和Line2D
、Polygon2D
等进行绘制和显示。
枚举
enum{
AXIS_X = 1,
AXIS_Y = 2,
}
enum{
SIDE_UP = 1,
SIDE_RIGHT = 2,
SIDE_BOTTOM = 3,
SIDE_LEFT = 4
}
测试场景
创建一个Control
为根节点的场景。我们将基于这个空的控件,来实现绘图函数的测试。
在你的Godot4.2测试工程中创建脚本文件ShapePoints.gd
,将ShapePoints
源码拷贝到这个脚本文件中。
为Control节点添加如下的基础脚本:
@tool
extends Control
func _draw():
pass
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
其中:
@tool
开启工具脚本模式,这样脚本会在编辑器中实时运行_draw()
是CanvasItem
类型的虚函数,用于执行draw_*
绘图函数的绘图任务- 隐含:
_draw()
会在控件进入场景树和改变大小等时机自动重绘。 get_draw_safety_rect()
函数可以获取在任意平移、旋转和缩放下都保持显示正确的控件矩形区域
基础图形点求取函数
rect(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array
返回长宽为size的矩形的四个顶点的数据。offset可以理解为整体的偏移。
使用CanvasItem内置draw_rect绘制矩形
CanvasItem
内置的draw_rect
函数本身就可以进行矩形的绘制。
@tool
extends Control
func _draw():
var rect = get_draw_safety_rect()
draw_rect(rect,Color.WHITE,false,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
绘制后的效果,无论是平移、旋转还是缩放,都可以看到矩形被正确绘制。
使用ShapePoints的Rect函数
ShapePoints
的Rect
函数返回的是一个包含矩形的5个顶点PackedVector2Array
,在Control
的_draw()
中,我们使用draw_polyline
绘制白色,宽度为2,和控件矩形一样大的空心矩形。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var points = ShapePoints.rect(ctl_rect.size,ctl_rect.position)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
将draw_polyline(points,Color.WHITE,2)
改为draw_polyline(points,[Color.WHITE])
可以绘制实心矩形。
regular_polygon(start_angle:int,edges:int,r:float,offset:Vector2) -> PackedVector2Array
返回正多边形顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var points = ShapePoints.regular_polygon(0,3,ctl_rect.size.y/2.0,ctl_rect.get_center())
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
把draw_polyline(points,Color.WHITE,2)
改为draw_polygon(points,[Color.WHITE])
,就可以绘制实心三角形。
通过改变edges
参数为4、5、6…可以创建正方形、正五边形、正六边形等等。
circle(r:float,offset:Vector2) -> PackedVector2Array
返回圆顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var points = ShapePoints.circle(ctl_rect.size.y/2.0,ctl_rect.get_center())
draw_polyline(points,Color.WHITE,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
sector(start_angle:int,end_angle:int,r:float) -> PackedVector2Array
返回扇形顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var points = ShapePoints.sector(0,90,ctl_rect.get_center().y,ctl_rect.size.y/2.0)
draw_polyline(points,Color.WHITE,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
起始角度0
,结束角度90
,半径为Control
高度一半的扇形:
sector(-120,45,ctl_rect.get_center().y,ctl_rect.get_center())
则表示起始角度-120
,结束角度45
,半径为Control
高度一半的扇形:
arc(start_angle:int,end_angle:int,r:float,offset:Vector2) -> void
返回圆弧顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var points = ShapePoints.arc(-120,45,ctl_rect.get_center().y,ctl_rect.get_center())
draw_polyline(points,Color.WHITE,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
起始角度-120
,结束角度45
,半径为Control
高度一半的弧形:
star(start_angle:int,edges:int,r:float,r2:float = 0,offset:Vector2 = Vector2.ZERO) -> void
返回星形顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.star(0,5,r1,r1/2.0,ctl_rect.get_center())
draw_polyline(points,Color.WHITE,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
起始角度0,5个角,外径为Control
高度一半,内径为外径一半的五角星:
其他edges
参数下生成的星形:
round_rect(size:Vector2,r1:float,r2:float,r3:float,r4:float) -> PackedVector2Array
这是是描述。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.round_rect(ctl_rect.size,10,10,10,10,ctl_rect.position)
draw_polyline(points,Color.WHITE,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
和Control
大小始终一致,四个圆角半径都固定是10px
的空心圆角矩形(下图左),改为draw_polygon(points,[Color.WHITE])
后就是实心矩形:
或者通过先draw_polygon
再draw_polyline
,绘制实心带描边的圆角矩形:
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.round_rect(ctl_rect.size,10,10,10,10,ctl_rect.position)
draw_polygon(points,[Color.WHITE])
draw_polyline(points,Color.ORANGE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
可以设定四个圆角半径的数值不同:
round_rect(ctl_rect.size,10,20,40,100,ctl_rect.position)
也可以将圆角半径设为一个动态变化的比例值。
var r = ctl_rect.size.x/20.0
var points = ShapePoints.round_rect(ctl_rect.size,r,r,r,r,ctl_rect.position)
chamfer_rect(size:Vector2,a:float,b:float,c:float,d:float) -> PackedVector2Array
返回倒角矩形顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.chamfer_rect(ctl_rect.size,10,20,30,40,ctl_rect.position)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
capsule(size:Vector2) -> PackedVector2Array
返回胶囊形顶点。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.capsule(ctl_rect.size,ctl_rect.position)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
spindle(size:Vector2) -> PackedVector2Array
返回梭形顶点。目前版本还有瑕疵。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.spindle(ctl_rect.size,ctl_rect.position)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
特殊图形
taiji(r:float,offset:Vector2) -> Dictionary
返回太极图案各部分的字典。
taiji["pan"]
:底盘的圆形taiji["yin"]
:阴鱼taiji["yang"]
:阳鱼taiji["yin_eye"]
:阴鱼眼taiji["yang_eye"]
:阳鱼眼
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var taiji = ShapePoints.taiji(ctl_rect.size.y/2.0,ctl_rect.get_center())
draw_polyline(taiji["pan"],Color.WHITE,2)
draw_polyline(taiji["yin"],Color.WHITE,2)
draw_polyline(taiji["yang"],Color.WHITE,2)
draw_polyline(taiji["yin_eye"],Color.WHITE,2)
draw_polyline(taiji["yang_eye"],Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
注意:目前版本有瑕疵,用draw_polygon绘制阳鱼部分时随着Control缩放,部分情况下无法绘制实心多边形。期待后续改进。
helix(start_angle:int,start_r:float,end_r:float,step:int,offset:Vector2) -> PackedVector2Array
返回螺旋线顶点。注意:目前版本有瑕疵,后续改进
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.helix(0,0,ctl_rect.size.x/2.0,10,ctl_rect.get_center())
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
边线重复半圆花纹
repeat_circle(length:float,r:float,space:float = 0,axis:int = AXIS_X,concave:bool = false,reverse:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array
返回重复半圆花纹的线。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.repeat_circle(ctl_rect.size.x,10)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
可以设定半圆之间的间隔:
repeat_circle(ctl_rect.size.x,10,10)
可以设定半圆是凸出还是凹进去:
repeat_circle(ctl_rect.size.x,10,10,true)
最后一个参数将点的位置全部逆序,可以用于拼接矩形。
repeat_circle(ctl_rect.size.x,10,10,true,true)
可以设定纵向:
repeat_circle(ctl_rect.size.y,10,0,ShapePoints.AXIS_Y)
repeat_circle_edge(size:Vector2,r:float,space:float,side:int,concave:bool) -> PackedVector2Array
返回指定size
大小的矩形所能使用的重复半圆边线。其中side
可以使用以下枚举的值:
enum{
SIDE_UP = 1,
SIDE_RIGHT = 2,
SIDE_BOTTOM = 3,
SIDE_LEFT = 4
}
分别代表矩形的上、右、底、左四边。根据side
的不同,会返回适用于矩形不同边的半圆重复花纹。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.repeat_circle_edge(ctl_rect.size,10,10,ShapePoints.SIDE_LEFT)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
repeat_circle_edge_rect(size:Vector2,r:float,space:float,concave:bool) -> PackedVector2Array
返回带重复半圆花边的矩形。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.repeat_circle_edge_rect(ctl_rect.size,10,10)
draw_polyline(points,Color.WHITE,2)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
repeat_circle_edge_rect(ctl_rect.size,10,10,true)
网格点、网格十字和棋盘格
line_cross(position:Vector2,length:float,start_angle:int) -> Array
这是是描述。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.line_cross(ctl_rect.get_center(),10,0)
draw_polyline(points[0],Color.WHITE,2) # 绘制水平线
draw_polyline(points[1],Color.WHITE,2) # 绘制垂直线
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
在控件中心绘制一个白色十字:
checker_board_rects(size:Vector2,cell_size:Vector2) -> Array
返回棋盘格矩形集合。返回一个包含2个Array[Rect2]
的数组。第1个数组存储所有空心矩形,第2个数组存储所有实心矩形。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var rects = ShapePoints.checker_board_rects(Vector2(10,10),ctl_rect.size/10.0)
for rect in rects[0]:
draw_rect(rect,Color.WHITE,false,1)
for rect in rects[1]:
draw_rect(rect,Color.WHITE,true,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
创建了一个始终随控件大小自适应的棋盘格,划分为10行10列:
rect_grid_points(size:Vector2,cell_size:Vector2) -> PackedVector2Array
返回矩形网格的所有顶点的位置。至于绘制什么,你可以自己说了算。
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var points = ShapePoints.rect_grid_points(Vector2(10,10),ctl_rect.size/10.0)
for point in points:
draw_circle(point,5,Color.WHITE)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
依然是10
行10
列网格,所有顶点绘制为半径5
像素,填充白色的圆:
rect_grid_lines(size:Vector2,cell_size:Vector2) -> Dictionary
返回矩形网格的水平线和垂直线集合。
lines["h_lines"]
:包含多个[p1,p2]
,也就是水平线段起止点信息的数组lines["v_lines"]
:包含多个[p1,p2]
,也就是垂直线段起止点信息的数组
@tool
extends Control
func _draw():
var ctl_rect = get_draw_safety_rect()
var r1 = ctl_rect.size.y/2.0
var lines = ShapePoints.rect_grid_lines(Vector2(10,10),ctl_rect.size/10.0)
for line in lines["h_lines"]:
draw_line(line[0],line[1],Color.WHITE,1)
# 获取绘制函数能正确使用的控件Rect2
func get_draw_safety_rect() -> Rect2:
var rect = get_rect()
return Rect2(rect.position - position,rect.size/scale)
只绘制横线:
绘制横线和竖线:
for line in lines["h_lines"]:
draw_line(line[0],line[1],Color.WHITE,1)
for line in lines["v_lines"]:
draw_line(line[0],line[1],Color.WHITE,1)
triangle_grid_points(size:Vector2,cell_size:Vector2) -> PackedVector2Array
这是是描述。2024年3月18日01:21:03,等待继续书写
hex_grid_points(size:Vector2,cell_size:Vector2) -> PackedVector2Array
这是是描述。
刻度线求取函数
arc_scale(start_angle:int,end_angle:int,steps:int,r:float,length:float) -> Array
这是是描述。
line_scale(ruler_width:float,steps:int,length:float) -> void
这是是描述。
连线和箭头求取函数
待扩展。
源代码
以下是完整源代码:
# ========================================================
# 名称:ShapePoints
# 类型:静态函数库
# 简介:用于生成常见几何图形的顶点数据(PackedVector2Array)
# 可用于_draw和Line2D、Polygon2D等进行绘制和显示
# 作者:巽星石
# Godot版本:4.1-stable (official) --> v4.2.1.stable.official [b09f793f5]
# 创建时间:2023-07-08 20:45:22
# 最后修改时间:2024年3月18日01:20:17
# ========================================================
class_name ShapePoints
# 返回矩形的顶点
static func rect(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array = [
offset,
offset + Vector2.RIGHT * size.x,
offset + size,
offset + Vector2.DOWN * size.y,
offset]
return points
# 返回正多边形顶点
static func regular_polygon(start_angle:int,edges:int,r:float,offset:Vector2 = Vector2.ZERO):
var points:PackedVector2Array
var vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * r
for i in range(edges):
points.append(vec.rotated(2* PI/edges * i) + offset)
points.append(points[0]) # 返回第一个点
return points
# 返回圆顶点
static func circle(r:float,offset:Vector2 = Vector2.ZERO):
var points = regular_polygon(0,2 * PI * r,r,offset)
points.append(points[0])
return points
# 返回扇形顶点
# 注意start_angle和end_angle都是角度
static func sector(start_angle:int,end_angle:int,r:float,offset:Vector2 = Vector2.ZERO):
var points:PackedVector2Array
points.append(Vector2.ZERO + offset)
points.append_array(arc(start_angle,end_angle,r,offset))
points.append(Vector2.ZERO + offset)
return points
# 弧形
# 注意start_angle和end_angle都是角度
static func arc(start_angle:int,end_angle:int,r:float,offset:Vector2 = Vector2.ZERO):
var points:PackedVector2Array
var angle = deg_to_rad(end_angle - start_angle)
var edges:float = ceilf(angle * r) # 要绘制的点的个数 = θ * r
var vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * r
for i in range(edges+1):
points.append(vec.rotated(angle/edges * i) + offset)
return points
# 星形
static func star(start_angle:int,edges:int,r1:float,r2:float = r1/2.0,offset:Vector2 = Vector2.ZERO):
var points:PackedVector2Array
# 外部半径
var vec = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * r1
# 内部半径
var vec2 = Vector2.RIGHT.rotated(deg_to_rad(start_angle + 180/edges)) * r2
for i in range(edges):
points.append(vec.rotated(2 * PI/edges * i) + offset)
points.append(vec2.rotated(2 * PI/edges * i) + offset)
points.append(points[0]) # 返回第一个点
return points
# 返回圆角矩形的顶点
# 注意:以(0,0)为几何中心
static func round_rect(size:Vector2,r1:float,r2:float,r3:float,r4:float,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array
points.append_array(arc(180,270,r1,Vector2(r1,r1) + offset))
points.append_array(arc(270,360,r2,Vector2(size.x - r2,r2) + offset))
points.append_array(arc(0,90,r3,Vector2(size.x - r3,size.y -r3) + offset))
points.append_array(arc(90,180,r4,Vector2(r4,size.y - r4) + offset))
points.append(Vector2(0,r1)+offset)
return points
# 返回倒角矩形的顶点
# 注意:以(0,0)为几何中心
static func chamfer_rect(size:Vector2,a:float,b:float,c:float,d:float,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array = [
Vector2(0,a) + offset,Vector2(a,0) + offset,
Vector2(size.x-b,0) + offset,Vector2(size.x,b) + offset,
Vector2(size.x,size.y-c) + offset,Vector2(size.x-c,size.y) + offset,
Vector2(d,size.y) + offset,Vector2(0,size.y-d) + offset
]
points.append(points[0]) # 闭合
return points
# 返回胶囊形的顶点
static func capsule(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array = []
var r:float = min(size.x,size.y)/2.0
if size.x>size.y: # 横向
points.append_array(arc(90,270,r,Vector2(r,r) + offset))
points.append_array(arc(-90,90,r,Vector2(size.x-r,r) + offset))
else: # 纵向
points.append_array(arc(180,360,r,Vector2(r,r) + offset))
points.append_array(arc(0,180,r,Vector2(r,size.y-r) + offset))
points.append(points[0]) # 闭合
return points
# 返回梭形的顶点
# 注意:以(0,0)为几何中心
static func spindle(size:Vector2,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array = []
var dx:float = size.x/2.0
var dy:float = size.y/2.0
var d_max = max(dx,dy)
var d_min = min(dx,dy)
var r = (pow(d_max,2.0) + pow(d_min,2.0))/(2.0 * d_min) # 圆弧半径
var angle = rad_to_deg(asin(d_max/r))
if dx<dy:
points.append_array(arc(180-angle,180+angle,r,Vector2(r,dy)))
points.append(Vector2(dx,0))
points.append_array(arc(-angle,angle,r,Vector2(-r+2*dx+1,dy)))
points.append(points[0]) # 闭合
else:
points.append_array(arc(270-angle,270+angle,r,Vector2(dx,r)))
points.append(Vector2(size.x,dy))
points.append_array(arc(90-angle,90+angle,r,Vector2(dx,-r+2*dy+1)))
points.append(points[0]) # 闭合
return points
# =================================== 特殊图形 ===================================
# 太极
static func taiji(r:float,offset:Vector2 = Vector2.ZERO) -> Dictionary:
var dict = {
pan = circle(r,offset), # 底部圆盘
yin = [], # 阴鱼
yang = [], # 阳鱼
yin_eye = circle(r/10,Vector2(0,-r/2)+ offset), # 阴鱼眼
yang_eye = circle(r/10,Vector2(0,r/2)+ offset), # 阳鱼眼
}
# 阴鱼
dict["yin"].append_array(arc(90,270,r,offset))
dict["yin"].append_array(arc(-90,90,r/2,Vector2(0,-r/2)+offset))
var ac = arc(90,270,r/2,Vector2(0,r/2)+offset)
ac.reverse()
dict["yin"].append_array(ac)
# 阳鱼
dict["yang"].append_array(arc(-90,90,r,offset))
dict["yang"].append_array(arc(90,270,r/2,Vector2(0,r/2)+offset))
var ac2 = arc(-90,90,r/2,Vector2(0,-r/2)+offset)
ac2.reverse()
dict["yang"].append_array(ac2)
return dict
# 螺旋线
static func helix(start_angle:int,start_r:float,end_r:float,
step:int =1,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array
var steps = end_r - start_r
for i in range(steps):
points.append(Vector2.RIGHT.rotated(deg_to_rad(start_angle + step * i)) * (start_r+i) + offset)
return points
# =================================== 花边图形 ===================================
enum{
AXIS_X = 1,
AXIS_Y = 2,
}
# 返回与实际矩形不相关的重复半圆边数据
static func repeat_circle(length:float,r:float,space:float = 0,axis:int = AXIS_X,concave:bool = false,reverse:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array
match axis:
AXIS_X: # 水平方向
var yu = fmod(length,(2.0 * r + space)) # 余数
if !concave: # 凸出
points.append(Vector2.ZERO + offset)
for i in floorf(length/(2.0 * r + space)):
points.append_array(arc(180,360,r,Vector2(2 * r + space,0) * i + Vector2(r + yu/2.0,0) + offset))
points.append(Vector2(length,0) + offset)
else: # 凹进去
points.append(Vector2.ZERO + offset)
for i in floorf(length/(2.0 * r + space)):
var ac = arc(0,180,r,Vector2(2 * r + space,0) * i + Vector2(r + yu/2.0,0) + offset)
ac.reverse()
points.append_array(ac)
points.append(Vector2(length,0) + offset)
AXIS_Y: # 垂直方向
var yu = fmod(length,(2.0 * r + space)) # 余数
if !concave: # 凸出
points.append(Vector2.ZERO + offset)
for i in floorf(length/(2.0 * r + space)):
points.append_array(arc(-90,90,r,Vector2(0,2 * r + space) * i + Vector2(0,r + yu/2.0) + offset))
points.append(Vector2(0,length) + offset)
else: # 凹进去
points.append(Vector2.ZERO + offset)
for i in floorf(length/(2.0 * r + space)):
var ac = arc(90,270,r,Vector2(0,2 * r + space) * i + Vector2(0,r + yu/2.0) + offset)
ac.reverse()
points.append_array(ac)
points.append(Vector2(0,length) + offset)
# 是否逆序所有点
if reverse:
points.reverse()
return points
enum{
SIDE_UP = 1,
SIDE_RIGHT = 2,
SIDE_BOTTOM = 3,
SIDE_LEFT = 4
}
# 返回边线重复半圆的矩形的边
static func repeat_circle_edge(size:Vector2,r:float,space:float = 0,side:int = SIDE_UP,concave:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array
match side:
SIDE_UP:
points.append_array(repeat_circle(size.x,r,space,AXIS_X,concave))
SIDE_RIGHT:
points.append_array(repeat_circle(size.y,r,space,AXIS_Y,concave,false,Vector2(size.x,0)))
SIDE_LEFT:
points.append_array(repeat_circle(size.y,r,space,AXIS_Y,!concave,true))
SIDE_BOTTOM:
points.append_array(repeat_circle(size.x,r,space,AXIS_X,!concave,true,Vector2(0,size.y)))
return points
# 返回边线重复半圆的矩形的边
static func repeat_circle_edge_rect(size:Vector2,r:float,space:float = 0,concave:bool = false,offset:Vector2 = Vector2.ZERO) -> PackedVector2Array:
var points:PackedVector2Array
points.append_array(repeat_circle_edge(size,r,space,SIDE_UP,concave,offset))
points.append_array(repeat_circle_edge(size,r,space,SIDE_RIGHT,concave,offset))
points.append_array(repeat_circle_edge(size,r,space,SIDE_BOTTOM,concave,offset))
points.append_array(repeat_circle_edge(size,r,space,SIDE_LEFT,concave,offset))
return points
# 返回指定点为中心,给定长度的两条互相垂直线段,可以用于绘制十字坐标线
static func line_cross(position:Vector2,length:float,start_angle:int = 0) -> Array:
var start_rad = deg_to_rad(start_angle)
# 水平线段俩端点
var h_line = [
Vector2.LEFT.rotated(start_rad) * length/2.0 + position,
Vector2.RIGHT.rotated(start_rad) * length/2.0 + position,
]
# 水平线段俩端点
var v_line = [
Vector2.UP.rotated(start_rad) * length/2.0 + position,
Vector2.DOWN.rotated(start_rad) * length/2.0 + position,
]
return [h_line,v_line]
# =================================== 网格矩形求取函数 ===================================
# 矩形网格 - 棋盘格矩形求取函数
static func checker_board_rects(size:Vector2,cell_size:Vector2) -> Array:
var rects_yang:Array[Rect2]
var rects_yin:Array[Rect2]
for x in range(size.x):
for y in range(size.y):
var pos = Vector2(x,y) * cell_size
if (x % 2 == 0 and y % 2 == 0) or (x % 2 == 1 and y % 2 == 1):
rects_yang.append(Rect2(pos,cell_size))
else:
rects_yin.append(Rect2(pos,cell_size))
return [rects_yang,rects_yin]
# =================================== 网格线和点求取函数 ===================================
# 方形 - 网格点求取函数
static func rect_grid_points(size:Vector2,cell_size:Vector2) ->PackedVector2Array:
var points:PackedVector2Array
for x in range(size.x + 1):
for y in range(size.y + 1):
points.append(Vector2(x,y) * cell_size)
return points
# 三角 - 网格点求取函数
static func triangle_grid_points(size:Vector2,cell_size:Vector2) ->PackedVector2Array:
var points:PackedVector2Array
for y in range(size.y + 1):
if y % 2 == 0: # 偶数行
for x in range(size.x + 1):
points.append(Vector2(x,y) * cell_size)
else: # 奇数行
for x in range(size.x):
points.append(Vector2(x,y) * cell_size + Vector2(cell_size.x/2,0))
return points
# 六边形 - 网格点求取函数
static func hex_grid_points(size:Vector2,cell_size:Vector2) ->PackedVector2Array:
var points:PackedVector2Array
for y in range(size.y + 1):
if y % 2 == 0: # 偶数行
for x in range(size.x):
if (x+1)% 3 != 0:
points.append(Vector2(x,y) * cell_size + Vector2(cell_size.x/2,0))
else: # 奇数行
for x in range(size.x + 1):
if x % 3 != 1:
points.append(Vector2(x,y) * cell_size)
return points
# 方形 - 网格线求取函数
static func rect_grid_lines(size:Vector2,cell_size:Vector2) -> Dictionary:
var lines = {
v_lines = [], # 垂直的网格线
h_lines = [] # 水平的网格线
}
var v_line1 = [Vector2.ZERO,Vector2.DOWN * cell_size.y * size.y]
var h_line1 = [Vector2.ZERO,Vector2.RIGHT * cell_size.x * size.x]
lines["v_lines"].append(v_line1)
lines["h_lines"].append(h_line1)
for x in range(1,size.x+1):
var offset_x = Vector2(cell_size.x,0) * x
lines["v_lines"].append([v_line1[0] + offset_x,v_line1[1] + offset_x])
for y in range(1,size.y+1):
var offset_y = Vector2(0,cell_size.y) * y
lines["h_lines"].append([h_line1[0] + offset_y,h_line1[1] + offset_y])
return lines
# =================================== 刻度线生成 ===================================
# 返回指定范围的弧形刻度线起始点坐标集合
# start_angle:起始角度
# end_angle:结束角度
# steps:切分次数
# r:半径
# length:刻度线长
static func arc_scale(start_angle:int,end_angle:int,steps:int,r:float,length:float) -> Array:
var scales:Array = []
var vec1 = (Vector2.RIGHT * (r-length)).rotated(deg_to_rad(start_angle))
var vec2 = (Vector2.RIGHT * r).rotated(deg_to_rad(start_angle))
var angle = deg_to_rad(end_angle - start_angle) # 夹角
for i in range(steps+1):
var line = [vec1.rotated((angle/steps) * i),vec2.rotated((angle/steps) * i)]
scales.append(line)
return scales
# 返回指定范围的直线刻度线起始点坐标集合
static func line_scale(ruler_width:float,steps:int,length:float):
var scales:Array = []
var vec1 = Vector2.ZERO
var vec2 = Vector2.DOWN * length
var space = ruler_width/steps # 单位间隔
for i in range(steps+1):
var line = [vec1 + Vector2(space,0) * i,vec2 + Vector2(space,0) * i]
scales.append(line)
return scales