-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolution.py
101 lines (79 loc) · 3.64 KB
/
solution.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import numpy as np
import math
import draw
class Mesh:
def __init__(self, faces, coordinates=None):
self.faces = faces
vertices = set(i for f in faces for i in f)
self.n = max(vertices) + 1
if coordinates is not None:
self.coordinates = np.array(coordinates)
assert set(range(self.n)) == vertices
for f in faces:
assert len(f) == 3
if coordinates is not None:
assert self.n == len(coordinates)
for c in coordinates:
assert len(c) == 3
@classmethod
def fromobj(cls, filename):
faces, vertices = draw.obj_read(filename)
return cls(faces, vertices)
def draw(self):
draw.draw(self.faces, self.coordinates.tolist())
def angleDefect(self, vertex): # vertex is an integer (vertex index from 0 to self.n-1)
sum_of_angles = 0
for face in self.faces:
if vertex in face:
cur_vertices = [self.coordinates[vertex]]
for v in face:
if v != vertex:
v = self.coordinates[v]
cur_vertices.append(v)
lengths = np.zeros(0)
for i in range(3):
lengths = np.append(lengths, [math.sqrt(np.sum((cur_vertices[(i+1) % 3]
- cur_vertices[(i+2) % 3]) ** 2))])
cur_angle = math.acos((lengths[1]*lengths[1] + lengths[2] * lengths[2]
- lengths[0] * lengths[0])/(2.0 * lengths[1] * lengths[2]))
sum_of_angles += cur_angle
return math.pi * 2 - sum_of_angles
def buildLaplacianOperator(self, anchors=None, anchor_weight=1.):
# anchors is a list of vertex indices, anchor_weight is a positive number
if anchors is None:
anchors = []
A = np.zeros((self.n, self.n))
B = np.zeros((self.n, self.n))
for f in self.faces:
for i in range(3):
a, b = self.coordinates[f[(i + 1) % 3]] - self.coordinates[f[i]], self.coordinates[f[(i + 2) % 3]] \
- self.coordinates[f[i]]
alpha = math.acos(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))
A[f[(i + 1) % 3]][f[(i + 2) % 3]] += 1 / (2 * math.tan(alpha))
A[f[(i + 2) % 3]][f[(i + 1) % 3]] += 1 / (2 * math.tan(alpha))
for i in range(self.n):
B[i][i] += -np.sum(A[i])
old_laplasian = A + B
for i in range(self.n):
old_laplasian[i] /= -old_laplasian[i][i]
laplasian_add = np.zeros((len(anchors), self.n))
for v in anchors:
laplasian_add[anchors.index(v)][v] = anchor_weight
laplasian = np.append(old_laplasian, laplasian_add, axis=0)
return laplasian
def smoothen(self):
L = self.buildLaplacianOperator()
self.coordinates += np.dot(L, self.coordinates)
def transform(self, anchors, anchor_coordinates, anchor_weight=1.):
# anchors is a list of vertex indices, anchor_coordinates is a list of same length of vertex coordinates
# (arrays of length 3), anchor_weight is a positive number
L = self.buildLaplacianOperator(anchors, anchor_weight)
L_start = L[:self.n]
delta = np.dot(L_start, self.coordinates)
delta = np.append(delta, anchor_coordinates, axis=0)
self.coordinates = np.dot(np.dot(np.linalg.inv(np.dot(np.transpose(L), L)), np.transpose(L)), delta)
def dragon():
#mesh = Mesh.fromobj("dragon.obj")
#mesh.smoothen()
#mesh.draw()
raise NotImplementedError