示例#1
0
    def point_position(self, in_anchor, offset, out_anchor=None):
        out_anchor = out_anchor or self.state

        if in_anchor == "in" and out_anchor == "out":
            return Position(offset, 0, 0)
        if in_anchor == "in" and out_anchor == "branch":
            t = self.intermediate_branch_t[max(
                0, min(int(offset / self.branch_length * 100), 99))]
            x, y = self.branch_bezier(t)

            x1, y1 = self.branch_bezier(t - 1e-6)
            x2, y2 = self.branch_bezier(t + 1e-6)
            theta = math.atan2(y2 - y1, x2 - x1)

            return Position(x, y, theta)
        if in_anchor == "branch":
            t = self.intermediate_branch_t[max(
                0, min(99 - int(offset / self.branch_length * 100), 99))]
            x, y = self.branch_bezier(t)

            x1, y1 = self.branch_bezier(t - 1e-6)
            x2, y2 = self.branch_bezier(t + 1e-6)
            theta = math.atan2(y2 - y1, x2 - x1)

            return Position(x, y, theta)
        if in_anchor == "out":
            return Position(32 - offset, 0, math.pi)
示例#2
0
 def relative_positions(self):
     return {
         **super().relative_positions(),
         "out": Position(self.length, 0, 0),
         "left": Position(self.length / 2, -self.length / 2, -math.pi / 2),
         "right": Position(self.length / 2, self.length / 2, math.pi / 2),
     }
示例#3
0
 def relative_positions(self):
     return {
         **super().relative_positions(),
         "out":
         Position(32, 0, 0),
         "branch":
         Position(*self.branch_point, math.tau / 16 * self.coordinate_sign),
     }
示例#4
0
 def point_position(self, in_anchor, offset, out_anchor=None) -> Position:
     if in_anchor == "in":
         return Position(offset, 0, 0)
     elif in_anchor == "out":
         return Position(self.length - offset, 0, math.pi)
     elif in_anchor == "left":
         return Position(self.length / 2, self.length / 2 - offset,
                         -math.pi / 2)
     elif in_anchor == "right":
         return Position(self.length / 2, offset - self.length / 2,
                         math.pi / 2)
     else:
         raise AssertionError
示例#5
0
    def test_anchor_position_bookkeeping(self):
        layout = Layout()
        drawing_area = unittest.mock.Mock()
        layout_drawer = LayoutDrawer(drawing_area, layout)

        piece_1 = Straight(layout=layout, placement=Position(0, 0, 0))
        layout.add_piece(piece_1)

        piece_2 = Straight(layout=layout)
        layout.add_piece(piece_2)

        piece_3 = Straight(layout=layout)
        layout.add_piece(piece_3)

        # Connect them explicitly not out->in, out->in, and check how many are positioned in the layout as we go
        self.assertEqual(2, len(layout_drawer.layout.anchors_qtree))
        piece_1.anchors["out"] += piece_2.anchors["in"]
        self.assertEqual(3, len(layout_drawer.layout.anchors_qtree))
        piece_3.anchors["in"] += piece_2.anchors["out"]
        # for anchor, bbox in layout_drawer.anchors_qtree._bounds.items():
        #     print(f'  {bbox} - {anchor}')
        self.assertEqual(4, len(layout_drawer.layout.anchors_qtree))

        layout.remove_piece(piece_2)
        self.assertEqual(4, len(layout_drawer.layout.anchors_qtree))
        layout.remove_piece(piece_1)
        self.assertEqual(2, len(layout_drawer.layout.anchors_qtree))
        layout.remove_piece(piece_3)
        self.assertEqual(0, len(layout_drawer.layout.anchors_qtree))
示例#6
0
 def on_piece_positioned(self, sender: Piece):
     if self.track_point.position:
         position = self.track_point.position + Position(0, 5, 0)
     else:
         position = None
     if position != self._position:
         self._position = position
         signals.sensor_positioned.send(self)
    def place_piece(self, piece_cls: Type[Piece], x: float, y: float):
        possible_anchors = self.layout.anchors_qtree.intersect(
            (x - 8, y - 8, x + 8, y + 8)
        )
        possible_anchors = [anchor for anchor in possible_anchors if len(anchor) < 2]
        if possible_anchors:
            piece = piece_cls(layout=self.layout)
            possible_anchors[0] += piece.anchors[piece.anchor_names[0]]
        else:
            # Snap to an 8x8 grid
            x = 8 * ((x + 4) // 8)
            y = 8 * ((y + 4) // 8)
            piece = piece_cls(layout=self.layout, placement=Position(x, y, angle=0))

        self.connect_coincident_anchors(piece)
        self.layout.add_piece(piece)
示例#8
0
    def relative_positions(self) -> Dict[str, Position]:
        """Returns a mapping from anchor name to that anchor's relative position.

        The base implementation provides a relative position for the first anchor,
        which should always be backwards out from the piece position (i.e. x=0, y=0,
        theta=pi).

        Subclasses should override and extend this method to provide relative positions
        for other anchors. e.g., for a hypothetical 90° 40R curve piece:

        >>> def relative_positions(self):
        >>>     return {
        >>>         **super().relative_positions(),
        >>>         'out': Position(40, -40, math.pi / 2),
        >>>     }

        This method is used when calculating positions for connected pieces, starting
        from the placement origin (i.e. the piece in a connected subset which has
        `self.placement` set).
        """
        return {self.anchor_names[0]: Position(0, 0, math.pi)}
示例#9
0
            piece_cls = self.piece_mapping[segment_data["type"]]
            node_count = int(segment_data["nodes"])
            assert len(piece_cls.anchor_names) == node_count
            node_ids = [
                int(segment_data[f"node{i}"])
                for i in range(1, node_count + 1)
            ]
            # if segment_data['type'] in self.anchor_name_mapping:
            #     node_ids = [
            #         node_ids[piece_cls.anchor_names.index(anchor_name)]
            #         for anchor_name in self.anchor_name_mapping[segment_data['type']]
            #     ]
            piece_nodes = [nodes[node_id] for node_id in node_ids]
            placement = Position(
                piece_nodes[0]["x"],
                piece_nodes[0]["y"],
                float(segment_data["angle"]) / 360 * math.tau,
            )
            piece = piece_cls(
                layout=layout,
                id=segment.find("index").attrib["value"],
                placement=placement,
                **self.piece_params.get(segment_data["type"], {}),
            )
            layout.add_piece(piece, announce=False)

            for node, anchor_name in zip(piece_nodes, piece.anchor_names):
                if node["anchor"]:
                    node["anchor"] += piece.anchors[anchor_name]
                else:
                    node["anchor"] = piece.anchors[anchor_name]