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