feat: cheplu

This commit is contained in:
gdamms 2022-10-10 12:26:30 +02:00
parent c8b16c818e
commit 0329b83aa6

134
main.py
View file

@ -4,11 +4,20 @@ import obja.obja as obja
import numpy as np import numpy as np
import argparse import argparse
from rich.progress import track
def sliding_window(l: list): def cot(x: float):
head = l[:-1] sin_x = np.sin(x)
tail = l[1:] if sin_x == 0:
return zip(head, tail) return 1e16
return np.cos(x) / sin_x
def sliding_window(l: list, n: int = 2):
k = n - 1
l2 = l + [l[i] for i in range(k)]
res = [(x for x in l2[i:i+n]) for i in range(len(l2)-k)]
return res
class MAPS(obja.Model): class MAPS(obja.Model):
@ -80,13 +89,14 @@ class MAPS(obja.Model):
tuple[float, float]: area and curvature tuple[float, float]: area and curvature
""" """
area_sum = 0 area_sum = 0
curvature_sum = 0 laplace_sum = 0
one_ring_vertices, _ = self.one_ring(index) one_ring_vertices, _ = self.one_ring(index)
teta = 0.0
p1 = self.vertices[index] # the center of the one-ring p1 = self.vertices[index] # the center of the one-ring
for index2, index3 in sliding_window(one_ring_vertices): for index1, index2, index3 in sliding_window(one_ring_vertices, n=3):
p2 = self.vertices[index2] # the second vertice of the triangle p2 = self.vertices[index1] # the second vertice of the triangle
p3 = self.vertices[index3] # the third vertice of the triangle p3 = self.vertices[index2] # the third vertice of the triangle
M = np.array([ # build the matrix, used to compute the area M = np.array([ # build the matrix, used to compute the area
[p1[0], p2[0], p3[0]], [p1[0], p2[0], p3[0]],
[p1[1], p2[1], p3[1]], [p1[1], p2[1], p3[1]],
@ -95,17 +105,27 @@ class MAPS(obja.Model):
area = abs(np.linalg.det(M) / 2) # compute the area area = abs(np.linalg.det(M) / 2) # compute the area
area_sum += area area_sum += area
curvature = 4 * area / ( # compute the curvature teta += self.compute_angle(index1, index, index2)
np.linalg.norm(p1-p2) *
np.linalg.norm(p2-p3) *
np.linalg.norm(p3-p1)
)
curvature_sum += curvature
return area_sum, curvature_sum, len(one_ring_vertices) laplace = self.compute_laplace(index, index1, index2, index3)
laplace_sum += laplace
def compute_priority(self, lamb: float = 0.5, max_length: int = 12) -> list[float]: K = (2 * np.pi - teta) / area * 3
""" Compute selection priority of vertices (0 -> hight priority ; 1 -> low priority) H = np.linalg.norm(laplace_sum) / 4 / area * 3
curvature = abs(H - np.sqrt(H*H - K)) + abs(H + np.sqrt(H*H - K))
curvature = K
return area_sum, curvature, len(one_ring_vertices)
def compute_laplace(self, i: int, j: int, a: int, b: int) -> np.ndarray:
alpha = self.compute_angle(i, a, j)
beta = self.compute_angle(i, b, j)
cot_sum = cot(alpha) + cot(beta)
vec = self.vertices[j] - self.vertices[i]
return cot_sum * vec
def compute_priority(self, lamb: float = 0.0, max_length: int = 12) -> list[float]:
""" Compute selection priority of vertices (0.0 -> hight priority ; 1.0 -> low priority)
Args: Args:
lamb (float, optional): convex combination factor. Defaults to 0.5. lamb (float, optional): convex combination factor. Defaults to 0.5.
@ -140,6 +160,7 @@ class MAPS(obja.Model):
priority = 2.0 priority = 2.0
priorities.append(priority) priorities.append(priority)
# return np.random.rand(len(priorities))
return priorities return priorities
def select_vertices(self) -> list[int]: def select_vertices(self) -> list[int]:
@ -178,13 +199,6 @@ class MAPS(obja.Model):
if face_vertex in vertices: if face_vertex in vertices:
vertices.remove(face_vertex) vertices.remove(face_vertex)
for ver in selected_vertices:
ring, _ = self.one_ring(ver)
for v in selected_vertices:
for r in ring:
if r == v:
print(f"fuck:{ver},{ring}")
print("Vertices selected.") print("Vertices selected.")
return selected_vertices return selected_vertices
@ -200,7 +214,7 @@ class MAPS(obja.Model):
ring, _ = self.one_ring(index) ring, _ = self.one_ring(index)
radius, angles = [], [] radius, angles = [], []
teta = 0.0 # cumulated angles teta = 0.0 # cumulated angles
for index1, index2 in sliding_window(ring + [ring[0]]): for index1, index2 in sliding_window(ring):
r = np.linalg.norm(self.vertices[index] - self.vertices[index1]) r = np.linalg.norm(self.vertices[index] - self.vertices[index1])
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)
@ -340,6 +354,49 @@ class MAPS(obja.Model):
# Check if point is in triangle # Check if point is in triangle
return (u >= 0) and (v >= 0) and (u + v < 1) return (u >= 0) and (v >= 0) and (u + v < 1)
def truc(self, output):
priorities = self.compute_priority()
min_p = min(priorities)
priorities = [p - min_p for p in priorities]
max_p = max(priorities)
# colors = [priorities[face.a] + priorities[face.b] + priorities[face.c] for face in self.faces]
# min_c = min(colors)
# colors = [c - min_c for c in colors]
# max_c = max(colors)
operations = []
for i, face in enumerate(self.faces):
if face != None:
# r, g, b = colors[i] / max_c, 1.0, 1.0
# operations.append(('fc', i, (r, g, b)))
operations.append(('af', i, face, 0, 0, 0))
for i, vertex in enumerate(self.vertices):
if type(vertex) != NoneType:
r, g, b = priorities[i] / max_p , 1.0, 1.0
operations.append(('av', i, vertex, r, g, b))
operations.reverse()
# Write the result in output file
output_model = obja.Output(output)
for (op, index, value, r, g, b) in operations:
if op == 'av':
output_model.add_vertex_rgb(index, value, r, g, b)
elif op == 'af':
output_model.add_face(index, value)
elif op == 'ev':
output_model.edit_vertex(index, value)
elif op == 'ef':
output_model.edit_face(index, value)
elif op == 'fc':
print('fc {} {} {} {}'.format(
len(output_model.face_mapping),
value[0],
value[1],
value[2]),
file=output
)
def contract(self, output: io.TextIOWrapper) -> None: def contract(self, output: io.TextIOWrapper) -> None:
""" Compress the 3d model """ Compress the 3d model
@ -349,12 +406,11 @@ class MAPS(obja.Model):
operations = [] operations = []
# while len(self.vertices) > 64: # while len(self.vertices) > 64:
for i in range(16): for i in range(1):
selected_vertices = self.select_vertices() # find the set of vertices to remove selected_vertices = self.select_vertices() # find the set of vertices to remove
while len(selected_vertices) > 0: for vertex in track(selected_vertices, description="compression"):
vertex = selected_vertices.pop(0) # get next vertex # print(f" {len(selected_vertices)} ", end='\r')
print(f" {len(selected_vertices)} ", end='\r')
# Extract ring faces # Extract ring faces
_, ring_faces = self.one_ring(vertex) _, ring_faces = self.one_ring(vertex)
@ -364,18 +420,18 @@ class MAPS(obja.Model):
# Edit the first faces # Edit the first faces
for i in range(len(faces)): for i in range(len(faces)):
operations.append( # operations.append(
('ef', ring_faces[i], self.faces[ring_faces[i]])) # ('ef', ring_faces[i], self.faces[ring_faces[i]]))
self.faces[ring_faces[i]] = faces[i] self.faces[ring_faces[i]] = faces[i]
# Remove the last faces # Remove the last faces
for i in range(len(faces), len(ring_faces)): for i in range(len(faces), len(ring_faces)):
operations.append( # operations.append(
('af', ring_faces[i], self.faces[ring_faces[i]])) # ('af', ring_faces[i], self.faces[ring_faces[i]]))
self.faces[ring_faces[i]] = None self.faces[ring_faces[i]] = None
# Remove the vertex # Remove the vertex
operations.append(('av', vertex, self.vertices[vertex])) # operations.append(('av', vertex, self.vertices[vertex]))
self.vertices[vertex] = None self.vertices[vertex] = None
# Register remaining vertices and faces # Register remaining vertices and faces
@ -401,6 +457,14 @@ class MAPS(obja.Model):
output_model.edit_vertex(index, value) output_model.edit_vertex(index, value)
elif op == 'ef': elif op == 'ef':
output_model.edit_face(index, value) output_model.edit_face(index, value)
elif op == 'fc':
print('fc {} {} {} {}'.format(
index,
value[0],
value[1],
value[2]),
file=output
)
def main(args): def main(args):
@ -413,7 +477,7 @@ def main(args):
model.parse_file(args.input) model.parse_file(args.input)
with open(args.output, 'w') as output: with open(args.output, 'w') as output:
model.contract(output) model.truc(output)
if __name__ == '__main__': if __name__ == '__main__':