【Godot4.0】几何图形、网格、刻度线顶点求取函数库ShapePoints

概述

用于生成常见二维几何图形顶点数据PackedVector2Array)的静态函数库。
生成的数据可用于_drawLine2DPolygon2D等进行绘制和显示。

枚举

enum{
    AXIS_X = 1,
    AXIS_Y = 2,
}
enum{
    SIDE_UP = 1,
    SIDE_RIGHT = 2,
    SIDE_BOTTOM = 3,
    SIDE_LEFT = 4
}

测试场景

创建一个Control为根节点的场景。我们将基于这个空的控件,来实现绘图函数的测试。
image.png
在你的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)

绘制后的效果,无论是平移、旋转还是缩放,都可以看到矩形被正确绘制。
image.pngimage.png

使用ShapePoints的Rect函数

ShapePointsRect函数返回的是一个包含矩形的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)

image.png
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]),就可以绘制实心三角形。
image.pngimage.png
通过改变edges参数为4、5、6…可以创建正方形、正五边形、正六边形等等。
edges=4edges=5edges=6edges=12

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)

image.png

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高度一半的扇形:
image.png
sector(-120,45,ctl_rect.get_center().y,ctl_rect.get_center())则表示起始角度-120,结束角度45,半径为Control高度一半的扇形:
image.png

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高度一半的弧形:
image.png

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高度一半,内径为外径一半的五角星:
image.png
其他edges参数下生成的星形:
edges=4edges=6edges=12

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])后就是实心矩形:
image.pngimage.png
或者通过先draw_polygondraw_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)

image.png
可以设定四个圆角半径的数值不同:

round_rect(ctl_rect.size,10,20,40,100,ctl_rect.position)

image.png
也可以将圆角半径设为一个动态变化的比例值。

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)

image.png

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)

image.pngimage.png

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)

image.pngimage.png

特殊图形

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)

image.png
注意:目前版本有瑕疵,用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)

image.png

边线重复半圆花纹

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)

image.png
可以设定半圆之间的间隔:

repeat_circle(ctl_rect.size.x,10,10)

image.png
可以设定半圆是凸出还是凹进去:

repeat_circle(ctl_rect.size.x,10,10,true)

image.png
最后一个参数将点的位置全部逆序,可以用于拼接矩形。

repeat_circle(ctl_rect.size.x,10,10,true,true)

可以设定纵向:

repeat_circle(ctl_rect.size.y,10,0,ShapePoints.AXIS_Y)

image.png

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)

image.pngimage.png
image.pngimage.png

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)

image.png

repeat_circle_edge_rect(ctl_rect.size,10,10,true)

image.png

网格点、网格十字和棋盘格

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)

在控件中心绘制一个白色十字:
image.png

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列:
image.pngimage.pngimage.png

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)

依然是1010列网格,所有顶点绘制为半径5像素,填充白色的圆:
image.png

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)

只绘制横线:
image.png
绘制横线和竖线:

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)

image.png

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和Line2DPolygon2D等进行绘制和显示
# 作者:巽星石
# Godot版本:4.1-stable (official) --> v4.2.1.stable.official [b09f793f5]
# 创建时间:2023-07-08 20:45:22
# 最后修改时间:202431801: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
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巽星石

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值