def GeneratePolygonCycles(self, epsilon=1e-7):
     # Find and return, as a list of polygons, the cycles of the
     # graph that do not encompass any other part of the graph.
     # Here we ignore the direction of the edges of the graph.
     # If there is more than one connected component of the graph,
     # then this may not produce a desirable result.
     graph = self.Copy()
     for edge in self.edge_list:
         reverse_edge = (edge[1], edge[0], edge[2])
         i = graph.FindEdge(reverse_edge, ignore_direction=False)
         if i is None:
             graph.edge_list.append(reverse_edge)
     from math2d_polygon import Polygon
     polygon_list = []
     while len(graph.edge_list) > 0:
         edge = graph.edge_list[0]
         cycle_list, cycle_found = graph.FindCycleContainingEdge(
             edge, wind_ccw=True)
         if cycle_found:
             polygon = Polygon()
             polygon.vertex_list = [
                 graph.vertex_list[edge[0]] for edge in cycle_list
             ]
             if polygon.IsWoundCCW(epsilon):
                 polygon_list.append(polygon)
         for edge in cycle_list:
             i = graph.FindEdge(edge, False, False)
             del graph.edge_list[i]
     return polygon_list
Exemple #2
0
 def GeneratePolygon(self):
     from math2d_polygon import Polygon
     polygon = Polygon()
     polygon.vertex_list.append(Vector(self.min_point.x, self.min_point.y))
     polygon.vertex_list.append(Vector(self.max_point.x, self.min_point.y))
     polygon.vertex_list.append(Vector(self.max_point.x, self.max_point.y))
     polygon.vertex_list.append(Vector(self.min_point.x, self.max_point.y))
     return polygon
    def __init__(self):
        super().__init__()

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(4, 7.0 * math.sqrt(2.0))
        hole = Polygon()
        hole.MakeRegularPolygon(4, 5.0 * math.sqrt(2.0))
        cut_region.region.sub_region_list[0].hole_list.append(hole)
        transform = AffineTransform()
        transform.RigidBodyMotion(math.pi / 4.0, Vector(3.0, 3.0))
        cut_region.Transform(transform)
        self.cut_region_list.append(cut_region)

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(4, 7.0 * math.sqrt(2.0))
        hole = Polygon()
        hole.MakeRegularPolygon(4, 5.0 * math.sqrt(2.0))
        cut_region.region.sub_region_list[0].hole_list.append(hole)
        transform = AffineTransform()
        transform.RigidBodyMotion(math.pi / 4.0, Vector(-3.0, -3.0))
        cut_region.Transform(transform)
        self.cut_region_list.append(cut_region)

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(4, 3.0 * math.sqrt(2.0))
        transform = AffineTransform()
        transform.RigidBodyMotion(math.pi / 4.0, Vector(0.0, 0.0))
        cut_region.Transform(transform)
        self.cut_region_list.append(cut_region)
Exemple #4
0
    def __init__(self):
        super().__init__()

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(0.0, 0.0))
        sub_region.polygon.vertex_list.append(Vector(0.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(3.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(3.0, 0.0))
        cut_region = CutRegion()
        cut_region.region = Region()
        cut_region.region.sub_region_list.append(sub_region)
        self.cut_region_list.append(cut_region)

        cut_region = CutRegion()
        cut_region.region = Region()
        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(0.0, 0.0))
        sub_region.polygon.vertex_list.append(Vector(0.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, 0.0))
        cut_region.region.sub_region_list.append(sub_region)
        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(2.0, -2.0))
        sub_region.polygon.vertex_list.append(Vector(2.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(3.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(3.0, -2.0))
        cut_region.region.sub_region_list.append(sub_region)
        self.cut_region_list.append(cut_region)

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(1.0, -1.0))
        sub_region.polygon.vertex_list.append(Vector(1.0, 2.0))
        sub_region.polygon.vertex_list.append(Vector(-2.0, 2.0))
        sub_region.polygon.vertex_list.append(Vector(-2.0, -1.0))
        hole = Polygon()
        hole.vertex_list.append(Vector(0.0, 0.0))
        hole.vertex_list.append(Vector(0.0, 1.0))
        hole.vertex_list.append(Vector(-1.0, 1.0))
        hole.vertex_list.append(Vector(-1.0, 0.0))
        sub_region.hole_list.append(hole)
        cut_region = CutRegion()
        cut_region.region = Region()
        cut_region.region.sub_region_list.append(sub_region)
        self.cut_region_list.append(cut_region)

        transform = AffineTransform()
        transform.Rotation(Vector(0.0, 0.0), math.pi / 4.0)
        for cut_region in self.cut_region_list:
            cut_region.Transform(transform)
Exemple #5
0
    def __init__(self):
        super().__init__()

        # This shape is almost a swashtica (I'm trying to avoid that for obvious reason) and
        # therefore only has rotational symmetry.
        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(1.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(1.0, 4.0))
        sub_region.polygon.vertex_list.append(Vector(-2.0, 4.0))
        sub_region.polygon.vertex_list.append(Vector(-2.0, 2.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, 2.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(-4.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(-4.0, -2.0))
        sub_region.polygon.vertex_list.append(Vector(-2.0, -2.0))
        sub_region.polygon.vertex_list.append(Vector(-2.0, -1.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, -1.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, -4.0))
        sub_region.polygon.vertex_list.append(Vector(2.0, -4.0))
        sub_region.polygon.vertex_list.append(Vector(2.0, -2.0))
        sub_region.polygon.vertex_list.append(Vector(1.0, -2.0))
        sub_region.polygon.vertex_list.append(Vector(1.0, -1.0))
        sub_region.polygon.vertex_list.append(Vector(4.0, -1.0))
        sub_region.polygon.vertex_list.append(Vector(4.0, 2.0))
        sub_region.polygon.vertex_list.append(Vector(2.0, 2.0))
        sub_region.polygon.vertex_list.append(Vector(2.0, 1.0))
        cut_region = CutRegion()
        cut_region.region = Region()
        cut_region.region.sub_region_list.append(sub_region)
        self.cut_region_list.append(cut_region)

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(-3.0, 0.0))
        sub_region.polygon.vertex_list.append(Vector(-3.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(3.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(3.0, 0.0))
        hole = Polygon()
        hole.vertex_list.append(Vector(-1.0, -1.0))
        hole.vertex_list.append(Vector(-1.0, -2.0))
        hole.vertex_list.append(Vector(1.0, -2.0))
        hole.vertex_list.append(Vector(1.0, -1.0))
        sub_region.hole_list.append(hole)
        cut_region = CutRegion()
        cut_region.region = Region()
        cut_region.region.sub_region_list.append(sub_region)
        self.cut_region_list.append(cut_region)
Exemple #6
0
 def Transform(self, object):
     from math2d_polygon import Polygon
     from math2d_region import Region, SubRegion
     from math2d_aa_rect import AxisAlignedRectangle
     if isinstance(object, Vector):
         return self.linear_transform.Transform(object) + self.translation
     elif isinstance(object, AffineTransform):
         transform = AffineTransform()
         transform.linear_transform.x_axis = self.linear_transform.Transform(
             object.linear_transform.x_axis)
         transform.linear_transform.y_axis = self.linear_transform.Transform(
             object.linear_transform.y_axis)
         transform.translation = self.Transform(object.translation)
         return transform
     elif isinstance(object, LineSegment):
         return LineSegment(self.Transform(object.point_a),
                            self.Transform(object.point_b))
     elif isinstance(object, Polygon):
         polygon = Polygon()
         for vertex in object.vertex_list:
             polygon.vertex_list.append(self.Transform(vertex))
         return polygon
     elif isinstance(object, Region):
         region = Region()
         for sub_region in object.sub_region_list:
             region.sub_region_list.append(self.Transform(sub_region))
         return region
     elif isinstance(object, SubRegion):
         sub_region = SubRegion()
         sub_region.polygon = self.Transform(object.polygon)
         for hole in object.hole_list:
             sub_region.hole_list.append(self.Transform(hole))
         return sub_region
     elif isinstance(object, AxisAlignedRectangle):
         return AxisAlignedRectangle(
             min_point=self.Transform(object.min_point),
             max_point=self.Transform(object.max_point))
    def __init__(self):
        super().__init__()

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(5, 5.0)
        hole = Polygon()
        hole.MakeRegularPolygon(5, 4.0)
        cut_region.region.sub_region_list[0].hole_list.append(hole)
        self.cut_region_list.append(cut_region)

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(5, 3.0)
        hole = Polygon()
        hole.MakeRegularPolygon(5, 2.0)
        cut_region.region.sub_region_list[0].hole_list.append(hole)
        self.cut_region_list.append(cut_region)

        # This is almost like puzzle 4, but with a subtle difference.
        cut_region = CutRegion()
        cut_region.GenerateRectangle(5.0, 1.0)
        transform = AffineTransform()
        transform.translation = Vector(-3.0, 0.0)
        cut_region.Transform(transform)
        self.cut_region_list.append(cut_region)
Exemple #8
0
    def __init__(self):
        super().__init__()

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(5, 5.0)
        hole = Polygon()
        hole.MakeRegularPolygon(5, 4.0)
        cut_region.region.sub_region_list[0].hole_list.append(hole)
        self.cut_region_list.append(cut_region)

        cut_region = CutRegion()
        cut_region.GenerateRegularPolygon(5, 3.0)
        hole = Polygon()
        hole.MakeRegularPolygon(5, 2.0)
        cut_region.region.sub_region_list[0].hole_list.append(hole)
        self.cut_region_list.append(cut_region)

        cut_region = CutRegion()
        cut_region.GenerateRectangle(5.0, 1.0)
        transform = AffineTransform()
        transform.translation = Vector(3.5 * math.cos(math.pi * 4.0 / 5.0),
                                       0.0)
        cut_region.Transform(transform)
        self.cut_region_list.append(cut_region)
    def GenerateLineMesh(self, thickness=0.5, epsilon=1e-7):
        half_thickness = thickness / 2.0
        from math2d_tri_mesh import TriangleMesh, Triangle
        from math2d_polygon import Polygon
        from math2d_affine_transform import AffineTransform
        mesh = TriangleMesh()

        def SortKey(vector):
            angle = Vector(1.0, 0.0).SignedAngleBetween(vector)
            if angle < 0.0:
                angle += 2.0 * math.pi
            return angle

        polygon_list = []
        for i in range(len(self.vertex_list)):
            center = self.vertex_list[i]
            vector_list = []
            adj_list = self.FindAllAdjacencies(i,
                                               ignore_direction=True,
                                               vertices=True)
            for j in adj_list:
                vector_list.append(self.vertex_list[j] - center)
            vector_list.sort(key=SortKey)
            polygon = Polygon()
            for j in range(len(vector_list)):
                vector_a = vector_list[j]
                vector_b = vector_list[(j + 1) % len(vector_list)]
                angle = vector_a.SignedAngleBetween(vector_b)
                if angle < 0.0:
                    angle += 2.0 * math.pi
                if math.fabs(angle - math.pi) < epsilon or angle < math.pi:
                    affine_transform = AffineTransform()
                    affine_transform.translation = center
                    affine_transform.linear_transform.x_axis = vector_a.Normalized(
                    )
                    affine_transform.linear_transform.y_axis = affine_transform.linear_transform.x_axis.RotatedCCW90(
                    )
                    if math.fabs(angle - math.pi) < epsilon:
                        length = 0.0
                    else:
                        length = half_thickness / math.tan(angle / 2.0)
                    point = affine_transform * Vector(length, half_thickness)
                    polygon.vertex_list.append(point)
                else:
                    # Here we might create a rounded joint or something fancy, but this is good for now.
                    polygon.vertex_list.append(vector_a.Normalized(
                    ).RotatedCCW90().Scaled(half_thickness) + center)
                    polygon.vertex_list.append(vector_b.Normalized(
                    ).RotatedCW90().Scaled(half_thickness) + center)
            polygon.Tessellate()
            mesh.AddMesh(polygon.mesh)
            polygon_list.append(polygon)
        for edge in self.edge_list:
            center_a = self.vertex_list[edge[0]]
            center_b = self.vertex_list[edge[1]]
            line_segment = LineSegment(center_a, center_b)

            def FindEdgeSegment(polygon):
                for edge_segment in polygon.GenerateLineSegments():
                    point = edge_segment.IntersectWith(line_segment)
                    if point is not None:
                        return edge_segment
                else:
                    raise Exception('Failed to find line quad end.')

            polygon_a = polygon_list[edge[0]]
            polygon_b = polygon_list[edge[1]]
            edge_segment_a = FindEdgeSegment(polygon_a)
            edge_segment_b = FindEdgeSegment(polygon_b)
            triangle_a = Triangle(edge_segment_a.point_a,
                                  edge_segment_b.point_b,
                                  edge_segment_b.point_a)
            triangle_b = Triangle(edge_segment_a.point_a,
                                  edge_segment_b.point_a,
                                  edge_segment_a.point_b)
            area_a = triangle_a.Area()
            area_b = triangle_b.Area()
            if area_a < 0.0 or area_b < 0.0:
                raise Exception('Miscalculated line quad triangles.')
            mesh.AddTriangle(triangle_a)
            mesh.AddTriangle(triangle_b)
        return mesh
    def ApplyCuts(self, region):
        # Turn all the cuts into bi-directional borders.  Discard cuts that don't cut anything.
        region.Tessellate()
        while True:
            for i, edge in enumerate(self.edge_list):
                if edge[2] == PlanarGraphEdgeLabel.CUT:
                    break
            else:
                break
            del self.edge_list[i]
            edge_segment = self.EdgeSegment(edge)
            if region.ContainsPoint(edge_segment.Lerp(0.5)):
                self.edge_list.append(
                    (edge[0], edge[1], PlanarGraphEdgeLabel.REGION_BORDER))
                self.edge_list.append(
                    (edge[1], edge[0], PlanarGraphEdgeLabel.REGION_BORDER))

        # Now go read-off all the perimeter and hole polygons.
        from math2d_polygon import Polygon
        perimeter_list = []
        hole_list = []
        while True:
            for edge in self.edge_list:
                if edge[2] == PlanarGraphEdgeLabel.REGION_BORDER:
                    break
            else:
                break
            polygon = Polygon()
            cycle_list, cycle_found = self.FindCycleContainingEdge(edge, True)
            polygon.vertex_list = [
                self.vertex_list[edge[0]] for edge in cycle_list
            ]
            if polygon.IsWoundCCW():
                polygon.Tessellate()
                perimeter_list.append(polygon)
            else:
                cycle_list, cycle_found = self.FindCycleContainingEdge(
                    edge, False)
                polygon.vertex_list = [
                    self.vertex_list[edge[0]] for edge in cycle_list
                ]
                if polygon.IsWoundCW():
                    polygon.ReverseWinding()
                    hole_list.append(polygon)
                else:
                    raise Exception('Failed to process cycle containing edge.')
            for edge in cycle_list:
                i = self.FindEdge(edge, False, False)
                del self.edge_list[i]

        # Finally, merry all the holes to the appropriate perimeters.
        # TODO: This is a bit tricky.  A hole may lie inside a perimeter, but that doesn't mean it belongs to that perimeter,
        #       because it may lie inside a yet smaller perimeter that is contained in a hole of the other perimeter.  Make sure
        #       we assign holes to containing perimeters of the smallest area.  I think this may fix the problem.
        from math2d_region import Region, SubRegion
        region = Region()
        for perimeter in perimeter_list:
            sub_region = SubRegion(perimeter)
            new_hole_list = []
            for hole in hole_list:
                # I believe we need only test a single point on the hole.
                if perimeter.ContainsPoint(
                        hole.vertex_list[0]
                ) and not perimeter.ContainsPointOnBorder(hole.vertex_list[0]):
                    sub_region.hole_list.append(hole)
                else:
                    new_hole_list.append(hole)
            hole_list = new_hole_list
            region.sub_region_list.append(sub_region)
        if len(hole_list) > 0:
            raise Exception('Failed to marry %d holes to perimeters.' %
                            len(hole_list))

        return region
Exemple #11
0
    def __init__(self):
        super().__init__()

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(-5.0, -4.0))
        sub_region.polygon.vertex_list.append(Vector(4.0, -4.0))
        sub_region.polygon.vertex_list.append(Vector(4.0, 3.0))
        sub_region.polygon.vertex_list.append(Vector(-5.0, 3.0))

        hole = Polygon()
        hole.vertex_list.append(Vector(-4.0, -3.0))
        hole.vertex_list.append(Vector(3.0, -3.0))
        hole.vertex_list.append(Vector(3.0, -2.0))
        hole.vertex_list.append(Vector(-3.0, -2.0))
        hole.vertex_list.append(Vector(-3.0, 1.0))
        hole.vertex_list.append(Vector(3.0, 1.0))
        hole.vertex_list.append(Vector(3.0, 2.0))
        hole.vertex_list.append(Vector(-4.0, 2.0))
        sub_region.hole_list.append(hole)

        hole = Polygon()
        hole.vertex_list.append(Vector(-2.0, -1.0))
        hole.vertex_list.append(Vector(0.0, -1.0))
        hole.vertex_list.append(Vector(0.0, 0.0))
        hole.vertex_list.append(Vector(-2.0, 0.0))
        sub_region.hole_list.append(hole)

        hole = Polygon()
        hole.vertex_list.append(Vector(1.0, -1.0))
        hole.vertex_list.append(Vector(3.0, -1.0))
        hole.vertex_list.append(Vector(3.0, 0.0))
        hole.vertex_list.append(Vector(1.0, 0.0))
        sub_region.hole_list.append(hole)

        self.region = Region()
        self.region.sub_region_list.append(sub_region)

        self.cut_region = Region()

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(-1.0, -5.0))
        sub_region.polygon.vertex_list.append(Vector(5.0, -5.0))
        sub_region.polygon.vertex_list.append(Vector(5.0, 4.0))
        sub_region.polygon.vertex_list.append(Vector(-1.0, 4.0))
        self.cut_region.sub_region_list.append(sub_region)

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(-6.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(-3.0, 1.0))
        sub_region.polygon.vertex_list.append(Vector(-3.0, 4.0))
        sub_region.polygon.vertex_list.append(Vector(-6.0, 4.0))
        self.cut_region.sub_region_list.append(sub_region)

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(-6.0, -5.0))
        sub_region.polygon.vertex_list.append(Vector(-3.0, -5.0))
        sub_region.polygon.vertex_list.append(Vector(-3.0, -3.0))
        sub_region.polygon.vertex_list.append(Vector(-6.0, -3.0))
        self.cut_region.sub_region_list.append(sub_region)

        sub_region = SubRegion()
        sub_region.polygon.vertex_list.append(Vector(0.5, 0.5))
        sub_region.polygon.vertex_list.append(Vector(0.5, -1.5))
        sub_region.polygon.vertex_list.append(Vector(3.5, -1.5))
        sub_region.polygon.vertex_list.append(Vector(3.5, 0.5))
        self.cut_region.sub_region_list.append(sub_region)

        self.result_region = None
        self.polygon_list = []
Exemple #12
0
 def GenerateConvexHull(self):
     from math2d_line import Line
     from math2d_polygon import Polygon
     from math2d_triangle import Triangle
     found = False
     for i in range(len(self.point_list)):
         for j in range(len(self.point_list)):
             if j == i:
                 continue
             for k in range(len(self.point_list)):
                 if k == i or k == j:
                     continue
                 triangle = Triangle(self.point_list[i], self.point_list[j],
                                     self.point_list[k])
                 if triangle.Area() > 0.0:
                     found = True
                     break
             if found:
                 break
         if found:
             break
     if not found:
         raise Exception('Failed to find initial triangle.')
     polygon = Polygon()
     polygon.vertex_list = [
         triangle.vertex_a, triangle.vertex_b, triangle.vertex_c
     ]
     point_list = [point for point in self.point_list]
     random.seed(0)
     while True:
         new_point_list = []
         for point in point_list:
             if not polygon.ContainsPoint(point, assume_convex=True):
                 new_point_list.append(point)
         point_list = new_point_list
         if len(point_list) == 0:
             break
         # Perhaps randomly choosing a point will help us terminate quicker on average?
         point = random.choice(point_list)
         point_cloud = PointCloud()
         point_cloud.Add(polygon)
         j = None
         k = None
         for i in range(len(polygon.vertex_list)):
             vertex = polygon.vertex_list[i]
             line = Line()
             line.MakeForPoints(point, vertex)
             point_cloud_back, point_cloud_front, point_cloud_neither = point_cloud.Split(
                 line)
             if point_cloud_front.Size() == 0:
                 j = i
             if point_cloud_back.Size() == 0:
                 k = i
             if j is not None and k is not None and j != k:
                 break
         else:
             raise Exception(
                 'Failed to determine how to add point to convex hull.')
         new_vertex_list = [point]
         i = k
         while True:
             new_vertex_list.append(polygon.vertex_list[i])
             if i == j:
                 break
             i = (i + 1) % len(polygon.vertex_list)
         polygon.vertex_list = new_vertex_list
     return polygon