travking fluid particle
This commit is contained in:
parent
8a5de47da3
commit
54bda855e5
10 changed files with 702 additions and 37 deletions
Objects
229
Objects/World.py
229
Objects/World.py
|
@ -7,6 +7,8 @@ from OpenGL.GLU import *
|
|||
from OpenGL.GL import *
|
||||
import math
|
||||
import numpy as np
|
||||
import random
|
||||
import sys
|
||||
|
||||
class WorldChunk(Structure):
|
||||
def __init__(self, width: int, length: int, height: int, programs: dict):
|
||||
|
@ -200,6 +202,11 @@ class World(Renderable):
|
|||
self.chunk_n_z = chunk_n_z
|
||||
self.programs = programs
|
||||
|
||||
self.fault_nodes = []
|
||||
self.fault_lines = []
|
||||
self.plates = None
|
||||
self.directions = None
|
||||
|
||||
self.chunks: [[[WorldChunk]]] = []
|
||||
for x in range(chunk_n_x):
|
||||
self.chunks.append([])
|
||||
|
@ -208,6 +215,228 @@ class World(Renderable):
|
|||
for z in range(chunk_n_z):
|
||||
self.chunks[x][y].append(None)
|
||||
|
||||
def generate(self, seed=None, sea_height=50, continental_height=200):
|
||||
if seed is None:
|
||||
seed = random.randrange(2**32)
|
||||
seed = 229805811
|
||||
print('Generation seed is %i' % seed)
|
||||
random.seed(seed)
|
||||
np.random.seed(seed)
|
||||
node_n = self.chunk_n_x + self.chunk_n_y
|
||||
total_x = self.chunk_n_x * self.chunk_size_x
|
||||
total_y = self.chunk_n_y * self.chunk_size_y
|
||||
nodes = []
|
||||
for _ in range(node_n):
|
||||
nodes.append([random.randint(0, total_x - 1), random.randint(0, total_y - 1)])
|
||||
|
||||
# connections = np.random.randint(2, 5, len(nodes)) #np.zeros(len(nodes)) + 3
|
||||
connections = (np.abs(np.random.normal(0, 5, len(nodes))) + 2).astype(np.int)
|
||||
|
||||
def calc_min_vector(start, end):
|
||||
dx = end[0] - start[0]
|
||||
wrapped_dx = dx % total_x
|
||||
|
||||
dy = end[1] - start[1]
|
||||
wrapped_dy = dy % total_y
|
||||
|
||||
vector = np.array([dx, dy])
|
||||
if wrapped_dx < abs(dx):
|
||||
vector[0] = wrapped_dx
|
||||
if wrapped_dy < abs(dy):
|
||||
vector[1] = wrapped_dy
|
||||
return vector
|
||||
|
||||
def is_intersecting_any(start, end, edges):
|
||||
vec1 = calc_min_vector(start, end)
|
||||
|
||||
for (start2_index, end2_index) in edges:
|
||||
start2 = nodes[start2_index]
|
||||
end2 = nodes[end2_index]
|
||||
|
||||
vec2 = calc_min_vector(start2, end2)
|
||||
|
||||
norm1 = vec1 / np.sqrt(np.sum(np.square(vec1)))
|
||||
norm2 = vec2 / np.sqrt(np.sum(np.square(vec2)))
|
||||
|
||||
# parrallel
|
||||
parallel_threshold = 0.0001
|
||||
if np.sqrt(np.sum(np.square(norm1 - norm2))) < parallel_threshold or np.sqrt(np.sum(np.square(norm1 + norm2))) < parallel_threshold:
|
||||
t = (start[0] - start2[0]) / vec2[0]
|
||||
t2 = (end[0] - start2[0]) / vec2[0]
|
||||
s = (start2[0] - start[0]) / vec1[0]
|
||||
s2 = (end2[0] - start[0]) / vec1[0]
|
||||
if (start2[1] + t * vec2[1]) - start[1] < parallel_threshold:
|
||||
if (0 <= t <= 1.0 and 0 <= t2 <= 1.0) or (0 <= s <= 1.0 and 0 <= s2 <= 1.0):
|
||||
return True
|
||||
else:
|
||||
if start != start2 and end != end2 and end != start2 and start != end2:
|
||||
t = (vec1[0] * start[1] + vec1[1] * start2[0] - vec1[1] * start[0] - start2[1] * vec1[0]) / (vec2[1] * vec1[0] - vec2[0] * vec1[1])
|
||||
if 0 <= t <= 1.0:
|
||||
intersection = np.array(start2) + vec2 * t
|
||||
s = (intersection[0] - start[0]) / vec1[0]
|
||||
if 0 <= s <= 1.0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
for index, node in enumerate(nodes):
|
||||
distances = []
|
||||
for other_index, other_node in enumerate(nodes):
|
||||
if node != other_node and (index, other_index) not in self.fault_lines and\
|
||||
(other_index, index) not in self.fault_lines:
|
||||
if (not is_intersecting_any(node, other_node, self.fault_lines)) and (not is_intersecting_any(other_node, node, self.fault_lines)):
|
||||
distances.append((other_index, np.sqrt(np.sum(np.square(calc_min_vector(node, other_node))))))
|
||||
|
||||
distances.sort(key=lambda element: element[1])
|
||||
while connections[index] > 0 and len(distances) > 0:
|
||||
self.fault_lines.append((index, distances[0][0]))
|
||||
connections[distances[0][0]] -= 1
|
||||
connections[index] -= 1
|
||||
distances.pop(0)
|
||||
|
||||
self.fault_nodes = nodes
|
||||
|
||||
plates = np.zeros((total_x, total_y))
|
||||
faults = np.zeros((total_x, total_y)) - 1
|
||||
plate_bordering_fault = {}
|
||||
# draw fault lines
|
||||
for fault_index, fault_line in enumerate(self.fault_lines):
|
||||
start = self.fault_nodes[fault_line[0]]
|
||||
end = self.fault_nodes[fault_line[1]]
|
||||
vector = calc_min_vector(start, end)
|
||||
vector = vector / np.sqrt(np.sum(np.square(vector)))
|
||||
|
||||
point = np.array(start, dtype=np.float)
|
||||
plate_bordering_fault[fault_index] = []
|
||||
|
||||
while np.sqrt(np.sum(np.square(point - np.array(end)))) > 0.5:
|
||||
plates[int(point[0]), int(point[1])] = -1
|
||||
if faults[int(point[0]), int(point[1])] == -1:
|
||||
faults[int(point[0]), int(point[1])] = fault_index
|
||||
elif faults[int(point[0]), int(point[1])] != fault_index:
|
||||
faults[int(point[0]), int(point[1])] = -2
|
||||
point += 0.5 * vector
|
||||
point[0] %= total_x
|
||||
point[1] %= total_y
|
||||
self.faults = faults
|
||||
|
||||
plate = 1
|
||||
while np.any(plates == 0):
|
||||
start = np.where(plates == 0)
|
||||
start = (start[0][0], start[1][0])
|
||||
plates[start] = plate
|
||||
work_list = [start]
|
||||
|
||||
while len(work_list) > 0:
|
||||
work = work_list.pop()
|
||||
|
||||
up = (work[0], (work[1] + 1) % total_y)
|
||||
down = (work[0], (work[1] - 1) % total_y)
|
||||
left = ((work[0] - 1) % total_x, work[1])
|
||||
right = ((work[0] + 1) % total_x, work[1])
|
||||
|
||||
if plates[up] == -1 and plates[down] == -1 and plates[left] == -1 and plates[right] == -1:
|
||||
plates[work] = -1
|
||||
continue
|
||||
|
||||
if plates[up] <= 0:
|
||||
if plates[up] == 0:
|
||||
work_list.append(up)
|
||||
plates[up] = plate
|
||||
if plates[down] <= 0:
|
||||
if plates[down] == 0:
|
||||
work_list.append(down)
|
||||
plates[down] = plate
|
||||
if plates[left] <= 0:
|
||||
if plates[left] == 0:
|
||||
work_list.append(left)
|
||||
plates[left] = plate
|
||||
if plates[right] <= 0:
|
||||
if plates[right] == 0:
|
||||
work_list.append(right)
|
||||
plates[right] = plate
|
||||
|
||||
if faults[up] > -1:
|
||||
if plate not in plate_bordering_fault[faults[up]]:
|
||||
plate_bordering_fault[faults[up]].append(plate)
|
||||
if faults[down] > -1:
|
||||
if plate not in plate_bordering_fault[faults[down]]:
|
||||
plate_bordering_fault[faults[down]].append(plate)
|
||||
if faults[left] > -1:
|
||||
if plate not in plate_bordering_fault[faults[left]]:
|
||||
plate_bordering_fault[faults[left]].append(plate)
|
||||
if faults[right] > -1:
|
||||
if plate not in plate_bordering_fault[faults[right]]:
|
||||
plate_bordering_fault[faults[right]].append(plate)
|
||||
plate += 1
|
||||
|
||||
plate_num = plate
|
||||
for plate in range(1, plate_num):
|
||||
if np.sum(plates == plate) < 20:
|
||||
plates[plates == plate] = -1
|
||||
for key, item in plate_bordering_fault.items():
|
||||
if plate in item:
|
||||
item.remove(plate)
|
||||
|
||||
directions = np.zeros((total_x, total_y, 3))
|
||||
heights = np.zeros((total_x, total_y))
|
||||
for plate in range(1, plate_num):
|
||||
if random.randint(1, 2) == 1:
|
||||
heights[plates == plate] = sea_height
|
||||
else:
|
||||
heights[plates == plate] = continental_height
|
||||
|
||||
coords = np.zeros((total_x, total_y, 2))
|
||||
for x in range(total_x):
|
||||
for y in range(total_y):
|
||||
coords[x, y, 0] = x
|
||||
coords[x, y, 1] = y
|
||||
|
||||
for fault_index, fault_line in enumerate(self.fault_lines):
|
||||
start = self.fault_nodes[fault_line[0]]
|
||||
end = self.fault_nodes[fault_line[1]]
|
||||
vector = calc_min_vector(start, end)
|
||||
vector = vector / np.sqrt(np.sum(np.square(vector)))
|
||||
|
||||
perpendicular = np.array([vector[1], -vector[0]])
|
||||
|
||||
if len(plate_bordering_fault[fault_index]) == 2:
|
||||
for plate in plate_bordering_fault[fault_index]:
|
||||
vecs = coords - np.array(start)
|
||||
lengths = np.sqrt(np.sum(np.square(vecs), axis=2, keepdims=True))
|
||||
norm_vecs = vecs / lengths
|
||||
scalars = np.sum(norm_vecs * perpendicular, axis=2, keepdims=True)
|
||||
scalars[lengths == 0] = 0
|
||||
|
||||
end_vecs = coords - np.array(end)
|
||||
end_lengths = np.sqrt(np.sum(np.square(end_vecs), axis=2, keepdims=True))
|
||||
end_min_length = np.min(end_lengths[np.logical_and(plates == plate, end_lengths[:, :, 0] > 0)])
|
||||
end_min_length_scalar = scalars[np.logical_and(plates == plate, end_lengths[:, :, 0] == end_min_length)][0, 0]
|
||||
|
||||
min_length = np.min(lengths[np.logical_and(plates == plate, lengths[:, :, 0] > 0)])
|
||||
min_length_scalar = scalars[np.logical_and(plates == plate, lengths[:, :, 0] == min_length)][0, 0]
|
||||
|
||||
mean_scalar = np.mean(scalars[plates == plate])
|
||||
|
||||
if (min_length_scalar / abs(min_length_scalar)) == (end_min_length_scalar / abs(end_min_length_scalar)):
|
||||
scalar = min_length_scalar
|
||||
else:
|
||||
if (min_length_scalar / abs(min_length_scalar)) == (mean_scalar / abs(mean_scalar)):
|
||||
scalar = min_length_scalar
|
||||
else:
|
||||
scalar = end_min_length_scalar
|
||||
|
||||
directions[plates == plate, :2] += perpendicular * (scalar / abs(scalar))
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
self.plates = plates
|
||||
self.directions = directions
|
||||
|
||||
def set_color(self, x: int, y: int, z: int, r: float, g: float, b: float):
|
||||
x = x % (self.chunk_size_x * self.chunk_n_x)
|
||||
y = y % (self.chunk_size_y * self.chunk_n_y)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue