【Godot4.3】三角形类
概述
在GDSCript中你想要表示一个平面三角形,只需要设定3个点的位置,也就是3个Vector2
就行了,或者一个size()==3
的PackedVector2Array
。
但是想要进一步处理三角形,获得它的一些几何特征,比如:某个内角的角度值,角平分线、垂直平分线、中线、高线,还有对应的内接圆、外接圆圆心与半径等,就会变得比较困难。
本篇就讲述如何在Godot4.3中,用类来表示三角形,并获取它的几何特征。
类设计
Triangle
类用于表示一个二维平面的三角形,可以获取内接圆、外接圆圆心与半径Angle
类用来表示一个角,可以获取角平分线、中线和高线Segment
类用来表示线段,比如三角形的边,可以获取垂直平分线
目前的设计只是一个初步实现,进一步可能会修改或添加一些方法。
三角形
# 三角形
class Triangle:
var point_a:Vector2
var point_b:Vector2
var point_c:Vector2
func _init(point_a:Vector2,point_b:Vector2,point_c:Vector2) -> void:
self.point_a = point_a
self.point_b = point_b
self.point_c = point_c
# 获取三角形的点集
func get_points() -> PackedVector2Array:
var points:PackedVector2Array
points.append_array([point_a,point_b,point_c,point_a])
return points
# 获取角A
func get_angle_a() -> Angle:
return Angle.new(point_a,point_b,point_c)
# 获取角B
func get_angle_b() -> Angle:
return Angle.new(point_b,point_a,point_c)
# 获取角C
func get_angle_c() -> Angle:
return Angle.new(point_c,point_a,point_b)
# 重心 - 任意两条中线的交点
func gravity_center():
var s1 = get_angle_a().get_mid_line()
var s2 = get_angle_b().get_mid_line()
return Geometry2D.line_intersects_line(s1.start,s1.vec().normalized(),s2.start,s2.vec().normalized())
# 垂心 - 任意两条垂线的交点
func high_center():
var s1 = get_angle_a().get_high_line()
var s2 = get_angle_b().get_high_line()
return Geometry2D.line_intersects_line(s1.start,s1.vec().normalized(),s2.start,s2.vec().normalized())
# 外心 - 任意两条垂直平分线的交点
func out_center():
var s1 = get_angle_a().seg_ab().mid_vertical_line()
var s2 = get_angle_a().seg_bc().mid_vertical_line()
return Geometry2D.line_intersects_line(s1.start,s1.vec().normalized(),s2.start,s2.vec().normalized())
# 外接圆半径 - 外心与三个顶点距离中最长的一个
func out_radius():
var c:Vector2 = out_center()
# 外心与各顶点的距离
var m:float = minf(c.distance_to(point_a),c.distance_to(point_b))
m = minf(m,c.distance_to(point_c))
return m
# 内心(内接圆圆心) - 任意两条角平分线的交点
func inner_center() :
var s1 = get_angle_a().get_half_angle_line()
var s2 = get_angle_b().get_half_angle_line()
return Geometry2D.line_intersects_line(s1.start,s1.vec().normalized(),s2.start,s2.vec().normalized())
# 内接圆半径 - 内心在三条角平分线上短的那段的长度中最短的一个
func inner_radius():
var c:Vector2 = inner_center()
# 内心与各边的垂直相交点
var p1:Vector2 = Geometry2D.get_closest_point_to_segment(c,point_a,point_b)
var p2:Vector2 = Geometry2D.get_closest_point_to_segment(c,point_a,point_c)
var p3:Vector2 = Geometry2D.get_closest_point_to_segment(c,point_b,point_c)
var m:float = minf(c.distance_to(p1),c.distance_to(p2))
m = minf(m,c.distance_to(p3))
return m
角
# 内角
class Angle:
# 点
var point_a:Vector2
var point_b:Vector2
var point_c:Vector2
# 永远以point_a作为角的顶点
func _init(point_a:Vector2,point_b:Vector2,point_c:Vector2) -> void:
self.point_a = point_a
self.point_b = point_b
self.point_c = point_c
# 线段ab
func seg_ab() -> Segment:
return Segment.new(point_a,point_b)
# 线段ab
func seg_ac() -> Segment:
return Segment.new(point_a,point_c)
# 线段ab
func seg_bc() -> Segment:
return Segment.new(point_b,point_c)
# 获取夹角(弧度)
func angle() -> float:
return abs(seg_ab().vec().angle_to(seg_ac().vec()))
# 获取角平分线
func get_half_angle_line() -> Segment:
var ang = seg_ab().vec().angle_to(seg_ac().vec())
var len = maxf(seg_ab().vec().length(),seg_ac().vec().length()) # 取较长边长度
var p = point_a + seg_ab().vec().normalized().rotated(ang/2.0) * len
var p1 = Geometry2D.line_intersects_line(point_b,seg_bc().vec(),point_a,point_a.direction_to(p))
return Segment.new(point_a,p1)
# 获取中线
func get_mid_line() -> Segment:
return Segment.new(point_a,seg_bc().mid_point())
# 获取高线
func get_high_line() -> Segment:
var p = Geometry2D.get_closest_point_to_segment_uncapped(point_a,point_b,point_c)
return Segment.new(point_a,p)
线段
# 线段
class Segment:
var start:Vector2
var end:Vector2
func _init(p1:Vector2,p2:Vector2) -> void:
start = p1
end = p2
# 返回向量
func vec() -> Vector2:
return end - start
# 获取点集
func points() -> PackedVector2Array:
var arr:PackedVector2Array
arr.append_array([start,end])
return arr
# 获取中点
func mid_point() -> Vector2:
return start.lerp(end,0.5)
# 垂直平分线
func mid_vertical_line() -> Segment:
var half_normal = vec().rotated(deg_to_rad(90))/2.0
var p1 = mid_point() + half_normal
var p2 = mid_point() - half_normal
return Segment.new(p1,p2)
测试
创建和绘制三角形
extends Node2D
var t1:Triangle = Triangle.new(Vector2(100,100),Vector2(200,100),Vector2(150,200))
func _process(delta: float) -> void:
t1.point_c = get_global_mouse_position()
queue_redraw()
func _draw() -> void:
draw_polyline(t1.get_points(),Color.WHITE,1)
中线和重心
func _draw() -> void:
draw_polyline(t1.get_points(),Color.WHITE,1)
# 三条中线
var l1 = t1.get_angle_a().get_mid_line().points()
var l2 = t1.get_angle_b().get_mid_line().points()
var l3 = t1.get_angle_c().get_mid_line().points()
draw_polyline(l1,Color.AQUAMARINE,1)
draw_polyline(l2,Color.AQUAMARINE,1)
draw_polyline(l3,Color.AQUAMARINE,1)
# 重心
draw_circle(t1.gravity_center(),3,Color.BROWN)
角平分线和内心
func _draw() -> void:
draw_polyline(t1.get_points(),Color.WHITE,1)
# 三条角平分线
var l4 = t1.get_angle_a().get_half_angle_line().points()
var l5 = t1.get_angle_b().get_half_angle_line().points()
var l6 = t1.get_angle_c().get_half_angle_line().points()
draw_polyline(l4,Color.AQUAMARINE,1)
draw_polyline(l5,Color.AQUAMARINE,1)
draw_polyline(l6,Color.AQUAMARINE,1)
# 重心
draw_circle(t1.inner_center(),3,Color.BROWN)
draw_circle(t1.inner_center(),t1.inner_radius(),Color.YELLOW,false,1)
垂直平分线和外心
func _draw() -> void:
draw_polyline(t1.get_points(),Color.WHITE,1)
# 三条边的垂直平分线
var l4 = t1.get_angle_a().seg_ab().mid_vertical_line().points()
var l5 = t1.get_angle_a().seg_bc().mid_vertical_line().points()
var l6 = t1.get_angle_a().seg_ac().mid_vertical_line().points()
draw_polyline(l4,Color.AQUAMARINE,1)
draw_polyline(l5,Color.AQUAMARINE,1)
draw_polyline(l6,Color.AQUAMARINE,1)
# 外心
draw_circle(t1.out_center(),3,Color.BROWN)
draw_circle(t1.out_center(),t1.out_radius(),Color.YELLOW,false,1)
高线和垂心
func _draw() -> void:
draw_polyline(t1.get_points(),Color.WHITE,1)
# 三条边的垂直平分线
var l4 = t1.get_angle_a().get_high_line().points()
var l5 = t1.get_angle_b().get_high_line().points()
var l6 = t1.get_angle_c().get_high_line().points()
draw_polyline(l4,Color.AQUAMARINE,1)
draw_polyline(l5,Color.AQUAMARINE,1)
draw_polyline(l6,Color.AQUAMARINE,1)
# 垂心
if t1.high_center():
draw_circle(t1.high_center(),3,Color.BROWN)
总结
本文所述,是三角形几何特性获得的初步,API肯定会大改,只是作为初步试验成功的结果。
三角形是一种特殊的多边形,一些几何特性值得深入研究。