Beispiel #1
0
 def get_support(self, shape1, shape2):
     """Gets a support point based on two points in
     the shapes that may be colliding.
     """
     opposite = [-x for x in self.search]
                 
     a = max(shape1.pts, key=lambda p: dot(minus(p, shape1.center), self.search))
     b = max(shape2.pts, key=lambda p: dot(minus(p, shape2.center), opposite))
                 
     return minus(a, b)
Beispiel #2
0
 def check_tetrahedron(self):
     """Determines whether the origin is enclosed within
     a 4-simplex.
     
     Changes self.hit to True if there's a hit.
     Otherwise, drops a point from the simplex and
     sets the search to its normal vector.
     """
     # we know triangle DCB is aligned correctly;
     # we need to check the other 3 normals for same_direction
     
     d, c, b, a = self.simplex
     triangles = [
         [c, b, a],
         [d, b, a],
         [d, c, a]
     ]
     
     # saving the order of points in the triangles so
     # we know which cross product order creates an
     # inward-facing normal when rolled out in reverse
     # order (c, b, a = triangle, not a, b, c = triangle)
     
     good_tris = []
     for tri in triangles:
         cc, bb, aa = tri
         ab_vec = minus(bb, aa)
         ac_vec = minus(cc, aa)
         
         # get the point to test the direction of the norm
         dd = [pt for pt in self.simplex if pt not in tri][0]
         norm = pt_cross(ab_vec, ac_vec)
         if dot(dd, norm) > 0:
             if self.same_direction(norm):
                 good_tris.append(tri)
         else:
             new_norm = [-x for x in norm]
             if self.same_direction(new_norm):
                 good_tris.append([bb, cc, aa])
     self.hit = len(good_tris) == 3
     if not self.hit:
         # i can admit, this is really just sort of flailing.
         # but it isn't entirely stupid; i'm just throwing out the oldest point
         # and starting over with a triangle and a new search direction.
         self.simplex.pop(0)
         c, b, a = self.simplex
         ab = minus(b, a)
         ac = minus(c, a)
         ab_x = pt_cross(ab, ac)
         if self.same_direction(ab_x):
             self.simplex = [c, b, a]
             self.search = ab_x
         else:
             self.simplex = [b, c, a]
             self.search = [-x for x in ab_x]
Beispiel #3
0
 def __init__(self, x, y, z, d):
     pts = coords([x, y, z], [
         [-1, -1, -1],
         [-1, 1, -1],
         [1, -1, -1],
         [1, 1, -1],
         [-1, -1, 1],
         [-1, 1, 1],
         [1, -1, 1],
         [1, 1, 1],
     ], d / 2.0)
     newlines = []
     for a in pts:
         for b in pts:
             vector = minus(a, b)
             if dot(vector, vector) == d**2:
                 newlines.append((a, b))
     super(ZCube, self).__init__(pts)
     pt_groups = ((pts[0], pts[1], pts[2],
                   pts[3]), (pts[4], pts[5], pts[6],
                             pts[7]), (pts[0], pts[1], pts[4], pts[5]),
                  (pts[2], pts[3], pts[6],
                   pts[7]), (pts[0], pts[2], pts[4],
                             pts[6]), (pts[1], pts[3], pts[5], pts[7]))
     for group in pt_groups:
         lines = [(a, b) for a in group for b in group
                  if (a, b) in newlines or (b, a) in newlines]
         self.set_face(group, lines)
Beispiel #4
0
 def sort_face_pts(self, pts):
     pt_list = pts[:]
     pt = pt_list[0]
     yield pt
     while pt_list:
         pt = min(pt_list, key=lambda p: sum(x * x for x in minus(pt, p)))
         pt_list.remove(pt)
         yield pt
Beispiel #5
0
 def set_norm(self, wrong_way):
     """Determines the correct order for calculating the surface
     normal. Ideally all points in this surface are coplanar so
     just three points are enough. The 'wrong way' point is needed
     to set the direction (line self.center -> wrong_way) 
     we do NOT want the normal to point.
     """
     wrong_vector = minus(wrong_way, self.center)
     if not dot(wrong_vector, self.get_norm()) < 0:
         self.order.append(self.order.pop(1))
Beispiel #6
0
 def cull_draw(self, qs):
     all_objs = []
     for q in qs:
         for s in q:
             all_objs.append(s)
     self.screen.lock()
     for zshape in sorted(all_objs,
                          key=lambda x: x.center[-1],
                          reverse=True):
         if not zshape.faces:
             for line in zshape.lines:
                 self.draw_zline(line[0], line[1], zshape.color, 1)
         else:
             for face in zshape.faces:
                 if dot(minus(face.order[0], self.camera),
                        face.get_norm()) < 0:
                     self.draw_face(face)
     self.screen.unlock()
Beispiel #7
0
 def check_line(self):
     """Determines which part of a 2-simplex is closest
     to the origin. Sets search direction in accordance.
     
     May reduce the simplex to a single point if self.simplex[-1]
     is the closest aspect.
     """
     ab = minus(self.simplex[0], self.simplex[1])
     if self.same_direction(ab):
         # set next search vector
         self.search = pt_cross(pt_cross(ab, self.ao), ab)
     else:
         # the closest aspect
         # is the last point in the simplex.
         # so the simplex is pt A
         # and the search direction is AO
         self.simplex.pop(0)
         self.search = self.ao
Beispiel #8
0
 def __init__(self, x, y, z, d, right=True):
     pts = coords([x, y, z],
                  [[0, sqrt(3) -
                    (1.0 / sqrt(3)), 0], [-1, -1.0 / sqrt(3), 0],
                   [1, -1.0 / sqrt(3), 0], [0, 0, 2.0 * sqrt(2 / 3.0)]], d)
     e = .000001
     lines = []
     for a in pts:
         for b in pts:
             vector = minus(a, b)
             if d - e <= (dot(vector, vector) / (d * 4)) <= d + e:
                 lines.append((a, b))
     super(ZTetra, self).__init__(pts)
     if right:
         self.rotate(-(2 * pi) / 4, "x")
     pt_group = ((pts[0], pts[1], pts[2]), (pts[0], pts[2], pts[3]),
                 (pts[0], pts[1], pts[3]), (pts[1], pts[2], pts[3]))
     for group in pt_group:
         line_group = ((group[0], group[1]), (group[1], group[2]),
                       (group[0], group[2]))
         self.set_face(group, line_group)
Beispiel #9
0
    def __init__(self, x, y, z, d):
        pts = coords([x, y, z], [[1, 0, 0], [0, 1, 0], [0, 0, 1], [-1, 0, 0],
                                 [0, -1, 0], [0, 0, -1]], d)

        e = .000001
        lines = []
        for a in pts:
            for b in pts:
                vector = minus(a, b)
                if d - e <= (dot(vector, vector) / (d * 2)) <= d + e:
                    lines.append((a, b))
        super(ZOcta, self).__init__(pts)
        pt_groups = ((pts[0], pts[1], pts[2]), (pts[0], pts[1], pts[5]),
                     (pts[3], pts[1], pts[2]), (pts[3], pts[1], pts[5]),
                     (pts[0], pts[4], pts[2]), (pts[0], pts[4], pts[5]),
                     (pts[3], pts[4], pts[2]), (pts[3], pts[4], pts[5]))

        for group in pt_groups:
            newlines = [(a, b) for a in group for b in group
                        if (a, b) in lines or (b, a) in lines]

            self.set_face(group, newlines)
Beispiel #10
0
 def find_collision(self, shape1, shape2):
     self.hit = False
     self.search = minus(shape1.center, shape2.center)
     self.simplex = [self.get_support(shape1, shape2)]
     self.search = [-x for x in self.search]
     # keeps it from working on the same
     # two shapes ad infinitum 
     for _ in xrange(len(shape1.pts) * len(shape2.pts)):
         next_pt = self.get_support(shape1, shape2)
         # if the dot product of line ON (origin -> next_pt) 
         # and line OS (origin -> search) is positive, 
         # then we evolve the simplex and continue.
         #
         # if not, we cannot have a hit - return False. Loop over!
         if dot(next_pt, self.search) > 0:
             self.simplex.append(next_pt)
             # if the origin is enclosed
             # by the tetrahedron, self.hit flips to True
             self.get_simplex()
         else:
             return False
         if self.hit:
             return True
Beispiel #11
0
    def flat_shading(self, face):
        n_norm = normalize_vector(face.get_norm())
        d_norm = normalize_vector(minus(self.light_source, face.order[0]))

        shade = abs(dot(n_norm, d_norm))
        return [int(c * shade) for c in face.color]
Beispiel #12
0
    def check_triangle(self):
        """Determines which part of a 3-simplex is closest
        to the origin. Sets search direction in accordance.

        May reduce the simplex to either a 2-simplex or a
        single point, depending on the results.
        """
        # note that at this point,
        # self.simplex is triangle
        # CBA, not ABC! we want to keep looking
        # towards line AO (simplex[-1] to origin)
        # so unroll the list accordingly
        c, b, a = self.simplex
                
        # these come up a lot here
        ab_vec = minus(b, a)
        ac_vec = minus(c, a)
        # get triangle normal
        abc_norm = pt_cross(ab_vec, ac_vec)
        # then get normal from the normal! this should
        # always point outward (away from triangle center)
        abc_x_ac = pt_cross(abc_norm, ac_vec)
        
        fall_thru = False        
        # if a line orthogonal from the triangle
        # AND line AC is the same as AO...
        if self.same_direction(abc_x_ac):
            # ...do another test because origin could
            # still be outside the triangle
            if self.same_direction(ac_vec):
                # simplex becomes line AC
                # search is the normal from AC x AO x AC
                self.simplex = [c, a]
                self.search = pt_cross(pt_cross(ac_vec, self.ao), ac_vec)
            else:
                fall_thru = True
        else:
            # otherwise check the other normal from the other side
            ab_x_abc = pt_cross(ab_vec, abc_norm)
            if not self.same_direction(ab_x_abc):
                # it's a NOT check because if ab_x_abc
                # dots positively to self.ao, it 
                # means that line AB is the closest, so
                # that becomes the new simplex.
                # otherwise, the triangle is the closest aspect
                # now we just need to find the right normal from
                # the triangle to search in
                if self.same_direction(abc_norm):
                    # just change the search, triangle is fine
                    self.search = abc_norm
                else:
                    # otherwise, flip the normal and the
                    # b & c points in the triangle!
                    self.simplex = [b, c, a]
                    self.search = [-x for x in abc_norm]
            else:
                fall_thru = True
        # if we're here it means that AB was closest
        # and so we pop simplex[0]
        if fall_thru:
            if self.same_direction(ab_vec):
                self.simplex = [b, a]
                self.search = pt_cross(pt_cross(ab_vec, self.ao), ab_vec)
            else:
                # must be that the triangle itself was pointed at the origin
                # and point A was closest, so pop again and set search to self.ao
                self.simplex = [a]
                self.search = self.ao