Source code for trnsystor.anchorpoint

"""AnchorPoint module."""

import itertools

from shapely.geometry import MultiPoint


[docs]class AnchorPoint(object): """Handles the anchor point. There are 6 anchor points around a component.""" def __init__(self, model, offset=20, height=40, width=40): """Initialize object. Args: model (Component): The Component. offset (float): The offset to give the anchor points from the center of the model position. height (float): The height of the component in points. width (float): The width of the component in points. """ self.offset = offset self.model = model self.height = height self.width = width
[docs] def studio_anchor(self, other, loc): """Return the studio anchor based on a location. Args: other (TrnsysModel): The other TrnsysModel used to find the anchor of self. loc (2-tuple): A 2-tuple of location, eg.: ("best", "best") or of :attr:`anchor_ids`. """ if "best" not in loc: return loc u_loc, v_loc = loc if u_loc == "best": u_loc, _ = self.find_best_anchors(other) if v_loc == "best": _, v_loc = self.find_best_anchors(other) return u_loc, v_loc
[docs] def find_best_anchors(self, other): """Find best anchor points to connect self and other.""" dist = {} for u in self.anchor_points.values(): for v in other.anchor_points.values(): dist[((u.x, u.y), (v.x, v.y))] = u.distance(v) (u_coords, v_coords), distance = sorted(dist.items(), key=lambda kv: kv[1])[0] u_loc, v_loc = ( self.reverse_anchor_points[u_coords], AnchorPoint(other).reverse_anchor_points[v_coords], ) return u_loc, v_loc
@property def anchor_points(self): """Return dict of anchor points str->tuple.""" return self.get_octo_pts_dict(self.offset) @property def reverse_anchor_points(self): """Return dict of anchor points tuple->str.""" pts = self.get_octo_pts_dict(self.offset) return {(pt.x, pt.y): key for key, pt in pts.items()} @property def studio_anchor_mapping(self): """Return dict of anchor mapping str->tuple.""" from shapely.affinity import translate p_ = {} minx, miny, maxx, maxy = MultiPoint( [p for p in self.anchor_points.values()] ).bounds for k, p in self.anchor_points.items(): p_[k] = translate(p, -minx, -maxy) minx, miny, maxx, maxy = MultiPoint([p for p in p_.values()]).bounds for k, p in p_.items(): p_[k] = translate(p, 0, -miny) return { k: tuple(itertools.chain(*tuple((map(abs, p) for p in p.coords)))) for k, p in p_.items() } @property def studio_anchor_reverse_mapping(self): """Return dict of anchor mapping tuple->str.""" return { (0, 0): "top-left", (20, 0): "top-center", (40, 0): "top-right", (40, 20): "center-right", (40, 40): "bottom-right", (20, 40): "bottom-center", (0, 40): "bottom-left", (0, 20): "center-left", }
[docs] def get_octo_pts_dict(self, offset=10): """Define 8-anchor :class:`Point` around the :class:`TrnsysModel`. In cartesian space and returns a named-dict with human readable meaning. These points are equally dispersed at the four corners and 4 edges of the center, at distance = :attr:`offset`. See Also: - :meth:`trnsystor.component.Component.set_link_style` - :class:`trnsystor.linkstyle.LinkStyle` Args: offset (float): The offset around the center point of :attr:`self`. Note: In the Studio, a component has 8 anchor points at the four corners and four edges. units.Links can be created on these connections. .. image:: ../_static/anchor-pts.png """ from shapely.affinity import translate center = self.centroid xy_offset = { "top-left": (-offset, offset), "top-center": (0, offset), "top-right": (offset, offset), "center-right": (offset, 0), "bottom-right": (-offset, -offset), "bottom-center": (0, -offset), "bottom-left": (-offset, -offset), "center-left": (-offset, 0), } return {key: translate(center, *offset) for key, offset in xy_offset.items()}
@property def centroid(self): """Return centroid of self.""" return self.model.studio.position