Example #1
0
class Camera(object):
    def __init__(self):
        # register configuration settings: default camera
        from zeobuilder.gui import fields
        from zeobuilder.gui.fields_dialogs import DialogFieldInfo
        config = context.application.configuration
        config.register_setting(
            "viewer_distance",
            100.0*angstrom,
            DialogFieldInfo("Default Viewer", (1, 0), fields.faulty.Length(
                label_text="Distance from origin",
                attribute_name="viewer_distance",
                low=0.0,
                low_inclusive=True,
            )),
        )
        config.register_setting(
            "opening_angle",
            0.0,
            DialogFieldInfo("Default Viewer", (1, 1), fields.faulty.MeasureEntry(
                measure="Angle",
                label_text="Camera opening angle",
                attribute_name="opening_angle",
                low=0.0,
                low_inclusive=True,
                high=0.5*numpy.pi,
                high_inclusive=False,
                show_popup=False,
            )),
        )
        config.register_setting(
            "window_size",
            25*angstrom,
            DialogFieldInfo("Default Viewer", (1, 2), fields.faulty.Length(
                label_text="Window size",
                attribute_name="window_size",
                low=0.0,
                low_inclusive=False,
            )),
        )
        config.register_setting(
            "window_depth",
            200.0*angstrom,
            DialogFieldInfo("Default Viewer", (1, 3), fields.faulty.Length(
                label_text="Window depth",
                attribute_name="window_depth",
                low=0.0,
                low_inclusive=False,
            )),
        )

        self.reset()

    def reset(self):
        config = context.application.configuration
        self.rotation_center = Translation()
        self.rotation = Rotation()
        self.eye = Translation()
        self.eye.t[2] = config.viewer_distance
        self.opening_angle = config.opening_angle
        self.window_size = config.window_size
        self.window_depth = config.window_depth

    def get_znear(self):
        if self.opening_angle > 0.0:
            return 0.5*self.window_size/numpy.tan(0.5*self.opening_angle)
        else:
            return 0.0
    znear = property(get_znear)

    # coordinate transformations

    def eye_to_camera(self, vector_e):
        tmp = numpy.ones(2, float)
        znear = self.znear
        if znear > 0:
            return -vector_e[:2]/vector_e[2]/self.window_size*znear
        else:
            return vector_e[:2]/self.window_size

    def camera_window_to_eye(self, vector_c):
        tmp = numpy.zeros(3, float)
        tmp[:2] = vector_c*self.window_size
        znear = self.znear
        if znear > 0:
            tmp[2] = -self.znear
        else:
            tmp[2] = -self.window_size/3.0
        return tmp

    def model_to_eye(self, vector_m):
        scene = context.application.scene
        tmp = scene.model_center.vector_apply_inverse(vector_m)
        tmp = self.rotation_center.vector_apply_inverse(tmp)
        tmp = self.rotation.vector_apply_inverse(tmp)
        tmp[2] -= self.znear
        tmp = self.eye.vector_apply_inverse(tmp)
        return tmp

    def eye_to_model(self, vector_e):
        scene = context.application.scene
        tmp = self.eye.vector_apply(vector_e)
        tmp[2] += self.znear
        tmp = self.rotation.vector_apply(tmp)
        tmp = self.rotation_center.vector_apply(tmp)
        tmp = scene.model_center.vector_apply(tmp)
        return tmp

    def model_to_camera(self, vector_m):
        return self.eye_to_camera(self.model_to_eye(vector_m))

    def camera_window_to_model(self, vector_c):
        return self.eye_to_model(self.camera_window_to_eye(vector_c))

    def object_to_depth(self, gl_object):
        result = -self.model_to_eye(gl_object.get_absolute_frame().t)[2]
        return result

    def object_to_camera(self, gl_object):
        return self.eye_to_camera(self.model_to_eye(gl_object.get_absolute_frame().t))

    def object_to_eye(self, gl_object):
        return self.model_to_eye(gl_object.get_absolute_frame().t)

    def object_eye_rotation(self, gl_object):
        """
            Returns a matrix that consists of the x, y and z axes of the
            eye frame in the coordinates of the parent frame of the given
            object.
        """
        if hasattr(gl_object, "parent") and \
           isinstance(gl_object.parent, GLTransformationMixin):
            parent_matrix = gl_object.parent.get_absolute_frame().r
        else:
            parent_matrix = numpy.identity(3, float)
        result = numpy.dot(self.rotation.r.transpose(), parent_matrix).transpose()
        return result

    def depth_to_scale(self, depth):
        """ transforms a depth into a scale (au/camcoords)"""
        znear = self.znear
        if znear > 0:
            return depth/znear*self.window_size
        else:
            return self.window_size

    def vector_in_plane(self, r, p_m):
        """Returns a vector at camera position r in a plane (through p, orthogonal to viewing direction)

        Arguments
            r  --  a two-dimensional vector in camera coordinates
            p_m  --  a three-dimensional vector in model coordinates

        Returns
            rp  --  a three-dimensional vector in model coordinates that lies
                    at the intersection of a plane and a line. The plane is
                    orthogonal to the viewing direction and goes through the
                    point p. The line connects the eye (eye_m below) with the
                    point r (r_m below) in the camera window.
        """

        eye_m = self.eye_to_model(numpy.zeros(3, float))
        r_m = self.camera_window_to_model(r)
        center_m = self.camera_window_to_model(numpy.zeros(2, float))

        normal = (eye_m - center_m)
        normal /= numpy.linalg.norm(normal)

        if self.znear > 0:
            # the line is defined as r = eye_m + d*t, where t = -infinity ... infinity
            d =  eye_m - r_m

            # t at the intersection:
            t = -numpy.dot(eye_m - p_m, normal)/numpy.dot(d, normal)

            return eye_m + d*t
        else:
            # the line is defined as r = r_m + d*t, where t = -infinity ... infinity
            d = normal

            # t at the intersection:
            t = -numpy.dot(r_m - p_m, normal)/numpy.dot(d, normal)

            return r_m + d*t