示例#1
0
def make_bundle(vsk, start, base_dir, k, freq, freq2):
    for t in np.linspace(0, freq2, 200):
        x = [vp.convert_length(start[0])]
        y = [vp.convert_length(start[1])]
        for _ in range(100):
            dx = k * (vsk.noise(x[-1] * freq, y[-1] * freq, 0 + t) -
                      0.5) + base_dir[0]
            dy = k * (vsk.noise(x[-1] * freq, y[-1] * freq, 1000 + t) -
                      0.5) + base_dir[1]

            x.append(x[-1] + dx)
            y.append(y[-1] + dy)
        vsk.polygon(x, y)
示例#2
0
    def draw(self, vsk: vsketch.Vsketch) -> None:
        if self.override_page_size:
            vsk.size(f"{self.page_width}x{self.page_height}")
        else:
            vsk.size(self.page_size, landscape=False)

        vsk.stroke(1)
        vsk.fill(1)

        for i, (y, x) in enumerate(
                itertools.product(range(self.row_count),
                                  range(self.column_count))):
            pw = self.smallest_width_mm + i * self.width_increment_mm

            vsk.penWidth(f"{pw}mm", 1)
            vsk.rect(
                x * self.horizontal_offset,
                y * self.vertical_offset,
                self.box_width,
                self.box_height,
            )
            vsk.text(
                f"{pw:.3}mm",
                x * self.horizontal_offset + self.box_width / 2,
                y * self.vertical_offset + self.box_height +
                vpype.convert_length("0.5cm"),
                mode="label",
                align="center",
                size=12,
            )
示例#3
0
def test_stroke_weight_detail(vsk, weight, detail_mm):
    """We ensure that the desired detail level is respected by strokeWeight"""
    detail_px = vp.convert_length(str(detail_mm) + "mm")
    vsk.detail(detail_px)
    vsk.strokeWeight(weight)

    # large geometries to filter out polygon's edges
    # vsk.triangle(0, 0, 160, 0, 80, 160)
    vsk.square(0, 0, 160)

    assert line_count_equal(vsk, weight)

    for line in vsk.document.layers[1]:
        seg_length = np.abs(np.diff(line))
        idx = (seg_length <= detail_px) | (seg_length > 140)
        assert np.all(idx)
示例#4
0
    def __init__(
        self,
        value: ParamType,
        min_value: Optional[ParamType] = None,
        max_value: Optional[ParamType] = None,
        *,
        choices: Optional[Sequence[ParamType]] = None,
        step: Union[None, float, int] = None,
        unit: str = "",
        decimals: Optional[int] = None,
    ):
        """Create a sketch parameter.

        This class implements a sketch parameter. Ts automatically recognized by ``vsk`` which
        generates the corresponding UI in the sketch interactive viewer. :class:`Param`
        instances must be declared as class member in the :class:`Vsketch` subclass and can
        then be used using the calling convention::

            import vsketch
            class MySketch(vsketch.Vsketch):
                page_size = vsketch.Param("a4", choices=["a3", "a4", "a5"])

                def draw(self):
                    self.size(self.page_size())
                    # ...

        :class:`Param` can encapsulate the following types: :class:`int`, :class:`float`,
        :class:`str`, and :class:`bool`.

        For numeral types, a minimum and maximum value may be specified, as well as the step
        size to use in the UI::

            low_bound_param = vsketch.Param(10, 0, step=5)  # may not be lower than 0
            bounded_param = vsketch.Param(0.5, 0., 1.)  # must be within 0.0 and 1.0

        For these types, a unit may also be specified::

            margin = vsketch.Param(10., unit="mm")

        In this case, the unit will be displayed in the UI and the value converted to pixel
        when accessed by the sketch.

        :class:`float` parameters may further define the number of decimals to display in the
        UI::

            precise_param = vsketch.Param(0.01, decimals=5)

        Numeral types and string parameters may have a set of possibly choices::

            mode = vsketch.Param("simple", choices=["simple", "complex", "versatile"])
        """
        self.value: ParamType = value
        self.type = type(value)
        self.min = self.type(
            min_value) if min_value is not None else None  # type: ignore
        self.max = self.type(
            max_value) if max_value is not None else None  # type: ignore
        self.step = step
        self.decimals = decimals
        self.unit = unit
        self.factor: Optional[
            float] = None if unit == "" else vp.convert_length(unit)

        self.choices: Optional[Tuple[ParamType, ...]] = None
        if choices is not None:
            self.choices = tuple(self.type(choice)
                                 for choice in choices)  # type: ignore
示例#5
0
def show(
    document: Document,
    show_axes: bool,
    show_grid: bool,
    show_pen_up: bool,
    show_points: bool,
    hide_legend: bool,
    colorful: bool,
    unit: str,
):
    """Display the geometry using matplotlib.

    By default, only the geometries are displayed without the axis. All geometries are
    displayed with black. When using the `--colorful` flag, each segment will have a different
    color (default matplotlib behaviour). This can be useful for debugging purposes.
    """

    # deferred import to optimise startup time
    import matplotlib.collections
    import matplotlib.pyplot as plt

    scale = 1 / convert_length(unit)

    fig = plt.figure()
    color_idx = 0
    collections = {}

    # draw page boundaries
    if document.page_size:
        w = document.page_size[0] * scale
        h = document.page_size[1] * scale
        dw = 10 * scale
        plt.plot(
            np.array([0, 1, 1, 0, 0]) * w,
            np.array([0, 0, 1, 1, 0]) * h,
            "-k",
            lw=0.25,
            label=None,
        )
        plt.fill(
            np.array([w, w + dw, w + dw, dw, dw, w]),
            np.array([dw, dw, h + dw, h + dw, h, h]),
            "k",
            alpha=0.3,
            label=None,
        )

    for layer_id, lc in document.layers.items():
        if colorful:
            color = COLORS[color_idx:] + COLORS[:color_idx]
            marker_color = "k"
            color_idx += len(lc)
        else:
            color = COLORS[color_idx]  # type: ignore
            marker_color = [color]  # type: ignore
            color_idx += 1
        if color_idx >= len(COLORS):
            color_idx = color_idx % len(COLORS)

        layer_lines = matplotlib.collections.LineCollection(
            (as_vector(line) * scale for line in lc),
            color=color,
            lw=1,
            alpha=0.5,
            label=str(layer_id),
        )
        collections[layer_id] = [layer_lines]
        plt.gca().add_collection(layer_lines)

        if show_points:
            points = np.hstack([line for line in lc]) * scale
            layer_points = plt.gca().scatter(points.real,
                                             points.imag,
                                             marker=".",
                                             c=marker_color,
                                             s=16)
            collections[layer_id].append(layer_points)

        if show_pen_up:
            pen_up_lines = matplotlib.collections.LineCollection(
                ((as_vector(lc[i])[-1] * scale,
                  as_vector(lc[i + 1])[0] * scale)
                 for i in range(len(lc) - 1)),
                color=(0, 0, 0),
                lw=0.5,
                alpha=0.5,
            )
            collections[layer_id].append(pen_up_lines)
            plt.gca().add_collection(pen_up_lines)

    plt.gca().invert_yaxis()
    plt.axis("equal")
    plt.margins(0, 0)

    if not hide_legend:
        lgd = plt.legend(loc="upper right")
        # we will set up a dict mapping legend line to orig line, and enable
        # picking on the legend line
        line_dict = {}
        for lgd_line, lgd_text in zip(lgd.get_lines(), lgd.get_texts()):
            lgd_line.set_picker(True)  # 5 pts tolerance
            lgd_line.set_pickradius(5)
            layer_id = int(lgd_text.get_text())
            if layer_id in collections:
                line_dict[lgd_line] = collections[layer_id]

        def on_pick(event):
            line = event.artist
            vis = not line_dict[line][0].get_visible()
            for ln in line_dict[line]:
                ln.set_visible(vis)

            if vis:
                line.set_alpha(1.0)
            else:
                line.set_alpha(0.2)
            fig.canvas.draw()

        fig.canvas.mpl_connect("pick_event", on_pick)

    if show_axes or show_grid:
        plt.axis("on")
        plt.xlabel(f"[{unit}]")
        plt.ylabel(f"[{unit}]")
    else:
        plt.axis("off")
    if show_grid:
        plt.grid("on")
    plt.show()

    return document
示例#6
0
def display_matplotlib(
    document: vp.Document,
    page_size: Tuple[float, float] = None,
    center: bool = False,
    show_axes: bool = True,
    show_grid: bool = False,
    show_pen_up: bool = False,
    colorful: bool = False,
    unit: str = "px",
    fig_size: Tuple[float, float] = None,
) -> None:
    scale = 1 / vp.convert_length(unit)

    if fig_size:
        plt.figure(figsize=fig_size)
    plt.cla()

    # draw page
    if page_size is not None:
        w = page_size[0] * scale
        h = page_size[1] * scale
        dw = 10 * scale
        plt.fill(
            np.array([w, w + dw, w + dw, dw, dw, w]),
            np.array([dw, dw, h + dw, h + dw, h, h]),
            "k",
            alpha=0.3,
        )
        plt.plot(np.array([0, 1, 1, 0, 0]) * w,
                 np.array([0, 0, 1, 1, 0]) * h,
                 "-k",
                 lw=0.25)

    # compute offset
    offset = complex(0, 0)
    if center and page_size:
        bounds = document.bounds()
        if bounds is not None:
            offset = complex(
                (page_size[0] - (bounds[2] - bounds[0])) / 2.0 - bounds[0],
                (page_size[1] - (bounds[3] - bounds[1])) / 2.0 - bounds[1],
            )
    offset_ndarr = np.array([offset.real, offset.imag])

    # plot all layers
    color_idx = 0
    collections = {}
    for layer_id, lc in document.layers.items():
        if colorful:
            color: Union[Tuple[float, float, float],
                         List[Tuple[float, float,
                                    float]]] = (COLORS[color_idx:] +
                                                COLORS[:color_idx])
            color_idx += len(lc)
        else:
            color = COLORS[color_idx]
            color_idx += 1
        if color_idx >= len(COLORS):
            color_idx = color_idx % len(COLORS)

        # noinspection PyUnresolvedReferences
        layer_lines = matplotlib.collections.LineCollection(
            (vp.as_vector(line + offset) * scale for line in lc),
            color=color,
            lw=1,
            alpha=0.5,
            label=str(layer_id),
        )
        collections[layer_id] = [layer_lines]
        plt.gca().add_collection(layer_lines)

        if show_pen_up:
            # noinspection PyUnresolvedReferences
            pen_up_lines = matplotlib.collections.LineCollection(
                ((
                    (vp.as_vector(lc[i])[-1] + offset_ndarr) * scale,
                    (vp.as_vector(lc[i + 1])[0] + offset_ndarr) * scale,
                ) for i in range(len(lc) - 1)),
                color=(0, 0, 0),
                lw=0.5,
                alpha=0.5,
            )
            collections[layer_id].append(pen_up_lines)
            plt.gca().add_collection(pen_up_lines)

    plt.gca().invert_yaxis()
    plt.axis("equal")
    plt.margins(0, 0)

    if show_axes or show_grid:
        plt.axis("on")
        plt.xlabel(f"[{unit}]")
        plt.ylabel(f"[{unit}]")
    else:
        plt.axis("off")
    if show_grid:
        plt.grid("on")

    plt.show()