feat: cheplu
This commit is contained in:
parent
c8b16c818e
commit
0329b83aa6
134
main.py
134
main.py
|
@ -4,11 +4,20 @@ import obja.obja as obja
|
|||
import numpy as np
|
||||
import argparse
|
||||
|
||||
from rich.progress import track
|
||||
|
||||
def sliding_window(l: list):
|
||||
head = l[:-1]
|
||||
tail = l[1:]
|
||||
return zip(head, tail)
|
||||
def cot(x: float):
|
||||
sin_x = np.sin(x)
|
||||
if sin_x == 0:
|
||||
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):
|
||||
|
@ -80,13 +89,14 @@ class MAPS(obja.Model):
|
|||
tuple[float, float]: area and curvature
|
||||
"""
|
||||
area_sum = 0
|
||||
curvature_sum = 0
|
||||
laplace_sum = 0
|
||||
one_ring_vertices, _ = self.one_ring(index)
|
||||
|
||||
teta = 0.0
|
||||
p1 = self.vertices[index] # the center of the one-ring
|
||||
for index2, index3 in sliding_window(one_ring_vertices):
|
||||
p2 = self.vertices[index2] # the second vertice of the triangle
|
||||
p3 = self.vertices[index3] # the third vertice of the triangle
|
||||
for index1, index2, index3 in sliding_window(one_ring_vertices, n=3):
|
||||
p2 = self.vertices[index1] # the second 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
|
||||
[p1[0], p2[0], p3[0]],
|
||||
[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_sum += area
|
||||
|
||||
curvature = 4 * area / ( # compute the curvature
|
||||
np.linalg.norm(p1-p2) *
|
||||
np.linalg.norm(p2-p3) *
|
||||
np.linalg.norm(p3-p1)
|
||||
)
|
||||
curvature_sum += curvature
|
||||
teta += self.compute_angle(index1, index, index2)
|
||||
|
||||
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]:
|
||||
""" Compute selection priority of vertices (0 -> hight priority ; 1 -> low priority)
|
||||
K = (2 * np.pi - teta) / area * 3
|
||||
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:
|
||||
lamb (float, optional): convex combination factor. Defaults to 0.5.
|
||||
|
@ -140,6 +160,7 @@ class MAPS(obja.Model):
|
|||
priority = 2.0
|
||||
priorities.append(priority)
|
||||
|
||||
# return np.random.rand(len(priorities))
|
||||
return priorities
|
||||
|
||||
def select_vertices(self) -> list[int]:
|
||||
|
@ -178,13 +199,6 @@ class MAPS(obja.Model):
|
|||
if face_vertex in vertices:
|
||||
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.")
|
||||
return selected_vertices
|
||||
|
||||
|
@ -200,7 +214,7 @@ class MAPS(obja.Model):
|
|||
ring, _ = self.one_ring(index)
|
||||
radius, 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])
|
||||
teta += self.compute_angle(index1, index, index2) # add new angle
|
||||
radius.append(r)
|
||||
|
@ -340,6 +354,49 @@ class MAPS(obja.Model):
|
|||
# Check if point is in triangle
|
||||
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:
|
||||
""" Compress the 3d model
|
||||
|
||||
|
@ -349,12 +406,11 @@ class MAPS(obja.Model):
|
|||
operations = []
|
||||
|
||||
# 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
|
||||
|
||||
while len(selected_vertices) > 0:
|
||||
vertex = selected_vertices.pop(0) # get next vertex
|
||||
print(f" {len(selected_vertices)} ", end='\r')
|
||||
for vertex in track(selected_vertices, description="compression"):
|
||||
# print(f" {len(selected_vertices)} ", end='\r')
|
||||
|
||||
# Extract ring faces
|
||||
_, ring_faces = self.one_ring(vertex)
|
||||
|
@ -364,18 +420,18 @@ class MAPS(obja.Model):
|
|||
|
||||
# Edit the first faces
|
||||
for i in range(len(faces)):
|
||||
operations.append(
|
||||
('ef', ring_faces[i], self.faces[ring_faces[i]]))
|
||||
# operations.append(
|
||||
# ('ef', ring_faces[i], self.faces[ring_faces[i]]))
|
||||
self.faces[ring_faces[i]] = faces[i]
|
||||
|
||||
# Remove the last faces
|
||||
for i in range(len(faces), len(ring_faces)):
|
||||
operations.append(
|
||||
('af', ring_faces[i], self.faces[ring_faces[i]]))
|
||||
# operations.append(
|
||||
# ('af', ring_faces[i], self.faces[ring_faces[i]]))
|
||||
self.faces[ring_faces[i]] = None
|
||||
|
||||
# Remove the vertex
|
||||
operations.append(('av', vertex, self.vertices[vertex]))
|
||||
# operations.append(('av', vertex, self.vertices[vertex]))
|
||||
self.vertices[vertex] = None
|
||||
|
||||
# Register remaining vertices and faces
|
||||
|
@ -401,6 +457,14 @@ class MAPS(obja.Model):
|
|||
output_model.edit_vertex(index, value)
|
||||
elif op == 'ef':
|
||||
output_model.edit_face(index, value)
|
||||
elif op == 'fc':
|
||||
print('fc {} {} {} {}'.format(
|
||||
index,
|
||||
value[0],
|
||||
value[1],
|
||||
value[2]),
|
||||
file=output
|
||||
)
|
||||
|
||||
|
||||
def main(args):
|
||||
|
@ -413,7 +477,7 @@ def main(args):
|
|||
model.parse_file(args.input)
|
||||
|
||||
with open(args.output, 'w') as output:
|
||||
model.contract(output)
|
||||
model.truc(output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in a new issue