102 lines
3.4 KiB
GDScript
102 lines
3.4 KiB
GDScript
extends RefCounted
|
|
class_name VizMid
|
|
|
|
var _seg1 : VizSegment
|
|
var _seg2 : VizSegment
|
|
var _width : float
|
|
var _inner_radius : float
|
|
|
|
var _rotation_point : VisualizationSpot
|
|
var _angle : float
|
|
var _error : String
|
|
|
|
func _init(p_seg1 : VizSegment, p_seg2 : VizSegment, p_stroke_width : float, p_inner_radius : float):
|
|
_seg1 = p_seg1
|
|
_seg2 = p_seg2
|
|
_width = p_stroke_width
|
|
_inner_radius = p_inner_radius
|
|
assert(p_seg1.get_end().is_equal(p_seg2.get_begin()))
|
|
_calc_rotation_point()
|
|
var center_distance := calc_center_distance(p_stroke_width, p_inner_radius)
|
|
var turn_distance := calc_turn_distance(center_distance, _angle)
|
|
p_seg1.adjust_end(turn_distance)
|
|
if p_seg1.is_invalid():
|
|
return
|
|
p_seg2.adjust_begin(turn_distance)
|
|
if p_seg2.is_invalid():
|
|
return
|
|
|
|
# ---------------------------------------------
|
|
# Public Methoeds
|
|
|
|
func is_invalid() -> bool:
|
|
return _error != ""
|
|
|
|
func get_error() -> String:
|
|
return _error
|
|
|
|
func update_mesh(_mesh_instance : MeshInstance3D, u : float, num_segs : int, mat : Material):
|
|
return _create_fan(_mesh_instance, u, num_segs, mat)
|
|
|
|
# ---------------------------------------------
|
|
# Private Methods
|
|
|
|
func _calc_rotation_point():
|
|
var seg1_ray := _seg1.get_end_ray()
|
|
var seg2_ray := _seg2.get_begin_ray()
|
|
_angle = seg1_ray.angle_to(seg2_ray)
|
|
var join_point := _seg1.get_end()
|
|
var plane_normal := seg1_ray.cross(seg2_ray).normalized()
|
|
if plane_normal == Vector3.ZERO:
|
|
plane_normal = join_point.normal
|
|
var binormal = plane_normal.cross(seg1_ray).normalized()
|
|
var d := calc_center_distance(_width, _inner_radius)
|
|
var e := calc_turn_distance(d, _angle)
|
|
_rotation_point = VisualizationSpot.new()
|
|
_rotation_point.point = join_point.point - e * seg1_ray + d * binormal
|
|
_rotation_point.normal = plane_normal
|
|
|
|
func _create_fan(mesh_node : Node3D, u : float, num_segs : int, mat : Material) -> float:
|
|
var radius := _width/2.0 + _inner_radius
|
|
var arc_len := absf(_angle) * radius
|
|
|
|
var begin_half_width := _seg1.get_end_binormal() * _width/2.0
|
|
var end_half_width := _seg2.get_begin_binormal() * _width/2.0
|
|
|
|
var st := SurfaceTool.new()
|
|
st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP)
|
|
st.set_color(Color(1, 0, 0))
|
|
st.set_normal(_seg1.get_end().normal)
|
|
|
|
st.set_uv(Vector2(u, 1))
|
|
st.add_vertex(_seg1.get_end().point + begin_half_width)
|
|
st.set_uv(Vector2(u, 0))
|
|
st.add_vertex(_seg1.get_end().point - begin_half_width)
|
|
|
|
var outer_base := _seg1.get_end().point + begin_half_width - _rotation_point.point
|
|
var inner_base := _seg1.get_end().point - begin_half_width - _rotation_point.point
|
|
for i in range(1, num_segs-1):
|
|
var cur_angle : float = _angle * float(i) / float(num_segs-1)
|
|
var cur_arc_len = absf(cur_angle) * radius
|
|
var inner := _rotation_point.point + inner_base.rotated(_rotation_point.normal, cur_angle)
|
|
var outer := _rotation_point.point + outer_base.rotated(_rotation_point.normal, cur_angle)
|
|
st.set_uv(Vector2(u+cur_arc_len, 1))
|
|
st.add_vertex(outer)
|
|
st.set_uv(Vector2(u+cur_arc_len, 0))
|
|
st.add_vertex(inner)
|
|
|
|
st.set_uv(Vector2(u+arc_len, 1))
|
|
st.add_vertex(_seg2.get_begin().point + end_half_width)
|
|
st.set_uv(Vector2(u+arc_len, 0))
|
|
st.add_vertex(_seg2.get_begin().point - end_half_width)
|
|
|
|
st.set_material(mat)
|
|
mesh_node.mesh = st.commit(mesh_node.mesh)
|
|
|
|
return u + arc_len
|
|
|
|
static func calc_center_distance(stroke_width : float, inner_radius : float) -> float:
|
|
return stroke_width / 2.0 + inner_radius
|
|
|
|
static func calc_turn_distance(center_distance : float, angle : float) -> float:
|
|
return center_distance * tan(abs(angle)/2.0)
|