def smoothing(self): for i in range(self.num_iterations): for n in self.grid.Nodes: neighbours = [] assert len(n.edges) > 1 for e in n.edges: assert len(e.nodes) == 2 n1 = e.nodes[0] n2 = e.nodes[1] if n1 == n: neighbours.append(n2) else: neighbours.append(n1) laplacian = Vector() for neighbour_node in neighbours: laplacian.sum(point_to_vector(neighbour_node.as_point())) laplacian.dev(len(neighbours)) laplacian.sub(point_to_vector(n.as_point())) backward_laplacian = deepcopy(laplacian) laplacian.mul(self.lamb) backward_laplacian.mul(self.mu) backward_laplacian.mul(-1) if i % 2 == 0: Smoothing.move_node(self, n, laplacian) else: Smoothing.move_node(self, n, backward_laplacian) Smoothing.write_grid_and_print_info(self, i)
def smoothing(self): Smoothing.write_grid_and_print_info(self, 0) for i in range(1, self.num_iterations): laplacians = [] fazzians = [] for n in self.grid.Nodes: m = len(n.faces) w = [f.area() for f in n.faces] N = self.create_matrix_of_normals(n) dv = self.vector_to_avg_of_centroids( n, self.n_neighbours_for_border_nodes) assert N.shape == (m, 3) assert len(w) == m assert isinstance(dv, Vector) W = diag(w) NTW = dot(N.T, W) A = dot(NTW, N) assert W.shape == (m, m) assert NTW.shape == (3, m) assert A.shape == (3, 3) eigenValues, eigenVectors = eig(A) idx = eigenValues.argsort()[::-1] eigenValues = eigenValues[idx] eigenVectors = eigenVectors[:, idx] assert abs(det(A) - cumprod(eigenValues)[-1]) < DETERMINANT_ACCURACY, \ print(det(A), cumprod(eigenValues)[-1]) k = sum((eigenValues > self.epsilon * eigenValues[0])) ns = eigenVectors[:, k:] dv = dv.coords_np_array().reshape(3, 1) assert ns.shape == (3, 3 - k), 'Wrong eigenvectors shape' assert dv.shape == (3, 1), 'Wrong shape' # self.print_info(n, eigenValues, ns, k) if k < 3: ttT = dot(ns, ns.T) if n.fixed: t = self.st * dot(ttT, dv) else: t = self.st * dot(ttT, dv) assert t.shape == (3, 1), 'Wrong shift shape' laplacian = Vector(float(t[0, 0]), float(t[1, 0]), float(t[2, 0])) else: laplacian = Vector(0, 0, 0) laplacians.append(laplacian) Smoothing.apply_laplacians(self, laplacians) FuzzyVectorMedian(self.grid).smoothing() Smoothing.write_grid_and_print_info(self, i)
def area(self): """Calculate the area of the face.""" assert len(self.nodes) == 3, "Wrong number of nodes in the face" n1, n2, n3 = self.nodes[0], self.nodes[1], self.nodes[2] p1, p2, p3 = n1.as_point(), n2.as_point(), n3.as_point() v1 = Vector.subtract_vectors(point_to_vector(p1), (point_to_vector(p2))) v2 = Vector.subtract_vectors(point_to_vector(p1), (point_to_vector(p3))) res = cross_product(v1, v2).norm() / 2 assert isinstance(res, float), print('Wrong area', res) return res
def normal(self): assert len(self.nodes) == 3, 'Wrong number of nodes in the face' p1 = self.nodes[0].as_point() p2 = self.nodes[1].as_point() p3 = self.nodes[2].as_point() v1 = Vector(p1.x, p1.y, p1.z) v2 = Vector(p2.x, p2.y, p2.z) v3 = Vector(p3.x, p3.y, p3.z) vf = Vector.subtract_vectors(v1, v2) vs = Vector.subtract_vectors(v1, v3) vr = cross_product(vf, vs) vr.make_unit() assert isinstance(vr, Vector) vr.mul(-1) return vr
def is_node_fixed(n): border_edges = [e for e in n.edges if e.border] assert len(border_edges) == 2, print('Wrong number of border edges', len(border_edges)) alpha = 0.01 be1_v = border_edges[0] be2_v = border_edges[1] # make vectors directed in different sides. # represent as (n1) --be1_v-- (n2) --be2_v-- (n3) n1 = None n2 = n n3 = None assert len(be1_v.nodes) == 2 assert len(be2_v.nodes) == 2 if be1_v.nodes[0] == n: n1 = be1_v.nodes[1] else: n1 = be1_v.nodes[0] assert be1_v.nodes[1] == n if be2_v.nodes[0] == n: n3 = be2_v.nodes[1] else: n3 = be2_v.nodes[0] assert be2_v.nodes[1] == n assert n1 is not n2 assert n2 is not n3 assert n3 is not n1 n1_v = Vector(n1.x, n1.y, n1.z) n2_v = Vector(n2.x, n2.y, n2.z) n3_v = Vector(n3.x, n3.y, n3.z) be1 = Vector.subtract_vectors(n1_v, n2_v) be2 = Vector.subtract_vectors(n3_v, n2_v) be1.make_unit() be2.make_unit() dot_between_unit_edges = dot_product(be1, be2) assert -1 <= dot_between_unit_edges <= 1 if dot_between_unit_edges > (-1 + alpha): return True, border_edges return False, border_edges
def vector_to_avg_of_centroids(self, node, n_neighbours=None): dv = Vector() p = point_to_vector(node.as_point()) weights = 0 # turn off condition len(node.faces) % 2 != 0 for a second if node.fixed: neighbours = self.find_n_neighbours_faces_of_node( node, n_neighbours) else: neighbours = node.faces assert len(neighbours) > 0 assert isinstance(node.Id, int) for f in neighbours: #self.grid.adj_list_for_border_nodes[node.Id - 1, f.Id] = 1 c = point_to_vector(f.centroid()) c.sub(p) if self.weight_faces_by_angle: weight = self.set_weight_for_face(node, f, c) else: weight = 1.0 assert isinstance(c, Vector) assert isinstance(weight, float) c.mul(weight) dv.sum(c) weights += weight dv.dev(weights) return dv
def test_dot(): v1 = Vector(1, 1, 1) v2 = Vector(1, 1, 1) assert dot_product(v1, v2) == 3, 'Wrong dot product' v1 = Vector(0, 0, 0) v2 = Vector(0, 0, 0) assert dot_product(v1, v2) == 0, 'Wrong dot product' v1 = Vector(-1, 0, 1) v2 = Vector(2, 1, -1) assert dot_product(v1, v2) == -3, 'Wrong dot product' v1 = Vector(0.5, 4, -1) v2 = Vector(2, 3, 1) assert dot_product(v1, v2) == 12, 'Wrong dot product'
def build_first_room(self): for corridor in self.corridors: print(corridor) """ Initialize dungeon by putting the first structure in queue """ directions = [Vector(d) for d in [[0, 1], [0, -1], [1, 0], [-1, 0]]] locations = [ self.origin + l for l in [[0, 1], [0, -1], [1, 0], [-1, 0]] ] for i in range(len(directions)): length = 6 #print("creating corridor: start=%s, direction=%s, length%s"%(locations[i], directions[i], length)) self.make_corridor(locations[i], directions[i], length) self.plan_construction(self.periodic, location=locations[i] + length * directions[i], direction=directions[i])
def laplacian(self, node): neighbours = [] assert len(node.edges) > 1 for e in node.edges: assert len(e.nodes) == 2 n1 = e.nodes[0] n2 = e.nodes[1] if n1 == node: neighbours.append(n2) else: neighbours.append(n1) laplacian = Vector() for neighbour_node in neighbours: laplacian.sum(point_to_vector(neighbour_node.as_point())) laplacian.dev(len(neighbours)) laplacian.sub(point_to_vector(node.as_point())) return laplacian
def border_edge_to_project_on(self, n, shift_vector): is_fixed, border_edges = self.is_node_fixed(n) if self.fix_corner_nodes and is_fixed: return Vector(0, 0, 0) dot_products_between_edges_and_shift = [ dot_product(edge_to_vector(e), shift_vector) for e in border_edges ] edge_to_project_on_number = argmax( dot_products_between_edges_and_shift) assert edge_to_project_on_number == 0 or edge_to_project_on_number == 1 edge_to_project_on = edge_to_vector( border_edges[edge_to_project_on_number]) edge_to_project_on.make_unit() assert isinstance(edge_to_project_on, Vector) return edge_to_project_on
def test_cross(): v1 = Vector(1, 1, 1) v2 = Vector(1, 1, 1) assert cross_product(v1, v2).x == 0, 'Wrong cross product' assert cross_product(v1, v2).y == 0, 'Wrong cross product' assert cross_product(v1, v2).z == 0, 'Wrong cross product' v1 = Vector(-1, 4, 19) v2 = Vector(1.5, 5, -3) assert cross_product(v1, v2).x == -107, 'Wrong cross product' assert cross_product(v1, v2).y == 25.5, 'Wrong cross product' assert cross_product(v1, v2).z == -11, 'Wrong cross product' v1 = Vector(-1, -1, -13) v2 = Vector(-32, -1, -12.4) assert cross_product(v1, v2).x == -0.5999999999999996, 'Wrong cross product' assert cross_product(v1, v2).y == 403.6, 'Wrong cross product' assert cross_product(v1, v2).z == -31, 'Wrong cross product'
def test_vector(): v = Vector() v2 = Vector(1, 0.1, -1) assert v.coords() == (0, 0, 0), "Wrong vector initialization" v.sum(v2) assert v.coords() == (1, 0.1, -1), 'Wrong vector sum' v.sub(v2) assert v.coords() == (0, 0, 0), 'Wrong subtraction' v.sum(v2) assert v.coords() == (1, 0.1, -1), print('Wrong vector sum', v.coords()) v.mul(3.1) assert v.coords() == (3.1, 0.31000000000000005, -3.1), print('Wrong vector multiplication', v.coords()) v.dev(2) assert v.coords() == (1.55, 0.15500000000000003, -1.55), print('Wrong vector division', v.coords())
def smoothing(self): """Performs smoothing using FVM.""" for it in range(self.num_iterations): for f in self.grid.Faces: f.fuzzy_median = f.normal() self.define_fvs() self.fuzzy_vector_medians() laplacians = [] for n in self.grid.Nodes: laplacian = Vector() if n.fixed: for e in n.edges: i = e.nodes[0] j = e.nodes[1] if i == n: pass else: assert j == n j = e.nodes[0] i = e.nodes[1] i = i.as_point() j = j.as_point() assert 0 < len(e.faces) < 3 aux_vector = Vector() for f in e.faces: assert f.fuzzy_median is not None diff = Vector.subtract_vectors( point_to_vector(j), point_to_vector(i)) dot = dot_product(f.fuzzy_median, diff) fm = deepcopy(f.fuzzy_median) assert abs(fm.norm() - 1.0) < EPSILON, print( fm.norm()) fm.mul(dot) aux_vector.sum(fm) laplacian.sum(aux_vector) laplacian.mul(self.lambd) laplacians.append(laplacian) Smoothing.apply_laplacians(self, laplacians) Smoothing.write_grid_and_print_info(self, it)
def fuzzy_vector_medians(self, iterations=1): """Calculates the fuzzy vector median of all faces in the grid. Calculation is based on the formula 10 from Shen and Barner, Fuzzy Vector Median-Based Surface Smoothing. """ for i in range(iterations): for f in self.grid.Faces: incident_faces = self.incident_faces(f) VM = f.vector_median sum_r = 0 res = Vector() for iface in incident_faces: R = self.gaussian_membership_function( iface.fuzzy_median, VM) assert isinstance(R, float) sum_r += R aux_vector = deepcopy(iface.fuzzy_median) aux_vector.mul(R) res.sum(aux_vector) res.dev(sum_r) if res.norm() is not 0.0: res.make_unit() else: res = deepcopy(VM) assert abs(res.norm() - 1.0) < EPSILON, print(res.norm()) f.fuzzy_median = res