Vista 3D del modello in una pagina HTML autonoma
Aggiunge --3d: genera un file HTML che si apre con un doppio clic e permette di ruotare il pezzo col mouse, ingrandire con la rotella e spostare col tasto destro. Mesh, stile e codice sono dentro la pagina: nessuna libreria esterna e nessuna connessione, cosi' funziona anche da una cartella di rete. Il disegno usa una canvas 2D con ordinamento per profondita' invece di WebGL, che su alcune postazioni e' disattivato. La forma non viene dal .prt ma da una mesh STL esportata da Creo, cercata accanto al modello per nome (9258400207.prt.11 -> 9258400207.stl). Se manca, il comando lo dice invece di fallire. Perche' serve la mesh: la geometria nel .prt e' scritta nel formato del kernel Granite di PTC ed e' compressa. Verificato con un attacco a testo noto, presi da un export STEP i 22 valori esatti del modello (raggi 1,6 / 2,1 / 2,5 / 2,75 / 5,25 e coordinate fino a 75,0) e cercati nel file in cinque codifiche su tutti i blocchi: nessun riscontro. La via ufficiale per leggere i .prt nativi senza Creo e' il Granite Interoperability Kernel di PTC, che si innesterebbe al posto di mesh.py senza toccare il resto. Quando la mesh c'e', il record guadagna un blocco "geometry" con ingombro, volume e area. Il peso NON viene calcolato: servirebbe la densita', che dipende dal materiale, e il materiale e' testo libero. Sul 9258400207 il parametro dice "Anticordal 100", che e' alluminio: applicare la densita' dell'acciaio darebbe 0,686 kg invece di 0,237. Gli export (stl, dxf, dwg, iges, pdf) sono esclusi dal repository come i modelli: sono geometria e tavole complete dei pezzi. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -175,6 +175,61 @@ class TestDisegni(unittest.TestCase):
|
||||
self.assertIn("prim_line", prims)
|
||||
|
||||
|
||||
class TestMesh(unittest.TestCase):
|
||||
"""La forma arriva da una mesh esportata: il .prt non la espone."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
from creoparams.extract import find_mesh
|
||||
cls.pairs = [(p, find_mesh(p)) for p in _parts()]
|
||||
cls.pairs = [(p, m) for p, m in cls.pairs if m]
|
||||
if not cls.pairs:
|
||||
raise unittest.SkipTest("nessun .stl accanto ai modelli")
|
||||
|
||||
def test_lettura_stl(self):
|
||||
from creoparams.mesh import read_stl
|
||||
for part, stl in self.pairs:
|
||||
with self.subTest(file=os.path.basename(stl)):
|
||||
mesh = read_stl(stl)
|
||||
self.assertGreater(len(mesh), 0)
|
||||
self.assertTrue(all(len(t) == 3 for t in mesh.triangles))
|
||||
self.assertTrue(all(len(v) == 3 for t in mesh.triangles for v in t))
|
||||
|
||||
def test_ingombro_positivo(self):
|
||||
from creoparams.mesh import read_stl
|
||||
for part, stl in self.pairs:
|
||||
with self.subTest(file=os.path.basename(stl)):
|
||||
mesh = read_stl(stl)
|
||||
self.assertTrue(all(d > 0 for d in mesh.size))
|
||||
self.assertGreater(mesh.volume(), 0)
|
||||
self.assertGreater(mesh.area(), 0)
|
||||
|
||||
def test_geometria_nel_record(self):
|
||||
for part, stl in self.pairs:
|
||||
with self.subTest(file=os.path.basename(part)):
|
||||
geometry = extract(part).get("geometry")
|
||||
self.assertIsNotNone(geometry)
|
||||
self.assertEqual(geometry["triangles"], len(read_stl_cached(stl)))
|
||||
|
||||
def test_pagina_html_autonoma(self):
|
||||
"""La pagina deve funzionare offline: nessun riferimento esterno."""
|
||||
from creoparams import viewer
|
||||
from creoparams.mesh import read_stl
|
||||
mesh = read_stl(self.pairs[0][1])
|
||||
page = viewer.build(mesh, "prova", viewer.describe(mesh))
|
||||
self.assertTrue(page.startswith("<!doctype html>"))
|
||||
self.assertIn("</html>", page)
|
||||
for marker in ('src="http', "href=\"http", "@import"):
|
||||
self.assertNotIn(marker, page, "la pagina carica risorse esterne")
|
||||
# la mesh deve essere incorporata, non referenziata
|
||||
self.assertIn("const TRI = [[", page)
|
||||
|
||||
|
||||
def read_stl_cached(path):
|
||||
from creoparams.mesh import read_stl
|
||||
return read_stl(path)
|
||||
|
||||
|
||||
class TestLzw(unittest.TestCase):
|
||||
def test_round_trip_noto(self):
|
||||
"""Verifica il decoder su uno stream prodotto da compress(1), se
|
||||
|
||||
Reference in New Issue
Block a user