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_Type, Knitting_Position, Knitting_Machine_Specification
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"
Gauge = "Gauge"
Yarn = "Yarn"
Position = "Position"
Carriers = "Carriers"
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
[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 = 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.carrier_system = 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.
"""
def __init__(self, knitting_machine: Knitting_Machine):
self.machine: Knitting_Machine = knitting_machine
self._header_lines: dict[Knitout_Header_Line_Type, Knitout_Header_Line] = {}
self.set_header_by_specification(self.machine.machine_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 would cause a change in the 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
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)
return header.get_header_lines(version)