Пример #1
0
    def test_colour(self, make_args, blue):
        # Check that colour filtering works
        args = make_args("--all --color #0000FF")

        outlines = MultiLineString(args_to_outlines(args))
        expected = self.dereg(blue)
        assert not outlines.is_empty
        assert outlines.difference(expected).is_empty
Пример #2
0
    def test_exclude_regmarks(self, make_args, regmarks, red, green, blue):
        args = make_args("--all")

        outlines = MultiLineString(args_to_outlines(args))
        expected = cascaded_union([
            self.dereg(red),
            self.dereg(green),
            self.dereg(blue),
        ])
        assert not outlines.is_empty
        assert outlines.difference(expected).is_empty
Пример #3
0
def generate_pcb_bridges(dxf_modelspace, area, cutout_width, count_x, count_y):
    __generate_bridges(dxf_modelspace, area, count_x, count_y)

    frame_lines = MultiLineString(cutout_lines)

    for splitter in splitter_rectangles:
        frame_lines = frame_lines.difference(splitter)

    dilated = frame_lines.buffer(cutout_width / 2)

    for element in dilated:
        dxf_modelspace.add_lwpolyline(element.exterior.coords)
Пример #4
0
    def test_regmarks_included_when_not_used(self, make_args, regmarks, red,
                                             green, blue):
        args = make_args("--all --no-regmarks")

        outlines = MultiLineString(args_to_outlines(args))
        expected = cascaded_union([
            regmarks,
            red,
            green,
            blue,
        ])
        assert not outlines.is_empty
        assert outlines.difference(expected).is_empty
def hatchbox(rect, angle, spacing, hole=None):
    """
    returns a Shapely geometry (MULTILINESTRING, or more rarely,
    GEOMETRYCOLLECTION) for a simple hatched rectangle.

    args:
    rect - a Shapely geometry for the outer boundary of the hatch
           Likely most useful if it really is a rectangle

    angle - angle of hatch lines, conventional anticlockwise -ve

    spacing - spacing between hatch lines

    GEOMETRYCOLLECTION case occurs when a hatch line intersects with
    the corner of the clipping rectangle, which produces a point
    along with the usual lines.
    """

    (llx, lly, urx, ury) = rect.bounds
    centre_x = (urx + llx) / 2
    centre_y = (ury + lly) / 2
    diagonal_length = sqrt((urx - llx)**2 + (ury - lly)**2)
    number_of_lines = 2 + int(diagonal_length / spacing)
    hatch_length = spacing * (number_of_lines - 1)

    # build a square (of side hatch_length) horizontal lines
    # centred on centroid of the bounding box, 'spacing' units apart
    coords = []
    for i in range(number_of_lines):
        # alternate lines l2r and r2l to keep HP-7470A plotter happy ☺
        if i % 2:
            coords.extend([((centre_x - hatch_length / 2,
                             centre_y - hatch_length / 2 + i * spacing),
                            (centre_x + hatch_length / 2,
                             centre_y - hatch_length / 2 + i * spacing))])
        else:
            coords.extend([((centre_x + hatch_length / 2,
                             centre_y - hatch_length / 2 + i * spacing),
                            (centre_x - hatch_length / 2,
                             centre_y - hatch_length / 2 + i * spacing))])
    # turn array into Shapely object
    lines = MultiLineString(coords)
    # Rotate by angle around box centre
    lines = rotate(lines, angle, origin='centroid', use_radians=False)
    # return clipped array
    if holes is not None:
        x0, y0, dx, dy = windef.minmax_coords()
        rect = box(x0, y0, x0 + dx, y0 + dy)
        lines = lines.difference(rect)
    return rect.intersection(lines)
Пример #6
0
def generate_subpanel_bridges(dxf_outline_space, dxf_drill_space, area,
                              cutout_width, count_x, count_y):
    __generate_bridges(dxf_outline_space, area, count_x, count_y)

    frame_lines = MultiLineString(cutout_lines)

    generate_mouse_bites(area, dxf_drill_space, frame_lines)

    for splitter in splitter_rectangles:
        frame_lines = frame_lines.difference(splitter)

    # Merge all lines, so the endpoints are not where lines cross
    frame_lines = ops.linemerge(frame_lines)

    inset_lines = []
    for frame_line in frame_lines:
        line = frame_line.parallel_offset(2, 'left')

        # line2 = frame_line.parallel_offset(2, 'right')
        if frame_line.boundary and line.boundary:
            inset_line = LineString([frame_line.boundary[0], line.boundary[0]])
            inset_lines.append(inset_line)
            inset_line = LineString([frame_line.boundary[1], line.boundary[1]])
            inset_lines.append(inset_line)

        line = frame_line.parallel_offset(2, 'right')
        if frame_line.boundary and line.boundary:
            inset_line = LineString([frame_line.boundary[0], line.boundary[1]])
            inset_lines.append(inset_line)
            inset_line = LineString([frame_line.boundary[1], line.boundary[0]])
            inset_lines.append(inset_line)

        # frame_lines = frame_lines.union(inset_line)

    inset_lines = MultiLineString(inset_lines)
    dilated_insets = inset_lines.buffer(cutout_width / 3, join_style=1)

    # Remove outward bridges TODO: Needs better solution, this one is a quick hack TODO: Check if interior exterior
    #  of polygon would work: https://gis.stackexchange.com/questions/341604/creating-shapely-polygons-with-holes
    # dilated_insets = clean_outer_perimeter(area, dilated_insets)

    # Merge cutouts and insets
    dilated = frame_lines.buffer(cutout_width / 2, cap_style=2, join_style=2)
    dilated = dilated.union(dilated_insets)
    # Round the corners of insets
    dilated = dilated.buffer(0.8, join_style=1).buffer(-0.8, join_style=1)
    for element in dilated:
        dxf_outline_space.add_lwpolyline(element.exterior.coords)
Пример #7
0
    def test_no_over_cut(self, make_args, red, green, blue, extra_args):
        args = make_args("--all --fast-order --inside-first " + extra_args)
        green_shifted = MultiLineString([[
            (70, 85),
            (70, 15),
            (30, 15),
            (30, 85),
            (70, 85),
        ]])
        # Sanity check
        assert green_shifted.difference(green).is_empty

        outlines = MultiLineString(args_to_outlines(args))
        expected = MultiLineString(
            list(self.dereg(blue).geoms) + list(self.dereg(red).geoms) +
            list(self.dereg(green_shifted).geoms))
        assert outlines == expected
Пример #8
0
    def test_inside_first_and_optimised(self, make_args, red, green, blue):
        args = make_args("--all --no-over-cut")

        # Re-order points so definition starts with bottom-right corner (which
        # is nearest point to end of red line)
        green_shifted = MultiLineString([[
            (70, 85),
            (70, 15),
            (30, 15),
            (30, 85),
            (70, 85),
        ]])
        # Sanity check
        assert green_shifted.difference(green).is_empty

        outlines = MultiLineString(args_to_outlines(args))
        expected = MultiLineString(
            list(self.dereg(blue).geoms) + list(self.dereg(red).geoms) +
            list(self.dereg(green_shifted).geoms))
        assert outlines == expected
Пример #9
0
    def compute_partition(self,
                          num_iters: int,
                          delta: float,
                          make_snapshots: bool = False
                          ) -> Tuple[Optional[Dict], Optional[List]]:
        """
        Computes a Markov partition for the given dynamic system by tracing stable and unstable manifolds in
        the hyperbolic fixed point in parallel and checking for their points of intersection. This procedure
        is repeated num_iters times until the partition is sufficiently fine enough to be Markov. All in all,
        this function implements the described algorithm in chapter 4.2 of the master's thesis.

        Args:
            num_iters (int): number of repetitions for tracing branches until points of intersections
            delta (float): sufficiently small integration constant for approximating branches

        Returns:
            (dict): keys are branch identifiers with lists of points as values
            (list): list of points of intersections between branches
        """
        if self.dynamic_system.fixed_point is None:
            if self.dynamic_system.compute_fixed_point() is None:
                print(
                    f"Failed calculating a partition, since no fixed point found."
                )
                return None, None

        if not self.dynamic_system.is_fixed_point(
                self.dynamic_system.fixed_point):
            print(
                f"Failed calculating a partition, since calculated fixed point is not a real fixed point."
            )
            return None, None

        if not self.dynamic_system.fixed_point_is_hyperbolic():
            print(
                f"Failed calculating a partition, since fixed point is not a hyperbolic one."
            )
            return None, None

        branches = {
            "W_u1": [[self.dynamic_system.fixed_point]],
            "W_u2": [[self.dynamic_system.fixed_point]],
            "W_s1": [[self.dynamic_system.fixed_point]],
            "W_s2": [[self.dynamic_system.fixed_point]],
        }
        unstable_branches = ["W_u1", "W_u2"]
        stable_branches = ["W_s1", "W_s2"]
        approx_funcs = {
            "W_u1": (self.wt_u, True),
            "W_u2": (self.wt_u, False),
            "W_s1": (self.wt_s, True),
            "W_s2": (self.wt_s, False),
        }
        overall_intersection_points = []

        snapshot_path = "/ma_project/experimental/notebooks/results/partitions"

        for i in range(num_iters):
            print(f"ITERATION: {i+1}")
            stopped_branches = []
            trace_branches = list(branches.keys())
            while len(stopped_branches) < len(branches.keys()):
                trace_branches = [
                    branch for branch in trace_branches
                    if branch not in stopped_branches
                ]
                for branch_key in trace_branches:
                    last_wt = branches[branch_key][-1][-1]
                    approx_func, rev_dir = approx_funcs[branch_key]
                    new_wt = approx_func(last_wt,
                                         delta=delta,
                                         reverse_direction=rev_dir)

                    if not self.dynamic_system.identification_occurs(new_wt):
                        branches[branch_key][-1].append(new_wt)
                    else:
                        if len(branches[branch_key][-1]) == 1:
                            branches[branch_key][-1].append(
                                branches[branch_key][-1][0])

                        new_wt = new_wt % self.dynamic_system.m_id
                        branches[branch_key].append([new_wt, new_wt])

                for unstable_branch in unstable_branches:
                    for stable_branch in stable_branches:
                        if unstable_branch in stopped_branches and stable_branch in stopped_branches:
                            continue
                        intersection_points = MultiLineString(
                            branches[unstable_branch]).intersection(
                                MultiLineString(branches[stable_branch]))
                        intersection_points = intersection_points.difference(
                            Point(self.dynamic_system.fixed_point))
                        num_intersections = self.get_num_of_intersections(
                            intersection_points)

                        if num_intersections > i:
                            intersection_point = self.get_new_intersection_point(
                                np.array(intersection_points),
                                num_intersections,
                                np.array(overall_intersection_points))
                            if intersection_point is None:
                                continue

                            dist_unstable = self.euclidean_dist_over_torus(
                                np.array(intersection_point),
                                branches[unstable_branch][-1][-1])
                            dist_stable = self.euclidean_dist_over_torus(
                                np.array(intersection_point),
                                branches[stable_branch][-1][-1])

                            latter_branch = unstable_branch if dist_unstable < dist_stable else stable_branch
                            if latter_branch not in stopped_branches:
                                stopped_branches.append(latter_branch)
                                print(
                                    f"Stop {latter_branch} at {intersection_point}."
                                )
                                overall_intersection_points.append(
                                    intersection_point)
                                self.intersection_points = overall_intersection_points

                                if make_snapshots:
                                    self.plot_partition(
                                        branches=branches,
                                        file_path=
                                        f"{snapshot_path}/snapshot-{i}-{len(stopped_branches)}.png",
                                    )

            if make_snapshots:
                self.plot_partition(
                    branches=branches,
                    file_path=f"{snapshot_path}/snapshot-{i}-total.png")

        self.branches = branches
        self.intersection_points = overall_intersection_points
        return self.branches, self.intersection_points
Пример #10
0
    def draw(self, vsk: vsketch.Vsketch) -> None:
        print(os.getcwd())
        vsk.size("a6", landscape=False, center=False)
        vsk.scale(1)
        vsk.penWidth(self.pen_width)

        glyph_poly = load_glyph(self.font, self.glyph, self.face_index)

        # normalize glyph size
        bounds = glyph_poly.bounds
        scale_factor = min(
            (vsk.width - 2 * self.glyph_margin) / (bounds[2] - bounds[0]),
            (vsk.height - 2 * self.glyph_margin) / (bounds[3] - bounds[1]),
        )
        glyph_poly = scale(glyph_poly, scale_factor, scale_factor)
        bounds = glyph_poly.bounds
        glyph_poly = translate(
            glyph_poly,
            vsk.width / 2 - bounds[0] - (bounds[2] - bounds[0]) / 2,
            vsk.height / 2 - bounds[1] - (bounds[3] - bounds[1]) / 2 +
            self.glyph_voffset,
        )

        if self.draw_glyph:
            vsk.strokeWeight(self.glyph_weight)
            if self.fill_glyph:
                vsk.fill(1)
            vsk.geometry(glyph_poly)

            if self.fill_glyph and self.glyph_chroma:
                angle = self.glyph_chroma_angle / 180.0 * math.pi
                glyph_poly_chroma1 = translate(
                    glyph_poly,
                    -self.glyph_chroma_offset * math.cos(angle),
                    -self.glyph_chroma_offset * math.sin(angle),
                ).difference(glyph_poly)
                glyph_poly_chroma2 = translate(
                    glyph_poly,
                    self.glyph_chroma_offset * math.cos(angle),
                    self.glyph_chroma_offset * math.sin(angle),
                ).difference(glyph_poly)

                vsk.strokeWeight(1)
                vsk.stroke(2)
                vsk.fill(2)
                vsk.geometry(glyph_poly_chroma1)
                vsk.stroke(3)
                vsk.fill(3)
                vsk.geometry(glyph_poly_chroma2)

                glyph_poly = unary_union(
                    [glyph_poly, glyph_poly_chroma1, glyph_poly_chroma2])

            vsk.strokeWeight(1)
            vsk.stroke(1)
            vsk.noFill()

        glyph_shadow = None
        if self.glyph_shadow:
            angle = self.glyph_chroma_angle / 180.0 * math.pi
            glyph_shadow = translate(
                glyph_poly,
                self.glyph_chroma_offset * math.cos(angle),
                self.glyph_chroma_offset * math.sin(angle),
            ).difference(glyph_poly)
            vsk.fill(3)
            vsk.stroke(3)
            vsk.geometry(glyph_shadow)
            vsk.noFill()
            vsk.stroke(1)
            glyph_poly = glyph_poly.union(glyph_shadow)

        if self.glyph_weight == 1:
            glyph_poly_ext = glyph_poly.buffer(
                self.glyph_space,
                join_style=JOIN_STYLE.mitre,
            )
            glyph_poly_int = glyph_poly.buffer(
                -self.glyph_space_inside,
                join_style=JOIN_STYLE.mitre,
            )
        else:
            buf_len = (self.glyph_weight - 1) / 2 * self.pen_width
            glyph_poly_ext = glyph_poly.buffer(
                buf_len * 2 + self.glyph_space,
                join_style=JOIN_STYLE.mitre,
            )
            glyph_poly_int = glyph_poly.buffer(
                -buf_len - self.glyph_space_inside,
                join_style=JOIN_STYLE.mitre,
            )

        if glyph_shadow is not None:
            glyph_poly_int = glyph_poly_int.difference(glyph_shadow)

        # horizontal stripes
        if self.draw_h_stripes:
            count = round(
                (vsk.height - 2 * self.margin) / self.h_stripes_pitch)
            corrected_pitch = (vsk.height - 2 * self.margin) / count
            hstripes = MultiLineString([[
                (self.margin, self.margin + i * corrected_pitch),
                (vsk.width - self.margin, self.margin + i * corrected_pitch),
            ] for i in range(count + 1)])

            vsk.geometry(hstripes.difference(glyph_poly_ext))

            if self.h_stripes_inside:
                inside_stripes = translate(hstripes, 0, corrected_pitch /
                                           2).intersection(glyph_poly_int)
                vsk.geometry(inside_stripes)

                if self.h_stripes_inside_chroma:
                    chroma_offset = math.sqrt(2) * self.pen_width
                    vsk.stroke(2)
                    vsk.geometry(
                        translate(inside_stripes, -chroma_offset,
                                  -chroma_offset))
                    vsk.stroke(3)
                    vsk.geometry(
                        translate(inside_stripes, chroma_offset,
                                  chroma_offset))
                    vsk.stroke(1)

        # concentric
        if self.draw_concentric:
            circle_count = int(
                math.ceil(
                    math.hypot(vsk.width, vsk.height) / 2 /
                    self.concentric_pitch))
            circles = unary_union([
                Point(vsk.width / 2, vsk.height / 2).buffer(
                    (i + 1) * self.concentric_pitch,
                    resolution=int(1 * (i + 1) * self.concentric_pitch),
                ).exterior for i in range(circle_count)
            ])
            vsk.geometry(
                circles.difference(glyph_poly_ext).intersection(
                    box(
                        self.margin,
                        self.margin,
                        vsk.width - self.margin,
                        vsk.height - self.margin,
                    )))

        # dots
        vsk.fill(1)
        if self.draw_dots or self.draw_cut_circles:
            v_pitch = self.pitch * math.tan(math.pi / 3) / 2
            h_count = int((vsk.width - 2 * self.margin) // self.pitch)
            v_count = int((vsk.height - 2 * self.margin) // v_pitch)
            h_offset = (vsk.width - h_count * self.pitch) / 2
            v_offset = (vsk.height - v_count * v_pitch) / 2

            dot_array = []
            for j in range(v_count + 1):
                odd_line = j % 2 == 1
                for i in range(h_count + (0 if odd_line else 1)):
                    dot = Point(
                        h_offset + i * self.pitch +
                        (self.pitch / 2 if odd_line else 0),
                        v_offset + j * v_pitch,
                    ).buffer(self.thickness / 2)

                    if self.draw_dots:
                        if not dot.buffer(
                                self.thickness / 2).intersects(glyph_poly_ext):
                            dot_array.append(dot)
                    else:
                        dot_array.append(dot)

            dots = unary_union(dot_array)

            if self.draw_dots:
                vsk.geometry(dots)

            if self.draw_cut_circles:
                if self.cut_circles_inside:
                    op_func = lambda geom: geom.intersection(glyph_poly_int)
                else:
                    op_func = lambda geom: geom.difference(glyph_poly_ext)

                vsk.geometry(op_func(dots))

                if self.cut_circle_chroma:
                    angle = math.pi / 6
                    dist = self.pitch * 0.1
                    vsk.fill(2)
                    vsk.stroke(2)
                    vsk.geometry(
                        op_func(
                            translate(dots, -dist * math.cos(angle), -dist *
                                      math.sin(angle)).difference(dots)))
                    vsk.fill(3)
                    vsk.stroke(3)
                    vsk.geometry(
                        op_func(
                            translate(dots, dist * math.cos(angle),
                                      dist *
                                      math.sin(angle)).difference(dots)))
                    vsk.fill(1)
                    vsk.stroke(1)

        vsk.stroke(4)  # apply line sort, see finalize()
        if self.draw_dot_matrix:
            h_count = int(
                (vsk.width - 2 * self.margin) // self.dot_matrix_pitch) + 1
            v_count = int(
                (vsk.height - 2 * self.margin) // self.dot_matrix_pitch) + 1
            h_pitch = (vsk.width - 2 * self.margin) / (h_count - 1)
            v_pitch = (vsk.height - 2 * self.margin) / (v_count - 1)

            mp = MultiPoint([
                (self.margin + i * h_pitch, self.margin + j * v_pitch)
                for i, j in itertools.product(range(h_count), range(v_count))
                if vsk.random(1) < self.dot_matrix_density
            ])

            if self.draw_dot_matrix_inside:
                mp = mp.intersection(glyph_poly_int)
            else:
                mp = mp.difference(glyph_poly_ext)

            vsk.geometry(mp)
            vsk.vpype("color -l4 black")

        vsk.vpype("color -l1 black color -l2 cyan color -l3 magenta")
Пример #11
0
def polygon_with_holes(coordinates_dictionary):
    def polygon_with_holes_coordinates(coordinates, outer_ring_linestring,
                                       interceptors_op_dict):
        first_op = outer_ring_linestring.coords[0]
        if first_op in interceptors_op_dict:
            coordinates.append(first_op)
            holes = interceptors_op_dict[first_op]
            for hole in holes:
                if hole.geom_type == 'LineString':
                    for coord in hole.coords:
                        coordinates.append(coord)
                if hole.geom_type == 'MultiLineString':
                    for coord in hole[1].coords:
                        coordinates.append(coord)
                    for coord in hole[0].coords[1:]:
                        coordinates.append(coord)
                coordinates.append(first_op)
            for coord in outer_ring_linestring.coords[1:-1]:
                coordinates.append(coord)
        else:
            for coord in outer_ring_linestring.coords[:-1]:
                coordinates.append(coord)
        return coordinates

    def dist_two_points(p1, p2):
        distance = math.sqrt(
            math.pow((p1[0] - p2[0]), 2) + math.pow((p1[1] - p2[1]), 2))
        return distance

    def inner_string(inner_ring_coordinates, irop):
        inner_coordinates = list(inner_ring_coordinates)

        for i, coord in enumerate(inner_coordinates):
            if coord == irop:
                split_position = i
                break
        if split_position == 0:
            inner_linestring = LineString(inner_coordinates)
        else:
            first = inner_coordinates[:(split_position + 1)]
            last = inner_coordinates[split_position:]
            inner_linestring = MultiLineString([first, last])
        return inner_linestring

    outer_ring_coordinates = coordinates_dictionary['outer_ring']
    interceptors_op_dict = dict()
    oi_min_linestring_list = list()
    for inner_ring_coordinates in coordinates_dictionary['inner_rings']:
        for i, orop in enumerate(outer_ring_coordinates[0][:-1]):
            for j, irop in enumerate(inner_ring_coordinates[:-1]):
                if i == 0 and j == 0:
                    oi_min_distance = dist_two_points(orop, irop)
                    if oi_min_distance > 0.015:
                        oi_min_linestring = LineString([orop, irop])
                        inner_linestring = inner_string(
                            inner_ring_coordinates, irop)
                    else:
                        oi_min_distance = 1e9
                else:
                    distance = dist_two_points(orop, irop)
                    if (distance < oi_min_distance) and (distance > 0.015):
                        oi_min_distance = distance
                        oi_min_linestring = LineString([orop, irop])
                        inner_linestring = inner_string(
                            inner_ring_coordinates, irop)

        if oi_min_linestring.coords[0] in interceptors_op_dict:
            interceptors_op_dict[oi_min_linestring.coords[0]].append(
                inner_linestring)
        else:
            interceptors_op_dict[oi_min_linestring.coords[0]] = [
                inner_linestring
            ]
        oi_min_linestring_list.append(oi_min_linestring)
    outer_ring = MultiLineString(coordinates_dictionary['outer_ring'])
    for oi_min_linestring in oi_min_linestring_list:
        outer_ring = outer_ring.difference(oi_min_linestring)
    coordinates = list()
    if outer_ring.geom_type == 'LineString':
        start_end_op = outer_ring.coords[0]
        coordinates = polygon_with_holes_coordinates(coordinates, outer_ring,
                                                     interceptors_op_dict)
    elif outer_ring.geom_type == 'MultiLineString':
        for i, linestring in enumerate(outer_ring):
            if i == 0:
                start_end_op = linestring.coords[0]
            coordinates = polygon_with_holes_coordinates(
                coordinates, linestring, interceptors_op_dict)
    coordinates.append(start_end_op)
    return [coordinates]