Source code for knit_graphs.knit_graph_builder

"""Module containing the Knit_Graph_Builder class."""

from collections.abc import Sequence
from typing import Any, Generic, TypeVar, cast

from knit_graphs.artin_wale_braids.Crossing_Direction import Crossing_Direction
from knit_graphs.Knit_Graph import Knit_Graph
from knit_graphs.Loop import Loop
from knit_graphs.Pull_Direction import Pull_Direction
from knit_graphs.Yarn import Yarn, Yarn_Properties

LoopT = TypeVar("LoopT", bound=Loop)


[docs] class Knit_Graph_Builder(Generic[LoopT]): """A general framework for building Knit_Graphs from standard knitting operations."""
[docs] def __init__( self, loop_class: type[LoopT] | None = None, yarn_class: type[Yarn[LoopT]] | None = None, ): if loop_class is not None: self._loop_class: type[LoopT] = loop_class else: self._loop_class: type[LoopT] = cast(type[LoopT], Loop) if yarn_class is not None: self._yarn_class: type[Yarn[LoopT]] = yarn_class else: self._yarn_class: type[Yarn[LoopT]] = cast(type[Yarn[LoopT]], Yarn) self.knit_graph: Knit_Graph[LoopT] = Knit_Graph[LoopT]() self._first_yarn: Yarn[LoopT] | None = None
[docs] def add_yarn(self, yarn_properties: Yarn_Properties | None = None, **yarn_kwargs: Any) -> Yarn[LoopT]: """ Create and add a new yarn to the Knit_Graph with the given properties. Args: yarn_properties (Yarn_Properties, optional): The properties of the yarn. Defaults to standard yarn-properties. **yarn_kwargs (Any, optional): Additional keyword arguments for forming the yarn. Defaults to no keyword arguments. Returns: Yarn[LoopT]: The new yarn in the Knit_Graph. """ yarn = self._make_yarn(yarn_properties, **yarn_kwargs) self.knit_graph.add_yarn(yarn) return yarn
[docs] def cut_yarn(self, yarn: Yarn[LoopT]) -> Yarn[LoopT]: """Cut yarn to make it no longer active and create a new yarn instance of the same type. Returns: Yarn[LoopT]: New yarn of the same type after cutting this yarn. """ cut_yarn = yarn.cut_yarn() self.knit_graph.add_yarn(cut_yarn) return cut_yarn
[docs] @staticmethod def position_float( first_loop: LoopT, loops_behind_float: Sequence[LoopT] | None = None, loops_in_front_of_float: Sequence[LoopT] | None = None, ) -> None: """ Position the float exiting the given loop relative to the given sets of loops. Args: first_loop (LoopT): First loop in the float to position. loops_behind_float (Sequence[LoopT]): The loops in front of the float to position. loops_in_front_of_float (Sequence[LoopT]): The loops behind the float to position. """ if loops_behind_float is not None: for loop in loops_behind_float: first_loop.add_loop_behind_started_float(loop) if loops_in_front_of_float is not None: for loop in loops_in_front_of_float: first_loop.add_loop_in_front_of_started_float(loop)
[docs] def tuck(self, yarn: Yarn[LoopT], **loop_kwargs: Any) -> LoopT: """ Forms a new loop at the end of the yarn with no parent loops. Args: yarn (Yarn[LoopT]): The yarn to form the loop from in the knitgraph. **loop_kwargs (Any, optional): Additional keywords to support base-classes of Loop. Defaults to None. Returns: LoopT: The new loop formed by the tuck. """ return self._make_loop(yarn, **loop_kwargs)
[docs] def knit( self, yarn: Yarn[LoopT], parent_loops: Sequence[LoopT], pull_direction: Pull_Direction | None = None, **loop_kwargs: Any, ) -> LoopT: """ Args: yarn (Yarn[LoopT]): The yarn to form the loop from in the knitgraph. parent_loops (Sequence[LoopT]): The parent loops of stitch in their stacking order. pull_direction (Pull_Direction, optional): Pull direction of the stitch. Defaults to the dominant pull direction of a loop or Back-to-front (i.e., knit-stitch) if the loop has no parents. **loop_kwargs (Any, optional): Additional keywords to support base-classes of Loop. Defaults to None. Returns: LoopT: The new loop formed by the knit. """ if pull_direction is None: pull_direction = Loop.majority_pull_direction(parent_loops) loop = self._make_loop(yarn, **loop_kwargs) for parent in parent_loops: self.knit_graph.connect_loops(parent, loop, pull_direction) return loop
[docs] def xfer( self, loop: LoopT, over_loops_to_right: Sequence[LoopT] | None = None, over_loops_to_left: Sequence[LoopT] | None = None, under_loops_to_right: Sequence[LoopT] | None = None, under_loops_to_left: Sequence[LoopT] | None = None, ) -> None: """ Cross the given loop over neighboring loops in the braid graph. Args: loop (LoopT): The loop to cross over neighbors over_loops_to_right (Sequence[LoopT], optional): The loops to cross over to the right. Defaults to no loops. over_loops_to_left (Sequence[LoopT], optional): The loops to cross over to the left. Defaults to no loops. under_loops_to_right (Sequence[LoopT], optional): The loops to cross under to the right. Defaults to no loops. under_loops_to_left (Sequence[LoopT], optional): The loops to cross under to the left. Defaults to no loops. """ if over_loops_to_right is not None: for right_loop in over_loops_to_right: self.knit_graph.braid_graph.add_crossing(loop, right_loop, Crossing_Direction.Over_Right) if under_loops_to_right is not None: for right_loop in under_loops_to_right: self.knit_graph.braid_graph.add_crossing(loop, right_loop, Crossing_Direction.Under_Right) if over_loops_to_left is not None: for left_loop in over_loops_to_left: self.knit_graph.braid_graph.add_crossing(left_loop, loop, Crossing_Direction.Under_Right) if under_loops_to_left is not None: for left_loop in under_loops_to_left: self.knit_graph.braid_graph.add_crossing(left_loop, loop, Crossing_Direction.Over_Right)
[docs] def split( self, yarn: Yarn[LoopT], parent_loops: Sequence[LoopT], pull_direction: Pull_Direction | None = None, over_loops_to_right: Sequence[LoopT] | None = None, over_loops_to_left: Sequence[LoopT] | None = None, under_loops_to_right: Sequence[LoopT] | None = None, under_loops_to_left: Sequence[LoopT] | None = None, **loop_kwargs: Any, ) -> LoopT: """ Args: yarn (Yarn[LoopT]): The yarn to form the loop from in the knitgraph. parent_loops (Sequence[LoopT]): The parent loops of stitch in their stacking order. pull_direction (Pull_Direction, optional): Pull direction of the stitch. Defaults to the dominant pull direction of a loop or Back-to-front (i.e., knit-stitch) if the loop has no parents. over_loops_to_right (Sequence[LoopT], optional): The loops to cross over to the right. Defaults to no loops. over_loops_to_left (Sequence[LoopT], optional): The loops to cross over to the left. Defaults to no loops. under_loops_to_right (Sequence[LoopT], optional): The loops to cross under to the right. Defaults to no loops. under_loops_to_left (Sequence[LoopT], optional): The loops to cross under to the left. Defaults to no loops. **loop_kwargs (Any, optional): Additional keyword arguments for forming the loop. Defaults to no keyword arguments. Returns: LoopT: The loop formed in the split. """ if pull_direction is None: pull_direction = Loop.majority_pull_direction(parent_loops) for loop in parent_loops: self.xfer(loop, over_loops_to_right, over_loops_to_left, under_loops_to_right, under_loops_to_left) return self.knit(yarn, parent_loops, pull_direction, **loop_kwargs)
def _make_yarn(self, yarn_properties: Yarn_Properties | None = None, **yarn_kwargs: Any) -> Yarn[LoopT]: """ Args: yarn_properties (Yarn_Properties, optional): The properties of the yarn. Defaults to standard yarn-properties. **yarn_kwargs (Any, optional): Additional keyword arguments for forming the yarn. Defaults to no keyword arguments. Returns: Yarn[LoopT]: The new yarn in the Knit_Graph. """ return self._yarn_class(self.knit_graph, yarn_properties, **yarn_kwargs) def _make_loop(self, yarn: Yarn[LoopT], **loop_kwargs: Any) -> LoopT: """ Create a loop at the end of the given yarn and add it to the Knit_Graph. Args: yarn (Yarn[LoopT]): The yarn to form the loop from in the knitgraph. **loop_kwargs (Any, optional): Additional keywords to support base-classes of Loop. Defaults to None. Returns: LoopT: The new loop in the Knit_Graph. """ loop = self._loop_class(yarn, **loop_kwargs) # type: ignore[arg-type] yarn.add_loop_to_end(loop) if yarn.knit_graph is not self.knit_graph: self.knit_graph.add_loop(loop) return loop