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
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
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))