def update_alignment(self): """ """ pos_for_x = math_utils.p3d_to_np( Frame2d.axis_direction_vectors[0]) * Ticks.get_tick_pos_along_axis( self.width, self.axes_ticks_numbers[0], 0.0) pos_for_y = math_utils.p3d_to_np( Frame2d.axis_direction_vectors[1]) * Ticks.get_tick_pos_along_axis( self.height, self.axes_ticks_numbers[1], 0.0) pos_tmp = math_utils.p3d_to_np(pos_for_y) + math_utils.p3d_to_np( pos_for_x) for line in self.linesin2dframe.lines: x_scale = self.get_p3d_to_frame_unit_length_scaling_factor(0) y_scale = self.get_p3d_to_frame_unit_length_scaling_factor(1) # print("x_scale, y_scale: ", x_scale, y_scale) cond = np.abs(x_scale) > 1e-8 and np.abs(y_scale) > 1e-8 if cond: line.setScale(x_scale, 1., y_scale) line.setPos(math_utils.np_to_p3d_Vec3(pos_tmp)) else: print( "scaling by too low is not supported by p3d, do it differently!" ) self.clear_plot()
def get_right_vec_norm(self): cross = -np.cross( math_utils.p3d_to_np(self.up_vec), math_utils.p3d_to_np(self.normal_vec) ) # in standard p3d view, the normal vector (0, 1, 0) points into the screen norm = cross / np.linalg.norm(cross) return norm
def set_cursor_position(self, a): """ """ cursor_pos = math_utils.np_to_p3d_Vec3( math_utils.p3d_to_np(self.get_v1()) + a * (math_utils.p3d_to_np(self.get_v2()) - math_utils.p3d_to_np(self.get_v1()))) self.p_c.setPos(cursor_pos)
def turn_clipping_planes_on(self): """ the lines may extend outside of the 'frame' setting clipping planes are one way to prevent them from being rendered outside if dimensions of the frame are updated, set_clipping_panel_geometry must be called before this with the appriopriate panel geometry """ self.turn_clipping_planes_off() for i, normal_vector in zip(Frame2d.axis_direction_indices, Frame2d.axis_direction_vectors): d = self.get_p3d_axis_length_from_axis_direction_index(i) a, b, c = math_utils.p3d_to_np(normal_vector) plane1 = LPlanef(a, b, c, 0) plane1_node = PlaneNode('', plane1) plane1_node.setClipEffect(1) plane1_nodepath = NodePath(plane1_node) plane2 = LPlanef(-a, -b, -c, d) plane2_node = PlaneNode('', plane2) plane2_node.setClipEffect(1) plane2_nodepath = NodePath(plane2_node) clipped_thing_nodepath = self.linesin2dframe.get_p3d_nodepath() plane1_nodepath.reparentTo(clipped_thing_nodepath) clipped_thing_nodepath.setClipPlane(plane1_nodepath) self.clipping_planes_p3d_nodepaths.append(plane1_nodepath) plane2_nodepath.reparentTo(clipped_thing_nodepath) clipped_thing_nodepath.setClipPlane(plane2_nodepath) self.clipping_planes_p3d_nodepaths.append(plane2_nodepath)
def get_cam_forward_vector_normalized(self): v_cam_forward = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( self.camera, self.camera.node().getLens().getViewVector())) return v_cam_forward / np.linalg.norm(v_cam_forward)
def turn_clipping_planes_on(self): """ the lines may extend outside of the 'frame' setting clipping planes are one way to prevent them from being rendered outside """ self.turn_clipping_planes_off() for length, normal_vector in zip( [self.clipping_panel_geometry.l1, self.clipping_panel_geometry.l2], [self.clipping_panel_geometry.n1, self.clipping_panel_geometry.n2 ]): d = length a, b, c = math_utils.p3d_to_np(normal_vector) plane1 = LPlanef(a, b, c, 0) plane1_node = PlaneNode('', plane1) plane1_node.setClipEffect(1) plane1_nodepath = NodePath(plane1_node) plane2 = LPlanef(-a, -b, -c, d) plane2_node = PlaneNode('', plane2) plane2_node.setClipEffect(1) plane2_nodepath = NodePath(plane2_node) plane1_nodepath.reparentTo(self.clipped_thing_p3d_nodepath) self.clipped_thing_p3d_nodepath.setClipPlane(plane1_nodepath) self.clipping_planes_p3d_nodepaths.append(plane1_nodepath) plane2_nodepath.reparentTo(self.clipped_thing_p3d_nodepath) self.clipped_thing_p3d_nodepath.setClipPlane(plane2_nodepath) self.clipping_planes_p3d_nodepaths.append(plane2_nodepath)
def init_dragging(self): """ save original position """ r0_obj = math_utils.p3d_to_np(self.pickablepoint.getPos()) self.position_before_dragging = Vec3(*r0_obj) DragDropEventManager.init_dragging(self)
def set_new_position_from_dragged_mouse(self, p_xy_offset, original_orbit_center): """ There is a new mouse position, now Args: p_xy_offset: the origin point (lies in the camera plane) to which the change point (calculated from the mouse displacement) is being added to """ v_cam_forward = math_utils.p3d_to_np(engine.tq_graphics_basics.tq_render.getRelativeVector( self.p3d_camera, self.p3d_camera.node().getLens().getViewVector())) v_cam_forward = v_cam_forward / np.linalg.norm(v_cam_forward) # print("--- > View Vector", self.p3d_camera.node().getLens().getViewVector()) v_cam_up = math_utils.p3d_to_np(engine.tq_graphics_basics.tq_render.getRelativeVector( self.p3d_camera, self.p3d_camera.node().getLens().getUpVector())) v_cam_up = v_cam_up / np.linalg.norm(v_cam_up) r_cam = math_utils.p3d_to_np(self.p3d_camera.getPos()) e_up = math_utils.p3d_to_np(v_cam_up/np.linalg.norm(v_cam_up)) e_cross = math_utils.p3d_to_np( np.cross(v_cam_forward/np.linalg.norm(v_cam_forward), e_up)) # -- calculate the bijection between mouse coordinates m_x, m_y and plane coordinates p_x, p_y mouse_pos = base.mouseWatcherNode.getMouse() # between -1 and 1 in both x and y p = conventions.getFilmCoordsFromMouseCoords( mouse_pos[0], mouse_pos[1], p_xy_offset[0], p_xy_offset[1]) drag_vec = p[0] * e_cross + p[1] * e_up print(drag_vec) # print("p: ", p) new_orbit_center = original_orbit_center + (-drag_vec) # self.set_corner_to_coords(math_utils.indexable_vec3_to_p3d_Vec3(new_orbit_center)) print("self.get_cam_coords: ", self.get_cam_coords()) self.x = -np.array(p) self.p_previous_offset = np.array(p) self.set_corner_to_coords(math_utils.indexable_vec3_to_p3d_Vec3(new_orbit_center))
def set_lookat_after_updated_camera_pos(self, lookat=None): """ the lookat point is in the center of the window """ _lookat = None if lookat is None: _lookat = self.get_lookat_vector() else: _lookat = lookat self.lookat = math_utils.p3d_to_np(_lookat) self.p3d_camera.look_at(Vec3(*self.lookat)) assert math_utils.vectors_parallel_or_antiparallel_p(Panner2d.plane_normal, self.get_cam_forward_vector_normalized())
def get_orbit_center(self, numpy=True): """ args: numpy: return in numpy or in p3d format """ if self._orbit_center is not None: if numpy == True: return math_utils.p3d_to_np(self._orbit_center) else: # otherwise it should be Vec3 return self._orbit_center else: print("self._orbit_center is None") exit(1)
def resize(self, handle_dragged=False): resize_box_handle_pos = math_utils.p3d_to_np( self.resize_box_handle.getPos()) normal_vec = self.get_normal_vec() right_vec = self.get_right_vec() # print("right_vec", right_vec) down_vec = self.get_down_vec() # print("down_vec", down_vec) # self.height and self.width are in actual coordinates v0 = self.get_v0() v1 = self.get_v1(down_vec, right_vec) resize_to_pos = None if handle_dragged == True: resize_to_pos = math_utils.LinePlaneCollision( normal_vec, # plane normal v0, # plane point normal_vec, # ray direction resize_box_handle_pos, # the position of the resize_box_handle epsilon=1e-6) else: resize_to_pos = v1 tmp_resize_handle_vec = resize_to_pos - v0 down_vec_normalized = down_vec / np.linalg.norm(down_vec) right_vec_normalized = right_vec / np.linalg.norm(right_vec) new_height = np.dot(down_vec_normalized, tmp_resize_handle_vec) new_width = np.dot(right_vec_normalized, tmp_resize_handle_vec) self.width, self.height = DraggableResizableFrame.clamp_width_height( new_width, new_height) # print("new_height", new_height, ", new_width", new_width) self.update_window_graphics()
def getCameraMouseRay(camera, mouse_pos): # aufpunkt of the plane -> just choose the camera position r0_obj = math_utils.p3d_to_np(base.cam.getPos()) v_cam_forward = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( camera, camera.node().getLens().getViewVector())) v_cam_forward = v_cam_forward / np.linalg.norm(v_cam_forward) # self.camera_gear.p3d_camera.node().getLens().getViewVector() v_cam_up = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( camera, camera.node().getLens().getUpVector())) v_cam_up = v_cam_up / np.linalg.norm(v_cam_up) r_cam = math_utils.p3d_to_np(camera.getPos()) e_up = math_utils.p3d_to_np(v_cam_up / np.linalg.norm(v_cam_up)) e_cross = math_utils.p3d_to_np( np.cross(v_cam_forward / np.linalg.norm(v_cam_forward), e_up)) # determine the middle origin of the draggable plane (where the plane intersects the camera's forward vector) r0_middle_origin = math_utils.LinePlaneCollision(v_cam_forward, r0_obj, v_cam_forward, r_cam) # p_xy_offset = conventions.getFilmCoordsFromMouseCoords(-self.mouse_position_before_dragging[0], -self.mouse_position_before_dragging[1], p_x_0=0., p_y_0=0.) p_x, p_y = conventions.getFilmCoordsFromMouseCoords( mouse_pos[0], mouse_pos[1] # , p_xy_offset[0], p_xy_offset[1] ) # p_x, p_y = conventions.getFilmCoordsFromMouseCoords(mouse_pos[0], mouse_pos[1], 0., 0.) in_plane_vector = p_x * e_cross + p_y * e_up ray_aufpunkt = r0_middle_origin + in_plane_vector ray_direction = v_cam_forward return ray_direction, ray_aufpunkt
def set_new_panning_orbit_center_from_dragged_mouse( camera_gear, p_xy_offset, original_orbit_center): """ There is a new mouse position, now Args: camera_gear: camera gear with camera member variable p_xy_offset: the origin point (lies in the camera plane) to which the change point (calculated from the mouse displacement) is being added to """ v_cam_forward = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( camera_gear.camera, camera_gear.camera.node().getLens().getViewVector())) v_cam_forward = v_cam_forward / np.linalg.norm(v_cam_forward) # print("--- > View Vector", camera_gear.camera.node().getLens().getViewVector()) v_cam_up = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( camera_gear.camera, camera_gear.camera.node().getLens().getUpVector())) v_cam_up = v_cam_up / np.linalg.norm(v_cam_up) r_cam = math_utils.p3d_to_np(camera_gear.camera.getPos()) e_up = math_utils.p3d_to_np(v_cam_up / np.linalg.norm(v_cam_up)) e_cross = math_utils.p3d_to_np( np.cross(v_cam_forward / np.linalg.norm(v_cam_forward), e_up)) # determine the middle origin of the draggable plane (where the plane intersects the camera's forward vector) # r0_middle_origin = math_utils.LinePlaneCollision(v_cam_forward, r0_obj, v_cam_forward, r_cam) # print("r0_obj", r0_obj) # print("v_cam_forward", v_cam_forward) # print("v_cam_up", v_cam_up) # print("r_cam", r_cam) # print("e_up", e_up) # print("e_cross", e_cross) # print("r0_middle_origin", r0_middle_origin) # -- calculate the bijection between mouse coordinates m_x, m_y and plane coordinates p_x, p_y mouse_pos = base.mouseWatcherNode.getMouse( ) # between -1 and 1 in both x and y # filmsize = self.camera.node().getLens().getFilmSize() # the actual width of the film size # print("p_xy_offset: ", p_xy_offset) p_x, p_y = conventions.getFilmCoordsFromMouseCoords( mouse_pos[0], mouse_pos[1], p_xy_offset[0], p_xy_offset[1]) # p_x, p_y = conventions.getFilmCoordsFromMouseCoords(mouse_pos[0], mouse_pos[1], 0., 0.) drag_vec = p_x * e_cross + p_y * e_up # print("px: ", p_x, ", py: ", p_y) # print("drag_vec: ", drag_vec) # camera_new_pos = camera_original_pos + drag_vec new_orbit_center = original_orbit_center + (-drag_vec) # print("original orbit center: ", original_orbit_center) # print("new orbit center: ", new_orbit_center) # print("current orbit center: ", camera_gear.get_orbit_center()) camera_gear.set_orbit_center( math_utils.indexable_vec3_to_p3d_Vec3(new_orbit_center))
def render_hints(self): """ render various on-hover things: - cursors - time labels """ if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() ray_direction, ray_aufpunkt = cameraray.getCameraMouseRay( self.cameragear.camera, base.mouseWatcherNode.getMouse()) r1 = ray_aufpunkt e1 = ray_direction closestedge = None d_min = float('inf') # points of shortest edge_length c1_min = None c2_min = None for edge in self.draggablegraph.graph_edges: # find closest line (infinite straight) r2 = edge.getTailPoint() edge_p1 = r2 edge_p2 = edge.getTipPoint() e2 = edge_p2 - edge_p1 # direction vector for edge infinite straight line d = np.abs(math_utils.shortestDistanceBetweenTwoStraightInfiniteLines(r1, r2, e1, e2)) c1, c2 = math_utils.getPointsOfShortestDistanceBetweenTwoStraightInfiniteLines( r1, r2, e1, e2) # only count this edge if the vector of shortest edge_length lies in-between the # start and end points of the line # if d is not None: # if d_min is None: # d_min = d # if closestedge is None: # closestedge = edge if c1_min is None: c1_min = c1 if c2_min is None: c2_min = c2 # conditions for closest edge # - d < d_min # - the line segment of shortest edge_length touches the edge's line within the # two node points of the edge: # if d < d_min and math_utils.isPointBetweenTwoPoints(edge_p1, edge_p2, c1): d_min = d closestedge = edge c1_min = c1 c2_min = c2 self.shortest_distance_line.setTipPoint(math_utils.np_to_p3d_Vec3(c1)) self.shortest_distance_line.setTailPoint(math_utils.np_to_p3d_Vec3(c2)) self.shortest_distance_line.show() # -- set the time label # ---- set the position of the label to the position of the mouse cursor, but a bit higher if closestedge is not None: self.time_label.textNodePath.show() self.time_label.setPos(*(ray_aufpunkt + ray_direction * 1.)) # figure out the parameter t t = np.linalg.norm(closestedge.getTailPoint() - math_utils.np_to_p3d_Vec3(c2))/np.linalg.norm(closestedge.getTailPoint() - closestedge.getTipPoint()) # print("t = np.linalg.norm(closestedge.getTailPoint() - math_utils.np_to_p3d_Vec3(c2))/np.linalg.norm(closestedge.getTailPoint() - closestedge.getTipPoint())") # print(t, "np.linalg.norm(", closestedge.getTailPoint(), " - ", math_utils.np_to_p3d_Vec3(c2), ")/, np.linalg.norm(", closestedge.getTailPoint(), " - ", closestedge.getTipPoint(), ")") self.time_label.setText("t = {0:.2f}".format(t)) self.time_label.update() self.time_label.textNodePath.setScale(0.04) else: self.time_label.textNodePath.hide() # -- color edges if closestedge is not None: for edge in self.draggablegraph.graph_edges: # color all edge.setColor(Vec4(1., 1., 1., 1.), 1) if edge is closestedge: edge.setColor(Vec4(1., 0., 0., 1.), 1) else: # hide the connection line self.shortest_distance_line.hide() # make all the same color for edge in self.draggablegraph.graph_edges: edge.setColor(Vec4(1., 1., 1., 1.), 1) self.hoverindicatorpoint.setPos(math_utils.np_to_p3d_Vec3( ray_aufpunkt + ray_direction * 1.)) # -- color point # ---- find closest point, # within a certain radius (FIXME: automatically calculate that radius based on the # sorroundings) d_min_point = None closestpoint = None for point in self.draggablegraph.graph_points: d = np.linalg.norm(math_utils.p3d_to_np(point.getPos()) - math_utils.p3d_to_np(ray_aufpunkt)) if d_min_point is not None: if d < d_min_point: d_min_point = d closestpoint = point else: d_min_point = d closestpoint = point # ---- color in point for point in self.draggablegraph.graph_points: point.setColor(Vec4(1., 0., 1., 1.), 1) if point is closestpoint: point.setColor(Vec4(1., 0., 0., 1.), 1) else: point.setColor(Vec4(1., 1., 1., 1.), 1)
def __init__(self, camera_gear, edge_player_recorder_spawner=None): self.camera_gear = camera_gear self.edge_player_recorder_spawner = edge_player_recorder_spawner self.state = EdgeRecorderState() # -- do geometry logic # make the line small, but pick initial direction # -- do graphics stuff tail_init_point = Vec3(0., 0., 0.) self.p_c = Point3dCursor() self.p_c.setPos(tail_init_point) self.p_c.reparentTo(self) self.line = Line1dSolid() tip_init_point = tail_init_point + Vec3(2., 2., 2.) self.line.setTipPoint(tip_init_point) self.line.setTailPoint(tail_init_point) # actions: record, pause, kill # setup the spacebar to continue/start recording or pausing self.space_direct_object = DirectObject.DirectObject() self.space_direct_object.accept('space', self.react_to_spacebar) self.set_recording_direct_object = DirectObject.DirectObject() self.set_recording_direct_object.accept('r', self.react_to_r) # -- do p3d sequence stuff # ---- initialize the sequence self.v1 = Vec3(0.5, 0.5, 0.) self.v_dir = Vec3(1., 1., 0.) / np.linalg.norm(Vec3(1., 1., 0.)) self.extraArgs = [ math_utils.p3d_to_np(self.v1), math_utils.p3d_to_np(self.v_dir), self.p_c, self.line ] self.init_recorder_label() self.cursor_sequence = Sequence() self.cursor_sequence.set_sequence_params( duration=EdgeRecorder.s_dur, extraArgs=self.extraArgs, update_function=self.update_while_moving_function, on_finish_function=self.on_finish_cursor_sequence) # --- additional ui stuff --- # -- init hover and click actions # self.edge_hoverer = EdgeHoverer(self, self.camera_gear) # self.edge_mouse_clicker = EdgeMouseClicker(self) # make a pinned label saying Rec. in thick red letters # --- set initial state ---- self.set_stopped_at_beginning() self.recorder = Recorder()
def render_hints(self): """ render various on-hover things: - cursors - time labels """ get_hover_points_success, ray_direction, ray_aufpunkt, edge_p1, edge_p2, c1, c2 = ( self.get_hover_points()) if get_hover_points_success is True: if math_utils.isPointBetweenTwoPoints(edge_p1, edge_p2, c1): self.shortest_distance_line.setTipPoint(math_utils.np_to_p3d_Vec3(c1)) self.shortest_distance_line.setTailPoint(math_utils.np_to_p3d_Vec3(c2)) self.shortest_distance_line.show() # -- set the time label # ---- set the position of the label to the position of the mouse cursor, # but a bit higher self.time_label.textNodePath.show() self.time_label.setPos(*(ray_aufpunkt + ray_direction * 1.)) a = self.get_a_param(c2) t = a * self.edge_graphics.get_duration_func() self.time_label.setText("t = {0:.2f}, a = {1:.2f}".format(t, a)) self.time_label.update() self.time_label.textNodePath.setScale(0.04) # -- color edges # on hover, change the color to be # darker than otherwise primary_color = self.edge_graphics.get_primary_color() darkening_factor = 0.5 new_rgb_v3 = np.array([ primary_color[0], primary_color[1], primary_color[2]]) * darkening_factor new_color = Vec4(new_rgb_v3[0], new_rgb_v3[1], new_rgb_v3[2], 1.) # when hovered-over self.edge_graphics.set_primary_color(new_color, change_logical_primary_color=False) else: self.shortest_distance_line.setColor(Vec4(1., 1., 1., 1.), 1) # when not hovered-over self.edge_graphics.set_primary_color(self.edge_graphics.get_primary_color()) self.shortest_distance_line.hide() self.time_label.textNodePath.hide() # -- color point # ---- find closest point, # within a certain radius d_min_point = None closestpoint = None playerline_limiting_positions = [self.edge_graphics.get_inset_v1(), self.edge_graphics.get_inset_v2()] for pos in playerline_limiting_positions: d = np.linalg.norm( math_utils.p3d_to_np(pos) - math_utils.p3d_to_np(ray_aufpunkt)) if d_min_point is not None: if d < d_min_point: d_min_point = d closestpoint = pos else: d_min_point = d closestpoint = pos
def getCoords_np(self): """ """ return np.array([math_utils.p3d_to_np(coord) for coord in self.coords])
def get_cam_pos(self): return math_utils.p3d_to_np(self.camera.getPos())
def get_v0(self): return math_utils.p3d_to_np(self.v0)
def get_down_vec_norm(self): vec = -math_utils.p3d_to_np(self.up_vec) norm = vec / np.linalg.norm(vec) return norm
def get_normal_vec(self): return math_utils.p3d_to_np(self.normal_vec) / np.linalg.norm( self.normal_vec)
def update(self): """ """ # print("counter: ", self.counter) # self.counter += 1 r0_obj = math_utils.p3d_to_np(self.pickablepoint.getPos()) v_cam_forward = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( self.camera, self.camera.node().getLens().getViewVector())) v_cam_forward = v_cam_forward / np.linalg.norm(v_cam_forward) # self.camera.node().getLens().getViewVector() v_cam_up = math_utils.p3d_to_np( engine.tq_graphics_basics.tq_render.getRelativeVector( self.camera, self.camera.node().getLens().getUpVector())) v_cam_up = v_cam_up / np.linalg.norm(v_cam_up) r_cam = math_utils.p3d_to_np(self.camera.getPos()) e_up = math_utils.p3d_to_np(v_cam_up / np.linalg.norm(v_cam_up)) e_cross = math_utils.p3d_to_np( np.cross(v_cam_forward / np.linalg.norm(v_cam_forward), e_up)) # determine the middle origin of the draggable plane (where the plane intersects the camera's forward vector) r0_middle_origin = math_utils.LinePlaneCollision( v_cam_forward, r0_obj, v_cam_forward, r_cam) # print("r0_obj", r0_obj) # print("v_cam_forward", v_cam_forward) # print("v_cam_up", v_cam_up) # print("r_cam", r_cam) # print("e_up", e_up) # print("e_cross", e_cross) # print("r0_middle_origin", r0_middle_origin) # -- calculate the bijection between mouse coordinates m_x, m_y and plane coordinates p_x, p_y mouse_pos = base.mouseWatcherNode.getMouse( ) # between -1 and 1 in both x and y # filmsize = base.cam.node().getLens().getFilmSize() # the actual width of the film size # print("p_xy_offset: ", self.p_xy_at_init_drag) p_x, p_y = conventions.getFilmCoordsFromMouseCoords( mouse_pos[0], mouse_pos[1], self.p_xy_at_init_drag[0], self.p_xy_at_init_drag[1]) # p_x, p_y = conventions.getFilmCoordsFromMouseCoords(mouse_pos[0], mouse_pos[1], 0., 0.) drag_vec = p_x * e_cross + p_y * e_up # print("drag_vec", drag_vec) # set the position while dragging self.this_frame_drag_pos = self.position_before_dragging + Vec3( *drag_vec) self.pickablepoint.setPos(self.this_frame_drag_pos) if self.last_frame_drag_pos is None: self.state_changed = True elif self.last_frame_drag_pos == self.this_frame_drag_pos: self.state_changed = False # TODO: in the future, a state change on drag will probably not only be the position else: self.state_changed = True # update the state between frames self.last_frame_drag_pos = self.this_frame_drag_pos
def get_e_x_prime(self): return math_utils.p3d_to_np( np.cross(self.get_cam_forward_vector_normalized(), self.get_cam_up_vector_normalized()))
def _get_length_logical(self): vec_length_logical = np.linalg.norm( math_utils.p3d_to_np(self.tail_point_logical - self.tip_point_logical)) return vec_length_logical