init_code
This commit is contained in:
141
pygarment/garmentcode/base.py
Normal file
141
pygarment/garmentcode/base.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from abc import ABC, abstractmethod
|
||||
import numpy as np
|
||||
|
||||
from pygarment.garmentcode.connector import Stitches
|
||||
|
||||
|
||||
class BaseComponent(ABC):
|
||||
"""Basic interface for garment-related components
|
||||
|
||||
NOTE: modifier methods return self object to allow chaining of the
|
||||
operations
|
||||
"""
|
||||
|
||||
def __init__(self, name, verbose=False) -> None:
|
||||
self.name = name
|
||||
self.verbose = verbose
|
||||
|
||||
# List or dictionary of the interfaces of this components
|
||||
# available for connectivity with other components
|
||||
self.interfaces = {}
|
||||
|
||||
# Rules for connecting subcomponents
|
||||
self.stitching_rules = Stitches()
|
||||
|
||||
# Info
|
||||
def pivot_3D(self):
|
||||
"""Pivot location of a component in 3D"""
|
||||
return [0, 0, 0]
|
||||
|
||||
def bbox(self):
|
||||
"""Bounding box -- in 2D"""
|
||||
return np.array([0, 0]), np.array([0, 0])
|
||||
|
||||
def bbox3D(self):
|
||||
"""Bounding box in 3D space"""
|
||||
return np.array([0, 0, 0]), np.array([0, 0, 0])
|
||||
|
||||
def is_self_intersecting(self):
|
||||
"""Check whether the component have self-intersections"""
|
||||
return False
|
||||
|
||||
# Operations
|
||||
@abstractmethod
|
||||
def translate_by(self, delta_translation):
|
||||
return self
|
||||
|
||||
@abstractmethod
|
||||
def translate_to(self, new_translation):
|
||||
"""Set panel translation to be exactly that vector"""
|
||||
return self
|
||||
|
||||
@abstractmethod
|
||||
def rotate_by(self, delta_rotation):
|
||||
return self
|
||||
|
||||
@abstractmethod
|
||||
def rotate_to(self, new_rot):
|
||||
return self
|
||||
|
||||
@abstractmethod
|
||||
def assembly(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
# ----- Placement routines: these are the same for panels and components
|
||||
def place_below(self, comp, gap=2):
|
||||
"""Place below the provided component"""
|
||||
other_bbox = comp.bbox3D()
|
||||
curr_bbox = self.bbox3D()
|
||||
|
||||
self.translate_by([0, other_bbox[0][1] - curr_bbox[1][1] - gap, 0])
|
||||
return self
|
||||
|
||||
def place_by_interface(
|
||||
self,
|
||||
self_interface,
|
||||
out_interface,
|
||||
gap=2,
|
||||
alignment='center',
|
||||
gap_dir=None
|
||||
):
|
||||
"""Adjust the placement of component according to the connectivity
|
||||
instruction
|
||||
|
||||
Alignment options:
|
||||
'center' center of the interface to center of the interface
|
||||
'top' - top on Y axis
|
||||
'bottom' - bottom on Y axis
|
||||
'left' - left on X axis
|
||||
'right' - right on X axis
|
||||
"""
|
||||
|
||||
# Align translation
|
||||
self_bbox = self_interface.bbox_3d()
|
||||
out_bbox = out_interface.bbox_3d()
|
||||
|
||||
# Determine alignment point depending on requested alignment type
|
||||
point_out = (out_bbox[1] + out_bbox[0]) / 2
|
||||
point_self = (self_bbox[1] + self_bbox[0]) / 2
|
||||
if alignment == 'center':
|
||||
pass # No modification needed
|
||||
elif alignment == 'top':
|
||||
point_out[1] = out_bbox[1][1] # Use max in Y
|
||||
point_self[1] = self_bbox[1][1]
|
||||
elif alignment == 'bottom':
|
||||
point_out[1] = out_bbox[0][1] # Use min in Y
|
||||
point_self[1] = self_bbox[0][1]
|
||||
elif alignment == 'right':
|
||||
point_out[0] = out_bbox[0][0] # Use min in X
|
||||
point_self[0] = self_bbox[0][0]
|
||||
elif alignment == 'left':
|
||||
point_out[0] = out_bbox[1][0] # Use max in X
|
||||
point_self[0] = self_bbox[1][0]
|
||||
else:
|
||||
raise ValueError(
|
||||
f'{self.__class__.__name__}::{self.name}::ERROR::'
|
||||
f'Uknown alignment type ({alignment}) requested in place_by_interface().'
|
||||
f' Available types: center, top, bottom, left, right')
|
||||
|
||||
# Add a gap outside the current
|
||||
if gap_dir is None:
|
||||
full_bbox = self.bbox3D()
|
||||
center = (full_bbox[0] + full_bbox[1]) / 2
|
||||
mid_self = (self_bbox[1] + self_bbox[0]) / 2
|
||||
gap_dir = mid_self - center
|
||||
|
||||
gap_dir = gap * gap_dir / np.linalg.norm(gap_dir)
|
||||
diff = point_out - (point_self + gap_dir)
|
||||
|
||||
self.translate_by(diff)
|
||||
|
||||
# NOTE: Norm evaluation of vertex set will fail
|
||||
# for the alignment of 2D panels, where they are likely
|
||||
# to be in one line or in a panel plane instead of
|
||||
# the interface place -- so I'm not using norms for gap estimation
|
||||
|
||||
# TODO Estimate rotation
|
||||
# TODO not just placement by the midpoint of the interfaces?
|
||||
# It created a little overlap when both interfaces are angled a little differently
|
||||
return self
|
||||
|
||||
|
||||
Reference in New Issue
Block a user