Skip to content

Commit 337d321

Browse files
committed
Working Trimesh learning environment with new quality actions analysis and with old geometrical analysis. There are still some kinds of meshes which create problems with the new analysis
1 parent 3d2ee56 commit 337d321

File tree

9 files changed

+919
-71
lines changed

9 files changed

+919
-71
lines changed

environment/actions/triangular_actions.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import copy
44
import numpy as np
55
from mesh_model.mesh_analysis.global_mesh_analysis import NodeAnalysis
6-
from mesh_model.mesh_analysis.trimesh_analysis import TriMeshQualityAnalysis
76
from mesh_model.mesh_struct.mesh_elements import Node, Dart
87
from view.mesh_plotter.mesh_plots import plot_mesh
98

@@ -103,7 +102,7 @@ def split_edge(mesh_analysis, n1: Node, n2: Node) -> True:
103102

104103
d2, d1, d11, d21, d211, n1, n2, n3, n4 = mesh_analysis.mesh.active_triangles(d)
105104

106-
# create a new node in the middle of [n1, n2]
105+
# Create a new node in the middle of [n1, n2]
107106
N5 = mesh_analysis.mesh.add_node((n1.x() + n2.x()) / 2, (n1.y() + n2.y()) / 2)
108107

109108
# modify existing triangles
@@ -254,20 +253,31 @@ def collapse_edge(mesh_analysis, n1: Node, n2: Node) -> True:
254253
plot_mesh(mesh_analysis.mesh)
255254
raise ValueError("Potential infinite loop in action collapse")
256255

257-
258-
if mesh_analysis.is_star_vertex(n1, mid):
259-
n1.set_xy(mid[0], mid[1])
260-
elif mesh_analysis.is_star_vertex(n1, near_n1):
261-
n1.set_xy(near_n1[0], near_n1[1])
262-
elif mesh_analysis.is_star_vertex(n1, near_n2):
263-
n1.set_xy(near_n2[0], near_n2[1])
264-
elif mesh_analysis.is_star_vertex(n1, np.array([n1.x(), n1.y()])):
265-
pass
266-
elif mesh_analysis.is_star_vertex(n1, np.array([n2x, n2y])):
267-
n1.set_xy(n2x, n2y)
256+
found, new_x, new_y = mesh_analysis.find_star_vertex(n1)
257+
if found:
258+
n1.set_xy(new_x, new_y)
268259
else:
260+
plot_mesh(mesh_before)
261+
plot_mesh(mesh_analysis.mesh)
262+
mesh_analysis.find_star_vertex(n1, plot=True)
269263
raise ValueError("No star vertex found")
270264

265+
# if mesh_analysis.is_star_vertex(n1, mid):
266+
# n1.set_xy(mid[0], mid[1])
267+
# elif mesh_analysis.is_star_vertex(n1, near_n1):
268+
# n1.set_xy(near_n1[0], near_n1[1])
269+
# elif mesh_analysis.is_star_vertex(n1, near_n2):
270+
# n1.set_xy(near_n2[0], near_n2[1])
271+
# elif mesh_analysis.is_star_vertex(n1, np.array([n1.x(), n1.y()])):
272+
# pass
273+
# elif mesh_analysis.is_star_vertex(n1, np.array([n2x, n2y])):
274+
# n1.set_xy(n2x, n2y)
275+
# else:
276+
# plot_mesh(mesh_before)
277+
# plot_mesh(mesh_analysis.mesh)
278+
# mesh_analysis.is_star_vertex(n1, np.array([n1.x(), n1.y()]), True)
279+
# raise ValueError("No star vertex found")
280+
271281
# Update dart quality
272282
n1_analysis = NodeAnalysis(n1)
273283
adj_darts = n1_analysis.adjacent_darts()
@@ -336,10 +346,10 @@ def check_mesh(mesh_analysis, m=None) -> bool:
336346
plot_mesh(m)
337347
plot_mesh(mesh_analysis.mesh)
338348
return False
339-
#if dart_info[5] not in [-1,0,1,2]:
340-
#plot_mesh(m)
341-
#plot_mesh(mesh_analysis.mesh)
342-
#return False
349+
if dart_info[5] not in [-1,0,1,2]:
350+
plot_mesh(m)
351+
plot_mesh(mesh_analysis.mesh)
352+
return False
343353
return True
344354

345355

environment/gymnasium_envs/trimesh_full_env/envs/trimesh.py

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import pygame
33
import imageio
44
import sys
5+
import os
56

67
import numpy as np
78
import gymnasium as gym
@@ -15,7 +16,7 @@
1516

1617
from mesh_model.random_trimesh import random_mesh
1718
from mesh_model.mesh_struct.mesh_elements import Dart
18-
from mesh_model.mesh_analysis.trimesh_analysis import TriMeshQualityAnalysis
19+
from mesh_model.mesh_analysis.trimesh_analysis import TriMeshQualityAnalysis, TriMeshOldAnalysis
1920
from environment.gymnasium_envs.trimesh_full_env.envs.mesh_conv import get_x
2021
from environment.actions.triangular_actions import flip_edge, split_edge, collapse_edge, check_mesh
2122
from view.mesh_plotter.mesh_plots import plot_mesh
@@ -40,19 +41,28 @@ def __init__(
4041
mesh=None,
4142
mesh_size=9,
4243
max_episode_steps=20,
43-
n_darts_selected=20,
44+
n_darts_selected=7,
4445
deep=6,
4546
with_quality_obs=False,
4647
action_restriction=False,
47-
render_mode=None
48+
render_mode=None,
49+
analysis_type = "quality"
4850
) -> None:
4951

5052
assert render_mode is None or render_mode in self.metadata["render_modes"]
5153
self.render_mode = render_mode
5254

53-
self.mesh_size = mesh_size
54-
self.mesh = mesh if mesh is not None else random_mesh(mesh_size)
55-
self.m_analysis = TriMeshQualityAnalysis(self.mesh)
55+
# If a mesh has been entered, it is used, otherwise a random mesh is generated.
56+
if mesh is not None:
57+
self.config = {"mesh": mesh}
58+
self.mesh = copy.deepcopy(mesh)
59+
self.mesh_size = 0
60+
else:
61+
self.config = {"mesh": None}
62+
self.mesh_size = mesh_size
63+
self.mesh = random_mesh(mesh_size)
64+
self.analysis_type = analysis_type
65+
self.m_analysis = TriMeshQualityAnalysis(self.mesh) if self.analysis_type == "quality" else TriMeshOldAnalysis(self.mesh)
5666
self._nodes_scores, self._mesh_score, self._ideal_score, self._nodes_adjacency = self.m_analysis.global_score()
5767
self._ideal_rewards = (self._mesh_score - self._ideal_score)*10
5868
self.next_mesh_score = 0
@@ -69,6 +79,12 @@ def __init__(
6979
self.darts_selected = []
7080
self.max_steps = max_episode_steps
7181

82+
self.actions_info = {
83+
"n_flip": 0,
84+
"n_split": 0,
85+
"n_collapse": 0,
86+
}
87+
7288
self.observation_space = spaces.Box(
7389
low=-15, # nodes min degree : 15
7490
high=15, # nodes max degree : 15
@@ -100,15 +116,19 @@ def __init__(
100116

101117
self.recording = False
102118
self.frames = []
119+
self._render_frame()
103120

104121
def reset(self, seed=None, options=None):
105122
# We need the following line to seed self.np_random
106123
super().reset(seed=seed)
107124
if options is not None:
108125
self.mesh = options['mesh']
126+
elif self.config["mesh"] is not None:
127+
self.mesh = copy.deepcopy(self.config["mesh"])
109128
else:
110129
self.mesh = random_mesh(self.mesh_size)
111-
self.m_analysis = TriMeshQualityAnalysis(self.mesh)
130+
131+
self.m_analysis = TriMeshQualityAnalysis(self.mesh) if self.analysis_type=="quality" else TriMeshOldAnalysis(self.mesh)
112132
self._nodes_scores, self._mesh_score, self._ideal_score, self._nodes_adjacency = self.m_analysis.global_score()
113133
self._ideal_rewards = (self._mesh_score - self._ideal_score) * 10
114134
self.nb_invalid_actions = 0
@@ -117,9 +137,15 @@ def reset(self, seed=None, options=None):
117137
self.observation = self._get_obs()
118138
info = self._get_info(terminated=False,valid_act=(None,None,None), action=(None,None), mesh_reward=None)
119139

140+
self.actions_info = {
141+
"n_flip": 0,
142+
"n_split": 0,
143+
"n_collapse": 0,
144+
}
145+
120146
if self.render_mode == "human":
121-
self._render_frame()
122147
self.recording = True
148+
self._render_frame()
123149
else:
124150
self.recording = False
125151

@@ -173,10 +199,13 @@ def step(self, action: np.ndarray):
173199
# before_mesh = deepcopy(self.mesh)
174200
if action[0] == Actions.FLIP.value:
175201
valid_action, valid_topo, valid_geo = flip_edge(self.m_analysis, n1, n2)
202+
self.actions_info["n_flip"] += 1
176203
elif action[0] == Actions.SPLIT.value:
177204
valid_action, valid_topo, valid_geo = split_edge(self.m_analysis, n1, n2)
205+
self.actions_info["n_split"] += 1
178206
elif action[0] == Actions.COLLAPSE.value:
179207
valid_action, valid_topo, valid_geo = collapse_edge(self.m_analysis, n1, n2)
208+
self.actions_info["n_collapse"] += 1
180209
else:
181210
raise ValueError("Action not defined")
182211

@@ -214,7 +243,14 @@ def step(self, action: np.ndarray):
214243
#Saving episode rendering as gif
215244
if terminated or self.ep_len>= self.max_steps:
216245
if self.recording and self.frames:
217-
imageio.mimsave(f"training/episode_recording/episode_{self.episode_count}.gif", self.frames, fps=1)
246+
base_path = f"training/episode_recording/del/episode_star_{self.episode_count}"
247+
filename = base_path + ".gif"
248+
index = 1
249+
while os.path.exists(filename):
250+
filename = f"{base_path}_{index}.gif"
251+
index += 1
252+
253+
imageio.mimsave(filename, self.frames, fps=1)
218254
print("Image recorded")
219255
self.episode_count +=1
220256

mesh_files/tri-delaunay.msh

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
$MeshFormat
2+
4.1 0 8
3+
$EndMeshFormat
4+
$Entities
5+
4 4 1 0
6+
2 3 0 0 0
7+
3 1 2 0 0
8+
4 1 -2 0 0
9+
6 -1 0 0 0
10+
1 -1 0 0 1 2 0 0 2 3 -6
11+
2 -1 -2 0 1 0 0 0 2 6 -4
12+
3 1 -2 0 3 0 0 0 2 4 -2
13+
4 1 0 0 3 2 0 0 2 2 -3
14+
1 -1 -2 0 3 2 0 0 4 1 2 3 4
15+
$EndEntities
16+
$Nodes
17+
9 21 1 21
18+
0 2 0 1
19+
1
20+
3 0 0
21+
0 3 0 1
22+
2
23+
1 2 0
24+
0 4 0 1
25+
3
26+
1 -2 0
27+
0 6 0 1
28+
4
29+
-1 0 0
30+
1 1 0 2
31+
5
32+
6
33+
0.3333333333351847 1.333333333335185 0
34+
-0.3333333333310193 0.6666666666689807 0
35+
1 2 0 2
36+
7
37+
8
38+
-0.3333333333350901 -0.6666666666649099 0
39+
0.3333333333315289 -1.333333333331529 0
40+
1 3 0 2
41+
9
42+
10
43+
1.666666666666666 -1.333333333333334 0
44+
2.333333333332406 -0.6666666666675944 0
45+
1 4 0 2
46+
11
47+
12
48+
2.333333333336016 0.6666666666639838 0
49+
1.666666666669397 1.333333333330603 0
50+
2 1 0 9
51+
13
52+
14
53+
15
54+
16
55+
17
56+
18
57+
19
58+
20
59+
21
60+
1.000000000000195 -2.053357484044227e-13 0
61+
1.833333333333501 -4.514097429197325e-13 0
62+
0.1666666666669092 5.088429677603714e-13 0
63+
1.000000000000573 0.8333333333331049 0
64+
0.9999999999997741 -0.8333333333337288 0
65+
1.65476190476127 -0.6547619047618515 0
66+
0.3452380952395821 0.6547619047612705 0
67+
0.3452380952388717 -0.6547619047606879 0
68+
1.654761904761082 0.6547619047601926 0
69+
$EndNodes
70+
$Elements
71+
9 44 1 44
72+
0 2 15 1
73+
1 1
74+
0 3 15 1
75+
2 2
76+
0 4 15 1
77+
3 3
78+
0 6 15 1
79+
4 4
80+
1 1 1 3
81+
5 2 5
82+
6 5 6
83+
7 6 4
84+
1 2 1 3
85+
8 4 7
86+
9 7 8
87+
10 8 3
88+
1 3 1 3
89+
11 3 9
90+
12 9 10
91+
13 10 1
92+
1 4 1 3
93+
14 1 11
94+
15 11 12
95+
16 12 2
96+
2 1 2 28
97+
17 1 11 14
98+
18 10 1 14
99+
19 6 4 15
100+
20 12 2 16
101+
21 2 5 16
102+
22 4 7 15
103+
23 3 9 17
104+
24 8 3 17
105+
25 14 13 18
106+
26 15 13 19
107+
27 13 16 19
108+
28 13 17 18
109+
29 13 15 20
110+
30 13 14 21
111+
31 16 13 21
112+
32 17 13 20
113+
33 11 12 21
114+
34 7 8 20
115+
35 5 6 19
116+
36 9 10 18
117+
37 14 11 21
118+
38 16 5 19
119+
39 15 7 20
120+
40 10 14 18
121+
41 17 9 18
122+
42 6 15 19
123+
43 12 16 21
124+
44 8 17 20
125+
$EndElements

0 commit comments

Comments
 (0)