travking fluid particle

This commit is contained in:
zomseffen 2021-12-20 17:21:46 +01:00
parent 8a5de47da3
commit 54bda855e5
10 changed files with 702 additions and 37 deletions
Objects

View file

@ -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)