def test_mapoverlay1(self): M1 = PlanarMap(Segment(0, 1, 2, 1)) M2 = PlanarMap(Segment(1, 0, 1, 2)) M3 = M1.map_overlay(M2) self.assertEqual(M3.v(), 5) self.assertEqual(M3.e(), 4) self.assertEqual(M3.f(), 1)
def setUp(self): self.M = PlanarMap() A, B, C, D = Point(0, 1), Point(1, 1), Point(0, 0), Point(1, 0) self.M.add_first_edge(Segment(A, B)) self.M.add_leaf(Segment(A, C)) self.M.add_leaf(Segment(B, D)) self.M.add_chord(Segment(C, B))
def test_itersegments_oriented(self): r1 = Rectangle(0, 0, 5, 6) L = list(r1.itersegments_oriented()) self.assertTrue(Segment(0, 0, 0, 6) in L) self.assertTrue(Segment(0, 6, 5, 6) in L) self.assertTrue(Segment(5, 6, 5, 0) in L) self.assertTrue(Segment(5, 0, 0, 0) in L)
def test_add_first_edge(self): M1 = PlanarMap() A, B, C, D = Point(0, 1), Point(1, 1), Point(0, 0), Point(1, 0) # not segment self.assertRaises(AssertionError, M1.add_first_edge, Edge(B, D)) M1.add_first_edge(Segment(A, B)) # second segment self.assertRaises(AssertionError, M1.add_first_edge, Segment(B, D))
def test_intersect(self): self.assertTrue(self.segment1.intersect(self.segment2)) self.assertTrue(self.segment1.intersect(Segment(1, -1, 1, 1))) # -|- self.assertTrue(self.segment1.intersect(Segment(1, 0, 3, 0))) # zachodza self.assertTrue(self.segment1.intersect(Segment(-1, 0, 3, 0))) # 1 w 2 self.assertFalse(self.segment1.intersect(Segment(1, 1, 3, 3))) # / - self.assertFalse(self.segment1.intersect(Segment(3, -1, 3, 1))) # - |
def test_contains(self): self.assertTrue(Point(1, 1) in self.r1) self.assertFalse(Point(1, 7) in self.r1) self.assertFalse(Point(7, 1) in self.r1) self.assertRaises(ValueError, Rectangle.__contains__, self.r1, 1) # segment in rectangle self.assertTrue(Segment(1, 1, 2, 2) in self.r1) self.assertFalse(Segment(1, 1, 7, 7) in self.r1)
def divide_edge(self, edge, node): """Divide edge at node.""" assert node in edge # for segment only assert self.has_edge(edge) edge18 = Segment(edge.source, node) edge28 = Segment(edge.target, node) # Aktualizacja scian. Czasem face1 == face2. # Liczba scian sie nie zmieni. face1 = self.edge2face[edge] face2 = self.edge2face[~edge] self.edge2face[edge18] = face1 self.edge2face[~edge28] = face1 self.edge2face[edge28] = face2 self.edge2face[~edge18] = face2 self.face2edge[face1] = edge18 self.face2edge[face2] = edge28 # Aktualizacja grafu abstrakcyjnego. self.del_edge(edge) self.add_edge(edge18) self.add_edge(edge28) if self.degree(edge.source) == 1 and self.degree(edge.target) == 1: #print ( "case: single edge divided" ) # face2edge[0] bedzie zawieralo edge lub ~edge, trzeba naprawic. # Aktualizacja grafu planarnego. self._update_del(edge) self._update1(edge18) self._update1(edge28) self._update3(~edge28, ~edge18, ~edge28) elif self.degree(edge.target) == 1: #print ( "case: degree(edge.target) == 1" ) edge13 = self.edge_next[edge] edge14 = self.edge_prev[edge] # Aktualizacja grafu planarnego. self._update_del(edge) self._update1(edge28) self._update3(~edge28, ~edge18, ~edge28) self._update3(edge14, edge18, edge13) elif self.degree(edge.source) == 1: #print ( "case: degree(edge.source) == 1" ) edge25 = self.edge_next[~edge] edge26 = self.edge_prev[~edge] # Aktualizacja grafu planarnego. self._update_del(edge) self._update1(edge18) self._update3(~edge28, ~edge18, ~edge28) self._update3(edge26, edge28, edge25) else: #print ( "case: both ends connected" ) edge13 = self.edge_next[edge] edge14 = self.edge_prev[edge] edge25 = self.edge_next[~edge] edge26 = self.edge_prev[~edge] # Aktualizacja grafu planarnego. self._update_del(edge) self._update3(~edge28, ~edge18, ~edge28) self._update3(edge14, edge18, edge13) self._update3(edge26, edge28, edge25)
def make_segment_list(n): """Prepare a segment list (ladder).""" # Intersection list (n-1 points): # [Point(3*1+2, 3*i+2) for i in range(n-1)] segment_list = [] for i in range(n-1): segment_list.append(Segment(1+3*i, 3+3*i, 3+3*i, 1+3*i)) segment_list.append(Segment(0, 0, 3*n+1, 3*n+1)) return segment_list
def setUp(self): segment1 = Segment(0, 0, 4, 4) segment2 = Segment(1, 3, 3, 1) self.event1 = Event(segment1.pt1, Event.LEFT, segment1) self.event2 = Event(segment1.pt2, Event.RIGHT, segment1) self.event3 = Event(Point(2, 2), Event.CROSSING, segment2, segment1) segment3 = Segment(0, 0, 0, 1) segment4 = Segment(0, 0, 1, 0) self.event4 = Event(segment3.pt1, Event.VERTICAL, segment3) self.event5 = Event(segment4.pt1, Event.HORIZONTAL, segment4)
def itersegments(self): """Generate all segments on demand (segment.pt1 < segment.pt2).""" n = len(self.point_list) for i in xrange(n): pt1 = self.point_list[i] pt2 = self.point_list[(i + 1) % n] if pt1 < pt2: yield Segment(pt1, pt2) else: yield Segment(pt2, pt1)
def test_divide_edge(self): M1 = PlanarMap() A, B, C, D = Point(0, 2), Point(2, 2), Point(0, 0), Point(2, 0) AB = Segment(A, B) M1.add_first_edge(AB) #M1.divide_edge(AB, Point(1, 2)) M1.divide_edge(Segment(A, B), Point(1, 2)) # it works self.assertEqual(M1.v(), 3) self.assertEqual(M1.e(), 2) self.assertEqual(M1.f(), 1)
def legalize(self, point, segment): #print ( "legalize {} {}".format(point, segment) ) # Trzeba znalezc trojkaty sasiadujace z krawedzia. tlist = self.tc.search(segment.center()) if len(tlist) == 1: # przypadek (i) de Berga # Nie przekrecamy krawedzi duzego trojkata, jest legalna. #print ( "big triangle segment" ) assert segment.pt1 in self.big_nodes and segment.pt2 in self.big_nodes return #print ( "tlist {}".format(tlist) ) assert len(tlist) == 2 t1 = tlist.pop() t2 = tlist.pop() if point in t2: # chcemy point in t1 t1, t2 = t2, t1 pt3 = t2.third_node(segment.pt1, segment.pt2) illegal = t1.in_circumcircle(pt3) if pt3 in self.big_nodes: #print ( "{} in big_nodes".format(pt3) ) # Trzeba sprawdzic, czy koniec krawedzi nie jest z big triangle. if segment.pt1 in self.big_nodes: # przypadek (iv) de Berga # Dokladnie dwa indeksy sa ujemne, jeden z krawedzi. illegal = False if segment.pt1 < pt3 else True #print ( "illegal 2 {}".format(illegal) ) elif segment.pt2 in self.big_nodes: # przypadek (iv) de Berga # Dokladnie dwa indeksy sa ujemne, jeden z krawedzi. illegal = False if segment.pt2 < pt3 else True #print ( "illegal 2 {}".format(illegal) ) else: # przypadek (iii) de Berga # Dokladnie jeden indeks ujemny (pt3), ale nie przy krawedzi. illegal = False # krawedz jest legalna #print ( "illegal 1 {}".format(illegal) ) else: # jeden koniec krawedzi moze byc z big triangle if segment.pt1 in self.big_nodes or segment.pt2 in self.big_nodes: # Przypadek (iii) de Berga, jeden indeks ujemny z krawedzi. illegal = True #print ( "illegal 1 {}".format(illegal) ) else: # cztery indeksy sa dodatnie, przypadek (ii) de Berga, pass # procedujemy normalnie if illegal: if orientation(point, segment.pt1, pt3) * orientation( point, segment.pt2, pt3) > 0: # Czworokat wklesly! Nie przekrecamy! #print ( "concave quadrilateral!" ) illegal = False if illegal: # jezeli krawedz nielegalna # Przekrecamy krawedz (edge flipping). #print ( "segment flip" ) self.tc.remove(t1) self.tc.remove(t2) self.tc.insert(Triangle(segment.pt1, point, pt3)) self.tc.insert(Triangle(segment.pt2, point, pt3)) self.legalize(point, Segment(segment.pt1, pt3)) self.legalize(point, Segment(segment.pt2, pt3))
def gnu(self, visible=False): """Return a string for Gnuplot.""" L = [] if visible: L.append(self.pt1.gnu()) L.append(self.pt2.gnu()) L.append(self.pt3.gnu()) L.append(Segment(self.pt1, self.pt2).gnu()) L.append(Segment(self.pt1, self.pt3).gnu()) L.append(Segment(self.pt2, self.pt3).gnu()) return "".join(L)
def test_add_leaf(self): M1 = PlanarMap() A, B, C, D = Point(0, 1), Point(1, 1), Point(0, 0), Point(1, 0) # empty map self.assertRaises(AssertionError, M1.add_leaf, Segment(B, D)) M1.add_first_edge(Segment(A, B)) M1.add_leaf(Segment(A, C)) # adding chord self.assertRaises(AssertionError, M1.add_leaf, Segment(B, C)) # adding the same leaf self.assertRaises(AssertionError, M1.add_leaf, Segment(A, C))
def test_contains(self): self.assertTrue(Point(2, 2) in self.t1) self.assertTrue(Point(4, 4) in self.t1) self.assertTrue(Point(3, 0) in self.t1) self.assertTrue(Point(0, 8) in self.t1) self.assertFalse(Point(6, 6) in self.t1) self.assertFalse(Point(7, 0) in self.t1) self.assertFalse(Point(0, 13) in self.t1) self.assertRaises(ValueError, Triangle.__contains__, self.t1, 1) # segment in tringle self.assertTrue(Segment(1, 1, 2, 2) in self.t1) self.assertFalse(Segment(1, 1, 6, 6) in self.t1)
def test_cmp(self): self.assertEqual(Segment(), Segment(0, 0, 1, 1)) self.assertTrue(self.segment1 == Segment(0, 0, 2, 0)) self.assertFalse(self.segment1 == self.segment2) self.assertTrue(self.segment1 != self.segment2) self.assertFalse(self.segment1 != Segment(0, 0, 2, 0)) self.assertTrue(self.segment2 < self.segment1) self.assertFalse(self.segment1 < self.segment2) self.assertTrue(self.segment2 <= self.segment1) self.assertFalse(self.segment1 <= self.segment2) self.assertTrue(self.segment3 > self.segment1) self.assertFalse(self.segment2 > self.segment3) self.assertTrue(self.segment3 >= self.segment1) self.assertFalse(self.segment2 >= self.segment1)
def is_simple(self): """Test if a polygon is simple in O(n^2) time (slow).""" n = len(self.point_list) for i in xrange(n): for j in xrange(2, n - 1): # krawedz niesasiednia k = (i + j) % n if k < i: # bylo sprawdzone continue segment1 = Segment(self.point_list[i], self.point_list[(i + 1) % n]) segment2 = Segment(self.point_list[k], self.point_list[(k + 1) % n]) if segment1.intersect(segment2): return False return True
def run(self): """Executable pseudocode.""" p_min = min(self.point_list, key=lambda p: (p.y, p.x)) # O(n) if p_min != self.point_list[0]: idx = self.point_list.index(p_min) # O(n) swap(self.point_list, 0, idx) m = 0 # index of the last point included to convex hull while True: i = (m + 1) % len(self.point_list) # new candidate for j in xrange(len(self.point_list)): if i == j or j == m: # the same point continue orient = oriented_area(self.point_list[m], self.point_list[i], self.point_list[j]) if orient < 0: i = j # new candidate to convex hull elif orient == 0: # degeneracy segment = Segment(self.point_list[m], self.point_list[j]) if self.point_list[i] in segment: i = j if i == 0: # doszlismy do p_min break else: m += 1 swap(self.point_list, m, i) self.convex_hull = self.point_list[0:m+1]
def test_exceptions(self): self.assertRaises(AssertionError, self.M.add_edge, Edge(Point(0, 0), Point(1, 0))) #self.assertRaises(ValueError, self.M.add_edge, Segment(Point(0, 0), Point(0, 0))) self.assertRaises(ValueError, self.M.add_edge, Segment(Point(1, 0), Point(1, 1))) self.assertRaises(AssertionError, self.M.add_node, "A")
def common_segment(self, other): """Find the common segment of two triangles.""" set1 = set([self.pt1, self.pt2, self.pt3]) set2 = set([other.pt1, other.pt2, other.pt3]) set3 = set1 & set2 assert len(set3) == 2 return Segment(set3.pop(), set3.pop())
def test_itersegments(self): L = list(self.polygon3.itersegments()) self.assertTrue(Segment(0, 0, 0, 2) in L) self.assertTrue(Segment(0, 2, 1, 2) in L) self.assertTrue(Segment(1, 1, 1, 2) in L) self.assertTrue(Segment(1, 1, 2, 1) in L) self.assertTrue(Segment(2, 0, 2, 1) in L) self.assertTrue(Segment(0, 0, 2, 0) in L)
def test_contains(self): self.assertTrue(Point(1, 0) in self.segment1) self.assertTrue(Point(1, 1) not in self.segment1) self.assertTrue(self.segment1.pt1 in self.segment1) self.assertTrue(self.segment1.pt2 in self.segment1) self.assertFalse(Point(6, 6) in self.segment1) self.assertFalse(Point(3, 0) in self.segment1) self.assertFalse(Point(-3, 0) in self.segment1) self.assertTrue(Point(0.5, 0.5) in self.segment2) self.assertTrue(Point(Fraction(1, 2), Fraction(1, 2)) in self.segment2) self.assertTrue(Point(Fraction(1, 3), Fraction(1, 3)) in self.segment2) self.assertRaises(ValueError, Segment.__contains__, self.segment1, 1) # segment1 in segment2 self.assertTrue(Segment(0, 0, 1, 0) in self.segment1) self.assertFalse(self.segment2 in self.segment1)
def itersegments_oriented(self): """Generate oriented segments (the face is on the right).""" if orientation(self.pt1, self.pt2, self.pt3) > 0: yield Segment(self.pt1, self.pt3) yield Segment(self.pt3, self.pt2) yield Segment(self.pt2, self.pt1) else: yield Segment(self.pt1, self.pt2) yield Segment(self.pt2, self.pt3) yield Segment(self.pt3, self.pt1)
def itersegments(self): """Generate all segments on demand (segment.pt1 < segment.pt2).""" if self.pt1 < self.pt2: yield Segment(self.pt1, self.pt2) else: yield Segment(self.pt2, self.pt1) if self.pt1 < self.pt3: yield Segment(self.pt1, self.pt3) else: yield Segment(self.pt3, self.pt1) if self.pt2 < self.pt3: yield Segment(self.pt2, self.pt3) else: yield Segment(self.pt3, self.pt2)
def add_to_triangulation(self, point): #print ( "add_to_triangulation {}".format(point) ) # Szukamy trojkata do ktorego wpada punkt. # Punkt moze byc na krawedzi, na granicy dwoch trojkatow. tlist = self.tc.search(point) # tlist moze zawierac jeden lub dwa trojkaty (wspolna krawedz). #print ( "tlist {}".format(tlist) ) if len(tlist) == 1: # punkt we wnetrzu trojkata # UWAGA Punkt moze trafic na krawedz big triangle, # a wtedy bedzie degeneracja. # Chyba ze zrobimy jeszcze wiekszy big triangle. t1 = tlist.pop() self.tc.remove(t1) self.tc.insert(Triangle(t1.pt1, t1.pt2, point)) self.tc.insert(Triangle(t1.pt2, t1.pt3, point)) self.tc.insert(Triangle(t1.pt3, t1.pt1, point)) self.legalize(point, Segment(t1.pt1, t1.pt2)) self.legalize(point, Segment(t1.pt2, t1.pt3)) self.legalize(point, Segment(t1.pt3, t1.pt1)) elif len(tlist) == 2: # punkt na krawedzi t1 = tlist.pop() t2 = tlist.pop() # Trzeba znalezc wspolna krawedz. segment = t1.common_segment(t2) assert point in segment # Konce wspolnej krawedzi. q1 = segment.pt1 q2 = segment.pt2 q3 = t1.third_node(q1, q2) q4 = t2.third_node(q1, q2) self.tc.remove(t1) self.tc.remove(t2) self.tc.insert(Triangle(q1, q3, point)) self.tc.insert(Triangle(q2, q3, point)) self.tc.insert(Triangle(q1, q4, point)) self.tc.insert(Triangle(q2, q4, point)) self.legalize(point, Segment(q1, q3)) self.legalize(point, Segment(q2, q3)) self.legalize(point, Segment(q1, q4)) self.legalize(point, Segment(q2, q4)) else: raise ValueError("more than 2 points in tlist")
def test_intersection_point(self): s1 = Segment(0, 0, 3, 3) s2 = Segment(1, 3, 3, 1) s3 = Segment(1, 0, 1, 2) #print(s1.intersection_point(s2)) self.assertEqual(s1.intersection_point(s2), Point(2, 2)) self.assertEqual(self.segment1.intersection_point(s2), None) self.assertEqual(s1.intersection_point(s3), Point(1, 1)) #print(s1.intersection_point(s3)) self.assertEqual(s1.intersection_point(Segment(0, 1, 2, 1)), Point(1, 1)) # Intersections at ends. self.assertEqual(self.segment1.intersection_point(self.segment2), Point(0, 0)) # L self.assertEqual(self.segment2.intersection_point(s3), Point(1, 1)) # T self.assertEqual(self.segment1.intersection_point(s3), Point(1, 0)) # T self.assertRaises(ValueError, Segment.intersection_point, self.segment2, s1) self.assertRaises(ValueError, Segment.intersection_point, self.segment1, Segment(1, 0, 3, 0)) self.assertRaises(ValueError, Segment.intersection_point, s3, Segment(1, 1, 1, 3))
def test_calculate(self): s1 = Segment(0, 0, 3, 3) self.assertEqual(s1.calculate_y(2), 2) self.assertEqual(s1.calculate_y(2.5), 2.5) self.assertEqual(s1.calculate_x(1), 1) self.assertEqual(s1.calculate_x(1.5), 1.5)
def test_invert(self): self.assertEqual(~self.segment1, Segment(2, 0, 0, 0)) self.assertEqual(~self.segment2, Segment(1, 1, 0, 0))
def test_perpendicular(self): self.assertTrue(self.segment1.perpendicular(Segment(1, 0, 1, 1))) self.assertTrue(self.segment2.perpendicular(Segment(1, 1, 2, 0))) self.assertFalse(self.segment1.perpendicular(self.segment2))
def test_move(self): self.assertEqual(self.segment1.move(1, 2), Segment(1, 2, 3, 2)) self.assertEqual(self.segment1.move(Point(1, 2)), Segment(1, 2, 3, 2)) self.assertRaises(ValueError, Segment.move, self.segment1, 1)