Пример #1
0
    def point_position(self, a_point, perspective_point=Point3(0, 0, 1)):
        """
        Check the position of a_point w.r.t. the segment on the plane formed by the segment and the point,
        as viewed from the perspective_point
        :param a_point: a Point object
        :param perspective_point: observation point (the default value should be used ONLY when working in 2D)
        :return: False, if the perspective point is COPLANAR with self and the a_point;
                 otherwise, either RIGHT (-1), LEFT (1), BEFORE (-2), BETWEEN (0), or AFTER (2)
        """

        if Point3.are_coplanar(self.start, self.end, a_point,
                               perspective_point):
            return False

        return Point3.orientation(self.start, self.end, a_point,
                                  perspective_point)
Пример #2
0
    def intersects(self, other):
        """
        :param other: Line or Vector
        :return: True if the two segments intersect, False otherwise
        """

        if isinstance(other, (Vector2, Vector3)):
            other = Line([Point3(0, 0, 0), Point3(other)])

        if not isinstance(other, Line):
            raise TypeError(
                "Line.intersects requires a Line or a Vector as parameter")

        l1, l2 = self, other  # handy aliases for the segments

        # in order for two segments to intersect they must lie on the same plane
        if not Point3.are_coplanar(l1.start, l1.end, l2.start, l2.end):
            print("Segments are not COPLANAR")
            return False

        # Ok, the segments are COPLANAR!
        # now, we have two cases to be treated separately: (1) the segments are COLLINEAR, (2) or not

        if l1.is_collinear_with(l2):
            # if COLLINEAR we need to check the relative distances between the extremes of the segments

            # We have only three possible cases where the segments intersect:
            # A) l2 is inside l1 (i.e., both l2 extremes are BETWEEN l1 extremes)
            # B) l1 is inside l2
            # C) none of the above, but one extreme of one of the two segments is BETWEEN the extremes of the other

            # compute the positions of the segments' extremes wrt the other segment
            l2_start_position = Point3.collinear_position(
                l1.start, l1.end, l2.start)
            l2_end_position = Point3.collinear_position(
                l1.start, l1.end, l2.end)
            l1_start_position = Point3.collinear_position(
                l2.start, l2.end, l1.start)
            l1_end_position = Point3.collinear_position(
                l2.start, l2.end, l1.end)

            # case A)
            if l2_start_position == BETWEEN and l2_end_position == BETWEEN:
                return True
            # case B)
            elif l1_start_position == BETWEEN and l1_end_position == BETWEEN:
                return True
            # case C)
            elif any(pos == BETWEEN for pos in [
                    l2_start_position, l2_end_position, l1_start_position,
                    l1_end_position
            ]):
                return True
            else:
                return False

        else:
            # if the two segments are not COLLINEAR, it can still be the case that one of the extremes of
            # one segment is COLLINEAR with the other segment. This case must be treated separately

            # consider l1 as reference segment and check if the extremes of l2 are COLLINEAR with l1
            is_l2_start_collinear = Point3.are_collinear(
                l1.start, l1.end, l2.start)
            is_l2_end_collinear = Point3.are_collinear(l1.start, l1.end,
                                                       l2.end)

            # consider l2 as reference segment and check if the extremes of l1 are COLLINEAR with l2
            is_l1_start_collinear = Point3.are_collinear(
                l2.start, l2.end, l1.start)
            is_l1_end_collinear = Point3.are_collinear(l2.start, l2.end,
                                                       l1.end)

            if is_l2_start_collinear or is_l2_end_collinear or is_l1_start_collinear or is_l1_end_collinear:
                # NOTE: at most one of the above variables can be True, otherwise it means that the two
                # segments are COLLINEAR and we would have entered the if condition above--l1.is_collinear_with(l2).

                # determine which is the reference segment
                ref_segment = l1 if is_l2_start_collinear or is_l2_end_collinear else l2

                # determine which extreme of the other segment is COLLINEAR with the ref_segment
                # assume it is l2.start
                coll_extreme = l2.start
                if ref_segment is l1:
                    if is_l2_end_collinear:
                        coll_extreme = l2.end
                else:
                    if is_l1_start_collinear:
                        coll_extreme = l1.start
                    else:
                        coll_extreme = l2.end

                # the only case when the two segments intersect is when the coll_extreme is positioned
                # BETWEEN the extremes of the reference segment
                return Point3.collinear_position(ref_segment.start,
                                                 ref_segment.end,
                                                 coll_extreme) == BETWEEN

            else:
                # the two segments are in general position. So, to determine if they intersect
                # we need to check the position of the extremes of each segment wrt the other segment.
                # To do this in 3-space we need an observation point that is not on the same plane
                # so, compute an observation point that is not on the same plane

                #  easily, we can take the cross product of the two segments
                v1 = Vector3(l1.end - l1.start)
                v2 = Vector3(l2.end - l2.start)
                v3 = v1.cross(v2)
                observation_point = Point3(v3) + l1.start

                # in order to intersect the extremes of each segment must lie on opposite sides of the other segment
                return \
                    l1.point_position(l2[0], observation_point) * l1.point_position(l2[1], observation_point) < 0 and \
                    l2.point_position(l1[0], observation_point) * l2.point_position(l1[1], observation_point) < 0
Пример #3
0
    def get_renderable_arrays(self):
        """
        traverse the DCEL structure and return a list of vertices and a list of elements for the rendering of the DCEL
        :return: vertices: a list of verices [a, b, c, ...],
        elements: a list of indices [idx_1, idx_2, idx_3, ...] from the list vertices.
         if the DCEL represents a set of point, each index refers a point to be rendered
         if the DCEL represents a linear entity, each pair of indices forms a segment to be rendered
         if the DCEL represents a polygon or a polyhedron, each triplet of indices form a face to be rendered
        """

        from app.geoms.point import Point3
        vertices = list()
        elements = list()
        outline_elements = list()

        if self.exterior_face.isolated_vertices:
            # if there are isolated vertices it means this DCEL represents a set of points (and nothing more)
            for v in self.exterior_face.isolated_vertices:
                elements.append(len(vertices))
                vertices.append(v)
        else:
            # otherwise we are treating either a linear geometry, a polygon, or a polyhedron
            visited_faces = set()

            faces_to_visit = set()
            faces_to_visit.add(self.exterior_face)

            while faces_to_visit:
                face = faces_to_visit.pop()
                if face not in visited_faces:

                    for ae in face.adjacent_edges:
                        edge_chain = ae.get_chain()

                        # if the first edge in the chain has no prev_edge the chain is open
                        open_chain = True if _is_chain_open(edge_chain) else False

                        v1_idx = None
                        first_edge, last_edge = 0, len(edge_chain)-1
                        # for i, edge in enumerate(reversed(edge_chain)):
                        #     # NOTE: OpenGL requires vertices of faces to be given in CW order, but our polygons
                        #     # have been constructed specifying vertices in CCW order, so we need to traverse
                        #     # the edge_chain in reverse order to create CW ordered vertices and elements
                        for i, edge in enumerate(edge_chain):
                            if edge.twin_edge.adjacent_face not in visited_faces and \
                                            edge.twin_edge.adjacent_face is not face:
                                faces_to_visit.add(edge.twin_edge.adjacent_face)

                            if i == first_edge:
                                v1 = edge.source_vertex()
                                if v1 in vertices:
                                    v1_idx = vertices.index(v1)
                                else:
                                    v1_idx = len(vertices)
                                    vertices.append(v1)

                            v2 = edge.target_vertex
                            if v2 in vertices:
                                v2_idx = vertices.index(v2)
                            else:
                                v2_idx = len(vertices)
                                vertices.append(v2)

                            if open_chain:
                                # if we are treating an open chain it means we are treating a linear entity
                                # so the elements must be given pair-wise. Each pair denotes the start and the
                                # end of the i-th segment making the linear entity
                                elements.extend([v1_idx, v2_idx])
                            else:
                                # otherwise we are treating a face. Faces can be only triangles (we assumed this before)
                                if i == first_edge:
                                    elements.append(v1_idx)

                                # the last vertex of the last edge is the first vertex of the first edge,
                                # so it was already treated
                                if i != last_edge:
                                    elements.append(v2_idx)

                                # treat the outline
                                # take the neighbor face (adjacent to the twin of this edge)
                                # access vertex opposite to the twin (REMEMBER: each face is a triangle)
                                # check if such a vertex is COPLANAR with

                                # get the face adjacent to this face through this edge
                                neighbor_face = edge.twin_edge.adjacent_face

                                # we proceed only if the neighbor face has been visited already
                                # in this way we avoid to add more than once the same part of the outline
                                if neighbor_face in visited_faces:
                                    # get the vertex opposite to this edge in the
                                    # face adjacent to this face through the current edge
                                    other_face_vertex = edge.twin_edge.next_edge.target_vertex

                                    # get the three vertices defining the face the current edge belongs to
                                    v3 = edge_chain[(i+1) % len(edge_chain)].target_vertex

                                    if not Point3.are_coplanar(v1.point, v2.point,
                                                                   v3.point, other_face_vertex.point):
                                        outline_elements.extend([v1_idx, v2_idx])

                            v1, v1_idx = v2, v2_idx  # advance the first vertex

                    visited_faces.add(face)

        return vertices, elements, outline_elements