def center_and_normalize(self, scale=1.0): ''' Scales down the object to fit in world space, defaulting to a box from (1, 1, 1) to (-1, -1, -1) :param scale: Applies a scalar to the final result. ''' count = 0 center = glm.vec3(0., 0., 0.) farthest = 0. for shape in self.shapes: for point in shape.points: count += 1 center += point.vertex center = center / float(count) # center the object for shape in self.shapes: for point in shape.points: point.vertex = point.vertex - center farthest = max([ glm.sqrt(point.vertex.x**2 + point.vertex.y**2 + point.vertex.z**2), farthest ]) # scale the objects verticies in relation to the furthest point from # the center scale = scale / farthest for shape in self.shapes: for point in shape.points: point.vertex = point.vertex * scale
def icoso_vertex(x, y, z): 'Return vertex coordinates fixed to the unit sphere' length = glm.sqrt(x * x + y * y + z * z) return Point3D( x * radius / length, y * radius / length, z * radius / length, )
def remove_child(self, child): self.children.remove(child) child_center = glm.vec3(self.M * glm.vec4(child.center, 1)) child_radius = child.radius * glm.length(self.M * glm.vec4(1, 1, 1, 0)) / glm.sqrt(3) if len(self.children) > 1: centers = [self.M * glm.vec4(child.center, 1) for child in self.children] self.min_x = min([center[0] for center in centers]) self.max_x = max([center[0] for center in centers]) self.min_y = min([center[1] for center in centers]) self.max_y = max([center[1] for center in centers]) self.min_z = min([center[2] for center in centers]) self.max_z = max([center[2] for center in centers]) self.center = glm.vec3((self.min_x + self.max_x) / 2, (self.min_y + self.max_y) / 2, (self.min_z + self.max_z) / 2) self.radius = max([glm.length(self.center - child.center) + child.radius for child in self.children])
def cull(self, C, cull_planes): if len(cull_planes) > 0: # Recalculate center and radius based on scene graph traversal center = glm.vec3(C * glm.vec4(self.center, 1)) radius = self.radius * glm.length( C * glm.vec4(1, 1, 1, 0)) / glm.sqrt(3) for point, normal in cull_planes: dist = glm.dot(center - point, normal) if dist > radius: # Cull if beyond plane if self.name == None: print( 'name:{} point:{!r} norm:{!r} dist:{} r:{} center:{!r} prev_center:{!r}' .format(self.name, point, normal, dist, radius, center, self.center)) return True return False
def calc_collide_rays(self, numViewDirections, length): directions=[] goldenRatio = (1 + glm.sqrt(5)) / 2; angleIncrement = glm.pi() * 2 * goldenRatio; i=0 while i < (numViewDirections): t = i / numViewDirections; inclination = glm.acos(1 - 2 * t); azimuth = angleIncrement * i; x = glm.sin(inclination) * glm.cos(azimuth); y = glm.sin (inclination) * glm.sin(azimuth); z = glm.cos (inclination); directions.append(glm.vec3(x, y, z)*length) i+=1 return directions
def add_child(self, child: Node): child_center = glm.vec3(self.M * glm.vec4(child.center, 1)) child_radius = child.radius * glm.length(self.M * glm.vec4(1, 1, 1, 0)) / glm.sqrt(3) if len(self.children) == 0: self.center = child_center self.radius = child_radius self.min_x = self.max_x = self.center[0] self.min_y = self.max_y = self.center[1] self.min_z = self.max_z = self.center[2] else: self.min_x = min(self.min_x, child_center[0]) self.max_x = max(self.max_x, child_center[0]) self.min_y = min(self.min_y, child_center[1]) self.max_y = max(self.max_y, child_center[1]) self.min_z = min(self.min_z, child_center[2]) self.max_z = max(self.max_z, child_center[2]) new_center = glm.vec3((self.min_x + self.max_x) / 2, (self.min_y + self.max_y) / 2, (self.min_z + self.max_z) / 2) self.radius += glm.length(self.center - new_center) self.center = new_center self.radius = max(self.radius, glm.length(child_center - self.center) + child_radius) self.children.append(child)
def apply_matrix(self, M): self.center = glm.vec3(M * glm.vec4(self.center, 1)) self.radius = self.radius * glm.length(M * glm.vec4(1, 1, 1, 0)) / glm.sqrt(3) self.M = M * self.M
def sphere(radius, first_point, detail=2, color=None): def middle_point(point_1, point_2): """ Find a middle point and project to the unit sphere """ # We check if we have already cut this edge first # to avoid duplicated verts smaller_index = min(point_1, point_2) greater_index = max(point_1, point_2) key = '{0}-{1}'.format(smaller_index, greater_index) if key in middle_point_cache: return middle_point_cache[key] # If it's not in cache, then we can cut it vert_1 = verts[point_1] vert_2 = verts[point_2] middle = [sum(i) / 2 for i in zip(vert_1.vertex, vert_2.vertex)] verts.append(icoso_vertex(*middle)) index = len(verts) - 1 middle_point_cache[key] = index return index def icoso_vertex(x, y, z): 'Return vertex coordinates fixed to the unit sphere' length = glm.sqrt(x * x + y * y + z * z) return Point3D( x * radius / length, y * radius / length, z * radius / length, ) middle_point_cache = {} PHI = (1 + glm.sqrt(5)) / 2 verts = [ icoso_vertex(-1, PHI, 0), icoso_vertex(1, PHI, 0), icoso_vertex(-1, -PHI, 0), icoso_vertex(1, -PHI, 0), icoso_vertex(0, -1, PHI), icoso_vertex(0, 1, PHI), icoso_vertex(0, -1, -PHI), icoso_vertex(0, 1, -PHI), icoso_vertex(PHI, 0, -1), icoso_vertex(PHI, 0, 1), icoso_vertex(-PHI, 0, -1), icoso_vertex(-PHI, 0, 1), ] faces = [ # 5 faces around point 0 [0, 11, 5], [0, 5, 1], [0, 1, 7], [0, 7, 10], [0, 10, 11], # Adjacent faces [1, 5, 9], [5, 11, 4], [11, 10, 2], [10, 7, 6], [7, 1, 8], # 5 faces around 3 [3, 9, 4], [3, 4, 2], [3, 2, 6], [3, 6, 8], [3, 8, 9], # Adjacent faces [4, 9, 5], [2, 4, 11], [6, 2, 10], [8, 6, 7], [9, 8, 1] ] for i in range(detail): faces_subdiv = [] for tri in faces: v1 = middle_point(tri[0], tri[1]) v2 = middle_point(tri[1], tri[2]) v3 = middle_point(tri[2], tri[0]) faces_subdiv.append([tri[0], v1, v3]) faces_subdiv.append([tri[1], v2, v1]) faces_subdiv.append([tri[2], v3, v2]) faces_subdiv.append([v1, v2, v3]) faces = faces_subdiv for i, face in enumerate(faces): # reuse faces to save a bit of memory here faces[i] = Shape2D([verts[point] for point in face]) sphere = Shape3D(faces) sphere.gen_normals() # sphere.offset = glm.vec4(first_point.vertex, 1) return sphere