88 lines
3.5 KiB
GDScript
88 lines
3.5 KiB
GDScript
extends FunctionPlotter
|
|
class_name ScatterPlotter
|
|
|
|
signal point_entered(point, function)
|
|
signal point_exited(point, function)
|
|
|
|
var points: Array[Point]
|
|
var points_positions: PackedVector2Array
|
|
var focused_point: Point
|
|
|
|
var point_size: float
|
|
|
|
func _init(function: Function) -> void:
|
|
super(function)
|
|
self.point_size = function.props.get("point_size", 3.0)
|
|
|
|
func _draw() -> void:
|
|
super._draw()
|
|
|
|
var box: Rect2 = get_box()
|
|
var x_sampled_domain: Dictionary = { lb = box.position.x, ub = box.end.x }
|
|
var y_sampled_domain: Dictionary = { lb = box.end.y, ub = box.position.y }
|
|
sample(x_sampled_domain, y_sampled_domain)
|
|
|
|
if function.get_marker() != Function.Marker.NONE:
|
|
for point in points:
|
|
# Don't plot points outside domain upper and lower bounds!
|
|
if point.position.y <= y_sampled_domain.lb and point.position.y >= y_sampled_domain.ub:
|
|
draw_function_point(point.position)
|
|
|
|
func sample(x_sampled_domain: Dictionary, y_sampled_domain: Dictionary) -> void:
|
|
points = []
|
|
points_positions = []
|
|
var lower_bound: int = max(0, function.__x.size() - get_chart_properties().max_samples) \
|
|
#disable sample display limits
|
|
if get_chart_properties().max_samples > 0 \
|
|
else 0
|
|
for i in range(lower_bound, function.__x.size()):
|
|
var _position: Vector2 = Vector2(
|
|
ECUtilities._map_domain(float(function.__x[i]), x_domain, x_sampled_domain),
|
|
ECUtilities._map_domain(float(function.__y[i]), y_domain, y_sampled_domain)
|
|
)
|
|
points.push_back(Point.new(_position, { x = function.__x[i], y = function.__y[i] }))
|
|
points_positions.push_back(_position)
|
|
|
|
func draw_function_point(point_position: Vector2) -> void:
|
|
match function.get_marker():
|
|
Function.Marker.SQUARE:
|
|
draw_rect(
|
|
Rect2(point_position - (Vector2.ONE * point_size), (Vector2.ONE * point_size * 2)),
|
|
function.get_color(), true, 1.0
|
|
)
|
|
Function.Marker.TRIANGLE:
|
|
draw_colored_polygon(
|
|
PackedVector2Array([
|
|
point_position + (Vector2.UP * point_size * 1.3),
|
|
point_position + (Vector2.ONE * point_size * 1.3),
|
|
point_position - (Vector2(1, -1) * point_size * 1.3)
|
|
]), function.get_color(), [], null
|
|
)
|
|
Function.Marker.CROSS:
|
|
draw_line(
|
|
point_position - (Vector2.ONE * point_size),
|
|
point_position + (Vector2.ONE * point_size),
|
|
function.get_color(), point_size, true
|
|
)
|
|
draw_line(
|
|
point_position + (Vector2(1, -1) * point_size),
|
|
point_position + (Vector2(-1, 1) * point_size),
|
|
function.get_color(), point_size / 2, true
|
|
)
|
|
Function.Marker.CIRCLE, _:
|
|
draw_circle(point_position, point_size, function.get_color())
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventMouse:
|
|
for point in points:
|
|
if Geometry2D.is_point_in_circle(get_relative_position(event.position), point.position, self.point_size * 4):
|
|
if focused_point == point:
|
|
return
|
|
else:
|
|
focused_point = point
|
|
emit_signal("point_entered", point, function)
|
|
return
|
|
# Mouse is not in any point's box
|
|
emit_signal("point_exited", focused_point, function)
|
|
focused_point = null
|