Updated to 4.4
This commit is contained in:
parent
eaa26d1361
commit
1aff15069a
151 changed files with 593 additions and 100 deletions
30
addons/PoissonDiscSampling/Demo/polygon_demo.gd
Normal file
30
addons/PoissonDiscSampling/Demo/polygon_demo.gd
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
extends Node2D
|
||||
|
||||
|
||||
@onready var polygon: Array = $Polygon2D.polygon
|
||||
@onready var n = polygon.size()
|
||||
|
||||
var p_radius: int = 20
|
||||
var k: int = 0
|
||||
var points := []
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
for i in n:
|
||||
draw_line(polygon[i], polygon[(i+1)%n], Color(1,1,0), 2, 1)
|
||||
|
||||
draw_circle(points[k], p_radius / 2, Color( 1, 0, 0, 1 ))
|
||||
draw_circle(points[k], 2, Color( 1, 1, 0, 1 ))
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var start_time = Time.get_ticks_msec()
|
||||
points = PoissonDiscSampling.generate_points_for_polygon($Polygon2D.polygon, p_radius, 30)
|
||||
# points = PoissonDiscSampling.generate_points_for_circle(Vector2(300,300),200, p_radius, 30)
|
||||
print(points.size(), " points generated in ", Time.get_ticks_msec() - start_time, " miliseconds" )
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if k < points.size() - 1:
|
||||
queue_redraw()
|
||||
k += 1
|
||||
1
addons/PoissonDiscSampling/Demo/polygon_demo.gd.uid
Normal file
1
addons/PoissonDiscSampling/Demo/polygon_demo.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ckgdl8g835gsm
|
||||
21
addons/PoissonDiscSampling/Demo/polygon_demo.tscn
Normal file
21
addons/PoissonDiscSampling/Demo/polygon_demo.tscn
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://c74o3ucws2ac4"]
|
||||
|
||||
[ext_resource type="Script" path="res://addons/PoissonDiscSampling/Demo/polygon_demo.gd" id="1_3y3ej"]
|
||||
|
||||
[node name="SubViewportContainer" type="SubViewportContainer"]
|
||||
offset_right = 40.0
|
||||
offset_bottom = 40.0
|
||||
|
||||
[node name="SubViewport" type="SubViewport" parent="."]
|
||||
handle_input_locally = false
|
||||
size = Vector2i(1152, 648)
|
||||
render_target_clear_mode = 1
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="PolygonDemo" type="Node2D" parent="SubViewport"]
|
||||
script = ExtResource("1_3y3ej")
|
||||
|
||||
[node name="Polygon2D" type="Polygon2D" parent="SubViewport/PolygonDemo"]
|
||||
color = Color(1, 1, 1, 0)
|
||||
antialiased = true
|
||||
polygon = PackedVector2Array(123, 266, 378, 26, 682, 157, 1002, 118, 1077, 424, 747, 541, 843, 302, 810, 217, 553, 446, 468, 227, 430, 560, 103, 560, 261, 475, 361, 268)
|
||||
114
addons/PoissonDiscSampling/poisson_disc_sampling.gd
Normal file
114
addons/PoissonDiscSampling/poisson_disc_sampling.gd
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
class_name PoissonDiscSampling
|
||||
|
||||
|
||||
enum ShapeType {CIRCLE, POLYGON}
|
||||
static var shape_info: Dictionary
|
||||
|
||||
|
||||
static func generate_points_for_circle(circle_position: Vector2, circle_radius: float, poisson_radius: float, retries: int, start_point := Vector2.INF) -> PackedVector2Array:
|
||||
var sample_region_rect = Rect2(circle_position.x - circle_radius, circle_position.y - circle_radius, circle_radius * 2, circle_radius * 2)
|
||||
if start_point.x == INF:
|
||||
var angle: float = 2 * PI * randf()
|
||||
start_point = circle_position + Vector2(cos(angle), sin(angle)) * circle_radius * randf()
|
||||
elif not Geometry2D.is_point_in_circle(start_point, circle_position, circle_radius):
|
||||
push_error("Starting point ", start_point, " is not a valid point inside the circle!")
|
||||
return PackedVector2Array()
|
||||
|
||||
shape_info[ShapeType.CIRCLE] = {
|
||||
"circle_position": circle_position,
|
||||
"circle_radius": circle_radius
|
||||
}
|
||||
return _generate_points(ShapeType.CIRCLE, sample_region_rect, poisson_radius, retries, start_point)
|
||||
|
||||
|
||||
static func generate_points_for_polygon(polygon: PackedVector2Array, poisson_radius: float, retries: int, start_point := Vector2.INF) -> PackedVector2Array:
|
||||
var start: Vector2 = polygon[0]
|
||||
var end: Vector2 = polygon[0]
|
||||
for i in range(1, polygon.size()):
|
||||
start.x = min(start.x, polygon[i].x)
|
||||
start.y = min(start.y, polygon[i].y)
|
||||
end.x = max(end.x, polygon[i].x)
|
||||
end.y = max(end.y, polygon[i].y)
|
||||
var sample_region_rect = Rect2(start, end - start)
|
||||
|
||||
if start_point.x == INF:
|
||||
var n: int = polygon.size()
|
||||
var i: int = randi() % n
|
||||
start_point = polygon[i] + (polygon[(i + 1) % n] - polygon[i]) * randf()
|
||||
elif not Geometry2D.is_point_in_polygon(start_point, polygon):
|
||||
push_error("Starting point ", start_point, " is not a valid point inside the polygon!")
|
||||
return PackedVector2Array()
|
||||
|
||||
shape_info[ShapeType.POLYGON] = {"points" = polygon}
|
||||
return _generate_points(ShapeType.POLYGON, sample_region_rect, poisson_radius, retries, start_point)
|
||||
|
||||
|
||||
static func _generate_points(shape: int, sample_region_rect: Rect2, poisson_radius: float, retries: int, start_pos: Vector2) -> PackedVector2Array:
|
||||
var points: PackedVector2Array = PackedVector2Array()
|
||||
points.clear()
|
||||
var cell_size: float = poisson_radius / sqrt(2)
|
||||
var cols: int = max(floor(sample_region_rect.size.x / cell_size), 1)
|
||||
var rows: int = max(floor(sample_region_rect.size.y / cell_size), 1)
|
||||
|
||||
# scale the cell size in each axis
|
||||
var cell_size_scaled: Vector2
|
||||
cell_size_scaled.x = sample_region_rect.size.x / cols
|
||||
cell_size_scaled.y = sample_region_rect.size.y / rows
|
||||
|
||||
# use tranpose to map points starting from origin to calculate grid position
|
||||
var transpose = -sample_region_rect.position
|
||||
|
||||
var grid: Array = []
|
||||
for i in cols:
|
||||
grid.append([])
|
||||
for j in rows:
|
||||
grid[i].append(-1)
|
||||
|
||||
var spawn_points: Array = []
|
||||
spawn_points.append(start_pos)
|
||||
|
||||
while spawn_points.size() > 0:
|
||||
var spawn_index: int = randi() % spawn_points.size()
|
||||
var spawn_centre: Vector2 = spawn_points[spawn_index]
|
||||
var sample_accepted: bool = false
|
||||
for i in retries:
|
||||
var angle: float = 2 * PI * randf()
|
||||
var sample: Vector2 = spawn_centre + Vector2(cos(angle), sin(angle)) * (poisson_radius + poisson_radius * randf())
|
||||
if _is_point_in_sample_region(sample, shape):
|
||||
if _is_valid_sample(shape, sample, transpose, cell_size_scaled, cols, rows, grid, points, poisson_radius):
|
||||
var cell: Vector2 = Vector2(int((transpose.x + sample.x) / cell_size_scaled.x), int((transpose.y + sample.y) / cell_size_scaled.y))
|
||||
# fix: https://github.com/udit/poisson-disc-sampling/issues/3
|
||||
if cell.x < cols and cell.y < rows:
|
||||
grid[cell.x][cell.y] = points.size()
|
||||
points.append(sample)
|
||||
spawn_points.append(sample)
|
||||
sample_accepted = true
|
||||
break
|
||||
if not sample_accepted and points.size() > 0:
|
||||
spawn_points.remove_at(spawn_index)
|
||||
return points
|
||||
|
||||
|
||||
static func _is_valid_sample(shape: int, sample: Vector2, transpose: Vector2, cell_size_scaled: Vector2, cols: int, rows: int, grid: Array, points: Array, poisson_radius: float) -> bool:
|
||||
var cell := Vector2(int((transpose.x + sample.x) / cell_size_scaled.x), int((transpose.y + sample.y) / cell_size_scaled.y))
|
||||
var cell_start := Vector2(max(0, cell.x - 2), max(0, cell.y - 2))
|
||||
var cell_end := Vector2(min(cell.x + 2, cols - 1), min(cell.y + 2, rows - 1))
|
||||
|
||||
for i in range(cell_start.x, cell_end.x + 1):
|
||||
for j in range(cell_start.y, cell_end.y + 1):
|
||||
var search_index: int = grid[i][j]
|
||||
if search_index != -1:
|
||||
var dist: float = points[search_index].distance_to(sample)
|
||||
if dist < poisson_radius:
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
static func _is_point_in_sample_region(sample: Vector2, shape: int) -> bool:
|
||||
if shape == ShapeType.POLYGON and Geometry2D.is_point_in_polygon(sample, shape_info[shape]["points"]):
|
||||
return true
|
||||
elif shape == ShapeType.CIRCLE and Geometry2D.is_point_in_circle(sample, shape_info[shape]["circle_position"], shape_info[shape]["circle_radius"]):
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
|
||||
1
addons/PoissonDiscSampling/poisson_disc_sampling.gd.uid
Normal file
1
addons/PoissonDiscSampling/poisson_disc_sampling.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cvht6xa8n4xvg
|
||||
1
addons/awesome_input_icons/InputIcon.gd.uid
Normal file
1
addons/awesome_input_icons/InputIcon.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dtrgkhmh6rdub
|
||||
1
addons/awesome_input_icons/awesome_input_icons.gd.uid
Normal file
1
addons/awesome_input_icons/awesome_input_icons.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://jljwkxt757na
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://dw6c8e4ha6c0u
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://go64dt8gl8gy
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bqi6n0pu0w6kb
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bd3kf8ujt6p16
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://rs374yrjy620
|
||||
1
addons/debug_menu/debug_menu.gd.uid
Normal file
1
addons/debug_menu/debug_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cfnbgy105dppi
|
||||
1
addons/debug_menu/plugin.gd.uid
Normal file
1
addons/debug_menu/plugin.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://d1ywuh58llyf2
|
||||
1
addons/script-ide/Popup.gd.uid
Normal file
1
addons/script-ide/Popup.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bv5t04c0f3yyg
|
||||
1
addons/script-ide/plugin.gd.uid
Normal file
1
addons/script-ide/plugin.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bvmoa4p7lhct6
|
||||
Loading…
Add table
Add a link
Reference in a new issue