示例#1
0
    def make(self):
        """Generates path from start pin to end pin."""
        p = self.parse_options()
        anchors = p.anchors

        # Set the CPW pins and add the points/directions to the lead-in/out arrays
        self.set_pin("start")
        self.set_pin("end")

        # Align the lead-in/out to the input options set from the user
        start_point = self.set_lead("start")
        end_point = self.set_lead("end")

        self.intermediate_pts = OrderedDict()
        for arc_num, coord in anchors.items():
            arc_pts = self.connect_astar_or_simple(self.get_tip(),
                                                   QRoutePoint(coord))
            if arc_pts is None:
                self.intermediate_pts[arc_num] = [coord]
            else:
                self.intermediate_pts[arc_num] = np.concatenate(
                    [arc_pts, [coord]], axis=0)
        arc_pts = self.connect_astar_or_simple(self.get_tip(), end_point)
        if arc_pts is not None:
            self.intermediate_pts[len(anchors)] = np.array(arc_pts)

        # concatenate all points, transforming the dictionary into a single numpy array
        self.trim_pts()
        self.intermediate_pts = np.concatenate(list(
            self.intermediate_pts.values()),
                                               axis=0)

        # Make points into elements
        self.make_elements(self.get_points())
示例#2
0
    def make(self):
        """Generates path from start pin to end pin."""
        p = self.parse_options()
        anchors = p.anchors
        between_anchors = p.between_anchors

        # Set the CPW pins and add the points/directions to the lead-in/out arrays
        self.set_pin("start")
        self.set_pin("end")

        # Align the lead-in/out to the input options set from the user
        start_point = self.set_lead("start")
        end_point = self.set_lead("end")

        # approximate length needed for individual meanders
        # the meander algorithm directly reads from self._length_segment
        count_meanders_list = [
            1 if x == "M" else 0 for x in list(between_anchors.values())
        ]
        self._length_segment = None
        if any(count_meanders_list):
            self._length_segment = ((self.p.total_length - (self.head.length + self.tail.length) \
                                   - self.free_manhattan_length_anchors()) / sum(count_meanders_list)) \
                                   + (self.free_manhattan_length_anchors() / len(count_meanders_list))

        # find the points to connect between each pair of anchors, or between anchors and leads
        # at first, store points "per segment" in a dictionary, so it is easier to apply length requirements
        self.intermediate_pts = OrderedDict()
        meanders = set()
        for arc_num, coord in anchors.items():
            # determine what is the connection strategy for this pair, based on user inputs
            connect_method = self.select_connect_method(arc_num)
            if connect_method == self.connect_meandered:
                meanders.add(arc_num)
            # compute points connecting the anchors, all but the last
            arc_pts = connect_method(self.get_tip(), QRoutePoint(coord))
            if arc_pts is None:
                self.intermediate_pts[arc_num] = [coord]
            else:
                self.intermediate_pts[arc_num] = np.concatenate(
                    [arc_pts, [coord]], axis=0)
        # compute last connection point to the output QRouteLead
        connect_method = self.select_connect_method(len(anchors))
        if connect_method == self.connect_meandered:
            meanders.add(len(anchors))
        arc_pts = connect_method(self.get_tip(), end_point)
        if arc_pts is not None:
            self.intermediate_pts[len(anchors)] = np.array(arc_pts)

        # concatenate all points, transforming the dictionary into a single numpy array
        self.trim_pts()
        dictionary_intermediate_pts = self.intermediate_pts
        self.intermediate_pts = np.concatenate(list(
            self.intermediate_pts.values()),
                                               axis=0)

        if any(count_meanders_list):
            # refine length of meanders
            total_delta_length = self.p.total_length - self.length
            individual_delta_length = total_delta_length / len(meanders)
            for m in meanders:
                arc_pts = dictionary_intermediate_pts[m][:-1]
                if m == 0:
                    meander_start_point = start_point
                else:
                    meander_start_point = QRoutePoint(anchors[m - 1])
                if m == len(anchors):
                    meander_end_point = end_point
                else:
                    meander_end_point = QRoutePoint(anchors[m])
                dictionary_intermediate_pts[m] = self.adjust_length(
                    individual_delta_length, arc_pts, meander_start_point,
                    meander_end_point)
                dictionary_intermediate_pts[m] = np.concatenate(
                    [dictionary_intermediate_pts[m], [anchors[m]]], axis=0)
        self.intermediate_pts = np.concatenate(list(
            dictionary_intermediate_pts.values()),
                                               axis=0)

        # Make points into elements
        self.make_elements(self.get_points())
示例#3
0
    def connect_astar_or_simple(self, start_pt: QRoutePoint,
                                end_pt: QRoutePoint) -> list:
        """Connect start and end via A* algo if connect_simple doesn't work.

        Args:
            start_direction (np.array): Vector indicating direction of starting point
            start (np.array): 2-D coordinates of first anchor
            end (np.array): 2-D coordinates of second anchor

        Returns:
            List of vertices of a CPW going from start to end

        Raises:
            QiskitMetalDesignError: If the connect_simple() has failed.
        """

        start_direction = start_pt.direction
        start = start_pt.position
        end_direction = end_pt.direction
        end = end_pt.position

        step_size = self.parse_options().step_size

        starting_dist = sum(
            abs(end - start))  # Manhattan distance between start and end
        key_starting_point = (starting_dist, start[0], start[1])
        pathmapper = {key_starting_point: [starting_dist, [start]]}
        # pathmapper maps tuple(total length of the path from self.start + Manhattan distance to destination, coordx, coordy) to [total length of
        # path from self.start, path]
        visited = set(
        )  # maintain record of points we've already visited to avoid self-intersections
        visited.add(tuple(start))
        # TODO: add to visited all of the current points in the route, to prevent self intersecting
        priority_queue = list()  # A* priority queue. Implemented as heap
        priority_queue.append(key_starting_point)
        # Elements in the heap are ordered by the following:
        # 1. The total length of the path from self.start + Manhattan distance to destination
        # 2. The x coordinate of the latest point
        # 3. The y coordinate of the latest point

        while priority_queue:
            tot_dist, x, y = heapq.heappop(
                priority_queue
            )  # tot_dist is the total length of the path from self.start + Manhattan distance to destination
            length_travelled, current_path = pathmapper[(tot_dist, x, y)]
            # Look in forward, left, and right directions a fixed distance away.
            # If the line segment connecting the current point and this next one does
            # not collide with any bounding boxes in design.components, add it to the
            # list of neighbors.
            neighbors = list()
            if len(current_path) == 1:
                # At starting point -> initial direction is start direction
                direction = start_direction
            else:
                # Beyond starting point -> look at vector difference of last 2 points along path
                direction = current_path[-1] - current_path[-2]
            # The dot product between direction and the vector connecting the current
            # point and a potential neighbor must be non-negative to avoid retracing.

            # Check if connect_simple works at each iteration of A*
            try:
                simple_path = self.connect_simple(
                    QRoutePoint(np.array([x, y]), direction),
                    QRoutePoint(end, end_direction))
            except QiskitMetalDesignError:
                simple_path = None
                # try the pathfinder algorithm
                pass

            if simple_path is not None:
                current_path.extend(simple_path)
                return current_path

            for disp in [
                    np.array([0, 1]),
                    np.array([0, -1]),
                    np.array([1, 0]),
                    np.array([-1, 0])
            ]:
                # Unit displacement in 4 cardinal directions
                if mao.dot(disp, direction) >= 0:
                    # Ignore backward direction
                    curpt = current_path[-1]
                    nextpt = curpt + step_size * disp
                    if self.unobstructed([curpt, nextpt]):
                        neighbors.append(nextpt)
            for neighbor in neighbors:
                if tuple(neighbor) not in visited:
                    new_remaining_dist = sum(abs(end - neighbor))
                    new_length_travelled = length_travelled + step_size
                    new_path = current_path + [neighbor]
                    if new_remaining_dist < 10**-8:
                        # Destination has been reached within acceptable error tolerance (errors due to rounding in Python)
                        return new_path[:-1] + [
                            end
                        ]  # Replace last element of new_path with end since they're basically the same
                    heapq.heappush(priority_queue,
                                   (new_length_travelled + new_remaining_dist,
                                    neighbor[0], neighbor[1]))
                    pathmapper[(new_length_travelled + new_remaining_dist,
                                neighbor[0], neighbor[1])] = [
                                    new_length_travelled, new_path
                                ]
                    visited.add(tuple(neighbor))
        return [
        ]  # Shouldn't actually reach here - if it fails, there's a convergence issue