【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 Controlfunc _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 Controlfunc _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 Controlfunc _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 Controlfunc _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 Controlfunc _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 Controlfunc _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 Controlfunc _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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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 Controlfunc _draw():var ctl_rect = get_draw_safety_rect()var r1 = ctl_rect.size.y/2.0var 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:PackedVector2Arrayvar vec  = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * rfor 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:PackedVector2Arraypoints.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:PackedVector2Arrayvar angle = deg_to_rad(end_angle - start_angle)var edges:float = ceilf(angle * r) # 要绘制的点的个数 = θ * rvar vec  = Vector2.RIGHT.rotated(deg_to_rad(start_angle)) * rfor 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)) * r2for 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:PackedVector2Arraypoints.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.0if 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.0var dy:float = size.y/2.0var 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:PackedVector2Arrayvar steps = end_r - start_rfor 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:PackedVector2Arraymatch 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:PackedVector2Arraymatch 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:PackedVector2Arraypoints.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_sizeif (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:PackedVector2Arrayfor 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:PackedVector2Arrayfor 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:PackedVector2Arrayfor 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) * xlines["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) * ylines["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.ZEROvar vec2 = Vector2.DOWN * lengthvar 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

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

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

相关文章

从JVM的退出机制分析Java程序的优雅关闭退出

前言 Java程序启动从main函数开始启动&#xff0c;是程序入口和主线程&#xff0c;但程序会在什么时候结束&#xff1f;为什么有的Java程序在启动后很快就结束了&#xff0c;比如HelloWorld程序&#xff0c;有的程序却能一直在运行&#xff0c;比如Tomcat启动后就一直保持进程…

c++中的类型转换(4种转换方式)

小编学习网站&#xff1a;https://www.ctvol.com 在C中&#xff1a; (类型) 强制类型转换 在c中&#xff1a; 1.static_cast<类型>(变量) 在某一个方向上 可以做隐式类型转换 int *pi new int(100); void *pvpi; 2.dynamic_cast<类型>(变量) 用在具有多态性…

odoo17开发教程(8):设置界面UI的字段属性

目录 添加字段 给字段设置只读和不可拷贝 给字段添加默认值 保留字段 本节目标&#xff1a;在本文末尾&#xff0c;售价(selling price)应为只读值&#xff0c;卧室数量(bedrooms)和可用日期(availability date)应为默认值。此外&#xff0c;在复制记录时&#xff0c;售价和…

【解读】保障软件供应链安全:SBOM推荐实践指南(含指南获取链接)

2023年11底&#xff0c;美国NSA&#xff08;National Security Agency&#xff09;、CISA&#xff08;Cybersecurity and Infrastructure Security Agency&#xff09;等多个政府机构部门组成的ESF&#xff08;Enduring Security Framework&#xff0c;持久安全框架&#xff09…

Linux服务器搭建笔记-007:为每位用户创建硬盘配额

一、问题说明 Ubuntu服务器在使用过程中创建的新用户&#xff0c;每位用户会在/home目录下生成一个属于其个人的主文件夹。如果不限制各个用户的使用空间&#xff0c;所有的用户都会共用/home所挂载的硬盘。在这种多用户情况下&#xff0c;会很快的填满/home目录&#xff0c;导…

OGRE Pittfals Design proposal for Ogre 2.0

OGRE Pittfals & Design proposal for Ogre 2.0

小程序开发——设备属性和设备移除 API汇总

设备属性API ty.device.setDeviceProperty 设置设备属性 需引入DeviceKit&#xff0c;且在>1.2.6版本才可使用 请求参数 Object object 属性类型默认值必填说明deviceIdstring是deviceIdcodestring是the custom data keyvaluestring是the custom data valuecompletefunc…

Python的网络爬虫介绍与实战

Python的网络爬虫基础介绍与实战 定义流程包和函数静动态网页爬虫实战红牛分公司&#xff1f;二手房数据&#xff08;静态网页&#xff09;豆瓣读书&#xff08;动态网页&#xff09; 定义 网络爬虫是按照一定的规则&#xff0c;自动地抓取万维网&#xff08;www&#xff09;信…

rust引用本地crate

我们可以动态引用crate&#xff0c;build时从crate.io下载&#xff0c;但可能因无法下载导致build失败。首次正常引用三方crate&#xff0c;build时自动下载的crate源码&#xff0c;我们将其拷贝到固定目录中&#xff1b; build后可在RustRover中按住Ctrl键&#xff0c;在crat…

图解Kafka架构学习笔记(一)

本文参考尚硅谷大数据技术之Kafka。 消息队列 &#xff08;1&#xff09;点对点模式&#xff08;一对一&#xff0c;消费者主动拉取数据&#xff0c;消息收到后消息清除&#xff09; 点对点模型通常是一个基于拉取或者轮询的消息传送模型&#xff0c;这种模型从队列中请求信息…

基于Spark的气象数据处理与分析

文章目录 一、实验环境二、实验数据介绍三、数据获取1.观察数据获取方式2.数据爬取3.数据存储4.数据读取5.数据结构6.爬虫过程截图 四、数据分析1.计算各个城市过去24小时累积雨量2.计算各个城市当日平均气温3.计算各个城市当日平均湿度4.计算各个城市当日平均风速 五、数据可视…

流媒体学习之路(WebRTC)——FEC逻辑分析(6)

流媒体学习之路(WebRTC)——FEC逻辑分析&#xff08;6&#xff09; —— 我正在的github给大家开发一个用于做实验的项目 —— github.com/qw225967/Bifrost目标&#xff1a;可以让大家熟悉各类Qos能力、带宽估计能力&#xff0c;提供每个环节关键参数调节接口并实现一个json全…

springboot/ssm冷链物流系统Java在线物流管理系统web物流平台

springboot/ssm冷链物流系统Java在线物流管理系统web物流平台 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;…

ARM_基础之RAS

Reliability, Availability, and Serviceability (RAS), for A-profile architecture 源自 https://developer.arm.com/documentation/102105/latest/ 1 Introduction to RAS 1.1 Faults,Errors,and failures 三个概念的区分&#xff1a; • A failure is the event of devia…

保研|资讯|夏令营|3.31截止!香港城市大学市场营销学系首届学术暑期夏令营

香港城市大学市场营销学系首届学术暑期夏令营 1 项目简介 我们的博士项目致力为未来营销科学和工商管理学界培养一流学者和行业领袖。博士项目一般为期四到六年&#xff0c;允许本科生直接申请。课程包括实证分析模型&#xff0c;消费者行为研究&#xff0c;博弈微观模型&…

从零开始学习数据结构与算法:Python实现【第139篇—Python实现】

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 从零开始学习数据结构与算法&#xff1a;Python实现 数据结构与算法是计算机科学中至关重要…

Redis7学习记录(1)

Redis入门概述 Redis介绍 Redis&#xff1a;REmote Dictionary Server&#xff08;远程字典服务器&#xff09; 官网&#xff1a;Redis 中文官网&#xff1a;Redis中文网 Redis的功能及应用 redis是基于内存的KV键值对内存数据库。 redis是key-value数据库&#xff08;NO…

[VCTF2024纳新赛]-PWN:ezhp_code解析

查看保护 查看ida 简单来说就是创建堆块和删除堆块而已&#xff0c;创建堆块的函数附带有写入函数。 但这里要注意一个程序里面的特殊的地方 在我们创建堆块时&#xff0c;程序会先创建一个0xa0大小堆块&#xff0c;并且这个地方还有个特殊的check_handle函数&#xff0c;如果…

测试人员Bug书写规范

&#x1f4cb; 个人简介 作者简介&#xff1a;大家好&#xff0c;我是凝小飞&#xff0c;软件测试领域作者支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; 在测试人员日常工作中&#xff0c;关于bug的编写和定义是一个比较经常的工作&#xff0c;如果bug编写描…

使用Thymeleaf导出PDF,页眉插入图片与内容重叠?

CSS 打印分页功能 需求&#xff1a;打印 在第一页的内容被挤到第二页的时候&#xff0c;又想每一页页头都有相同的样式&#xff0c;使用页眉。 问题&#xff1a;第二页的内容与页眉重叠了&#xff1f; 查各路找出的原因&#xff1a;header 页眉不占空间 解决&#xff1a;不…