Example #1
0
 def test_includes_point_buffer(self):
     '''The point is slightly outside the line, so by increasing the buffer
     we use to test collinearity between vectors we make it pass'''
     segment = LineSegment(Point(0, 0), Point(1, 0))
     self.assertTrue(segment.includes_point(Point(0.5, 0)))
     self.assertFalse(segment.includes_point(Point(0.5, 0.01)))
     self.assertTrue(segment.includes_point(Point(0.5, 0.01), 0.01))
Example #2
0
 def perimeter(self):
     return [
         LineSegment(self.top_left(), self.top_right()),
         LineSegment(self.top_right(), self.bottom_right()),
         LineSegment(self.bottom_right(), self.bottom_left()),
         LineSegment(self.bottom_left(), self.top_left())
     ]
 def test_elements_multiple_segments_path(self):
     [a, b, c, d] = self._road_points()
     lane = Street.from_control_points([a, b, c, d]).lane_at(0)
     geometry = lane.path_for(PolylineGeometry)
     expected_elements = [
         LineSegment(a, b),
         LineSegment(b, c),
         LineSegment(c, d)
     ]
     self.assertEquals(geometry.elements(), expected_elements)
    def test_elements_short_S_path(self):
        a = Point(0, 0)
        b = Point(50, 0)
        c = Point(50, 10)
        d = Point(100, 10)

        lane = Street.from_control_points([a, b, c, d]).lane_at(0)
        geometry = lane.path_for(LinesAndArcsGeometry)

        expected_elements = [
            LineSegment(a, Point(45, 0)),
            Arc(Point(45, 0), 0, 5, 90),
            Arc(Point(50, 5), 90, 5, -90),
            LineSegment(Point(55, 10), d)]
        self.assertAlmostEqual(geometry.elements(), expected_elements)
Example #5
0
    def test_includes_point_3d(self):
        segment = LineSegment(Point(0, 0, 0), Point(1, 1, 1))

        self.assertTrue(segment.includes_point(Point(0, 0, 0)))
        self.assertTrue(segment.includes_point(Point(1, 1, 1)))
        self.assertTrue(segment.includes_point(Point(0.5, 0.5, 0.5)))

        self.assertFalse(segment.includes_point(Point(1, 1, 1.01)))
        self.assertFalse(segment.includes_point(Point(1, 1.01, 1)))
        self.assertFalse(segment.includes_point(Point(1.01, 1, 1)))
        self.assertFalse(segment.includes_point(Point(-0.01, 0, 0)))
        self.assertFalse(segment.includes_point(Point(0, -0.01, 0)))
        self.assertFalse(segment.includes_point(Point(0, 0, -0.01)))
        self.assertFalse(segment.includes_point(Point(0.51, 0.5, 0.5)))
        self.assertFalse(segment.includes_point(Point(0.5, 0.51, 0.5)))
        self.assertFalse(segment.includes_point(Point(0.5, 0.5, 0.51)))
 def test_elements_single_segment_path(self):
     a = Point(0, 0)
     b = Point(50, -50)
     lane = Street.from_control_points([a, b]).lane_at(0)
     geometry = lane.path_for(LinesAndArcsGeometry)
     expected_elements = [LineSegment(a, b)]
     self.assertAlmostEqual(geometry.elements(), expected_elements)
Example #7
0
 def polyline_from_points(cls, points):
     if len(points) < 2:
         raise ValueError(
             "{0} points given. At least two points are needed".format(
                 points))
     pairs = zip(points, points[1:])
     segments = map(lambda (p1, p2): LineSegment(p1, p2), pairs)
     return cls(segments)
    def test_elements_two_non_collinear_segment_path(self):
        a = Point(0, 0)
        b = Point(50, 0)
        c_up = Point(100, 10)
        c_down = Point(100, -10)

        lane = Street.from_control_points([a, b, c_up]).lane_at(0)
        geometry = lane.path_for(LinesAndArcsGeometry)

        expected_elements = [
            LineSegment(a, Point(45.0, 0.0)),
            Arc(Point(45.0, 0.0), 0.0, 50.49509756, 11.30993247),
            LineSegment(Point(54.90290337, 0.98058067), c_up)]
        self.assertAlmostEqual(geometry.elements(), expected_elements)

        lane = Street.from_control_points([a, b, c_down]).lane_at(0)
        geometry = lane.path_for(LinesAndArcsGeometry)

        expected_elements = [
            LineSegment(a, Point(45.0, 0.0)),
            Arc(Point(45.0, 0.0), 0.0, 50.49509756, -11.30993247),
            LineSegment(Point(54.90290337, -0.98058067), c_down)]
        self.assertAlmostEqual(geometry.elements(), expected_elements)
Example #9
0
    def build_path_and_waypoints(cls, lane, mapped_centers):
        if lane.road_nodes_count() < 2:
            raise ValueError(
                "At least two nodes are required to build a geometry")

        road_nodes = lane.road_nodes()
        node_pairs = zip(road_nodes, road_nodes[1:])
        path = Path()
        waypoints = []
        for start_node, end_node in node_pairs:
            start_point = mapped_centers[start_node]
            end_point = mapped_centers[end_node]
            segment = LineSegment(start_point, end_point)
            path.add_element(segment)
            waypoints.append(cls._new_waypoint(lane, segment, start_node))
        # The last waypoint is missing, as we have been processing the
        # start of each segment
        waypoint = cls._new_waypoint(lane, path.last_element(), road_nodes[-1],
                                     False)
        waypoints.append(waypoint)
        return (path, waypoints)
Example #10
0
 def connect(cls, exit_waypoint, entry_waypoint):
     return LineSegment(exit_waypoint.center(), entry_waypoint.center())
    def build_path_and_waypoints(cls, lane, mapped_centers):
        if lane.road_nodes_count() < 2:
            raise ValueError(
                "At least two nodes are required to build a geometry")

        road_nodes = list(lane.road_nodes())
        is_circular = mapped_centers[road_nodes[0]].almost_equal_to(
            mapped_centers[road_nodes[-1]], 5)
        path = Path()
        waypoints = []

        previous_node = road_nodes.pop(0)
        previous_point = mapped_centers[previous_node]

        nodes_count = len(road_nodes)

        for index, node in enumerate(road_nodes):
            point = mapped_centers[node]
            is_last_node = index + 1 == nodes_count

            if is_last_node:
                if is_circular:
                    next_point = mapped_centers[road_nodes[0]]
                else:
                    next_point = None
            else:
                next_point = mapped_centers[road_nodes[index + 1]]

            if path.is_empty():
                previous_element_end_point = previous_point
            else:
                previous_element_end_point = path.element_at(-1).end_point()

            if next_point is None:
                element = LineSegment(previous_element_end_point, point)
                path.add_element(element)
                waypoints.append(
                    cls._new_waypoint(lane, element, previous_node))
                waypoints.append(
                    cls._new_waypoint(lane, element, road_nodes[-1], False))
            else:
                previous_vector = point - previous_point
                next_vector = next_point - point
                if previous_vector.is_collinear_with(next_vector):
                    element = LineSegment(previous_element_end_point, point)
                    path.add_element(element)
                    waypoints.append(
                        cls._new_waypoint(lane, element, previous_node))
                    if is_last_node:
                        waypoints.append(
                            cls._new_waypoint(lane, element, road_nodes[0],
                                              False))
                else:

                    inverted_previous_segment = LineSegment(
                        point, previous_point)
                    real_inverted_previous_segment = LineSegment(
                        point, previous_element_end_point)
                    next_segment = LineSegment(point, next_point)
                    if is_last_node:
                        real_next_segment = LineSegment(
                            point,
                            path.element_at(0).end_point())
                        delta = min(real_inverted_previous_segment.length(),
                                    real_next_segment.length(), 5)
                    else:
                        delta = min(real_inverted_previous_segment.length(),
                                    next_segment.length() / 2.0, 5)

                    previous_segment_new_end_point = real_inverted_previous_segment.point_at_offset(
                        delta)
                    next_segment_new_start_point = next_segment.point_at_offset(
                        delta)

                    previous_segment = LineSegment(
                        previous_element_end_point,
                        previous_segment_new_end_point)

                    # Try to avoid small segments
                    if previous_segment.length() < 0.25:
                        # `- 1e-10` to avoid length overflow due to floating point math
                        new_delta = delta + previous_segment.length() - 1e-10
                        if next_segment.length() > new_delta:
                            previous_segment_new_end_point = real_inverted_previous_segment.point_at_offset(
                                new_delta)
                            next_segment_new_start_point = next_segment.point_at_offset(
                                new_delta)
                            previous_segment = LineSegment(
                                previous_element_end_point,
                                previous_segment_new_end_point)

                    angle_between_vectors = previous_vector.angle(next_vector)
                    d2 = previous_segment_new_end_point.squared_distance_to(
                        next_segment_new_start_point)
                    cos = math.cos(math.radians(angle_between_vectors))
                    radius = math.sqrt(d2 / (2.0 * (1.0 - cos)))

                    # If there should be no segment, just an arc. Use previous_element_end_point to
                    # avoid rounding errors and make a perfect overlap
                    if previous_segment.length() < 1e-8:
                        if path.not_empty():
                            heading = path.element_at(-1).end_heading()
                        else:
                            heading = inverted_previous_segment.inverted(
                            ).start_heading()
                        connection_arc = Arc(previous_element_end_point,
                                             heading, radius,
                                             angle_between_vectors)
                        path.add_element(connection_arc)
                        waypoints.append(
                            cls._new_waypoint(lane, connection_arc, node))

                        if not connection_arc.end_point().almost_equal_to(
                                next_segment_new_start_point, 3):
                            raise RuntimeError(
                                "Expecting arc end {0} to match next segment entry point {1}"
                                .format(connection_arc.end_point(),
                                        next_segment_new_start_point))
                    else:
                        heading = inverted_previous_segment.inverted(
                        ).start_heading()
                        connection_arc = Arc(previous_segment_new_end_point,
                                             heading, radius,
                                             angle_between_vectors)

                        path.add_element(previous_segment)
                        waypoints.append(
                            cls._new_waypoint(lane, previous_segment,
                                              previous_node))

                        path.add_element(connection_arc)
                        waypoints.append(
                            cls._new_waypoint(lane, connection_arc, node))

                        if not connection_arc.end_point().almost_equal_to(
                                next_segment_new_start_point, 3):
                            raise RuntimeError(
                                "Expecting arc end {0} to match next segment entry point {1}"
                                .format(connection_arc.end_point(),
                                        next_segment_new_start_point))

                    if is_last_node:
                        if connection_arc.end_point().distance_to(
                                path.element_at(1).start_point()) < 1e-8:
                            path.remove_first_element()
                            waypoints.pop(0)
                        else:
                            first_element = path.element_at(0)
                            new_first_element = LineSegment(
                                connection_arc.end_point(),
                                first_element.end_point())
                            path.replace_first_element(new_first_element)
                            waypoints[0] = cls._new_waypoint(
                                lane, new_first_element,
                                lane.road_nodes()[0])
                        waypoints.append(
                            cls._new_waypoint(lane, connection_arc,
                                              road_nodes[0], False))

            previous_node = node
            previous_point = mapped_centers[previous_node]
        return (path, waypoints)
 def test_elements_single_segment_path(self):
     a, b = self._road_points()[0:2]
     lane = Street.from_control_points([a, b]).lane_at(0)
     geometry = lane.path_for(PolylineGeometry)
     expected_elements = [LineSegment(a, b)]
     self.assertEquals(geometry.elements(), expected_elements)
Example #13
0
    def test_is_orthogonal_to_non_touching_segments(self):
        target_segment = LineSegment(Point(2, 2), Point(4, 2))
        orthogonal_segment = LineSegment(Point(3, 1), Point(3, 1.9))
        non_orthogonal_segment = LineSegment(Point(3, 1), Point(3.01, 1.9))
        self.assertTrue(target_segment.is_orthogonal_to(orthogonal_segment))
        self.assertFalse(
            target_segment.is_orthogonal_to(non_orthogonal_segment))

        target_segment = LineSegment(Point(2, 2), Point(2, 4))
        orthogonal_segment = LineSegment(Point(1, 3), Point(1.9, 3))
        non_orthogonal_segment = LineSegment(Point(1, 3), Point(1.9, 3.01))
        self.assertTrue(target_segment.is_orthogonal_to(orthogonal_segment))
        self.assertFalse(
            target_segment.is_orthogonal_to(non_orthogonal_segment))

        target_segment = LineSegment(Point(2, 2), Point(5, 5))
        orthogonal_segment = LineSegment(Point(5, 3), Point(4.1, 3.9))
        non_orthogonal_segment = LineSegment(Point(5.01, 3), Point(3.9, 3.9))
        self.assertTrue(target_segment.is_orthogonal_to(orthogonal_segment))
        self.assertFalse(
            target_segment.is_orthogonal_to(non_orthogonal_segment))
Example #14
0
File: demo.py Project: m43/fer-ooup
# -*- coding: utf-8 -*-

from tkinter import *

from geometry.line_segment import LineSegment
from geometry.oval import Oval
from gui import Painter

if __name__ == '__main__':
    objects = []

    objects.append(LineSegment())
    objects.append(Oval())

    root = Tk()
    root.title("ma paint")
    root.geometry("600x741+210+120")
    painter = Painter(objects)
    root.mainloop()
Example #15
0
    def test_extended_by(self):
        original = LineSegment(Point(0, 0), Point(0, 1))
        expected = LineSegment(Point(0, 0), Point(0, 2))
        self.assertAlmostEqual(original.extended_by(1), expected)

        original = LineSegment(Point(0, 0), Point(1, 0))
        expected = LineSegment(Point(0, 0), Point(3, 0))
        self.assertAlmostEqual(original.extended_by(2), expected)

        original = LineSegment(Point(0, 0), Point(1, 1))
        expected = LineSegment(Point(0, 0), Point(2, 2))
        self.assertAlmostEqual(original.extended_by(sqrt(2)), expected)
Example #16
0
    def test_two_segments_intersect(self):
        first_segment = LineSegment(Point(1, 0), Point(3, 4))
        second_segment = LineSegment(Point(1, 4), Point(3, 0))
        non_intersect_segment = LineSegment(Point(3, 1), Point(3, 2))
        self.assertEqual(first_segment.find_intersection(second_segment),
                         [Point(2, 2, 0)])
        self.assertEqual(
            first_segment.find_intersection(non_intersect_segment), [])

        first_segment = LineSegment(Point(28.5299698219, 160.06688421),
                                    Point(-48.1969708416, -28.3309145497))
        second_segment = LineSegment(Point(-193.740103155, 132.470681),
                                     Point(193.740103155, 132.470681))
        non_intersect_segment = LineSegment(Point(193.740103155, 132.470681),
                                            Point(193.740103155, -132.470681))
        self.assertAlmostEqual(first_segment.find_intersection(second_segment),
                               [Point(17.2911323186, 132.470681, 0)])
        self.assertEqual(
            first_segment.find_intersection(non_intersect_segment), [])

        # Intersection happens in the edges
        first_segment = LineSegment(Point(27.78, -86.73), Point(22.79, -77.32))
        second_segment = LineSegment(Point(18.39, -78.46),
                                     Point(22.79, -77.32))
        self.assertAlmostEqual(first_segment.find_intersection(second_segment),
                               [Point(22.79, -77.32)])
    def connect(cls, exit_waypoint, entry_waypoint):
        if abs(exit_waypoint.heading() - entry_waypoint.heading()) < 1e-3:
            waypoints_angle = math.degrees(exit_waypoint.center().yaw(
                entry_waypoint.center()))
            if abs(exit_waypoint.heading() - waypoints_angle) < 1e-3:
                # Waypoints are in collinear lanes and can be connected by a line
                # segment with the same heading
                return LineSegment(exit_waypoint.center(),
                                   entry_waypoint.center())
            else:
                # Waypoints are in collinear lanes but have different offsets,
                # so they must be connected by an S-shaped path
                exit_line = exit_waypoint.defining_line()
                entry_line = entry_waypoint.defining_line()
                cutting_line = entry_line.perpendicular_line_at(
                    entry_waypoint.center())

                delta_length = (exit_waypoint.center() -
                                exit_line.intersection(cutting_line)).norm()
                segment_extension = delta_length / 5.0
                exit_extension = LineSegment.from_point_and_heading(
                    exit_waypoint.center(), exit_waypoint.heading(),
                    segment_extension)
                entry_extension = LineSegment.from_point_and_heading(
                    entry_waypoint.center(),
                    entry_waypoint.heading() + 180, segment_extension)
                connecting_segment = LineSegment(exit_extension.end_point(),
                                                 entry_extension.end_point())
                connecting_segment = connecting_segment.extended_by(
                    -segment_extension).inverted()
                connecting_segment = connecting_segment.extended_by(
                    -segment_extension).inverted()

                start_arc = cls._build_arc(exit_waypoint.center(),
                                           exit_waypoint.heading(),
                                           connecting_segment.start_point(),
                                           connecting_segment.start_heading())
                end_arc = cls._build_arc(connecting_segment.end_point(),
                                         connecting_segment.end_heading(),
                                         entry_waypoint.center(),
                                         entry_waypoint.heading())
                path = Path()
                path.add_element(start_arc)
                path.add_element(connecting_segment)
                path.add_element(end_arc)
                return path

        else:
            exit_point = exit_waypoint.center()
            exit_line = exit_waypoint.defining_line()

            entry_point = entry_waypoint.center()
            entry_line = entry_waypoint.defining_line()

            intersection = exit_line.intersection(entry_line)

            exit_distance = exit_point.distance_to(intersection)
            entry_distance = entry_point.distance_to(intersection)

            path = None
            delta = abs(exit_distance - entry_distance)

            if delta > 1e-1:
                path = Path()
                if exit_distance > entry_distance:
                    end_point = exit_point + (exit_waypoint.heading_vector() *
                                              delta)
                    segment = LineSegment(exit_point, end_point)
                    arc = cls._build_arc(end_point, exit_waypoint.heading(),
                                         entry_point, entry_waypoint.heading())
                    path.add_element(segment)
                    path.add_element(arc)
                else:
                    start_point = entry_point - (
                        entry_waypoint.heading_vector() * delta)
                    arc = cls._build_arc(exit_point, exit_waypoint.heading(),
                                         start_point, entry_waypoint.heading())
                    segment = LineSegment(arc.end_point(), entry_point)
                    path.add_element(arc)
                    path.add_element(segment)
                return path
            else:
                return cls._build_arc(exit_point, exit_waypoint.heading(),
                                      entry_point, entry_waypoint.heading())