120 lines
4.2 KiB
GDScript
120 lines
4.2 KiB
GDScript
extends RefCounted
|
|
class_name VizCompoundLeg
|
|
|
|
var _error : String = ""
|
|
var _begin : VisualizationSpot
|
|
var _end : VisualizationSpot
|
|
var _width : float
|
|
var _bend_lip : float
|
|
var _intermediate_spot : VisualizationSpot = null
|
|
var _norm_distance : float
|
|
var _max_join_point_on_begin : Vector3
|
|
var _max_join_point_on_end : Vector3
|
|
|
|
func _init(p_begin : VisualizationSpot, p_end : VisualizationSpot, p_width : float, p_bend_lip : float):
|
|
_begin = p_begin
|
|
_end = p_end
|
|
_width = p_width
|
|
_bend_lip = p_bend_lip
|
|
_calc_intermediate_point()
|
|
# _calc_max_offset()
|
|
_calc_intermediate_normal()
|
|
|
|
func _to_string():
|
|
return "CLEG(%s to %s through %s)" % [_begin, _end, _intermediate_spot]
|
|
|
|
# ---------------------------------------------
|
|
# Public Methoeds
|
|
|
|
func is_invalid() -> bool:
|
|
return _error != ""
|
|
|
|
func get_error() -> String:
|
|
return _error
|
|
|
|
func get_begin() -> VisualizationSpot:
|
|
return _begin
|
|
|
|
func get_begin_ray() -> Vector3:
|
|
return (_max_join_point_on_begin - _begin.point).normalized()
|
|
|
|
func adjust_begin(distance : float):
|
|
var new_begin := VisualizationSpot.new()
|
|
new_begin.point = _begin.point + distance * get_begin_ray()
|
|
new_begin.normal = _begin.normal
|
|
_begin = new_begin
|
|
_calc_intermediate_normal()
|
|
|
|
func get_end() -> VisualizationSpot:
|
|
return _end
|
|
|
|
func get_end_ray() -> Vector3:
|
|
return (_end.point - _max_join_point_on_end).normalized()
|
|
|
|
func adjust_end(distance : float):
|
|
var new_end := VisualizationSpot.new()
|
|
new_end.point = _end.point - distance * get_end_ray()
|
|
new_end.normal = _end.normal
|
|
_end = new_end
|
|
_calc_intermediate_normal()
|
|
|
|
var test_mat : Material = load("res://example/common/materials/white.tres")
|
|
|
|
func update_mesh(mesh_node : Node3D, u : float, segs : int, sharpness : float, mat : Material) -> float:
|
|
var leg1 := VizSimpleLeg.new(_begin, _intermediate_spot, _width, _bend_lip)
|
|
if leg1.is_invalid():
|
|
print("leg1=%s: error=%s" % [ leg1, leg1.get_error() ])
|
|
assert(!leg1.is_invalid())
|
|
var leg2 := VizSimpleLeg.new(_intermediate_spot, _end, _width, _bend_lip)
|
|
if leg2.is_invalid():
|
|
print("leg2: error=%s" % leg2.get_error())
|
|
assert(!leg2.is_invalid())
|
|
u = leg1.update_mesh(mesh_node, u, segs, sharpness, mat)
|
|
var left := leg1.get_end_left()
|
|
var right := leg1.get_end_right()
|
|
u = leg2.extend_mesh(mesh_node, u, left, right, segs, sharpness, mat)
|
|
return u
|
|
|
|
# ---------------------------------------------
|
|
# Local Methods
|
|
|
|
func _calc_intermediate_point():
|
|
_intermediate_spot = VisualizationSpot.new()
|
|
var intermediate_segment := _end.point - _begin.point
|
|
_intermediate_spot.point = _begin.point + intermediate_segment / 2.0
|
|
|
|
func _calc_intermediate_normal():
|
|
var begin_plane := Plane(_begin.normal, _begin.point)
|
|
var max_point := begin_plane.project(_intermediate_spot.point)
|
|
# var mid_point_distance := _intermediate_spot.point.distance_to(max_point)
|
|
var mid_point_distance := _begin.point.distance_to(max_point)
|
|
var cur_norm_distance = _bend_lip + VizSimpleLeg.MIN_SEGMENT_LENGTH
|
|
var dir := (max_point - _begin.point).normalized()
|
|
var valid := false
|
|
while cur_norm_distance < mid_point_distance:
|
|
var data := _check_normal(dir, cur_norm_distance)
|
|
if data.size() == 3:
|
|
_max_join_point_on_begin = data[0]
|
|
_max_join_point_on_end = data[1]
|
|
_intermediate_spot.normal = data[2]
|
|
valid = true
|
|
break
|
|
cur_norm_distance += 0.01
|
|
if not valid:
|
|
_error = "%s is too close to %s to make compund leg with lip %s" % [ _begin.point, _end.point, _bend_lip ]
|
|
|
|
func _check_normal(dir : Vector3, norm_distance : float) -> Array:
|
|
var candidate_segment := _intermediate_spot.point - (_begin.point + norm_distance * dir)
|
|
var candidate_segment_dir := candidate_segment.normalized()
|
|
var candidate_normal := ((_begin.normal + _end.normal)/2.0).normalized()
|
|
var candidate_binormal := candidate_normal.cross(candidate_segment_dir).normalized()
|
|
var candidate_mid := VisualizationSpot.new()
|
|
candidate_mid.point = _intermediate_spot.point
|
|
candidate_mid.normal = candidate_segment_dir.cross(candidate_binormal).normalized()
|
|
var leg1 := VizSimpleLeg.new(_begin, candidate_mid, _width, _bend_lip)
|
|
if not leg1.is_invalid():
|
|
var leg2 := VizSimpleLeg.new(candidate_mid, _end, _width, _bend_lip)
|
|
if not leg2.is_invalid():
|
|
return [ leg1.get_leg_bend_begin(), leg2.get_leg_bend_end(), candidate_mid.normal ]
|
|
return []
|
|
|