示例#1
0
 def run(self):
     for (p1, p2, p3) in itertools.combinations(self.point_list, 3):
         # Counterclockwise orientation of points.
         if orientation(p1, p2, p3) < 0:
             p2, p3 = p3, p2
         elif orientation(p1, p2, p3) == 0:  # collinear points
             continue
         triangle = Triangle(p1, p2, p3)
         if all(not triangle.in_circumcircle(p4) for p4 in self.point_list
                if p4 != p1 and p4 != p2 and p4 != p3):
             self.tc.insert(triangle)
示例#2
0
 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))
示例#3
0
def winding_number(polygon, point):
    """Return the winding number for a point."""
    wn = 0
    n = len(polygon.point_list)
    for i in xrange(n):
        a = polygon.point_list[i]
        b = polygon.point_list[(i + 1) % n]
        if a.y <= point.y:
            if b.y > point.y and orientation(a, b, point) > 0:
                wn += 1  # upward edge
        else:  # a.y > point.y
            if b.y <= point.y and orientation(a, b, point) < 0:
                wn -= 1  # downward edge
    return wn
示例#4
0
 def test_orientation(self):
     self.assertEqual(orientation(self.p00, self.p11, self.p22), 0)
     self.assertEqual(orientation(self.p00, self.p10, self.p22), 1)
     self.assertEqual(orientation(self.p00, self.p10, self.p11), 1)
     self.assertEqual(orientation(self.p10, self.p11, self.p01), 1)
     self.assertEqual(orientation(self.p00, self.p01, self.p22), -1)
     self.assertEqual(orientation(self.p00, self.p01, self.p11), -1)
     self.assertEqual(orientation(self.p01, self.p11, self.p10), -1)
示例#5
0
 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)
示例#6
0
 def iterpoints(self):
     """Generate all points on demand (counterclockwise)."""
     if orientation(self.pt1, self.pt2, self.pt3) > 0:
         yield self.pt1
         yield self.pt2
         yield self.pt3
     else:
         yield self.pt1
         yield self.pt3
         yield self.pt2
示例#7
0
 def in_circumcircle(self, point):
     """Check if point is inside triangle circumcircle.
     
     Formula is taken from
     https://en.wikipedia.org/wiki/Delaunay_triangulation#Algorithms
     """
     # Preparing parameters for calculating det for 3x3 matrix.
     a = self.pt1 - point
     b = self.pt2 - point
     c = self.pt3 - point
     det = (a*a) * b.cross(c) - (b*b) * a.cross(c) + (c*c) * a.cross(b)
     if orientation(self.pt1, self.pt2, self.pt3) > 0:
         return det > 0
     else:
         return det < 0
示例#8
0
 def is_convex(self, test_is_simple=True):
     """Test if a polygon is convex."""
     if test_is_simple:  # mozemy pominac test
         if not self.is_simple():
             # Nie mamy wersji dla wielokata zlozonego.
             raise ValueError("polygon is not simple")
     # Obliczamy orientacje.
     orient = self.orientation()
     # Sprawdzamy katy wewnetrzne.
     n = len(self.point_list)
     for i in xrange(n):
         pt1 = self.point_list[i]
         pt2 = self.point_list[(i + 1) % n]
         pt3 = self.point_list[(i + 2) % n]
         if orientation(pt1, pt2, pt3) * orient < 0:
             return False
     return True
示例#9
0
    def run(self):
        """Executable pseudocode."""
        # Find the lowest y-coordinate and leftmost point.
        p_min = min(self.point_list, key=lambda p: (p.y, p.x))

        # Sort points by polar angle with p_min, if several points have
        # the same polar angle then only keep the farthest.
        self.point_list.sort(
            key=lambda p: ((p - p_min).alpha(), (p - p_min) * (p - p_min)))

        # After sorting p_min will be at the beginning of point_list.
        for point in self.point_list:
            # Pop the last point from the stack if we turn clockwise
            # to reach this point.
            while len(self.convex_hull) > 1 and orientation(
                    self.convex_hull[-2], self.convex_hull[-1], point) <= 0:
                self.convex_hull.pop()
            self.convex_hull.append(point)
示例#10
0
 def run(self):
     """Executable pseudocode."""
     p_min = min(self.point_list, key=lambda p: (p.y, p.x))
     self.point_list.sort(
         key=lambda p: ((p - p_min).alpha(), (p - p_min) * (p - p_min)))
     m = 1  # index of the last point included to convex hull
     i = 2  # index of the next point to test
     while i < len(self.point_list):
         if orientation(self.point_list[m - 1], self.point_list[m],
                        self.point_list[i]) > 0:  # left turn
             # self.point_list[m] outside
             m += 1
             swap(self.point_list, m, i)
             i += 1
         else:  # self.point_list[m] inside or on the edge
             if m > 1:  # do not move i, because we need to test m
                 m -= 1
             else:  # we can move i, but still m=1
                 swap(self.point_list, m, i)
                 i += 1
     self.convex_hull = self.point_list[0:m + 1]
示例#11
0
 def __contains__(self, other):
     """Test if a point is in a triangle."""
     if isinstance(other, Point):
         # Chyba wystarczy sprawdzic, czy punkt jest po tej samej
         # stronie boku, co przeciwlegly wierzcholek.
         # Trojkat jest domkniety, zawiera swoj brzeg.
         # Tu mozna tez uzyc oriented_area(), bo chodzi o znak.
         a12 = orientation(self.pt1, self.pt2, self.pt3)
         b12 = orientation(self.pt1, self.pt2, other)
         a23 = orientation(self.pt2, self.pt3, self.pt1)
         b23 = orientation(self.pt2, self.pt3, other)
         a31 = orientation(self.pt3, self.pt1, self.pt2)
         b31 = orientation(self.pt3, self.pt1, other)
         return (a12 * b12 >= 0) and (a23 * b23 >= 0) and (a31 * b31 >= 0)
     elif isinstance(other, Segment):
         return other.pt1 in self and other.pt2 in self
     else:
         raise ValueError()
示例#12
0
 def orientation(self, test_is_simple=True):
     """Simple polygon orientation."""
     if test_is_simple:  # mozemy pominac test
         if not self.is_simple():
             # Nie mamy wersji dla wielokata zlozonego.
             raise ValueError("polygon is not simple")
     # First find rightmost lowest vertex of the polygon.
     n = len(self.point_list)
     rmin = 0
     xmin = self.point_list[0].x
     ymin = self.point_list[0].y
     for i in xrange(1, n):
         if self.point_list[i].y > ymin:
             continue
         if self.point_list[i].y == ymin:
             if self.point_list[i].x < xmin:
                 continue
         rmin = i
         xmin = self.point_list[i].x
         ymin = self.point_list[i].y
     # Test orientation at the rmin vertex.
     return orientation(self.point_list[(rmin + n - 1) % n],
                        self.point_list[rmin],
                        self.point_list[(rmin + 1) % n])
示例#13
0
 def orientation(self):
     """Triangle orientation."""
     return orientation(self.pt1, self.pt2, self.pt3)