CarolineM5 commited on
Commit
884ceca
·
verified ·
1 Parent(s): f0ba3cf

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -56
app.py CHANGED
@@ -145,57 +145,49 @@ def run(fibers: Image.Image, rings: Image.Image, num_steps: int):
145
 
146
  # Construire le HTML/JS pour le visualiseur Three.js
147
  html = f"""
148
- <div id="viewer" style="width:100%;height:480px; border:1px solid #ddd;"></div>
149
- <p style="font-size:0.9em;color:#444;margin-top:6px;">Manipulez la souris pour faire tourner, molette pour zoomer.</p>
 
 
 
150
  <script src="https://unpkg.com/three@0.152.2/build/three.min.js"></script>
151
  <script src="https://unpkg.com/three@0.152.2/examples/js/controls/OrbitControls.js"></script>
152
  <script>
153
  (function() {{
154
- const images = {data_uris!r}; // array of 4 data URIs
155
-
156
- // cleanup previous canvas if any
157
  const container = document.getElementById('viewer');
158
- container.innerHTML = "";
159
-
160
- const scene = new THREE.Scene();
161
- const camera = new THREE.PerspectiveCamera(45, container.clientWidth / container.clientHeight, 0.1, 1000);
162
- camera.position.set(2.5, 2.0, 3.5);
163
-
164
- const renderer = new THREE.WebGLRenderer({{antialias:true}});
165
- renderer.setSize(container.clientWidth, container.clientHeight);
166
- renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);
167
- container.appendChild(renderer.domElement);
168
-
169
- // Lights (soft)
170
- const hemi = new THREE.HemisphereLight(0xffffff, 0x444444, 1.0);
171
- scene.add(hemi);
172
-
173
- // Load textures from data URIs
174
- const loader = new THREE.TextureLoader();
175
- const texPromises = images.map((uri) => new Promise((res, rej) => {{
176
- loader.load(uri, (tex) => {{ tex.flipY = false; res(tex); }}, undefined, rej);
177
- }}));
178
-
179
- Promise.all(texPromises).then((textures) => {{
180
- // materials for box: order is [right, left, top, bottom, front, back]
181
- const neutral = new THREE.MeshBasicMaterial({{ color:0xcccccc }});
182
- const mats = [
183
- new THREE.MeshBasicMaterial({{ map: textures[0] }}), // right
184
- new THREE.MeshBasicMaterial({{ map: textures[1] }}), // left
185
- neutral, // top
186
- neutral, // bottom
187
- new THREE.MeshBasicMaterial({{ map: textures[2] }}), // front
188
- new THREE.MeshBasicMaterial({{ map: textures[3] }}) // back
189
- ];
190
-
191
- // ensure correct filtering / orientation
192
- mats.forEach(m => {{ if (m.map) {{ m.map.minFilter = THREE.LinearFilter; m.map.wrapS = THREE.ClampToEdgeWrapping; m.map.wrapT = THREE.ClampToEdgeWrapping; }} }});
193
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  const geometry = new THREE.BoxGeometry(1.6,1.6,1.6);
195
- const cube = new THREE.Mesh(geometry, mats);
 
 
196
  scene.add(cube);
197
 
198
- // grid & axes for context
199
  const grid = new THREE.GridHelper(6, 12, 0x888888, 0x444444);
200
  grid.position.y = -1.2;
201
  scene.add(grid);
@@ -203,27 +195,85 @@ def run(fibers: Image.Image, rings: Image.Image, num_steps: int):
203
  // controls
204
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
205
  controls.enableDamping = true;
206
- controls.dampingFactor = 0.07;
207
  controls.target.set(0,0,0);
208
 
209
- // responsive
210
- function onWindowResize() {{
211
- renderer.setSize(container.clientWidth, container.clientHeight);
212
- camera.aspect = container.clientWidth / container.clientHeight;
213
- camera.updateProjectionMatrix();
214
- }}
215
- window.addEventListener('resize', onWindowResize);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
 
217
  // animation loop
218
- (function animate() {{
219
  requestAnimationFrame(animate);
220
  controls.update();
221
  renderer.render(scene, camera);
222
- }})();
223
- }}).catch((e) => {{
224
- container.innerHTML = "<div style='padding:16px;color:#900;'>Erreur chargement textures : " + (e && e.message ? e.message : e) + "</div>";
225
- console.error(e);
226
- }});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  }})();
228
  </script>
229
  """
 
145
 
146
  # Construire le HTML/JS pour le visualiseur Three.js
147
  html = f"""
148
+ <div id="viewer" style="width:100%;height:480px; border:1px solid #ddd; position:relative;background:#f6f6f6;">
149
+ <div id="viewer-msg" style="position:absolute;left:8px;top:8px;padding:6px 8px;background:rgba(255,255,255,0.9);border-radius:6px;font-size:12px;color:#333;z-index:2;">
150
+ Manipulez la souris pour tourner, molette pour zoomer.
151
+ </div>
152
+ </div>
153
  <script src="https://unpkg.com/three@0.152.2/build/three.min.js"></script>
154
  <script src="https://unpkg.com/three@0.152.2/examples/js/controls/OrbitControls.js"></script>
155
  <script>
156
  (function() {{
157
+ const images = {data_uris!r};
 
 
158
  const container = document.getElementById('viewer');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
+ function safeLog(...args) {{ try{{console.log(...args)}}catch(e){{}} }}
161
+
162
+ function initScene() {{
163
+ const w = container.clientWidth || 800;
164
+ const h = container.clientHeight || 480;
165
+
166
+ const scene = new THREE.Scene();
167
+ const camera = new THREE.PerspectiveCamera(45, w/h, 0.1, 1000);
168
+ camera.position.set(2.5, 2.0, 3.5);
169
+
170
+ const renderer = new THREE.WebGLRenderer({{antialias:true}});
171
+ renderer.setSize(w, h);
172
+ renderer.domElement.style.width = '100%';
173
+ renderer.domElement.style.height = '100%';
174
+ container.appendChild(renderer.domElement);
175
+
176
+ // lights
177
+ const ambient = new THREE.AmbientLight(0xffffff, 0.7);
178
+ scene.add(ambient);
179
+ const dir = new THREE.DirectionalLight(0xffffff, 0.6);
180
+ dir.position.set(5,10,7);
181
+ scene.add(dir);
182
+
183
+ // fallback cube (visible immédiatement)
184
  const geometry = new THREE.BoxGeometry(1.6,1.6,1.6);
185
+ const fallbackMats = [];
186
+ for (let i=0;i<6;i++) fallbackMats.push(new THREE.MeshStandardMaterial({{color:0x999999}}));
187
+ const cube = new THREE.Mesh(geometry, fallbackMats);
188
  scene.add(cube);
189
 
190
+ // grid for context
191
  const grid = new THREE.GridHelper(6, 12, 0x888888, 0x444444);
192
  grid.position.y = -1.2;
193
  scene.add(grid);
 
195
  // controls
196
  const controls = new THREE.OrbitControls(camera, renderer.domElement);
197
  controls.enableDamping = true;
198
+ controls.dampingFactor = 0.08;
199
  controls.target.set(0,0,0);
200
 
201
+ // attempt to load textures, but keep fallback if it fails
202
+ const loader = new THREE.TextureLoader();
203
+ Promise.all(images.map(uri => new Promise((res, rej) => {{
204
+ try {{
205
+ loader.load(uri, tex => {{ tex.flipY = false; tex.generateMipmaps = true; res(tex); }}, undefined, err => rej(err));
206
+ }} catch(e) {{ rej(e); }}
207
+ }}))).then(textures => {{
208
+ safeLog('Textures loaded', textures);
209
+ const mats = [
210
+ new THREE.MeshStandardMaterial({{map: textures[0]}}), // right
211
+ new THREE.MeshStandardMaterial({{map: textures[1]}}), // left
212
+ new THREE.MeshStandardMaterial({{color:0xcccccc}}), // top
213
+ new THREE.MeshStandardMaterial({{color:0xcccccc}}), // bottom
214
+ new THREE.MeshStandardMaterial({{map: textures[2]}}), // front
215
+ new THREE.MeshStandardMaterial({{map: textures[3]}}) // back
216
+ ];
217
+ // set wrapping/filter
218
+ mats.forEach(m => {{
219
+ if (m.map) {{
220
+ m.map.minFilter = THREE.LinearFilter;
221
+ m.map.wrapS = THREE.ClampToEdgeWrapping;
222
+ m.map.wrapT = THREE.ClampToEdgeWrapping;
223
+ }}
224
+ }});
225
+ cube.material = mats;
226
+ }}).catch(err => {{
227
+ safeLog('Erreur chargement textures (on garde fallback):', err);
228
+ // affiche un petit message utilisateur (optionnel)
229
+ const msg = document.getElementById('viewer-msg');
230
+ if (msg) msg.innerText = "Rendu 3D : textures non chargées, affichage fallback (voir console).";
231
+ }});
232
 
233
  // animation loop
234
+ function animate() {{
235
  requestAnimationFrame(animate);
236
  controls.update();
237
  renderer.render(scene, camera);
238
+ }}
239
+ animate();
240
+
241
+ // responsive: observe container size
242
+ if (typeof ResizeObserver !== 'undefined') {{
243
+ const ro = new ResizeObserver(() => {{
244
+ const ww = container.clientWidth || 800;
245
+ const hh = container.clientHeight || 480;
246
+ renderer.setSize(ww, hh);
247
+ camera.aspect = ww / hh;
248
+ camera.updateProjectionMatrix();
249
+ }});
250
+ ro.observe(container);
251
+ }} else {{
252
+ window.addEventListener('resize', () => {{
253
+ const ww = container.clientWidth || 800;
254
+ const hh = container.clientHeight || 480;
255
+ renderer.setSize(ww, hh);
256
+ camera.aspect = ww / hh;
257
+ camera.updateProjectionMatrix();
258
+ }});
259
+ }}
260
+ }}
261
+
262
+ // wait until container has non-zero size and THREE is available
263
+ let tries = 0;
264
+ function waitForReady() {{
265
+ tries++;
266
+ if (container.clientWidth > 0 && typeof THREE !== 'undefined') {{
267
+ try {{ initScene(); }} catch(e) {{ safeLog('Erreur initScene', e); container.innerHTML = "<div style='padding:10px;color:#900;'>Erreur initialisation rendu 3D (voir console)</div>"; }}
268
+ }} else {{
269
+ if (tries < 60) setTimeout(waitForReady, 100);
270
+ else {{
271
+ // give it one last try
272
+ try {{ initScene(); }} catch(e) {{ safeLog('Derniere tentative échouée', e); container.innerHTML = "<div style='padding:10px;color:#900;'>Impossible d'initialiser le rendu 3D (voir console)</div>"; }}
273
+ }}
274
+ }}
275
+ }}
276
+ waitForReady();
277
  }})();
278
  </script>
279
  """