2021-03-30 17:07:13 +00:00
|
|
|
extends "res://src/Tools/ShapeDrawer.gd"
|
|
|
|
|
|
|
|
|
|
|
|
func _get_shape_points_filled(size: Vector2) -> PoolVector2Array:
|
2022-07-04 17:44:23 +00:00
|
|
|
var offseted_size := size + Vector2.ONE * (_thickness - 1)
|
2021-03-30 17:07:13 +00:00
|
|
|
var border := _get_ellipse_points(Vector2.ZERO, offseted_size)
|
|
|
|
var filling := []
|
|
|
|
var bitmap := _fill_bitmap_with_points(border, offseted_size)
|
|
|
|
|
|
|
|
for x in range(1, ceil(offseted_size.x / 2)):
|
|
|
|
var fill := false
|
|
|
|
var prev_is_true := false
|
|
|
|
for y in range(0, ceil(offseted_size.y / 2)):
|
|
|
|
var top_l_p := Vector2(x, y)
|
|
|
|
var bit := bitmap.get_bit(top_l_p)
|
|
|
|
|
|
|
|
if bit and not fill:
|
|
|
|
prev_is_true = true
|
|
|
|
continue
|
|
|
|
|
|
|
|
if not bit and (fill or prev_is_true):
|
|
|
|
filling.append(top_l_p)
|
|
|
|
filling.append(Vector2(x, offseted_size.y - y - 1))
|
|
|
|
filling.append(Vector2(offseted_size.x - x - 1, y))
|
|
|
|
filling.append(Vector2(offseted_size.x - x - 1, offseted_size.y - y - 1))
|
|
|
|
|
|
|
|
if prev_is_true:
|
|
|
|
fill = true
|
|
|
|
prev_is_true = false
|
|
|
|
elif bit and fill:
|
|
|
|
break
|
|
|
|
|
|
|
|
return PoolVector2Array(border + filling)
|
|
|
|
|
|
|
|
|
|
|
|
func _get_shape_points(size: Vector2) -> PoolVector2Array:
|
|
|
|
# Return ellipse with thickness 1
|
|
|
|
if _thickness == 1:
|
|
|
|
return PoolVector2Array(_get_ellipse_points(Vector2.ZERO, size))
|
|
|
|
|
2022-07-04 17:44:23 +00:00
|
|
|
var size_offset := Vector2.ONE * (_thickness - 1)
|
2021-03-30 17:07:13 +00:00
|
|
|
var new_size := size + size_offset
|
2022-07-04 17:44:23 +00:00
|
|
|
var inner_ellipse_size = new_size - size_offset
|
2021-03-30 17:07:13 +00:00
|
|
|
|
2021-11-25 12:48:30 +00:00
|
|
|
# The inner ellipse is to small to create a gap in the middle of the ellipse,
|
|
|
|
# just return a filled ellipse
|
2021-03-30 17:07:13 +00:00
|
|
|
if inner_ellipse_size.x <= 2 and inner_ellipse_size.y <= 2:
|
|
|
|
return _get_shape_points_filled(size)
|
|
|
|
|
|
|
|
# Adapted scanline algorithm to fill between 2 ellipses, to create a thicker ellipse
|
|
|
|
var res_array := []
|
2021-11-25 12:48:30 +00:00
|
|
|
var border_ellipses := (
|
|
|
|
_get_ellipse_points(Vector2.ZERO, new_size)
|
|
|
|
+ _get_ellipse_points(size_offset, inner_ellipse_size)
|
|
|
|
) # Outer and inner ellipses
|
2021-03-30 17:07:13 +00:00
|
|
|
var bitmap := _fill_bitmap_with_points(border_ellipses, new_size)
|
2021-11-25 12:48:30 +00:00
|
|
|
var smallest_side := min(new_size.x, new_size.y)
|
|
|
|
var largest_side := max(new_size.x, new_size.y)
|
|
|
|
var scan_dir := Vector2(0, 1) if smallest_side == new_size.x else Vector2(1, 0)
|
|
|
|
var iscan_dir := Vector2(1, 0) if smallest_side == new_size.x else Vector2(0, 1)
|
2021-03-30 17:07:13 +00:00
|
|
|
var ie_relevant_offset_side = size_offset.x if smallest_side == new_size.x else size_offset.y
|
|
|
|
var h_ls_c := ceil(largest_side / 2)
|
|
|
|
|
|
|
|
for s in range(ceil(smallest_side / 2)):
|
|
|
|
if s <= ie_relevant_offset_side:
|
|
|
|
var draw := false
|
|
|
|
for l in range(h_ls_c):
|
|
|
|
var pos := scan_dir * l + iscan_dir * s
|
|
|
|
if bitmap.get_bit(pos):
|
|
|
|
draw = true
|
|
|
|
if draw:
|
|
|
|
var mirror_smallest_side := iscan_dir * (smallest_side - 1 - 2 * s)
|
|
|
|
var mirror_largest_side := scan_dir * (largest_side - 1 - 2 * l)
|
|
|
|
res_array.append(pos)
|
|
|
|
res_array.append(pos + mirror_largest_side)
|
|
|
|
res_array.append(pos + mirror_smallest_side)
|
|
|
|
res_array.append(pos + mirror_smallest_side + mirror_largest_side)
|
|
|
|
else:
|
|
|
|
# Find outer ellipse
|
|
|
|
var l_o := 0
|
2021-11-25 12:48:30 +00:00
|
|
|
for l in range(h_ls_c):
|
2021-03-30 17:07:13 +00:00
|
|
|
var pos := scan_dir * l + iscan_dir * s
|
|
|
|
if bitmap.get_bit(pos):
|
|
|
|
l_o = l
|
|
|
|
break
|
|
|
|
# Find inner ellipse
|
|
|
|
var li := 0
|
|
|
|
for l in range(h_ls_c, 0, -1):
|
|
|
|
var pos := scan_dir * l + iscan_dir * s
|
|
|
|
if bitmap.get_bit(pos):
|
|
|
|
li = l
|
|
|
|
break
|
|
|
|
# Fill between both
|
|
|
|
for l in range(l_o, li + 1):
|
|
|
|
var pos := scan_dir * l + iscan_dir * s
|
|
|
|
var mirror_smallest_side := iscan_dir * (smallest_side - 1 - 2 * s)
|
|
|
|
var mirror_largest_side := scan_dir * (largest_side - 1 - 2 * l)
|
|
|
|
res_array.append(pos)
|
|
|
|
res_array.append(pos + mirror_largest_side)
|
|
|
|
res_array.append(pos + mirror_smallest_side)
|
|
|
|
res_array.append(pos + mirror_smallest_side + mirror_largest_side)
|
|
|
|
|
|
|
|
return PoolVector2Array(res_array)
|
|
|
|
|
|
|
|
|
|
|
|
# Algorithm based on http://members.chello.at/easyfilter/bresenham.html
|
2021-11-25 12:48:30 +00:00
|
|
|
func _get_ellipse_points(pos: Vector2, size: Vector2) -> Array:
|
2021-03-30 17:07:13 +00:00
|
|
|
var array := []
|
|
|
|
var x0 := int(pos.x)
|
|
|
|
var x1 := pos.x + int(size.x - 1)
|
|
|
|
var y0 := int(pos.y)
|
|
|
|
var y1 := int(pos.y) + int(size.y - 1)
|
|
|
|
var a := int(abs(x1 - x0))
|
|
|
|
var b := int(abs(y1 - x0))
|
|
|
|
var b1 := b & 1
|
2021-11-25 12:48:30 +00:00
|
|
|
var dx := 4 * (1 - a) * b * b
|
|
|
|
var dy := 4 * (b1 + 1) * a * a
|
|
|
|
var err := dx + dy + b1 * a * a
|
2021-03-30 17:07:13 +00:00
|
|
|
var e2 := 0
|
|
|
|
|
|
|
|
if x0 > x1:
|
|
|
|
x0 = x1
|
|
|
|
x1 += a
|
|
|
|
|
|
|
|
if y0 > y1:
|
|
|
|
y0 = y1
|
|
|
|
|
|
|
|
# warning-ignore:integer_division
|
2021-11-25 12:48:30 +00:00
|
|
|
y0 += (b + 1) / 2
|
|
|
|
y1 = y0 - b1
|
|
|
|
a *= 8 * a
|
|
|
|
b1 = 8 * b * b
|
2021-03-30 17:07:13 +00:00
|
|
|
|
|
|
|
while x0 <= x1:
|
|
|
|
var v1 := Vector2(x1, y0)
|
|
|
|
var v2 := Vector2(x0, y0)
|
|
|
|
var v3 := Vector2(x0, y1)
|
|
|
|
var v4 := Vector2(x1, y1)
|
|
|
|
array.append(v1)
|
|
|
|
array.append(v2)
|
|
|
|
array.append(v3)
|
|
|
|
array.append(v4)
|
|
|
|
|
2021-11-25 12:48:30 +00:00
|
|
|
e2 = 2 * err
|
2021-03-30 17:07:13 +00:00
|
|
|
|
|
|
|
if e2 <= dy:
|
|
|
|
y0 += 1
|
|
|
|
y1 -= 1
|
|
|
|
dy += a
|
|
|
|
err += dy
|
|
|
|
|
2021-11-25 12:48:30 +00:00
|
|
|
if e2 >= dx || 2 * err > dy:
|
|
|
|
x0 += 1
|
|
|
|
x1 -= 1
|
2021-03-30 17:07:13 +00:00
|
|
|
dx += b1
|
|
|
|
err += dx
|
|
|
|
|
2021-11-25 12:48:30 +00:00
|
|
|
while y0 - y1 < b:
|
|
|
|
var v1 := Vector2(x0 - 1, y0)
|
|
|
|
var v2 := Vector2(x1 + 1, y0)
|
|
|
|
var v3 := Vector2(x0 - 1, y1)
|
|
|
|
var v4 := Vector2(x1 + 1, y1)
|
2021-03-30 17:07:13 +00:00
|
|
|
array.append(v1)
|
|
|
|
array.append(v2)
|
|
|
|
array.append(v3)
|
|
|
|
array.append(v4)
|
2021-11-25 12:48:30 +00:00
|
|
|
y0 += 1
|
|
|
|
y1 -= 1
|
2021-03-30 17:07:13 +00:00
|
|
|
|
|
|
|
return array
|
|
|
|
|
|
|
|
|
|
|
|
func _fill_bitmap_with_points(points: Array, size: Vector2) -> BitMap:
|
|
|
|
var bitmap := BitMap.new()
|
|
|
|
bitmap.create(size)
|
|
|
|
|
|
|
|
for point in points:
|
|
|
|
bitmap.set_bit(point, 1)
|
|
|
|
|
|
|
|
return bitmap
|