@tool extends Resource class_name SS2D_NormalRange ## This class will determine if the normal of a vector falls within the specifed angle ranges. ## ## - if begin and end are equal, any angle is considered to be within range [br] ## - 360.0 and 0.0 degrees are considered equivilent [br] @export_range (0, 360, 1) var begin: float = 0.0 : set = set_begin @export_range (0, 360, 1) var distance: float = 0.0 : set = set_distance # This is a hack to support the custom editor, needed a property # to exist to lock the TextureProgressBar to. Makes it flow better # in the Inspector. @export var edgeRendering: Vector2 func set_distance(f: float) -> void: distance = f emit_changed() func set_begin(f: float) -> void: begin = f emit_changed() func _to_string() -> String: return "NormalRange: %s - %s" % [begin, begin + distance] static func get_angle_from_vector(vec: Vector2) -> float: var normal: Vector2 = vec.normalized() # With respect to the X-axis # This is how Vector2.angle() is calculated, best to keep it consistent var comparison_vector := Vector2(1, 0) var ab: Vector2 = normal var bc: Vector2 = comparison_vector var dot_prod: float = ab.dot(bc) var determinant: float = (ab.x * bc.y) - (ab.y * bc.x) var angle: float = atan2(determinant, dot_prod) # This angle has a range of 360 degrees # Is between 180 and - 180 var deg: float = rad_to_deg(angle) # Get range between 0.0 and 360.0 if deg < 0: deg = 360.0 + deg return deg # Get in range between 0.0 and 360.0. static func _get_positive_angle_deg(degrees: float) -> float: while degrees < 0: degrees += 360 return fmod(degrees, 360.0) # Get in range between -360.0 and 360.0 static func _get_signed_angle_deg(degrees: float) -> float: var new_degrees: float = degrees while absf(new_degrees) > 360.0: new_degrees += (360.0 * signf(degrees) * -1.0) return new_degrees # Saving a scene with this resource requires a parameter-less init method func _init(_begin: float = 0.0, _distance: float = 0.0) -> void: _begin = SS2D_NormalRange._get_signed_angle_deg(_begin) _distance = SS2D_NormalRange._get_signed_angle_deg(_distance) begin = _begin distance = _distance func is_in_range(vec: Vector2) -> bool: # A Distance of 0 or 360 is the entire circle if distance == 0 or SS2D_NormalRange._get_positive_angle_deg(distance) == 360.0: return true var begin_positive: float = SS2D_NormalRange._get_positive_angle_deg(begin) var end_positive: float = SS2D_NormalRange._get_positive_angle_deg(begin + distance) # If positive, counter clockwise direction # If negative, clockwise direction var direction: float = signf(distance) var angle: float = SS2D_NormalRange.get_angle_from_vector(vec) # Swap begin and end if direction is negative if direction == -1: var t: float = begin_positive begin_positive = end_positive end_positive = t if begin_positive < end_positive: return ((angle >= begin_positive) and (angle <= end_positive)) else: return ((angle >= begin_positive) or (angle <= end_positive))