-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOcttree.py
174 lines (150 loc) · 5.99 KB
/
Octtree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
from vectors import Vector
#the data struct
class Octree:
def __init__(self, center, size):
self.center = Vector(*center)
self.size = size
self.stars = []
self.children = [None] * 8
self.total_mass = 0
def insert_star(self, star):
# deja divisé ou pas
if all(child is None for child in self.children):
if len(self.stars) == 0:
# cas cube vide
self.stars.append(star)
self.total_mass += star.masse
else:
index = self.get_octant_index(star.position)
if self.children[index] is None:
self.subdivide(index)
self.children[index].insert_star(star)
self.insert_star(self.stars[0])
self.stars=[]
else:
# trouve dans quel cube se situe l'etoile
index = self.get_octant_index(star.position)
# si le fils n'existe pas on le cree
if self.children[index] is None:
self.subdivide(index)
# Recursively insert the star into the appropriate child
self.children[index].insert_star(star)
def get_octant_index(self, position):
# cette fonction determine dans quel cube des 8 sera l'etoiles en fonction de leur coordonnee
x, y, z = position
index = 0
if x >= self.center[0]:
index |= 1
if y >= self.center[1]:
index |= 2
if z >= self.center[2]:
index |= 4
return index
def subdivide(self, index):
# Calculate the size of the new child octant
new_size = (self.size / 2)
# Calculate the new center of the child octant
new_center = self.center + Vector(
new_size * (1 if index & 1 else -1),
new_size * (1 if index & 2 else -1),
new_size * (1 if index & 4 else -1)
)
# Creation de "child"
self.children[index] = Octree(new_center, new_size)
def update_all(self):
pass
def update_recursive(self): #useless function
for star in self.stars:
star.move()
star.draw()
for child in self.children:
if child is not None:
child.update_recursive()
def __repr__(self, level=0):
indentation = " " * level
#représentation pour cet Octree
representation = f"{indentation}Octree(center={self.center}, size={self.size}, num_stars={len(self.stars)})"
#appel pour les enfants
for child in self.children:
if child is not None:
representation += f"\n{child.__repr__(level + 1)}"
return representation
# -------------- /// Barnes-Hut Algorithm
def calculate_force(self, star):
# si il y a d'enfant le calcul il est direct
if all(child is None for child in self.children):
force = self.calculate_direct_methode_force(star)
else:
# calcul de theta
direction = self.center - Vector(*star.position)
distance =direction.get_norme()
theta = self.size /distance
if theta < 1:# condition non verifie
force = self.calculate_direct_methode_force(star)
else:
# calcul recursive de la force
force =Vector(0,0,0)
for child in self.children:
if child is not None:
force += child.calculate_force(star)
return force
def calculate_direct_methode_force(self, star):
# Calcule la force d'attraction gravitationnelle directe entre l'étoile et cet octree
direction = self.center - Vector(*star.position)
distance = direction.get_norme()
if distance == 0:
return Vector(0, 0, 0) # Éviter une division par zéro
force = ( direction * float(self.total_mass) ) / (distance ** 3)
return force
def remove_star(self):
if self.head is None:# cas de pere de centre 0,0,0
self.stars=[]
return
# Supprimer cette étoile de l'octree actuel
self.stars = []
# Vérifier le nombre de fils du parent
index=self.head.children.index(self)
self.head.children[index]=None
# S'il reste un seul fils, supprimer le fils, la division et réinsérer le fils
self.equi()
# Appeler la méthode remove_star sur le parent récursivement
#self.head.remove_star()
def equi(self):
first_octtree=self.head
while first_octtree.head != None:
first_octtree = first_octtree.head
pere = self.head
#print(pere.children)
if pere.children.count(None) == 7:
#print("in",pere)
#index = pere.children.index(pere)
#pere.head.children[index]=None
etoileTemp=None
for child in pere.children:
if child ==None:
continue
if len(child.stars)!=0:
for etoile in child.stars:
etoileTemp=etoile
print(etoile)
if etoileTemp != None:
first_octtree.insert_star(etoileTemp)
if pere.head!=None:
pere.head.equi()
else:
return
elif pere.children.count(None) == 8:
index = pere.head.children.index(pere)
pere.head.children[index]=None
pere.head.equi()
else : return
def star_inside(self):
x,y,z = get_first_non_none_element(self.stars).position
center = self.center
size = self.size
return center-size <= x <= size+center and center-size <= y <= size+center and center-size <= z <= size+center
def get_first_non_none_element(my_list):
for element in my_list:
if element is not None:
return element
return None