Source code for knitout_interpreter.knitout_operations.Header_Line

"""Module containing the classes for Header Lines in Knitout"""
import warnings
from enum import Enum
from typing import Any

from knit_graphs.Yarn import Yarn_Properties
from virtual_knitting_machine.Knitting_Machine import Knitting_Machine
from virtual_knitting_machine.Knitting_Machine_Specification import (
    Knitting_Machine_Specification,
    Knitting_Machine_Type,
    Knitting_Position,
)
from virtual_knitting_machine.knitting_machine_warnings.Knitting_Machine_Warning import (
    Knitting_Machine_Warning,
)
from virtual_knitting_machine.machine_components.yarn_management.Yarn_Carrier import (
    Yarn_Carrier,
)
from virtual_knitting_machine.machine_components.yarn_management.Yarn_Carrier_Set import (
    Yarn_Carrier_Set,
)

from knitout_interpreter.knitout_operations.Knitout_Line import (
    Knitout_Line,
    Knitout_Version_Line,
)


[docs] class Knitout_Header_Line_Type(Enum): """Enumeration of properties that can be set in the header.""" Machine = "Machine" # Denotes the type of machine to build Gauge = "Gauge" # Denotes the needles per inch of the machine Yarn = "Yarn" # Sets a specific yarn on a specified carrier. Position = "Position" # Denotes the position of the knitting pattern on the needle beds. Carriers = "Carriers" # Denotes the carriers on the machine. def __str__(self) -> str: return self.value def __repr__(self) -> str: return str(self)
[docs] class Knitout_Header_Line(Knitout_Line): def __init__(self, header_type: Knitout_Header_Line_Type, header_value: Any, comment: str | None): super().__init__(comment) self._header_value: Any = header_value self._header_type: Knitout_Header_Line_Type = header_type @property def header_type(self) -> Knitout_Header_Line_Type: """ Returns: Knitout_Header_Line_Type: The type of value to be changed by this header line. """ return self._header_type
[docs] def updates_machine_state(self, machine_state: Knitting_Machine) -> bool: """Check if this header would update the given machine state. Args: machine_state: The machine state to check against. Returns: True if this header would update the given machine state, False otherwise. """ return False
def __str__(self) -> str: return f";;{self.header_type}: {self._header_value}{self.comment_str}"
[docs] class Machine_Header_Line(Knitout_Header_Line): def __init__(self, machine_type: str, comment: str | None = None): super().__init__(Knitout_Header_Line_Type.Machine, Knitting_Machine_Type[machine_type], comment)
[docs] def updates_machine_state(self, machine_state: Knitting_Machine) -> bool: return bool(self._header_value != machine_state.machine_specification.machine)
[docs] def execute(self, machine_state: Knitting_Machine) -> bool: if self.updates_machine_state(machine_state): machine_state.machine_specification.machine = self._header_value return True else: return False
[docs] class Gauge_Header_Line(Knitout_Header_Line): def __init__(self, gauge: int, comment: str | None = None): super().__init__(Knitout_Header_Line_Type.Gauge, gauge, comment)
[docs] def updates_machine_state(self, machine_state: Knitting_Machine) -> bool: return bool(self._header_value != machine_state.machine_specification.gauge)
[docs] def execute(self, machine_state: Knitting_Machine) -> bool: if self.updates_machine_state(machine_state): machine_state.machine_specification.gauge = self._header_value return True else: return False
[docs] class Position_Header_Line(Knitout_Header_Line): def __init__(self, position: str, comment: str | None = None): super().__init__(Knitout_Header_Line_Type.Position, Knitting_Position[position], comment)
[docs] def updates_machine_state(self, machine_state: Knitting_Machine) -> bool: return bool(self._header_value != machine_state.machine_specification.position)
[docs] def execute(self, machine_state: Knitting_Machine) -> bool: if self.updates_machine_state(machine_state): machine_state.machine_specification.position = self._header_value return True else: return False
[docs] class Yarn_Header_Line(Knitout_Header_Line): def __init__(self, carrier_id: int, plies: int, yarn_weight: float, color: str, comment: str | None = None): self._yarn_properties: Yarn_Properties = Yarn_Properties(f"carrier+{carrier_id}_yarn", plies, yarn_weight, color) self._carrier_id: int = carrier_id super().__init__(Knitout_Header_Line_Type.Yarn, self._yarn_properties, comment) def __str__(self) -> str: return f";;{self.header_type}-{self._carrier_id}: {self._yarn_properties.plies}-{self._yarn_properties.weight} {self._yarn_properties.color}{self.comment_str}"
[docs] def updates_machine_state(self, machine_state: Knitting_Machine) -> bool: return bool(self._yarn_properties != machine_state.carrier_system[self._carrier_id].yarn.properties)
[docs] def execute(self, machine_state: Knitting_Machine) -> bool: if self.updates_machine_state(machine_state): machine_state.carrier_system[self._carrier_id].yarn.properties = self._yarn_properties return True else: return False
[docs] class Carriers_Header_Line(Knitout_Header_Line): def __init__(self, carrier_ids: list[int] | int | Yarn_Carrier_Set | Yarn_Carrier, comment: str | None = None): if isinstance(carrier_ids, int): carrier_ids = Yarn_Carrier_Set([i + 1 for i in range(carrier_ids)]) elif isinstance(carrier_ids, Yarn_Carrier): carrier_ids = Yarn_Carrier_Set([carrier_ids.carrier_id]) elif isinstance(carrier_ids, list): carrier_ids = Yarn_Carrier_Set(carrier_ids) super().__init__(Knitout_Header_Line_Type.Carriers, carrier_ids, comment)
[docs] def updates_machine_state(self, machine_state: Knitting_Machine) -> bool: return len(machine_state.carrier_system.carriers) != len(self._header_value)
[docs] def execute(self, machine_state: Knitting_Machine) -> bool: carrier_count = len(self._header_value) if self.updates_machine_state(machine_state): machine_state.machine_specification.carrier_count = carrier_count return True return False
[docs] class Knitting_Machine_Header: """A class structure for maintaining the relationship between header lines and knitting machine state. This class manages the relationship between header lines read from a knitout file and the state of a given knitting machine. Attributes: specification (Knitting_Machine_Specification): The specification of the knitting machine created by this header. machine (Knitting_Machine): The knitting machine currently created by this header. """ def __init__(self, initial_specification: Knitting_Machine_Specification = Knitting_Machine_Specification()): self.specification: Knitting_Machine_Specification = initial_specification self.machine: Knitting_Machine = Knitting_Machine(self.specification) self._header_lines: dict[Knitout_Header_Line_Type, Knitout_Header_Line] = {} self.set_header_by_specification(self.specification)
[docs] def update_header(self, header_line: Knitout_Header_Line, update_machine: bool = False) -> bool: """Update this header with the given header line. Args: header_line: The header line to update this header with. update_machine: If True, the header line will update the machine state to the new values in this header_line, if present. If False, the header line will only update this header if there is no explicitly set header line for that value. In this case, if the header line would require the machine state to update, a warning is raised. Returns: True if this header is updated by the given header line. Note: If update_machine is False, no updates are allowed and this will always return False. If the update changes an active machine, then a warning is raised, and it makes no changes to the machine state. """ if update_machine: # update the machine state and then add this to the header if it caused an update updated = header_line.execute(self.machine) if updated: self._header_lines[header_line.header_type] = header_line self.specification = self.machine.machine_specification return True else: return False else: would_update = header_line.updates_machine_state(self.machine) if would_update: warnings.warn(Knitting_Machine_Warning(f"Ignored Header Updates Active Machine: {header_line}".rstrip())) return False
[docs] def set_header_by_specification(self, machine_specification: Knitting_Machine_Specification) -> None: """Set the header lines to produce the given machine specification. Args: machine_specification: The machine specification to set this header to. """ self._header_lines = {Knitout_Header_Line_Type.Machine: Machine_Header_Line(str(machine_specification.machine)), Knitout_Header_Line_Type.Gauge: Gauge_Header_Line(machine_specification.gauge), Knitout_Header_Line_Type.Position: Position_Header_Line(str(machine_specification.position)), Knitout_Header_Line_Type.Carriers: Carriers_Header_Line(machine_specification.carrier_count)}
[docs] def get_header_lines(self, version: int = 2) -> list[Knitout_Line]: """Get a complete knitout header from the stored header lines. Args: version: The knitout version number to process with. Defaults to 2. Returns: List of header lines that form a complete knitout header. This starts with a version line. """ values = [Knitout_Version_Line(version)] values.extend(self._header_lines.values()) return values
[docs] def get_machine_header(knitting_machine: Knitting_Machine, version: int = 2) -> list[Knitout_Line]: """Get a list of header lines that describe the given machine state. Args: knitting_machine: The machine state to specify as a header. version: The desired knitout version of the header. Defaults to 2. Returns: A list containing header lines and a version line that describes the given machine state. """ header = Knitting_Machine_Header(knitting_machine.machine_specification) return header.get_header_lines(version)