from typing import Union, Optional from collections import Counter from dataclasses import dataclass import cadquery as Cq from nhf.materials import Role, KEY_ROLE, KEY_ITEM @dataclass(frozen=True) class Item: """ A pre-fabricated item """ mass: float #@property #def mass(self) -> float: # """ # Mass, in grams # """ # return self._mass #@mass.setter #def mass(self, value): # assert value >= 0, "Mass cannot be negative" # self._mass = value @property def name(self) -> str: pass @property def role(self) -> Optional[Role]: return None def generate(self, **kwargs) -> Union[Cq.Assembly, Cq.Workplane]: """ Creates an assembly for this item. Subclass should implement this """ return Cq.Assembly() def assembly(self, **kwargs) -> Cq.Assembly: """ Interface for creating assembly with the necessary metadata """ a = self.generate(**kwargs) if isinstance(a, Cq.Workplane): a = Cq.Assembly(a) if role := self.role: a.metadata[KEY_ROLE] = role a.color = role.color_avg() assert isinstance(a, Cq.Assembly) assert KEY_ITEM not in a.metadata a.metadata[KEY_ITEM] = self return a @staticmethod def count(a: Cq.Assembly) -> Counter: """ Counts the number of items """ occ = Counter() for _, obj in a.traverse(): if KEY_ITEM not in obj.metadata: continue item = obj.metadata[KEY_ITEM] assert isinstance(item, Item) occ[item.name] += 1 return occ