what if ALL meses work?

This commit is contained in:
gdamms 2022-10-19 19:44:16 +02:00
parent 9f9d271693
commit b542c7783f
2 changed files with 80 additions and 38 deletions

116
maps.py
View file

@ -1,4 +1,5 @@
import io import io
from requests import delete
from rich.progress import Progress from rich.progress import Progress
import obja.obja as obja import obja.obja as obja
@ -6,6 +7,10 @@ from object import Edge, Face, Vertex
from utils import * from utils import *
class FixModel(Exception):
pass
class MAPS(obja.Model): class MAPS(obja.Model):
"""MAPS compression model""" """MAPS compression model"""
@ -40,34 +45,32 @@ class MAPS(obja.Model):
def fix(self) -> None: def fix(self) -> None:
"""Fix the model""" """Fix the model"""
fixed = True
# Find a vertex with less than 3 faces # Find a vertex with less than 3 faces
for i, vertex in enumerate(self.vertices): for i, vertex in enumerate(self.vertices):
if vertex is None: if vertex is None:
continue continue
if len(vertex.face_ring) < 3: # Remove lonely vertices
# Remove the vertex and its faces if len(vertex.face_ring) == 0:
for face in vertex.face_ring: self.delete_vertex(i)
if not self.final_only: raise FixModel
self.operations.append(
('af', face, self.faces[face].to_obja()))
self.faces[face] = None
if not self.final_only:
self.operations.append(
('av', i, vertex.to_obja()))
self.vertices[i] = None
# Indicate that the model has to be fixed again # Pass if vertex has only 2 same faces
fixed = False if len(vertex.face_ring) != 2:
continue
if self.faces[vertex.face_ring[0]] != self.faces[vertex.face_ring[1]]:
continue
return fixed # Remove the vertex and its faces
self.delete_vertex(i)
# Indicate that the model has to be fixed again
raise FixModel
def update_edges(self) -> None: def update_edges(self) -> None:
"""Update edges""" """Update edges"""
self.edges = {} self.edges: dict[str, Edge] = {}
for face in self.faces: for face in self.faces:
if face is None: if face is None:
@ -99,13 +102,27 @@ class MAPS(obja.Model):
# Add the new edge to the list # Add the new edge to the list
self.edges[f"{new_edge.a}:{new_edge.b}"] = new_edge self.edges[f"{new_edge.a}:{new_edge.b}"] = new_edge
def delete_vertex(self, index: int) -> None:
"""Delete a vertex and its faces
Args:
index (int): index of the vertex to delete
"""
vertex = self.vertices[index]
for face in vertex.face_ring:
if not self.final_only:
self.operations.append(
('af', face, self.faces[face].to_obja()))
self.faces[face] = None
if not self.final_only:
self.operations.append(
('av', index, vertex.to_obja()))
self.vertices[index] = None
def update_rings(self) -> None: def update_rings(self) -> None:
"""Update vertex and face rings""" """Update vertex and face rings"""
try:
fixed = False
# Wait till the model is fixed
while not fixed:
for vertex in self.vertices: for vertex in self.vertices:
# Reset vertex ring # Reset vertex ring
if vertex is None: if vertex is None:
@ -120,16 +137,19 @@ class MAPS(obja.Model):
self.vertices[vertex_i].face_ring.append(i) self.vertices[vertex_i].face_ring.append(i)
# Fix the model # Fix the model
fixed = self.fix() self.fix()
for i, vertex in enumerate(self.vertices): for i, vertex in enumerate(self.vertices):
vertex = self.vertices[i] vertex = self.vertices[i]
if vertex is None: if vertex is None:
continue continue
# Compute rings # Compute rings
ring = self.one_ring(i) ring = self.one_ring(i)
vertex.vertex_ring = ring vertex.vertex_ring = ring
except FixModel:
self.update_rings()
def update_area_curvature(self) -> None: def update_area_curvature(self) -> None:
"""Update area and curvature""" """Update area and curvature"""
@ -146,6 +166,9 @@ class MAPS(obja.Model):
# Find feature edges # Find feature edges
self.feature_edges = [] self.feature_edges = []
for edge in self.edges.values(): for edge in self.edges.values():
if edge.face2 is None:
continue
edge.fold = np.dot(edge.face1.normal, edge.face2.normal) edge.fold = np.dot(edge.face1.normal, edge.face2.normal)
if edge.fold < 0.5: if edge.fold < 0.5:
@ -197,16 +220,21 @@ class MAPS(obja.Model):
ring_faces = [self.faces[i] for i in self.vertices[index].face_ring] ring_faces = [self.faces[i] for i in self.vertices[index].face_ring]
# Initialize the ring # Initialize the ring
start_index = (ring_faces[0].a if ring_faces[0].a != index and ring_faces[0].c != index else start_index, revert_index = (
ring_faces[0].b if ring_faces[0].a != index and ring_faces[0].b != index else (ring_faces[0].c, ring_faces[0].b) if ring_faces[0].a == index else
ring_faces[0].c) (ring_faces[0].a, ring_faces[0].c) if ring_faces[0].b == index else
(ring_faces[0].b, ring_faces[0].a)
)
ring = [start_index] ring = [start_index]
ring_faces.pop(0) ring_faces.pop(0)
revert_looking = False
# Select the indexes of the ring in the right order # Select the indexes of the ring in the right order
while len(ring_faces) > 0: while len(ring_faces) > 0:
broke = False broke = False
prev_index = ring[-1] prev_index = ring[-1] if not revert_looking else ring[0]
for i, face in enumerate(ring_faces): for i, face in enumerate(ring_faces):
if prev_index in (face.a, face.b, face.c): if prev_index in (face.a, face.b, face.c):
# Found the face that correspond to the next vertex # Found the face that correspond to the next vertex
@ -215,13 +243,22 @@ class MAPS(obja.Model):
face.b if face.b != index and face.b != prev_index else face.b if face.b != index and face.b != prev_index else
face.c face.c
) )
ring.append(current_index) if not revert_looking:
ring.append(current_index)
else:
ring.insert(0, current_index)
ring_faces.pop(i) ring_faces.pop(i)
broke = True broke = True
break break
if not broke: if not broke:
raise Exception('Ring corrupted') if revert_looking:
self.delete_vertex(index)
raise FixModel
revert_looking = True
ring.insert(0, revert_index)
self.vertices[index].border = True
return ring return ring
@ -284,7 +321,7 @@ class MAPS(obja.Model):
# Compute priorities # Compute priorities
priorities = [] priorities = []
for vertex in self.vertices: for vertex in self.vertices:
if vertex is not None and len(vertex.vertex_ring) < max_length: if vertex is not None and 1 < len(vertex.vertex_ring) < max_length:
# Compute priority # Compute priority
priority = ( priority = (
lamb * vertex.area / max_area + lamb * vertex.area / max_area +
@ -365,7 +402,10 @@ class MAPS(obja.Model):
teta += self.compute_angle(index1, index, index2) # add new angle teta += self.compute_angle(index1, index, index2) # add new angle
radius.append(r) radius.append(r)
angles.append(teta) angles.append(teta)
angles = [2 * np.pi * a / teta for a in angles] # normalize angles
full_rotate = 2 * np.pi if not self.vertices[index].border else np.pi
angles = [full_rotate * a / teta for a in angles] # normalize angles
coordinates = [np.array([r * np.cos(a), r * np.sin(a)]) coordinates = [np.array([r * np.cos(a), r * np.sin(a)])
for r, a in zip(radius, angles)] # parse polar to cartesian for r, a in zip(radius, angles)] # parse polar to cartesian

View file

@ -101,6 +101,8 @@ class Vertex:
self.area: float = 0.0 self.area: float = 0.0
self.curvature: float = 0.0 self.curvature: float = 0.0
self.border: bool = False
def to_obja(self) -> np.ndarray: def to_obja(self) -> np.ndarray:
"""Convert vertex to obja format """Convert vertex to obja format