1374 lines
40 KiB
GDScript
1374 lines
40 KiB
GDScript
extends Node
|
|
signal complete
|
|
|
|
var map_width = 1280
|
|
var map_height = 1280
|
|
var map_rect = Rect2(0, 0, map_width, map_height)
|
|
|
|
enum {STATE_INIT, STATE_ITERATION, STATE_EDGES1, STATE_EDGES2, STATE_EDGES3, STATE_POLYGONS1, STATE_POLYGONS2, STATE_COMPLETE}
|
|
var state = STATE_INIT
|
|
|
|
var min_distance = 12.0
|
|
var pgrow = 0.5
|
|
|
|
var rules = {}
|
|
var edges = []
|
|
var pos2vertex = {}
|
|
var lot_points = []
|
|
var lot_triangles = []
|
|
var pos2edge = {}
|
|
var road_width: float = 6.0
|
|
var pos2id = {}
|
|
var minpos = Vector2()
|
|
var maxpos = Vector2()
|
|
var vertex_queue = []
|
|
var vertices = []
|
|
var front = []
|
|
var lots : Lots
|
|
var grid: GridData
|
|
class Lots:
|
|
enum {LOT_FOREST, LOT_AIRPORT, LOT_PARK, LOT_CEMETERY, LOT_RESIDENTAL, LOT_INDUSTRIAL}
|
|
var lot_types = {
|
|
"forest": {
|
|
"w": 500,
|
|
"h": 500,
|
|
"type": LOT_FOREST,
|
|
"center_distance": 400.0
|
|
},
|
|
"airport": {
|
|
"w": 500,
|
|
"h": 500,
|
|
"type": LOT_AIRPORT,
|
|
"center_distance": 400.0
|
|
},
|
|
"park": {
|
|
"w": 300,
|
|
"h": 300,
|
|
"type": LOT_PARK,
|
|
"center_distance": 0.0
|
|
},
|
|
"cemetery": {
|
|
"w": 200,
|
|
"h": 200,
|
|
"type": LOT_CEMETERY,
|
|
"center_distance": 0.0
|
|
},
|
|
"residental1": {
|
|
"w": 100,
|
|
"h": 100,
|
|
"type": LOT_RESIDENTAL,
|
|
"center_distance": 0.0
|
|
},
|
|
"residental2": {
|
|
"w": 50,
|
|
"h": 50,
|
|
"type": LOT_RESIDENTAL,
|
|
"center_distance": 0.0
|
|
},
|
|
"residental3": {
|
|
"w": 20,
|
|
"h": 20,
|
|
"type": LOT_RESIDENTAL,
|
|
"center_distance": 0.0
|
|
},
|
|
"industrial": {
|
|
"w": 100,
|
|
"h": 100,
|
|
"type": LOT_RESIDENTAL,
|
|
"center_distance": 200.0
|
|
},
|
|
}
|
|
var lots = []
|
|
func make_lot_polygon(lot_name: String):
|
|
var lot_type = lot_types[lot_name]
|
|
var p1 = Vector2(-lot_type.w * 0.5, -lot_type.h * 0.5)
|
|
var p2 = Vector2(lot_type.w * 0.5, -lot_type.h * 0.5)
|
|
var p3 = Vector2(lot_type.w * 0.5, lot_type.h * 0.5)
|
|
var p4 = Vector2(-lot_type.w * 0.5, lot_type.h * 0.5)
|
|
return [p1, p2, p3, p4]
|
|
# func get_polygon_center(polygon):
|
|
# var ret: Vector2 = Vector2()
|
|
# for m in range(polygon.size()):
|
|
# ret += polygon[m]
|
|
# return ret / 4.0
|
|
func get_lot_transform(p1: Vector2, p2: Vector2, road_width: float, sidewalk_width: float, polygon: Array):
|
|
var n = (p2-p1).tangent().normalized()
|
|
var offset1 = n * (road_width + sidewalk_width)
|
|
var offset2 = Vector2()
|
|
for v in range(polygon.size()):
|
|
if offset2.x < polygon[v].x:
|
|
offset2.x = polygon[v].x
|
|
if offset2.y < polygon[v].y:
|
|
offset2.y = polygon[v].y
|
|
var ret = Transform2D((p2 - p1).angle(), p1.linear_interpolate(p2, 0.5) + offset1 + offset2)
|
|
return ret
|
|
func transformed_polygon(xform: Transform2D, polygon: Array):
|
|
return Array(Geometry.transform_points_2d(PoolVector2Array(polygon), xform))
|
|
func polygon_intersects_road(polygon, vertices):
|
|
for v in range(vertices.size()):
|
|
var p1 = vertices[v].pos
|
|
for k in vertices[v]._neighbors:
|
|
var p2 = vertices[k].pos
|
|
if Geometry.segment_intersects_segment_2d(p1, p2, polygon[0], polygon[1]):
|
|
return true
|
|
if Geometry.segment_intersects_segment_2d(p1, p2, polygon[1], polygon[2]):
|
|
return true
|
|
if Geometry.segment_intersects_segment_2d(p1, p2, polygon[2], polygon[3]):
|
|
return true
|
|
if Geometry.segment_intersects_segment_2d(p1, p2, polygon[3], polygon[0]):
|
|
return true
|
|
if Geometry.point_is_inside_triangle(p1, polygon[0], polygon[1], polygon[2]):
|
|
return true
|
|
if Geometry.point_is_inside_triangle(p1, polygon[0], polygon[2], polygon[3]):
|
|
return true
|
|
if Geometry.point_is_inside_triangle(p2, polygon[0], polygon[1], polygon[2]):
|
|
return true
|
|
if Geometry.point_is_inside_triangle(p2, polygon[0], polygon[2], polygon[3]):
|
|
return true
|
|
return false
|
|
|
|
func generate_lots(vertices, road_width, sidewalk_width, map_width, map_height):
|
|
for v in range(vertices.size()):
|
|
var p1 = vertices[v].pos
|
|
for k in vertices[v]._neighbors:
|
|
for d in range(10):
|
|
var p2 = vertices[k].pos
|
|
var lot_type_name = lot_types.keys()[randi() % lot_types.keys().size()]
|
|
var polygon = make_lot_polygon(lot_type_name)
|
|
var xform = get_lot_transform(p1, p2, road_width, sidewalk_width, polygon)
|
|
if polygon_intersects_road(transformed_polygon(xform, polygon), vertices):
|
|
continue
|
|
var xfpoly = transformed_polygon(xform, polygon)
|
|
var bad = false
|
|
for r in lots:
|
|
var poly2 = transformed_polygon(r.xform, r.polygon)
|
|
if Geometry.intersect_polygons_2d(xfpoly, poly2).size() > 0:
|
|
bad = true
|
|
break
|
|
if xform.origin.distance_to(Vector2(map_width * 0.5, map_height * 0.5)) < lot_types[lot_type_name].center_distance:
|
|
bad = true
|
|
if bad:
|
|
continue
|
|
lots.push_back({
|
|
"polygon": polygon,
|
|
"xform": xform,
|
|
"type": lot_types[lot_type_name].type,
|
|
"type_name": lot_type_name
|
|
})
|
|
break
|
|
yield()
|
|
return true
|
|
|
|
func get_point3d(v: Vector2):
|
|
var v3d : = Vector3()
|
|
v3d.x = v.x - map_width * 0.5
|
|
v3d.z = v.y - map_height * 0.5
|
|
|
|
class GridData:
|
|
var grid = {}
|
|
var p2id = {}
|
|
func _point2grid(v: Vector2):
|
|
var grid_x = int(v.x / 100.0)
|
|
var grid_y = int(v.y / 100.0)
|
|
return hash([grid_x, grid_y])
|
|
func add_point_to_grid(p: Vector2, id: int) -> bool:
|
|
var g = _point2grid(p)
|
|
if grid.has(g):
|
|
if !p in grid[g]:
|
|
grid[g].push_back(p)
|
|
p2id[p] = id
|
|
return true
|
|
else:
|
|
return false
|
|
else:
|
|
grid[g] = PoolVector2Array()
|
|
grid[g].push_back(p)
|
|
p2id[p] = id
|
|
return true
|
|
func radius_search(p: Vector2, radius: float):
|
|
var p0 = Vector2(p.x - radius, p.y - radius)
|
|
var p1 = Vector2(p.x + radius, p.y + radius)
|
|
var p0x = _point2grid(p0) - Vector2(1, 1)
|
|
var p1x = _point2grid(p0) + Vector2(1, 1)
|
|
var posx = int(p0x.x)
|
|
var posy = int(p0x.y)
|
|
var rangex = p1x - p0x
|
|
var rangex_x = int(rangex.x)
|
|
var rangex_y = int(rangex.y)
|
|
var points = []
|
|
for gy in range(rangex_y):
|
|
for gx in range(rangex_x):
|
|
var id = hash([posx + gx, posy + gy])
|
|
if grid.has(id):
|
|
points += Array(grid[id])
|
|
var radius_sq = radius * radius
|
|
var ret = PoolIntArray()
|
|
for e in points:
|
|
if e.distance_squared_to(p) <= radius_sq:
|
|
ret.push_back(p2id[e])
|
|
return ret
|
|
|
|
#class PointDB:
|
|
# var _points: PoolVector2Array = PoolVector2Array()
|
|
# var _triangles: PoolIntArray = PoolIntArray()
|
|
# var _grid: Array = []
|
|
# var _grid_size: int = -1
|
|
# var grid_w: int
|
|
# var grid_h: int
|
|
# var grid_offset: Vector2
|
|
# var _edges = {}
|
|
# var _eid2id = {}
|
|
# var _id2data = {}
|
|
# var _id2pos = {}
|
|
# var _pos2id = {}
|
|
# var _id2edge = {}
|
|
# var _edge2data = {}
|
|
# func build_grid(points: Array, grid_size: int):
|
|
# _points = points
|
|
# _triangles = Geometry.triangulate_delaunay_2d(_points)
|
|
# _grid_size = grid_size
|
|
# _pos2id.clear()
|
|
# _id2pos.clear()
|
|
# _id2data.clear()
|
|
# _id2edge.clear()
|
|
# _grid.clear()
|
|
# _edges.clear()
|
|
# _edge2data.clear()
|
|
# var rect: Rect2 = Rect2()
|
|
# for p in range(_points.size()):
|
|
# rect = rect.expand(_points[p])
|
|
# _pos2id[_points[p]] = p
|
|
# _id2pos[p] = _points[p]
|
|
# rect.position.x = floor(rect.position.x / grid_size - 1) * grid_size
|
|
# rect.position.y = floor(rect.position.x / grid_size - 1) * grid_size
|
|
# rect.size.x = ceil(rect.size.x / grid_size + 1) * grid_size
|
|
# rect.size.y = ceil(rect.size.x / grid_size + 1) * grid_size
|
|
# grid_w = int((rect.size.x + 1)/ grid_size)
|
|
# grid_h = int((rect.size.x + 1)/ grid_size)
|
|
# grid_offset = rect.position
|
|
# _grid.resize((grid_w + 1) * (grid_h + 1))
|
|
# for p in range(_points.size()):
|
|
# var grid_x = int((_points[p].x - grid_offset.x) / grid_size)
|
|
# var grid_y = int((_points[p].y - grid_offset.y) / grid_size)
|
|
# if !_grid[grid_w * grid_y + grid_x]:
|
|
# _grid[grid_w * grid_y + grid_x] = PoolIntArray()
|
|
# _grid[grid_w * grid_y + grid_x].push_back(p)
|
|
# for tri in range(0, _triangles.size(), 3):
|
|
# var p1 = _triangles[tri + 0]
|
|
# var p2 = _triangles[tri + 1]
|
|
# var p3 = _triangles[tri + 2]
|
|
# add_edge_id(p1, p2)
|
|
# add_edge_id(p2, p3)
|
|
# add_edge_id(p3, p1)
|
|
# func add_point_data(p: Vector2, data: Dictionary):
|
|
# if _pos2id.has(p):
|
|
# _id2data[_pos2id[p]] = data
|
|
# else:
|
|
# breakpoint
|
|
# print_debug("Bad point added")
|
|
# func get_point_data(p: Vector2) -> Dictionary:
|
|
# if _pos2id.has(p):
|
|
# return _id2data[_pos2id[p]]
|
|
# else:
|
|
# return {}
|
|
# func add_edge_id(a: int, b: int):
|
|
# var edge_id = hash([a, b])
|
|
# _edges[edge_id] = [a, b]
|
|
# if _id2edge.has(a):
|
|
# _id2edge[a].push_back(edge_id)
|
|
# else:
|
|
# _id2edge[a] = [edge_id]
|
|
# if _id2edge.has(b):
|
|
# _id2edge[b].push_back(edge_id)
|
|
# else:
|
|
# _id2edge[b] = [edge_id]
|
|
# func add_edge(a: Vector2, b: Vector2):
|
|
# if _pos2id.has(a) && _pos2id.has(b):
|
|
# add_edge_id(_pos2id[a], _pos2id[b])
|
|
# else:
|
|
# breakpoint
|
|
# print_debug("Bad edge added")
|
|
# func add_edge_data(a: Vector2, b: Vector2, data: Dictionary):
|
|
# assert a in _points
|
|
# assert b in _points
|
|
# var ai = _pos2id[a]
|
|
# var bi = _pos2id[b]
|
|
# var edge_id = hash([ai, bi])
|
|
# var edge_id_rev = hash([bi, ai])
|
|
# if _edges.has(edge_id):
|
|
# _edge2data[edge_id] = data
|
|
# return true
|
|
# elif _edges.has(edge_id_rev):
|
|
# _edge2data[edge_id_rev] = data
|
|
# return true
|
|
# else:
|
|
# print_debug("No such edge ", [a, b])
|
|
# return false
|
|
# func get_edge_data(a: Vector2, b: Vector2) -> Dictionary:
|
|
# var ai = _pos2id[a]
|
|
# var bi = _pos2id[b]
|
|
# var edge_id = hash([ai, bi])
|
|
# var edge_id_rev = hash([bi, ai])
|
|
# if _edge2data.has(edge_id):
|
|
# return _edge2data[edge_id]
|
|
# elif _edge2data.has(edge_id_rev):
|
|
# return _edge2data[edge_id_rev]
|
|
# else:
|
|
# return {}
|
|
# func get_point_edges(a: Vector2) -> Array:
|
|
# var ret : = []
|
|
# var edges = _id2edge[_pos2id[a]]
|
|
# for e in edges:
|
|
# var ed = _edges[e]
|
|
# ret.push_back([_id2pos[ed[0]], _id2pos[ed[1]]])
|
|
# return ret
|
|
# func get_polygons() -> Array:
|
|
# var ret = []
|
|
# for t in range(0, _triangles.size(), 3):
|
|
# var p1 = _points[_triangles[t + 0]]
|
|
# var p2 = _points[_triangles[t + 1]]
|
|
# var p3 = _points[_triangles[t + 2]]
|
|
# ret.push_back([p1, p2, p3, get_edge_data(p1, p2), get_edge_data(p2, p3), get_edge_data(p3, p1)])
|
|
# return ret
|
|
|
|
|
|
|
|
var rnd: RandomNumberGenerator
|
|
var noise: OpenSimplexNoise
|
|
var complete = false
|
|
#var db: PointDB
|
|
|
|
var axiom = [
|
|
new_vertex(10, 10),
|
|
new_vertex(60, 10),
|
|
new_vertex(110, 10),
|
|
new_vertex(110, 60),
|
|
new_vertex(110, 110),
|
|
new_vertex(110, 160),
|
|
new_vertex(60, 160),
|
|
new_vertex(10, 160),
|
|
new_vertex(10, 110),
|
|
new_vertex(10, 60),
|
|
]
|
|
|
|
|
|
func cleanup():
|
|
minpos = Vector2()
|
|
maxpos = Vector2()
|
|
vertex_queue.clear()
|
|
vertices.clear()
|
|
edges.clear()
|
|
pos2vertex.clear()
|
|
pos2edge.clear()
|
|
pos2id.clear()
|
|
front.clear()
|
|
|
|
func new_vertex(x, y):
|
|
return {
|
|
"pos": Vector2(x, y),
|
|
"neighbors": [],
|
|
"type": 0,
|
|
"seed": false
|
|
}
|
|
|
|
func are_lines_intersecting(a, b, c, d):
|
|
var cd = d - c
|
|
var ab = b - a
|
|
var div = cd.y * ab.x - cd.x * ab.y
|
|
if abs(div) > 0.001:
|
|
var ac = a - c
|
|
var ua = ((cd.x * ac.y) - (cd.y * ac.x)) / div
|
|
if not ua >= 0.0 or not ua <= 1.0:
|
|
return false
|
|
var ub = ((ab.x * ac.y) - (ab.y * ac.x)) / div
|
|
if ub >= 0.0 and ub <= 1.0:
|
|
return true
|
|
return false
|
|
|
|
func find_edge(p1, p2):
|
|
if pos2edge.has(p1) && pos2edge.has(p2):
|
|
for e in pos2edge[p1] + pos2edge[p2]:
|
|
if edges[e].p1 == p1 && edges[e].p2 == p2:
|
|
return e
|
|
if edges[e].p1 == p2 && edges[e].p2 == p1:
|
|
return e
|
|
return null
|
|
func add_edge(p1, p2, road):
|
|
var id = edges.size()
|
|
var edge = {
|
|
"p1": p1,
|
|
"p2": p2,
|
|
"road": road,
|
|
"id": id,
|
|
}
|
|
edges.push_back(edge)
|
|
if pos2edge.has(vertices[p1].pos):
|
|
pos2edge[vertices[p1].pos].push_back(id)
|
|
else:
|
|
pos2edge[vertices[p1].pos] = [id]
|
|
if pos2edge.has(vertices[p2].pos):
|
|
pos2edge[vertices[p2].pos].push_back(id)
|
|
else:
|
|
pos2edge[p2] = [id]
|
|
|
|
return id
|
|
|
|
#func get_internal_angle(ecur, enext):
|
|
# var adj_p = -1
|
|
# var p_a = -1
|
|
# var p_b = -1
|
|
# var road_a = false
|
|
# var road_b = false
|
|
# var m_a = [-1, -1]
|
|
# var m_b = [-1, -1]
|
|
# var idx_a = -1
|
|
# var idx_b = -1
|
|
# road_a = edges[ecur].road
|
|
# road_b = edges[enext].road
|
|
# if !road_a && !road_b:
|
|
# return null
|
|
# if edges[ecur].p1 == edges[enext].p1:
|
|
# adj_p = edges[ecur].p1
|
|
# p_a = edges[ecur].p2
|
|
# p_b = edges[enext].p2
|
|
# road_a = edges[ecur].road
|
|
# road_b = edges[enext].road
|
|
# m_a = [adj_p, p_a]
|
|
# m_b = [adj_p, p_b]
|
|
# idx_a = 0
|
|
# idx_b = 0
|
|
# elif edges[ecur].p1 == edges[enext].p2:
|
|
# adj_p = edges[ecur].p1
|
|
# p_a = edges[ecur].p2
|
|
# p_b = edges[enext].p1
|
|
# m_a = [adj_p, p_a]
|
|
# m_b = [p_b, adj_p]
|
|
# idx_a = 0
|
|
# idx_b = 1
|
|
# elif edges[ecur].p2 == edges[enext].p1:
|
|
# adj_p = edges[ecur].p2
|
|
# p_a = edges[ecur].p1
|
|
# p_b = edges[enext].p2
|
|
# m_a = [p_a, adj_p]
|
|
# m_b = [adj_p, p_b]
|
|
# idx_a = 1
|
|
# idx_b = 0
|
|
# elif edges[ecur].p2 == edges[enext].p2:
|
|
# adj_p = edges[ecur].p2
|
|
# p_a = edges[ecur].p1
|
|
# p_b = edges[enext].p1
|
|
# m_a = [p_a, adj_p]
|
|
# m_b = [p_b, adj_p]
|
|
# idx_a = 1
|
|
# idx_b = 1
|
|
# var v_a = vertices[p_a].pos - vertices[adj_p].pos
|
|
# var v_b = vertices[p_b].pos - vertices[adj_p].pos
|
|
# var n_a = v_a.tangent().normalized()
|
|
# var n_b = v_b.tangent().normalized()
|
|
# var pos = vertices[adj_p].pos
|
|
# if road_a:
|
|
# pos += n_a * road_width
|
|
# if road_b:
|
|
# pos += n_a * road_width
|
|
# var ret = {}
|
|
# ret.vertex = new_vertex(pos.x, pos.y)
|
|
# ret.adj = adj_p
|
|
# ret.a = p_a
|
|
# ret.b = p_b
|
|
# ret.vertex._neighbors = [p_a, p_b]
|
|
# ret.vertex.neighbors = [vertices[p_a], vertices[p_b]]
|
|
# ret.m_a = m_a
|
|
# ret.m_b = m_b
|
|
# ret.idx_a = idx_a
|
|
# ret.idx_b = idx_b
|
|
# return ret
|
|
|
|
#func adjust_triangle(tri):
|
|
# var newtri = []
|
|
# var new_edges = []
|
|
# for i in range(3):
|
|
# newtri.push_back(tri[i])
|
|
# for i in range(3):
|
|
# var j = (i + 1) % 3
|
|
# var ecur = tri[i]
|
|
# var enext = tri[(i + 1) % 3]
|
|
# var ang = get_internal_angle(ecur, enext)
|
|
# if ang != null:
|
|
# var id = vertices.size()
|
|
# ang.vertex._index = id
|
|
# vertices.push_back(ang.vertex)
|
|
# var m_a = ang.m_a.duplicate()
|
|
# m_a[ang.idx_a] = id
|
|
# var m_b = ang.m_a.duplicate()
|
|
# m_b[ang.idx_b] = id
|
|
# add_edge(m_a[0], m_b[0], false)
|
|
|
|
func convert_vertices():
|
|
for e in range(vertices.size()):
|
|
pos2vertex[vertices[e].pos] = vertices[e]
|
|
vertices[e]._index = e
|
|
pos2id[vertices[e].pos] = e
|
|
for e in range(vertices.size()):
|
|
vertices[e]._neighbors = []
|
|
for h in vertices[e].neighbors:
|
|
assert h
|
|
# print(pos2vertex[h.pos])
|
|
vertices[e]._neighbors.push_back(pos2vertex[h.pos]._index)
|
|
func has_neighbor(v, n):
|
|
var ret = false
|
|
for p in v.neighbors:
|
|
if p.pos == n.pos:
|
|
ret = true
|
|
break
|
|
return ret
|
|
func add_neighbor(v, n):
|
|
if !has_neighbor(v, n):
|
|
v.neighbors.push_back(n)
|
|
if !has_neighbor(n, v):
|
|
v.neighbors.push_back(n)
|
|
if !n._index in v._neighbors:
|
|
v._neighbors.push_back(n._index)
|
|
if !v._index in n._neighbors:
|
|
n._neighbors.push_back(v._index)
|
|
func remove_neighbor(v, n):
|
|
if has_neighbor(v, n):
|
|
v.neighbors.erase(n)
|
|
if has_neighbor(n, v):
|
|
n.neighbors.erase(v)
|
|
if n._index in v._neighbors:
|
|
v._neighbors.erase(n._index)
|
|
if v._index in n._neighbors:
|
|
n._neighbors.erase(v._index)
|
|
|
|
#func update_neighbors():
|
|
# for e in range(points.size()):
|
|
# if pos2vertex.has(points[e]):
|
|
# continue
|
|
# var nv = new_vertex(points[e].x, points[e].y)
|
|
# nv._index = vertices.size()
|
|
# nv._neighbors = []
|
|
# vertices.push_back(nv)
|
|
# pos2vertex[nv.pos] = vertices[nv._index]
|
|
# pos2id[nv.pos] = nv._index
|
|
# for t in range(0, triangulation.size(), 3):
|
|
# for k in range(3):
|
|
# var prev = k
|
|
# var cur = (k + 1) % 3
|
|
# var next = (k + 2) % 3
|
|
# var pprev = triangulation[t + prev]
|
|
# var pcur = triangulation[t + cur]
|
|
# var pnext = triangulation[t + next]
|
|
# add_neighbor(pos2vertex[points[pcur]], pos2vertex[points[pprev]])
|
|
# add_neighbor(pos2vertex[points[pcur]], pos2vertex[points[pnext]])
|
|
#func build_edges():
|
|
# print("tri count: ", triangulation.size() / 3)
|
|
# for i in range(0, triangulation.size(), 3):
|
|
# var p1 = points[triangulation[i + 0]]
|
|
# var p2 = points[triangulation[i + 1]]
|
|
# var p3 = points[triangulation[i + 2]]
|
|
# var e1 = null
|
|
# var e2 = null
|
|
# var e3 = null
|
|
# e1 = find_edge(pos2id[p1], pos2id[p2])
|
|
# e2 = find_edge(pos2id[p2], pos2id[p3])
|
|
# e3 = find_edge(pos2id[p3], pos2id[p1])
|
|
# if e1 == null:
|
|
# e1 = add_edge(pos2vertex[p1]._index, pos2vertex[p2]._index, false)
|
|
# if e2 == null:
|
|
# e2 = add_edge(pos2vertex[p2]._index, pos2vertex[p3]._index, false)
|
|
# if e3 == null:
|
|
# e3 = add_edge(pos2vertex[p3]._index, pos2vertex[p1]._index, false)
|
|
# var triangle = [e1, e2, e3]
|
|
# triangles.push_back(triangle)
|
|
func sort_edges(edge_data: PoolIntArray) -> PoolIntArray:
|
|
assert edge_data.size() > 0
|
|
var inb = Array(edge_data)
|
|
var cur = -1
|
|
var cur_p = -1
|
|
var ret = PoolIntArray()
|
|
while inb.size() > 0:
|
|
var data = inb.pop_front()
|
|
if cur == -1:
|
|
cur = data
|
|
cur_p = edges[cur].p2
|
|
ret.push_back(data)
|
|
else:
|
|
var cur_p1 = edges[cur].p1
|
|
var cur_p2 = edges[cur].p2
|
|
var data_p1 = edges[data].p1
|
|
var data_p2 = edges[data].p2
|
|
if cur_p == data_p1:
|
|
ret.push_back(data)
|
|
cur = data
|
|
cur_p = data_p2
|
|
elif cur_p == data_p2:
|
|
ret.push_back(-(data + 1))
|
|
cur = data
|
|
cur_p = data_p1
|
|
else:
|
|
# print("unmatched ", cur, " ", data)
|
|
# print(cur, ": ", edges[cur].p1, " - ", edges[cur].p2)
|
|
# print(data, ": ", edges[data].p1, " - ", edges[data].p2)
|
|
inb.push_back(data)
|
|
# for p in edge_data:
|
|
# print(p, ": ", edges[p].p1, " - ", edges[p].p2)
|
|
# print(ret.size(), " ", edge_data.size(), " ", edge_data, " -> ", ret)
|
|
assert ret.size() > 0 && ret.size() == edge_data.size()
|
|
return ret
|
|
func edges2points(edge_data):
|
|
var ret = {}
|
|
var sorted_data = sort_edges(PoolIntArray(edge_data))
|
|
ret.points = []
|
|
ret.edges = []
|
|
var idx = 0
|
|
for e in sorted_data:
|
|
if e >= 0:
|
|
ret.points.push_back(vertices[edges[e].p1].pos)
|
|
else:
|
|
ret.points.push_back(vertices[edges[-(e + 1)].p2].pos)
|
|
ret.edges.push_back({
|
|
"indices": [idx, (idx + 1) % sorted_data.size()],
|
|
"road": edges[e].road
|
|
})
|
|
idx += 1
|
|
assert ret.points.size() > 0 && ret.points.size() == edge_data.size()
|
|
return ret
|
|
#func build_polygons():
|
|
# print("triangulation: ", triangulation.size())
|
|
# print("triangles count: ", triangles.size())
|
|
# print("points count: ", points.size())
|
|
# for p in range(triangles.size()):
|
|
# var polygon = {}
|
|
# var data = edges2points(triangles[p])
|
|
# polygon.vertices = data.points
|
|
# polygon.edges = data.edges
|
|
# polygon.road = false
|
|
# for e in range(triangles[p].size()):
|
|
# if edges[triangles[p][e]].road:
|
|
# polygon.road = true
|
|
# polygons.push_back(polygon)
|
|
# if p % 100 == 0:
|
|
# print(p)
|
|
#func separate_polygons(p):
|
|
# var ret = []
|
|
# var new_p = {}
|
|
# var modp = p.duplicate()
|
|
# for w in range(p.edges.size()):
|
|
# var ecur = w
|
|
# var enext = (w + 1) % p.edges.size()
|
|
## print(ecur, " ", enext, " ", p.edges[ecur].indices[0], " ", p.edges[enext].indices[0])
|
|
## print(p.points)
|
|
## print(p.points[p.edges[ecur].indices[0]])
|
|
# var cur_p1 = p.vertices[p.edges[ecur].indices[0]]
|
|
# var cur_p2 = p.vertices[p.edges[ecur].indices[1]]
|
|
# var next_p1 = p.vertices[p.edges[enext].indices[0]]
|
|
# var next_p2 = p.vertices[p.edges[enext].indices[1]]
|
|
# assert cur_p2 == next_p1
|
|
# var v_a = cur_p1 - cur_p2
|
|
# var v_b = next_p2 - cur_p2
|
|
# var n_a = v_a.tangent().normalized()
|
|
# var n_b = v_b.tangent().normalized()
|
|
# var pos = cur_p2
|
|
# if p.edges[ecur].road:
|
|
# pos += n_a * road_width
|
|
# if p.edges[enext].road:
|
|
# pos += n_a * road_width
|
|
# new_p[p.edges[ecur].indices[1]] = pos
|
|
# new_p[p.edges[enext].indices[0]] = pos
|
|
# modp.vertices[p.edges[ecur].indices[1]] = pos
|
|
# modp.vertices[p.edges[enext].indices[0]] = pos
|
|
# p.edges[ecur].road = false
|
|
# modp.road = false
|
|
# ret.push_back(modp)
|
|
# for e in p.edges:
|
|
# if !e.road:
|
|
# continue
|
|
# var p1 = p.vertices[e.indices[0]]
|
|
# var p2 = p.vertices[e.indices[1]]
|
|
# var p3 = new_p[e.indices[0]]
|
|
# var p4 = new_p[e.indices[1]]
|
|
# var road_polygon = {}
|
|
# road_polygon.vertices = [p3, p1, p2]
|
|
# road_polygon.edges = [
|
|
# {
|
|
# "indices": [0, 1],
|
|
# "road": true
|
|
# },
|
|
# {
|
|
# "indices": [1, 2],
|
|
# "road": true
|
|
# },
|
|
# {
|
|
# "indices": [2, 0],
|
|
# "road": true
|
|
# },
|
|
# ]
|
|
# road_polygon.road = true
|
|
# ret.push_back(road_polygon)
|
|
# road_polygon.vertices = [p3, p2, p4]
|
|
# road_polygon.edges = [
|
|
# {
|
|
# "indices": [0, 1],
|
|
# "road": true
|
|
# },
|
|
# {
|
|
# "indices": [1, 2],
|
|
# "road": true
|
|
# },
|
|
# {
|
|
# "indices": [2, 0],
|
|
# "road": true
|
|
# },
|
|
# ]
|
|
# road_polygon.road = true
|
|
# road_polygon = {}
|
|
# ret.push_back(road_polygon)
|
|
# return ret
|
|
#func separate_roads():
|
|
# var new_polys = []
|
|
# for p in polygons:
|
|
# if p.road:
|
|
# polygon_queue.push_back(p)
|
|
# else:
|
|
# new_polys.push_back(p)
|
|
# polygons = new_polys
|
|
# while polygon_queue.size() > 0:
|
|
# var item = polygon_queue.pop_front()
|
|
# var road = false
|
|
# var lot = true
|
|
# for e in item.edges:
|
|
# if e.road == true:
|
|
# road = true
|
|
# if e.road == false:
|
|
# lot = true
|
|
# if road && lot:
|
|
# var new_polygons = separate_polygons(item)
|
|
# for p in new_polygons:
|
|
# polygon_queue.push_back(p)
|
|
# else:
|
|
# polygons.push_back(item)
|
|
|
|
func adjacent_edges(e1, e2):
|
|
if edges[e1].p1 == edges[e2].p1:
|
|
return true
|
|
elif edges[e1].p1 == edges[e2].p2:
|
|
return true
|
|
elif edges[e1].p2 == edges[e2].p1:
|
|
return true
|
|
elif edges[e1].p2 == edges[e2].p2:
|
|
return true
|
|
else:
|
|
return false
|
|
#func check_triangles():
|
|
# for t in triangles:
|
|
# if !adjacent_edges(t[0], t[1]):
|
|
# return false
|
|
# if !adjacent_edges(t[1], t[2]):
|
|
# return false
|
|
# if !adjacent_edges(t[2], t[0]):
|
|
# return false
|
|
# return true
|
|
|
|
func build(rnd_seed):
|
|
cleanup()
|
|
rnd.seed = rnd_seed
|
|
noise.seed = rnd_seed
|
|
for k in range(axiom.size()):
|
|
var cur = k
|
|
var next = (k + 1) % axiom.size()
|
|
if !axiom[cur] in axiom[next].neighbors:
|
|
axiom[next].neighbors.push_back(axiom[cur])
|
|
if !axiom[next] in axiom[cur].neighbors:
|
|
axiom[cur].neighbors.push_back(axiom[next])
|
|
axiom[cur].axiom = true
|
|
vertices.push_back(axiom[k])
|
|
for k in vertices:
|
|
if minpos.x > k.pos.x:
|
|
minpos.x = k.pos.x
|
|
if minpos.y > k.pos.y:
|
|
minpos.y = k.pos.y
|
|
if maxpos.x < k.pos.x:
|
|
maxpos.x = k.pos.x
|
|
if maxpos.y < k.pos.y:
|
|
maxpos.y = k.pos.y
|
|
front += vertices
|
|
state = STATE_ITERATION
|
|
print_debug("starting iteration")
|
|
set_process(true)
|
|
# for v in vertices:
|
|
# print(v.pos)
|
|
func check_suggestion(s, n, front):
|
|
# print(s.pos, " ", map_rect)
|
|
var newfront = front.duplicate()
|
|
if !map_rect.has_point(s.pos):
|
|
return newfront
|
|
if s.pos.distance_to(n.pos) < min_distance:
|
|
return newfront
|
|
for k in n.neighbors:
|
|
if s.pos.distance_to(k.pos) < min_distance:
|
|
return newfront
|
|
|
|
# requires partitioning algorithm for speedup
|
|
for k in vertices:
|
|
if s.pos.distance_to(k.pos) < min_distance:
|
|
if ! k in n.neighbors:
|
|
n.neighbors.append(k)
|
|
if ! n in k.neighbors:
|
|
k.neighbors.append(n)
|
|
return newfront
|
|
for kn in k.neighbors:
|
|
if n.pos == k.pos || n == k || n == kn || n.pos == kn.pos:
|
|
continue
|
|
if are_lines_intersecting(s.pos, n.pos, k.pos, kn.pos):
|
|
return newfront
|
|
if ! s in n.neighbors:
|
|
n.neighbors.push_back(s)
|
|
if ! n in s.neighbors:
|
|
s.neighbors.push_back(n)
|
|
vertices.push_back(s)
|
|
newfront.push_back(s)
|
|
if s.seed:
|
|
vertex_queue.push_back({"data": s, "priority": 4})
|
|
return newfront
|
|
|
|
# simple density map
|
|
# better use image as data source
|
|
func get_density(pos):
|
|
return 0.7
|
|
|
|
func get_suggestion(v):
|
|
return rules.grid.get_suggestion(rnd, v, get_density(v.pos))
|
|
|
|
func iteration(front):
|
|
var newfront = []
|
|
# var s = calc_s(front[0])
|
|
for k in front:
|
|
var suggestion = get_suggestion(k)
|
|
for l in suggestion:
|
|
newfront = check_suggestion(l, k, newfront)
|
|
# better use priority queue for actual code
|
|
if vertex_queue.size() > 0:
|
|
var item = vertex_queue.pop_front()
|
|
if item.priority == 0:
|
|
newfront.push_back(item.data)
|
|
else:
|
|
item.priority -= 1
|
|
vertex_queue.push_back(item)
|
|
return newfront
|
|
|
|
func get_height(x, y):
|
|
return noise.get_noise_2d(x * 10.0, y * 10.0) * 5.0
|
|
|
|
const sidewalk_width = 1.5
|
|
#var potential_edges = []
|
|
#func implode_road():
|
|
## for t in range(0, db._triangles.size(), 3):
|
|
#
|
|
## potential_edges.clear()
|
|
# for v in vertices:
|
|
# for n in v._neighbors:
|
|
# var p1 = v.pos
|
|
# var p2 = vertices[n].pos
|
|
# var dir = (p2 - p1).normalized()
|
|
# var t = dir.tangent()
|
|
# for offset in [-road_width - sidewalk_width,
|
|
# -road_width,
|
|
# road_width,
|
|
# road_width + sidewalk_width]:
|
|
# var ep1 = p1 + offset
|
|
# var ep2 = p2 + offset
|
|
# for p in [ep1, ep2]:
|
|
# if !p in extra_points && !p in points:
|
|
# extra_points.push_back(p)
|
|
# if !p in road_points:
|
|
# road_points.push_back(p)
|
|
# for offset in [-road_width - sidewalk_width - 0.1,
|
|
# road_width + sidewalk_width + 0.1]:
|
|
# var ep1 = p1 + offset
|
|
# var ep2 = p2 + offset
|
|
# for p in [ep1, ep2]:
|
|
# if !p in extra_points && !p in points:
|
|
# extra_points.push_back(p)
|
|
#
|
|
# if !p1 in road_points:
|
|
# road_points.push_back(p1)
|
|
# if !p2 in road_points:
|
|
# road_points.push_back(p2)
|
|
# potential_edges.push_back([p1, ep1])
|
|
# potential_edges.push_back([p1, ep2])
|
|
# potential_edges.push_back([p2, ep3])
|
|
# potential_edges.push_back([p2, ep4])
|
|
# potential_edges.push_back([p1, p2])
|
|
# potential_edges.push_back([ep1, ep2])
|
|
# potential_edges.push_back([ep3, ep4])
|
|
# potential_edges.push_back([ep1, ep4])
|
|
# potential_edges.push_back([ep2, ep3])
|
|
|
|
|
|
|
|
#func adjust_triangles():
|
|
# for e in range(0, triangulation.size(), 3):
|
|
# for c in range(3):
|
|
# var adj = points[triangulation[e + (c + 1) % 3]]
|
|
# var point_a = points[triangulation[e + c]]
|
|
## print(points.size())
|
|
## print(e + (c + 2) % 3)
|
|
# var point_b = points[triangulation[e + (c + 2) % 3]]
|
|
# var n1 = (point_a - adj).normalized()
|
|
# var n2 = (point_b - adj).normalized()
|
|
# var pos = adj + n1 * road_width + n2 * road_width
|
|
# if !pos in extra_points && !pos in points:
|
|
# extra_points.push_back(pos)
|
|
|
|
|
|
|
|
#func build_simple_mesh():
|
|
# var arrays = []
|
|
# var verts = PoolVector3Array()
|
|
# var normals = PoolVector3Array()
|
|
# arrays.resize(ArrayMesh.ARRAY_MAX)
|
|
# var mesh = ArrayMesh.new()
|
|
# for p in polygons:
|
|
# for v in p.vertices:
|
|
# var v3d = Vector3()
|
|
# v3d.x = v.x - float(map_width) / 2.0
|
|
# v3d.z = v.x - float(map_height) / 2.0
|
|
# v3d.y = 0
|
|
# verts.push_back(v3d)
|
|
# normals.push_back(Vector3(1, 1, 1))
|
|
# arrays[ArrayMesh.ARRAY_VERTEX] = verts
|
|
# arrays[ArrayMesh.ARRAY_NORMAL] = normals
|
|
# mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
|
# return mesh
|
|
|
|
#func build_d_mesh():
|
|
# var arrays = []
|
|
# var verts = PoolVector3Array()
|
|
# var normals = PoolVector3Array()
|
|
# var indices = PoolIntArray(Geometry.triangulate_delaunay_2d(points))
|
|
# arrays.resize(ArrayMesh.ARRAY_MAX)
|
|
# var mesh = ArrayMesh.new()
|
|
# for v in points:
|
|
# var v3d = Vector3()
|
|
# v3d.x = v.x - float(map_width) / 2.0
|
|
# v3d.z = v.x - float(map_height) / 2.0
|
|
# v3d.y = 0
|
|
# verts.push_back(v3d)
|
|
# normals.push_back(Vector3(1, 1, 1))
|
|
# arrays[ArrayMesh.ARRAY_VERTEX] = verts
|
|
# arrays[ArrayMesh.ARRAY_NORMAL] = normals
|
|
# arrays[ArrayMesh.ARRAY_INDEX] = indices
|
|
# mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
|
|
# return mesh
|
|
|
|
|
|
#func build_mesh(aabb: AABB, vn: Node):
|
|
# var polylist = []
|
|
# var mesh_aabb = AABB()
|
|
# var rect = Rect2(aabb.position.x + map_width / 2.0,
|
|
# aabb.position.z + map_width / 2.0, aabb.size.x, aabb.size.z)
|
|
# for p in polygons:
|
|
# for v in p.vertices:
|
|
## print(v)
|
|
# if rect.has_point(v) || true:
|
|
# polylist.push_back(p)
|
|
# break
|
|
# var verts_road = PoolVector3Array()
|
|
# var indices_road = PoolIntArray()
|
|
# var normals_road = PoolVector3Array()
|
|
# var verts_lot = PoolVector3Array()
|
|
# var indices_lot = PoolIntArray()
|
|
# var normals_lot = PoolVector3Array()
|
|
# var mesh = ArrayMesh.new()
|
|
# var arrays_roads = []
|
|
# var arrays_lots = []
|
|
# arrays_roads.resize(ArrayMesh.ARRAY_MAX)
|
|
# arrays_lots.resize(ArrayMesh.ARRAY_MAX)
|
|
# var idx_road = 0
|
|
# var idx_lot = 0
|
|
# for p in polylist:
|
|
# var vid = 0
|
|
# for v in p.vertices:
|
|
## var v = p.vertices[e.indices[0]]
|
|
# var v3d = Vector3()
|
|
# v3d.x = v.x - float(map_width) / 2.0
|
|
# v3d.z = v.x - float(map_height) / 2.0
|
|
# v3d.y = get_height(v3d.x, v3d.z)
|
|
# v3d.y = 0
|
|
# v3d *= 0.005
|
|
# mesh_aabb = mesh_aabb.expand(v3d)
|
|
# if p.road:
|
|
# verts_road.push_back(v3d)
|
|
# normals_road.push_back(Vector3(0, 1, 0))
|
|
# indices_road.push_back(idx_road + vid)
|
|
# else:
|
|
# verts_lot.push_back(v3d)
|
|
# normals_lot.push_back(Vector3(0, 1, 0))
|
|
# indices_lot.push_back(idx_lot + vid)
|
|
# vid += 1
|
|
# if p.road:
|
|
# idx_road += 3
|
|
# else:
|
|
# idx_lot += 3
|
|
# print(verts_lot.size())
|
|
# print(verts_lot)
|
|
## print(indices_lot)
|
|
## print(mesh_aabb)
|
|
# arrays_roads[ArrayMesh.ARRAY_VERTEX] = verts_road
|
|
## arrays_roads[ArrayMesh.ARRAY_NORMAL] = normals_road
|
|
## arrays_roads[ArrayMesh.ARRAY_INDEX] = indices_road
|
|
# arrays_lots[ArrayMesh.ARRAY_VERTEX] = verts_lot
|
|
## arrays_lots[ArrayMesh.ARRAY_NORMAL] = normals_lot
|
|
## arrays_lots[ArrayMesh.ARRAY_INDEX] = indices_lot
|
|
## print(verts_lot)
|
|
# mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_roads)
|
|
## arrays_lots[ArrayMesh.ARRAY_VERTEX] = PoolVector3Array([Vector3(-1, -1, -1), Vector3(0, 0, 0), Vector3(0, 0, 1)])
|
|
# mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays_lots)
|
|
## mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, PlaneMesh.new().get_mesh_arrays())
|
|
# var mat = SpatialMaterial.new()
|
|
# mat.params_cull_mode = SpatialMaterial.CULL_DISABLED
|
|
# mesh.surface_set_material(0, mat)
|
|
# mesh.surface_set_material(1, mat)
|
|
# mesh.custom_aabb = mesh_aabb
|
|
# var mi = MeshInstance.new()
|
|
# vn.add_child(mi)
|
|
# mi.mesh = mesh
|
|
#
|
|
# return mesh
|
|
|
|
func _ready():
|
|
set_process(false)
|
|
rules.grid = GridRule.new()
|
|
rnd = RandomNumberGenerator.new()
|
|
noise = OpenSimplexNoise.new()
|
|
# db = PointDB.new()
|
|
|
|
func inset_point(v: Dictionary, n:Dictionary, new_pos: Vector2):
|
|
var nv = new_vertex(new_pos.x, new_pos.y)
|
|
nv._index = vertices.size()
|
|
nv._neighbors = []
|
|
remove_neighbor(v, n)
|
|
add_neighbor(v, nv)
|
|
add_neighbor(n, nv)
|
|
vertices.push_back(nv)
|
|
|
|
class VertexData:
|
|
var data: Dictionary
|
|
var _road_width: float
|
|
var _sidewalk_width: float
|
|
func _init(v: Dictionary, road_width: float, sidewalk_width: float):
|
|
data = v
|
|
_road_width = road_width
|
|
_sidewalk_width = sidewalk_width
|
|
assert v.has("_index")
|
|
assert v.has("_neighbors")
|
|
func angle_sort_helper(a, b):
|
|
var v1: Vector2 = a[1] - a[0]
|
|
var v2: Vector2 = b[1] - b[0]
|
|
if v1.angle() < v2.angle():
|
|
return true
|
|
return false
|
|
func get_wedges(vertices: Array) -> Array:
|
|
assert data
|
|
var edges = []
|
|
for id in data._neighbors:
|
|
edges.push_back([data.pos, vertices[id].pos, data._index, id])
|
|
edges.sort_custom(self, "angle_sort_helper")
|
|
var wedges = []
|
|
for h in range(edges.size()):
|
|
var cur = h
|
|
var next = (h + 1) % edges.size()
|
|
var wedge = PoolIntArray([edges[cur][3], edges[cur][2], edges[next][3]])
|
|
wedges.push_back(wedge)
|
|
return wedges
|
|
func get_dir(a: Dictionary, b: Dictionary) -> Vector2:
|
|
return (b.pos - a.pos).normalized()
|
|
func get_dir_pos(a: Vector2, b: Vector2) -> Vector2:
|
|
return (b - a).normalized()
|
|
func get_tangent_pos(a: Vector2, b: Vector2) -> Vector2:
|
|
return get_dir_pos(a, b).tangent().normalized()
|
|
func get_tangent(a: Dictionary, b: Dictionary) -> Vector2:
|
|
return get_tangent_pos(a.pos, b.pos)
|
|
func get_road_end_point(a: Dictionary, intersection: Dictionary) -> Vector2:
|
|
var dir = get_dir(intersection, a)
|
|
return intersection.pos + dir * (_road_width + _sidewalk_width)
|
|
func get_road_offset(a: Dictionary, b: Dictionary):
|
|
var side = get_tangent(a, b)
|
|
return side * _road_width
|
|
func get_sidewalk_offset(a: Dictionary, b: Dictionary):
|
|
var side = get_tangent(a, b)
|
|
return side * _sidewalk_width
|
|
func get_intersection_road_points(a: Dictionary, intersection: Dictionary, b: Dictionary):
|
|
var mida: Vector2 = a.pos.linear_interpolate(intersection.pos, 0.5)
|
|
var midb: Vector2 = b.pos.linear_interpolate(intersection.pos, 0.5)
|
|
var enda: Vector2 = get_road_end_point(a, intersection)
|
|
var endb: Vector2 = get_road_end_point(b, intersection)
|
|
var dira: Vector2 = get_dir(a, intersection)
|
|
var dirb: Vector2 = get_dir(intersection, b)
|
|
var offset_a = get_tangent_pos(a.pos, enda) * _road_width
|
|
var offset_b = get_tangent_pos(endb, b.pos) * _road_width
|
|
# a.pos enda.pos intersection.pos endb.pos b.pos
|
|
var a_side = mida + offset_a
|
|
var enda_side = enda + offset_a
|
|
var b_side = midb + offset_b
|
|
var endb_side = endb + offset_b
|
|
var intersection_side_a = intersection.pos + offset_a
|
|
var intersection_side_b = intersection.pos + offset_b
|
|
var intersection_side = intersection.pos.linear_interpolate(intersection.pos + offset_a + offset_b, 0.5)
|
|
var mid_point = Geometry.segment_intersects_segment_2d(
|
|
enda_side,
|
|
intersection_side_a + dira * _road_width * 2.0,
|
|
intersection_side_b - dirb * _road_width * 2.0,
|
|
endb_side)
|
|
if mid_point:
|
|
intersection_side = mid_point
|
|
|
|
var points_main = [mida, enda, intersection.pos, endb, midb]
|
|
var points_side = [a_side, enda_side, intersection_side, endb_side, b_side]
|
|
var triangles = []
|
|
for k in range(5 - 1):
|
|
triangles += [k + 5, k, k + 1, k + 5, k + 1, k + 6]
|
|
return {
|
|
"points_main": points_main,
|
|
"points_side": points_side,
|
|
"points_total": points_main + points_side,
|
|
"triangles": triangles
|
|
}
|
|
|
|
func get_straight_road_segment_points(a: Dictionary, b: Dictionary):
|
|
var mida: Vector2 = a.pos.linear_interpolate(b.pos, 0.5)
|
|
var enda: Vector2 = get_road_end_point(a, b)
|
|
var offset_a = get_tangent_pos(a.pos, enda) * _road_width
|
|
var a_side = a.pos + offset_a
|
|
var mida_side = mida + offset_a
|
|
var enda_side = enda + offset_a
|
|
var b_side = b.pos + offset_a
|
|
var a_side2 = a.pos - offset_a
|
|
var mida_side2 = mida - offset_a
|
|
var enda_side2 = enda - offset_a
|
|
var b_side2 = b.pos - offset_a
|
|
var points_main = [a.pos, mida, enda, b.pos]
|
|
var points_side = [a_side, mida_side, enda_side, b_side]
|
|
var points_side2 = [a_side2, mida_side2, enda_side2, b_side2]
|
|
var triangles = []
|
|
for k in range(4 - 1):
|
|
triangles += [k + 4, k, k + 1, k + 4, k + 1, k + 5]
|
|
for k in range(8, 12 - 1, 1):
|
|
triangles += [k + 4, k, k + 1, k + 4, k + 1, k + 5]
|
|
return {
|
|
"points_main": points_main,
|
|
"points_side": points_side,
|
|
"points_side2": points_side2,
|
|
"points_total": points_side2 + points_main + points_main + points_side,
|
|
"triangles": triangles
|
|
}
|
|
|
|
func get_wedge_road_points(wedge: Array, vertices: Array):
|
|
if wedge[0] != wedge[2]:
|
|
var a = vertices[wedge[0]]
|
|
var b = vertices[wedge[2]]
|
|
var intersection = vertices[wedge[1]]
|
|
return get_intersection_road_points(a, intersection, b)
|
|
else:
|
|
var a = vertices[wedge[0]]
|
|
var b = vertices[wedge[1]]
|
|
return get_straight_road_segment_points(a, b)
|
|
func get_all_road_points(vertices: Array) -> Array:
|
|
var ret : = []
|
|
var wedges = get_wedges(vertices)
|
|
for wedge in wedges:
|
|
ret.push_back(get_wedge_road_points(wedge, vertices))
|
|
return ret
|
|
|
|
var vertex_data_queue = []
|
|
var lot_state
|
|
|
|
func _process(delta):
|
|
if randf() < 0.8:
|
|
return
|
|
match(state):
|
|
STATE_INIT:
|
|
pass
|
|
STATE_ITERATION:
|
|
if randf() > 0.8:
|
|
if front.size() > 0 || vertex_queue.size() > 0:
|
|
front = iteration(front)
|
|
else:
|
|
state = STATE_EDGES1
|
|
print("vertex num: ", vertices.size())
|
|
STATE_EDGES1:
|
|
print_debug("iteration finished")
|
|
# var ax_verts = []
|
|
# for k in vertices:
|
|
# if k.has("axiom") && k.axiom == true:
|
|
# for l in vertices:
|
|
# if l == k:
|
|
# continue
|
|
# if k in l.neighbors:
|
|
# l.neighbors.erase(k)
|
|
# ax_verts.push_back(k)
|
|
# for v in ax_verts:
|
|
# vertices.erase(v)
|
|
# print_debug("cleanup finished")
|
|
convert_vertices()
|
|
print_debug("conversion finished")
|
|
state = STATE_EDGES2
|
|
vertex_data_queue = range(vertices.size())
|
|
STATE_EDGES2:
|
|
if randf() > 0.8:
|
|
var count: int = 0
|
|
while vertex_data_queue.size() > 0 && count < 20:
|
|
var v = vertex_data_queue.pop_front()
|
|
var vdata = VertexData.new(vertices[v], road_width, sidewalk_width)
|
|
vertices[v]._vdata = vdata
|
|
vertices[v]._points = vdata.get_all_road_points(vertices)
|
|
count += 1
|
|
# points = []
|
|
# for k in vertices:
|
|
# points.push_back(k.pos)
|
|
# db = PointDB.new()
|
|
# db.build_grid(points, 64)
|
|
# print_debug("points: ", points.size())
|
|
# assert points.size() == db._points.size()
|
|
# for v in vertices:
|
|
# assert db._pos2id.has(v.pos)
|
|
# for v in vertices:
|
|
# for n in v.neighbors:
|
|
# assert db._pos2id.has(n.pos)
|
|
# print_debug("data tests passed")
|
|
# print(points.size(), " ", db._points.size())
|
|
|
|
# for e in range(vertices.size()):
|
|
# for h in vertices[e]._neighbors:
|
|
# add_edge(e, h, true)
|
|
# print_debug("edges added")
|
|
if vertex_data_queue.size() == 0:
|
|
state = STATE_EDGES3
|
|
print_debug("road points complete")
|
|
STATE_EDGES3:
|
|
for v in range(vertices.size()):
|
|
for entry in range(vertices[v]._points.size()):
|
|
var points = vertices[v]._points[entry].points_total
|
|
var points_3d = []
|
|
for p in points:
|
|
var p3d = Vector3(p.x - map_width * 0.5, get_height(p.x - map_width * 0.5, p.y - map_height * 0.5), p.y - map_height * 0.5)
|
|
points_3d.push_back(p3d)
|
|
vertices[v]._points[entry].points3d = points_3d
|
|
print("points complete")
|
|
|
|
# implode_road()
|
|
# print(points.size(), " ", extra_points.size())
|
|
# adjust_triangles()
|
|
# print(points.size(), " ", extra_points.size())
|
|
# points = PoolVector2Array(Array(points) + extra_points)
|
|
# print(extra_points.size())
|
|
# triangulation = Geometry.triangulate_delaunay_2d(points)
|
|
# db.build_grid(points,64)
|
|
# print_debug("edges3")
|
|
#
|
|
# var bad_edges = []
|
|
# for v in vertices:
|
|
# for n in v.neighbors:
|
|
## print(points.size(), " ", db._points.size())
|
|
# assert points.size() == db._points.size()
|
|
# assert v.pos in points
|
|
# assert n.pos in points
|
|
# assert v.pos in db._points
|
|
# assert n.pos in db._points
|
|
# if !db.add_edge_data(v.pos, n.pos, {"road": true}):
|
|
# bad_edges.push_back([v._index, n._index])
|
|
# if bad_edges.size() > 0:
|
|
# print("bad edges: ", bad_edges, " ", bad_edges.size())
|
|
# for pe in extra_points:
|
|
# var e = db.get_point_edges(pe)
|
|
# for d in e:
|
|
# db.add_edge_data(d[0], d[1], {"road": true})
|
|
# for e in bad_edges:
|
|
# var p1: Vector2 = vertices[e[0]].pos
|
|
# var p2: Vector2 = vertices[e[1]].pos
|
|
# var new_pos: Vector2
|
|
# if p1.distance_squared_to(p2) > 20.0 * 20.0:
|
|
# new_pos = p1 + (p2 - p1).normalized() * 20.0
|
|
# else:
|
|
# new_pos = vertices[e[0]].pos.linear_interpolate(vertices[e[1]].pos, 0.5)
|
|
# inset_point(vertices[e[0]], vertices[e[1]], new_pos)
|
|
# state = STATE_EDGES2
|
|
# else:
|
|
# state = STATE_POLYGONS1
|
|
state = STATE_POLYGONS1
|
|
#
|
|
# for p in extra_points:
|
|
# db.add_point_data(p, {"road": false})
|
|
# var edges = db.get_point_edges(p)
|
|
# for me in edges:
|
|
# var np = me[0]
|
|
# if np == p:
|
|
# np = me[1]
|
|
# var edges2 = db.get_point_edges(np)
|
|
# var road = false
|
|
# for me2 in edges2:
|
|
# var data = db.get_edge_data(me2[0], me2[1])
|
|
# if data.has("road") && data.road == true:
|
|
# road = true
|
|
# break
|
|
# if road:
|
|
# db.add_edge_data(me[0], me[1], {"road": true})
|
|
|
|
# update_neighbors()
|
|
# print("neighbors updated")
|
|
# build_edges()
|
|
# print("edges built")
|
|
# print_debug("edges build complete")
|
|
# if !check_triangles():
|
|
# print("bad triangles")
|
|
# print(triangulation)
|
|
STATE_POLYGONS1:
|
|
if lot_state == null:
|
|
lots = Lots.new()
|
|
lot_state = lots.generate_lots(vertices, road_width, sidewalk_width, map_width, map_height)
|
|
elif lot_state is GDScriptFunctionState:
|
|
lot_state = lot_state.resume()
|
|
else:
|
|
state = STATE_POLYGONS2
|
|
print("polygons built")
|
|
# db = LotsDB.new(vertices, road_width, sidewalk_width)
|
|
# polygon_queue = db.get_polygons()
|
|
# for r in range(polygon_queue.size()):
|
|
# if polygon_queue[r].size() == 6:
|
|
# polygon_queue[r].push_back({})
|
|
#
|
|
# print("building polygons")
|
|
# build_polygons()
|
|
STATE_POLYGONS2:
|
|
grid = GridData.new()
|
|
for v in range(vertices.size()):
|
|
grid.add_point_to_grid(vertices[v].pos, v)
|
|
# if polygon_queue.size() > 0:
|
|
# var item = polygon_queue.pop_front()
|
|
# var p1 = item[0]
|
|
# var p2 = item[1]
|
|
# var p3 = item[2]
|
|
# var e1 = [p1, p2]
|
|
# var e2 = [p2, p3]
|
|
# var e3 = [p3, p1]
|
|
# var more_polys = []
|
|
# if !item[6].has("type"):
|
|
# if item[3].has("road") && item[3].road == true:
|
|
# more_polys += implode_road_poly(0, item)
|
|
# elif item[4].has("road") && item[3].road == true:
|
|
# more_polys += implode_road_poly(1, item)
|
|
# elif item[5].has("road") && item[3].road == true:
|
|
# more_polys += implode_road_poly(2, item)
|
|
# else:
|
|
# assert false
|
|
|
|
|
|
# separate_roads()
|
|
# print(polygons)
|
|
state = STATE_COMPLETE
|
|
STATE_COMPLETE:
|
|
print_debug("world build complete")
|
|
set_process(false)
|
|
emit_signal("complete")
|
|
state = STATE_INIT
|