예제 #1
0
    def add_straight_segment_to_intersection(self, line_origin, line_angle,
                                             **line_kw):
        """
        Add a straight line until it intersects with an other line.

        The other line is described by the support vector and the line angle.

        :param line_origin: Intersection line support vector.
        :param line_angle: Intersection line angle.
        :param line_kw: Parameters passed on to add_straight_segment.
        :raise ArithmeticError: When there is no intersection due to being parallel or if
                                the intersection is behind the waveguide.
        """
        r1 = self._current_port.origin
        r2 = np.array(line_origin)

        try:
            intersection_point, distance = find_line_intersection(
                r1, self.angle, r2, line_angle)
            if np.isclose(distance[0], 0):
                return self
            elif distance[0] < 0:
                raise ArithmeticError(
                    'No forward intersection of waveguide with given line')
            self.add_straight_segment(distance[0], **line_kw)
        except linalg.LinAlgError:
            # We do not find an intersection if lines are parallel
            raise ArithmeticError(
                'There is no intersection with the given line')
        return self
예제 #2
0
    def add_route_single_circle_to(self,
                                   final_coordinates,
                                   final_angle,
                                   final_width=None,
                                   max_bend_strength=None,
                                   on_line_only=False):
        """
        Connect two points by straight lines and one circle.

        Works for geometries like round edges and others. The final straight line can also be omitted so that
        the waveguide only end on the line described by the support vector and angle.

        By default, this method tries to route to the target with the greatest possible circle. But the valid
        bending range may be limited via the `max_bend_strength` parameter.

        This method does not work for geometries which cannot be connected only by straight lines and one
        circle, such as parallel lines etc.

        Still, this method can prove extremely useful for routing to i.e. grating couplers etc.

        :param final_coordinates: Final destination point.
        :param final_angle: Final angle of the waveguide.
        :param final_width: Final width of the waveguide.
        :param max_bend_strength: The maximum allowed bending radius.
        :param on_line_only: Omit the last straight line and only route to described line.
        """
        # We are given an out angle, but the internal math is for inward pointing lines
        final_angle = normalize_phase(final_angle) + np.pi
        final_width = final_width if final_width is not None else self.width
        # We need to to some linear algebra. We first find the intersection of the two waveguides
        r1 = self._current_port.origin
        r2 = np.array(final_coordinates)
        intersection_point, distance = find_line_intersection(
            r1, self.angle, r2, final_angle)

        assert distance[
            0] >= 0, 'Origin waveguide is too close to target. No curve possible'
        assert on_line_only or distance[
            1] >= 0, 'Target position is too close to target. No curve possible'

        # Calculate the angle bisector
        u1 = np.array([np.cos(self.angle), np.sin(self.angle)])
        u2 = np.array([np.cos(final_angle), np.sin(final_angle)])
        u_half = u1 + u2
        half_angle = np.arctan2(u_half[1], u_half[0])
        diff_angle = normalize_phase(self.angle - final_angle - np.pi)

        _, r1 = find_line_intersection(r1, self.angle + np.pi / 2,
                                       intersection_point, half_angle)

        if not on_line_only:
            max_poss_radius = min(
                np.abs([
                    r1[0], distance[0] / np.tan(diff_angle / 2),
                    distance[1] / np.tan(diff_angle / 2)
                ]))
        else:
            max_poss_radius = min(
                np.abs([r1[0], distance[0] / np.tan(diff_angle / 2)]))

        radius = min([max_bend_strength, max_poss_radius
                      ]) if max_bend_strength is not None else max_poss_radius
        d = abs(radius * np.tan(diff_angle / 2))
        if on_line_only:
            segments = [distance[0] - d, radius * diff_angle]
        else:
            segments = [distance[0] - d, radius * diff_angle, distance[1] - d]
        segment_ratio = np.cumsum(segments / sum(segments))
        segment_widths = [(final_width - self.current_port.width) * ratio +
                          self.current_port.width for ratio in segment_ratio]
        tmp_wg = Waveguide.make_at_port(self._current_port)
        tmp_wg.add_straight_segment(length=distance[0] - d,
                                    final_width=segment_widths[0])
        tmp_wg.add_bend(-diff_angle, radius, final_width=segment_widths[1])
        if not on_line_only:
            tmp_wg.add_straight_segment(distance[1] - d,
                                        final_width=segment_widths[2])

        self._segments.append(
            (self._current_port.copy(), tmp_wg.get_shapely_object(),
             tmp_wg.get_shapely_outline(), tmp_wg.length,
             tmp_wg.center_coordinates))
        self._current_port = tmp_wg.current_port

        return self
예제 #3
0
 def test_find_line_intersection(self):
     test_intersection = find_line_intersection(np.array((2, 0)), np.pi / 2,
                                                np.array((0, 1)), 0)
     npt.assert_almost_equal(test_intersection[0], (2, 1))
     npt.assert_almost_equal(test_intersection[1], (1, 2))