def circumcenter(*points, homogeneous=True): """Computes a circumcenter for a set of n+1 points in n dimensions, ignoring the extended homogeneous coordinates. Unless you pass homogeneous=False, the last coordinate of each point will be lopped off. Behavior may not be defined if any of the homogeneous coordinates is not 1. """ if homogeneous: if [pt[-1] for pt in points] != [1] * len(points): tmp = [] for v in [p.to_vector() for p in points]: if v[-1] == 0: v *= 1000000000 tmp.append(v) # Just strip off the homogeneous coordinates. tmp = [v[:-1] for v in tmp] points = [Point(*v.to_array()) for v in tmp] else: points = [pt[:-1] for pt in points] vectors = [p - points[0] for p in points[1:]] A = Matrix(*vectors).transpose() p0_squared = points[0].to_vector().norm_squared() b = Vector(*[ 0.5 * (p.to_vector().norm_squared() - p0_squared) for p in points[1:] ]) x = A.inverse() * b # If the arguments had homogeneous coordinates, we want to tack the extra # coordinate back on: return Point(*x, *([1] if homogeneous else []))
def test_ccw_euclidean(self): """Right now this only tests ccw for 1 and 2 dimensions.""" # one-dimensional test. one_dim_high = Point(1) one_dim_low = Point(0) # I don't much care which way is negative, but one had better be # positive and the other negative. And they'd better be ints. (Of # course, ccw in 1D is equivalent to numeric comparison.) self.assertEqual((ccw(one_dim_high, one_dim_low, homogeneous=False) * ccw(one_dim_low, one_dim_high, homogeneous=False)), -1) self.assertIsInstance((ccw(one_dim_high, one_dim_low, homogeneous=False) * ccw(one_dim_low, one_dim_high, homogeneous=False)), int) # co-hyperplanar --> 0 self.assertEqual(ccw(one_dim_high, one_dim_high, homogeneous=False), 0) # Now for 2D stuff: # Invariance under rotation of args self.assertEqual(ccw(self.r2north, self.r2east, self.r2south, homogeneous=False), ccw(self.r2south, self.r2north, self.r2east, homogeneous=False)) self.assertEqual(ccw(self.r2north, self.r2east, self.r2south, homogeneous=False), -1) self.assertEqual(ccw(self.r2east, self.r2south, self.r2west, homogeneous=False), -1) self.assertEqual(ccw(self.r2south, self.r2north, self.r2orig, homogeneous=False), 0) self.assertEqual(ccw(self.r2east, self.r2orig, self.r2east, homogeneous=False), 0) self.assertEqual(ccw(self.r2west, self.r2east, self.r2south, homogeneous=False), -1) self.assertEqual(ccw(self.r2west, self.r2south, self.r2north, homogeneous=False), 1) # Swapping two args flips the sign self.assertEqual(ccw(self.r2west, self.r2south, self.r2north, homogeneous=False), -ccw(self.r2south, self.r2west, self.r2north, homogeneous=False)) self.assertEqual(ccw(self.r2west, self.r2east, self.r2orig, homogeneous=False), -ccw(self.r2east, self.r2west, self.r2orig, homogeneous=False)) # Warn us when we make non-square matrices self.assertRaises(Exception, ccw, self.r2west, self.r2south, self.r2north, self.r2east, homogeneous=False) self.assertRaises(Exception, ccw, self.r2orig, self.r2south, homogeneous=False)
def test_lift(self): """Make sure lifting works nicely.""" # Define a function to use for testing def f(x): return x[0] * 2 self.assertTrue(self.b.lift(f) == Point(1, 2, 2)) self.assertFalse(self.c.lift(f) == Point(1, 2, 3, 4)) self.assertFalse(self.c.lift(f) == Point(1, 2, 3)) # Make sure that lifting a Point returns a Point self.assertIsInstance(self.b.lift(f), Point)
def test_hashing(self): """Make sure point hashing works and does not cause collisions""" # Add 400 points' hashes to a set and make sure 400 things are in the # set some_hashes = set() for x in range(-10, 10): for y in range(-10, 10): some_hashes.add(hash(Point(x, y, 1))) self.assertEqual(len(some_hashes), 400) self.assertEqual(hash(Point(0, 1, 2)), hash(Point(0, 1, 2)))
def test_in_general_position(self): """Test rigorously, but only for nice inputs""" points = [ Point(0.5, -400, 1), Point(10, 21, 1), Point(-5, 0, 1), Point(1, 2, 1), Point(2, 1, 1) ] deltri = DelT(points, randomize=False) self.assertTrue(deltri.test_is_delaunay())
def test_2d_case(self): """Test the output for a super simple 2D case""" del_tri = DelT([Point(3, 4), Point(-3, 4), Point(0, -5)], homogeneous=False, randomize=False) vor = Voronoi(del_tri) expected_center = Point(0.0, 0.0, 1.0) self.assertTrue(expected_center in vor.points) self.assertTrue(len(vor.points) == 1) self.assertTrue(len(vor.edges) == 3)
def test_misc_niceties(self): """I don't want the empty point to be a thing. You may disagree.""" with self.assertRaises(ValueError): Point() # Try to make an empty point. # Make sure that we can evaluate a point to True self.assertTrue(self.a)
def ccw(*points, homogeneous=True): """tests if triangle a, b, c is oriented counterclockwise. Returns 1 if ccw, 0 if colinear, -1 if cw. Also does the scary analogous n-dimensional test, which essentially tests if, from the perspective of the last point, the other points appear to be well-oriented according to the (n-1)-dimensional test. """ if not homogeneous: mtrx = Matrix(*[pt.lift(lambda v: 1).to_vector() for pt in points]) else: mtrx = None for pt in points: if pt[-1] == 1: # We need at list one non-infinite point # for this to work normally mtrx = Matrix(*[pt.to_vector() for pt in points]) break if mtrx is not None: return mtrx.sign_det() # If all points have 0 for extended homogeneous coordinate, # win by using the ccw test for one dimension higher: return ccw(*points, Point(*(0 for i in range(len(points[0]) - 1)), -1), homogeneous=False)
def __init__(self, triangulation): self.points = set() self.edges = set() finite_faces = (f for f in triangulation.faces if self._is_finite(f)) for face in finite_faces: point = circumcenter(*face.points()) self.points.add(point) for half_facet in face.iter_facets(): if half_facet.twin: adj_point = circumcenter(*half_facet.twin.face.points()) if not self._is_finite(half_facet.twin.face): tmp_vec = ((adj_point.to_vector()[:-1]) * (1 / 1000000000)) adj_point = Point(*tmp_vec.to_array()) adj_point = adj_point.lift(lambda *args: 0) self.edges.add(frozenset([point, adj_point]))
def setUp(self): """Make some objects that are useful for most tests.""" # Make points on the unit circle in the plane # North, East, South, and West shouldn't bend your brain self.r2north = Point(0, 1) self.r2south = Point(0, -1) self.r2east = Point(1, 0) self.r2west = Point(-1, 0) self.r2orig = Point(0, 0) # Now the homogeneous version of the same thing (We use the plane z=1 # to represent the plane R^2 but with a boundary (homeomorphic to a # circle). Points with z=0 are essentially infinitely far away. The # same idea works in higher dimensions. self.homo_north = Point(0, 1, 1) self.homo_south = Point(0, -1, 1) self.homo_east = Point(1, 0, 1) self.homo_west = Point(-1, 0, 1) self.homo_orig = Point(0, 0, 1)
def outer_face_pts(dimension): """Get some points whose simplex contains all of R^{dimension} This ought to be a triangulation method, I guess. But I'm leaving it here for now. (This is all the standard basis vectors, plus the vector of all -1s. Er, but points, not vectors.) """ coords = [0] * (dimension + 1) results = [] for i in range(dimension): # Generate a standard basis vector coords[i] = 1 results.append(Point(*coords)) coords[i] = 0 results.append(Point(*(-1 for i in range(dimension)), 0)) return results
def test_vertex_compare(self): """Make sure vertices have an order that's reasonable.""" verts = [] for i in range(-5, 5): for j in range(-5, 5): verts.append(DelT.Vertex(Point(i, j, 1))) self.assertEqual(sorted(verts), sorted(verts[::-1])) # consistency self.assertEqual(sorted(verts), sorted(verts)) self.assertLess(sorted(verts)[0], sorted(verts)[1]) self.assertNotEqual(verts[0], verts[1]) self.assertEqual(verts[0], verts[0])
def test_point_equal(self): """Tests if comparison of points for equality works""" self.assertTrue(Point(0, -9, 11.2) == Point(0, -9, 11.2)) self.assertFalse(Point(0, -9, 1600002) == Point(0, -8, 1600002)) # Different location self.assertFalse(Point(1, 4) == Point(1, 4, 5)) # Drew's tests: self.assertFalse(self.a == self.b) self.assertTrue(self.b == self.b) self.assertTrue(Point(1, 2, 3) == Point(1, 2, 3)) self.assertFalse(self.b == self.c) self.assertFalse(self.b == (1, 2))
def test_incircle_euclidean(self): """Test the incircle predicate in the plane.""" a = Point(1, 0) b = Point(0, 1) c = Point(-1, 0) d = Point(0, 0) self.assertTrue(incircle(a, b, c, d, homogeneous=False) == 1) self.assertTrue(incircle(a, b, d, c, homogeneous=False) == -1) self.assertTrue(incircle(a, b, c, c, homogeneous=False) == 0) r2far_east = Point(50, -0.5) # circle of radius 0... ought to be 0 (co-circular) self.assertEqual(incircle(self.r2east, self.r2east, self.r2east, self.r2east, homogeneous=False), 0) # The origin is in fact inside the (counterclockwise) unit circle self.assertEqual(incircle(self.r2east, self.r2north, self.r2west, self.r2orig, homogeneous=False), 1) # SHOULD depend on orientation of circle, so we can # have stuff like inside-out circles self.assertNotEqual(incircle(self.r2east, self.r2west, self.r2north, self.r2orig, homogeneous=False), incircle(self.r2west, self.r2east, self.r2north, self.r2orig, homogeneous=False)) self.assertNotEqual(incircle(self.r2east, self.r2north, self.r2west, self.r2orig, homogeneous=False), incircle(self.r2north, self.r2east, self.r2west, self.r2orig, homogeneous=False)) # Finitely faraway pt not in (counterclockwise) unit circle self.assertEqual(incircle(self.r2north, self.r2west, self.r2east, r2far_east, homogeneous=False), -1) # Finitely faraway pt is in the clockwise (inside-out) unit circle self.assertEqual(incircle(self.r2west, self.r2north, self.r2east, r2far_east, homogeneous=False), 1)
def test_easy_peasy_case(self): """Test with one point and see if the structure makes sense.""" point = Point(-3, 2, 1) deltri = DelT([point]) self.assertEqual(len(deltri.faces), 3) for face in deltri.faces: self.assertIn(point, face.points()) for hafacet in face.half_facets.values(): self.assertNotIn(hafacet.opposite, hafacet.points()) null_twin_count = 0 for face in deltri.faces: self.assertEqual(len(face.vertices), 3) for halffacet in face.half_facets.values(): if halffacet.twin is None: null_twin_count += 1 else: self.assertIs(halffacet.twin.twin, halffacet) self.assertEqual(null_twin_count, 3) self.assertTrue(deltri.test_is_delaunay())
def test_convex_hull_bug(self): """Eliminate bugs where the the convex hull becomes concave.""" # This case is prohibitively big to test properly # points = [Point(*coords) for coords in [ # (248, 508, 1), (709, 346, 1), (820, 535, 1), (427, 274, 1), # (671, 220, 1), (927, 342, 1), (612, 627, 1), (762, 633, 1), # (161, 238, 1), (71, 102, 1), (185, 25, 1), (233, 6, 1)]] # del_tri = DelT(points, homogeneous=True, randomize=False) # self.assertTrue(del_tri.test_is_delaunay()) # A nice clean 4 points that caused a bug. points = [ Point(*coords) for coords in [(582, 245, 1), (649, 400, 1), (854, 279, 1), (411, 176, 1)] ] del_tri = DelT(points, homogeneous=True, randomize=False) self.assertEqual(len(del_tri.face_point_sets()), 3)
def test_3d_case(self): fn = os.path.join(os.path.dirname(__file__), 'data/points.csv') f = open(fn) points = csv.reader(f) points = list(points) points = [[float(y) for y in x] for x in points] point_array = [Point(*point) for point in points] del_tri = DelT(point_array, homogeneous=False, randomize=False) self.assertTrue(del_tri.test_is_delaunay()) face_sets = set([ frozenset(face) for face in del_tri.face_point_sets(homogeneous=False) ]) fn = os.path.join(os.path.dirname(__file__), 'data/dt.csv') with open(fn, 'r') as f: triangles = list(csv.reader(f)) triangles = [[int(y) for y in x] for x in triangles] expected_face_sets = set([ frozenset([point_array[y - 1] for y in x]) for x in triangles ]) for face_set in face_sets: self.assertEqual(len(face_set), 4) self.assertEqual(face_sets, expected_face_sets)
def test_2d_case(self): """Test the output for a 2D case transfered from a notebook""" # First just make sure face equality works like I hope: self.assertEqual(set(frozenset([Point(0, 3.7)])), set(frozenset([Point(0, 3.7)]))) del_tri = DelT([ Point(-0.6, 3.2), Point(3.2, 2.1), Point(-2, 0), Point(1, -0.2), Point(3.6, -0.3), Point(-1.4, -2.1), Point(2.5, -1.7) ], homogeneous=False, randomize=False) self.assertTrue(del_tri.test_is_delaunay()) face_sets = set([ frozenset(face) for face in del_tri.face_point_sets(homogeneous=False) ]) expected_face_sets = set([ frozenset([Point(-2, 0), Point(-0.6, 3.2), Point(1, -0.2)]), frozenset([Point(3.2, 2.1), Point(-0.6, 3.2), Point(1, -0.2)]), frozenset([Point(3.2, 2.1), Point(3.6, -0.3), Point(1, -0.2)]), frozenset([Point(2.5, -1.7), Point(3.6, -0.3), Point(1, -0.2)]), frozenset([Point(2.5, -1.7), Point(-1.4, -2.1), Point(1, -0.2)]), frozenset([Point(-1.4, -2.1), Point(-2, 0), Point(1, -0.2)]) ]) # Note that equality of faces works exactly like you'd want. The test # even nicely tells you the differences between the sets, if it fails. for face_set in face_sets: self.assertEqual(len(face_set), 3) # triangles have 3 vertices self.assertEqual(face_sets, expected_face_sets)
def testCircumCenter(self): """Tests for the circumcenter utility""" # Make sure the unit circle is centered at the origin center1 = circumcenter(Point(1, 0), Point(0, 1), Point(0, -1), homogeneous=False) self.assertIsInstance(center1, Point) self.assertEqual(center1, Point(0, 0)) # Do the same but with the unit sphere in R^3 center2 = circumcenter(Point(1, 0, 0), Point(0, 1, 0), Point(0, -1, 0), Point(0, 0, 1), homogeneous=False) self.assertIsInstance(center2, Point) self.assertEqual(center2, Point(0, 0, 0)) # Make sure it isn't just returning zero all the time center3 = circumcenter(Point(1, 2), Point(2, 1), Point(1, 0), homogeneous=False) self.assertEqual(center3, Point(1.0, 1.0)) # Now let's see how it deals with homogeneous coordinates # Now make sure homogeneous coordinates are properly ignored # if they are all 1. (But the point returned should be # of the same dimension as the input.) self.assertEqual( circumcenter(Point(2, 3, 1), Point(3, 2, 1), Point(2, 1, 1)), Point(2, 2, 1))
def test_incircle_homogeneous(self): """Tests incircle on points with homogeneous coordinates (representing points in R^d but with a boundary) """ far_east_finite = Point(50, 0, 1) far_east_infinite = Point(1, 0, 0) # Counterclockwise circle around origin contains origin: self.assertEqual(incircle(self.homo_east, self.homo_north, self.homo_south, self.homo_orig), 1) # But it shouldn't contain any faraway point: self.assertEqual(incircle(self.homo_east, self.homo_north, self.homo_south, far_east_finite), -1) self.assertEqual(incircle(self.homo_east, self.homo_north, self.homo_south, far_east_infinite), -1) # And of course, another point on the unit circle should be cocircular: self.assertEqual(incircle(self.homo_east, self.homo_north, self.homo_south, self.homo_west), 0) # Clockwise circle around origin does not contain origin: self.assertEqual(incircle(self.homo_north, self.homo_east, self.homo_south, self.homo_orig), -1) # But it SHOULD contain faraway points: self.assertEqual(incircle(self.homo_north, self.homo_east, self.homo_south, far_east_finite), 1) self.assertEqual(incircle(self.homo_north, self.homo_east, self.homo_south, far_east_infinite), 1) # Cocircular stuff should still be cocircular: self.assertEqual(incircle(self.homo_north, self.homo_east, self.homo_south, self.homo_west), 0) # Check for subtle arithmetic errors: self.assertEqual(incircle(Point(0, -10, 1), Point(0, 0, 1), Point(-0.001, 10, 1), Point(-0.0005, 10, 1)), -1) # Counterclockwise infinite triangle contains everything inf_triangle = [Point(1, 0, 0), Point(-1, 1, 0), Point(-1, -1, 0)] self.assertEqual(incircle(*inf_triangle, Point(12, -14, 1)), 1) self.assertEqual(incircle(*inf_triangle, Point(-1, 1, 1)), 1) # Clockwise infinite triangle contains nothing self.assertEqual(incircle(*inf_triangle[::-1], Point(12, -14, 1)), -1) self.assertEqual(incircle(*inf_triangle[::-1], Point(-1, 1, 1)), -1) # Tricky cases: self.assertEqual(incircle( Point(-1, -1, 0), Point(-3, 2, 1), Point(1, 0, 0), Point(0, 1, 0)), 1) self.assertEqual(incircle( Point(-3, 2, 1), Point(-1, -1, 0), Point(1, 0, 0), Point(0, 1, 0)), -1) # The following tests are based on pencil-and-paper drawings # as well as hours spent debugging the DelaunayTriangulation. self.assertEqual(incircle( Point(1, 0, 0), Point(-0.6, 3.2, 1), Point(3.2, 2.1, 1), Point(-2, 0, 1)), -1) self.assertEqual(incircle( Point(-2, 0, 1), Point(-0.6, 3.2, 1), Point(0, 1, 0), Point(1, 0, 0)), -1)
def setUp(self): """Make some objects that are useful for most tests.""" self.a = Point(0, 0) self.b = Point(1, 2) self.c = Point(1, 2, 3)
def test_locally_delaunay(self): """Make sure that the locally delaunay test works.""" def quick_delaunay_test(*points, expectation=True): """Tests that the faces defined by points[:-1] and points[1:] share an edge that is locally delaunay iff we expect it to be so. """ vertices = [DelT.Vertex(point) for point in points] face_1 = DelT.Face(vertices[:-1]) face_2 = DelT.Face(vertices[1:]) facet_1 = face_1.half_facets[vertices[0]] facet_2 = face_2.half_facets[vertices[-1]] facet_1.twin = facet_2 facet_2.twin = facet_1 self.assertEqual(facet_1.lineside(facet_1.opposite.point), 1) self.assertEqual(facet_1.lineside(facet_1.opposite.point), 1) self.assertEqual(facet_1.locally_delaunay(), expectation) self.assertEqual(facet_1.locally_delaunay(), facet_2.locally_delaunay()) # Test for one dimension first. quick_delaunay_test(Point(-1, 1), Point(2, 1), Point(3, 1), expectation=True) # points_1 = [Point(-1, 1), Point(2, 1), Point(3, 1)] # vertices_1 = [DelT.Vertex(point) for point in points_1] # half_facet_1 = DelT.HalfFacet(vertices_1[0], vertices_1[1:2], # None) # Basic cases in 2 dimensions quick_delaunay_test(Point(0, 2, 1), Point(-1, 0, 1), Point(1, 0, 1), Point(0, -1, 1), expectation=True) quick_delaunay_test(Point(0, 2, 1), Point(-1, 0, 1), Point(1, 0, 1), Point(0, -0.3, 1), expectation=False) # Similar basic 3D cases unit_circle_pts_3d = [ Point(0, 0, -1, 1), Point(0, 1, 0, 1), Point(0, -1, 0, 1), Point(1, 0, 0, 1) ] quick_delaunay_test(*unit_circle_pts_3d, Point(0, 0, 1.5, 1), expectation=True) quick_delaunay_test(*unit_circle_pts_3d, Point(0, 0, 0.5, 1), expectation=False) # Cases with infinite points in the plane: quick_delaunay_test(Point(0, 1, 0), Point(0.5, -400, 1), Point(0, 0, 1), Point(-1, -1, 0), expectation=True) quick_delaunay_test(Point(-2, 0, 1), Point(-0.6, 3.2, 1), Point(3.2, 2.1, 1), Point(1, 0, 0), expectation=True)
def test_length(self): """Test to see if length of a point makes sense""" self.assertTrue(len(self.c) == 3) self.assertTrue(len(Point(1, 2, 3, 4)) == 4) self.assertFalse(len(self.b) == 3)
def test_subtraction(self): """Test point subtraction""" self.assertIsInstance(self.b - self.a, Vector) self.assertTrue(self.b - self.b == Vector(0, 0)) self.assertTrue(self.b - self.a == Vector(1, 2)) self.assertFalse(self.b - self.b == Point(0, 0))
def test_ccw_homogeneous(self): """Tests ccw with extended homogeneous coordinates""" # One dimensional case: # Basic, hair-not-on-fire requirement self.assertNotEqual(ccw(Point(0, 1), Point(1, 1)), 0) self.assertEqual(ccw(Point(0, 1), Point(1, 1)), ccw(Point(0), Point(1), homogeneous=False)) # With one homogeneous coordinate self.assertEqual(ccw(Point(0, 1), Point(1, 1)), ccw(Point(-1, 0), Point(2, 1))) # With two homogeneous coordinates self.assertEqual(ccw(Point(0, 1), Point(1, 1)), ccw(Point(-10, 0), Point(5, 0))) # Make sure simple stuff works # Should be counterclockwise: self.assertEqual(ccw(self.homo_north, self.homo_south, self.homo_east), 1) # Should be colinear: self.assertEqual(ccw(Point(1, 0, 1), Point(0, 0, 1), Point(-1, 0, 1)), 0) # Should be clockwise: self.assertEqual(ccw(self.homo_north, self.homo_east, self.homo_south), -1) # Now try some weird stuff # Tests involving one infinitely distance point: self.assertEqual(ccw(Point(1, 0, 1), Point(0, 0, 1), Point(0, 1, 0)), -1) # Tests involving two infinitely distance points: self.assertEqual(ccw(Point(1, 0, 0), Point(0, 0, 1), Point(0, 1, 0)), -1) self.assertEqual(ccw(Point(0, 1, 0), Point(0, 0, 1), Point(1, 0, 0)), 1) # Test with three points on the "boundary of the plane" self.assertEqual(ccw(Point(0, 1, 0), Point(-1, 0, 0), Point(0, -1, 0)), 1) self.assertEqual(ccw(Point(0, 1, 0), Point(1, 0, 0), Point(0, -1, 0)), -1) # Same but with weirder points self.assertEqual(ccw(Point(1.8, 19, 0), Point(309.7, 1, 0), Point(-0.05, -10, 0)), -1) # ANY finite point must satisfy this: queries = [Point(0, 0, 1), Point(1232, 4, 1), Point(-320, -0.0, 1), Point(-1, -1, 1), Point(1, 0, 1), Point(0, 1, 1)] for query in queries: self.assertEqual(ccw(Point(0, 1, 0), Point(-1, -1, 0), query), 1) self.assertEqual(ccw(Point(1, 0, 0), Point(0, 1, 0), query), 1)
class PointTestCase(unittest.TestCase): """Unit tests for the Point class.""" def setUp(self): """Make some objects that are useful for most tests.""" self.a = Point(0, 0) self.b = Point(1, 2) self.c = Point(1, 2, 3) def test_point_equal(self): """Tests if comparison of points for equality works""" self.assertTrue(Point(0, -9, 11.2) == Point(0, -9, 11.2)) self.assertFalse(Point(0, -9, 1600002) == Point(0, -8, 1600002)) # Different location self.assertFalse(Point(1, 4) == Point(1, 4, 5)) # Drew's tests: self.assertFalse(self.a == self.b) self.assertTrue(self.b == self.b) self.assertTrue(Point(1, 2, 3) == Point(1, 2, 3)) self.assertFalse(self.b == self.c) self.assertFalse(self.b == (1, 2)) def test_misc_niceties(self): """I don't want the empty point to be a thing. You may disagree.""" with self.assertRaises(ValueError): Point() # Try to make an empty point. # Make sure that we can evaluate a point to True self.assertTrue(self.a) def test_lift(self): """Make sure lifting works nicely.""" # Define a function to use for testing def f(x): return x[0] * 2 self.assertTrue(self.b.lift(f) == Point(1, 2, 2)) self.assertFalse(self.c.lift(f) == Point(1, 2, 3, 4)) self.assertFalse(self.c.lift(f) == Point(1, 2, 3)) # Make sure that lifting a Point returns a Point self.assertIsInstance(self.b.lift(f), Point) def test_length(self): """Test to see if length of a point makes sense""" self.assertTrue(len(self.c) == 3) self.assertTrue(len(Point(1, 2, 3, 4)) == 4) self.assertFalse(len(self.b) == 3) def test_indexing(self): """Make sure that we can access elements of a point by index""" self.assertTrue(self.a[0] == 0) self.assertTrue(self.c[2] == 3) self.assertFalse(self.b[-1] == 10) with self.assertRaises(Exception): # I want a warning when I accidentally try to set values: self.b[-1] = 10 self.assertIsInstance(self.a[:-1], Point) def test_subtraction(self): """Test point subtraction""" self.assertIsInstance(self.b - self.a, Vector) self.assertTrue(self.b - self.b == Vector(0, 0)) self.assertTrue(self.b - self.a == Vector(1, 2)) self.assertFalse(self.b - self.b == Point(0, 0)) def test_to_vector(self): """Test turning points into vectors""" self.assertEqual(self.c.to_vector(), Vector(1, 2, 3)) self.assertEqual(self.a.to_vector(), Vector(0, 0)) self.assertEqual(self.b.to_vector(), Vector(1, 2)) self.assertNotEqual(self.b.to_vector(), Vector(1, 2, 0)) def test_hashing(self): """Make sure point hashing works and does not cause collisions""" # Add 400 points' hashes to a set and make sure 400 things are in the # set some_hashes = set() for x in range(-10, 10): for y in range(-10, 10): some_hashes.add(hash(Point(x, y, 1))) self.assertEqual(len(some_hashes), 400) self.assertEqual(hash(Point(0, 1, 2)), hash(Point(0, 1, 2)))