class StabilityExperiment(ViewTowers): def __init__(self, *args, **kwargs): ViewTowers.__init__(self, *args, **kwargs) # ignore keys set by viewer for key in self.getAllAccepting(): if key in ("s", "escape"): continue self.ignore(key) self.permanent_events = self.getAllAccepting() # global variables self.text_bg = (1, 1, 1, 0.7) self.font = self.loader.loadFont('cmr12.egg') self.question = [ "Will this tower fall?", [[1, "definitely will not fall"], [2, "probably will not fall"], [3, "might not fall"], [4, "don't know"], [5, "might fall"], [6, "probably will fall"], [7, "definitely will fall"]]] self.question_keys = ["1", "2", "3", "4", "5", "6", "7"] self.choice_text_start = 0.65 self.feedback_time = 3.0 self.buffer_time = 0.75 # create text self.create_all_text() def run(self): # Show the start screen self.toggle_task("show_start_screen") # Call parent's run(). ShowBase.run(self) def create_all_text(self): self.continue_text = OnscreenText(**{ "text": ( "In a moment, you will be asked the question displayed on " "the left. When you are ready, press the spacebar to begin."), "style": 1, "fg": (.75, 0, 0, 1), "bg": self.text_bg, "pos": (.4, .4), "align": TextNode.ACenter, "scale": .08, "font": self.font, "wordwrap": 20 }) self.text_parent = self.continue_text.getParent() self.continue_text.detachNode() xpos = -1.25 skip = .15 self.question_text = OnscreenText(**{ "text": self.question[0], "style": 1, "fg": (0, 0, .8, 1), "bg": self.text_bg, "pos": ((xpos + .05), .8), "align": TextNode.ALeft, "scale": .075, "font": self.font, "wordwrap": 35}) self.question_choice_text = [] for i in xrange(len(self.question[1])): n = len(self.question[1]) - i - 1 ypos = self.choice_text_start - (skip * n) t1 = OnscreenText(**{ "text": "%s" % self.question[1][i][0], "style": 1, "fg": (0, .1, 0, 1), "bg": self.text_bg, "pos": ((xpos + .1), ypos), "align": TextNode.ALeft, "scale": .075, "font": self.font}) t2 = OnscreenText(**{ "text": "%s" % self.question[1][i][1], "style": 1, "fg": (0, .1, 0, 1), "bg": self.text_bg, "pos": ((xpos + 0.17), ypos), "align": TextNode.ALeft, "scale": .05, "font": self.font}) t = NodePath("choice_%s" % i) t.reparentTo(self.text_parent) t1.reparentTo(t) t2.reparentTo(t) self.question_choice_text.append(t) for t in self.question_choice_text: t.detachNode() self.trials_remaining_text = OnscreenText(**{ "text": "", "style": 1, "fg": (0, 0, 0, 1), "bg": self.text_bg, "pos": (-xpos, -.95), "align": TextNode.ARight, "scale": .05, "font": self.font}) def show_start_screen(self, task): self.continue_text.reparentTo(self.text_parent) for t in self.question_choice_text: t.reparentTo(self.text_parent) self.accept("space", self.toggle_task, ["show_trial"]) def show_trial(self, task): if self.sso is None: self.goto_sso(0) elif self.ssos.index(self.sso) == (self.n_ssos - 1): self.exit() else: self.next() n = self.n_ssos - self.ssos.index(self.sso) self.trials_remaining_text.setText("Trials remaining: %d" % n) self.continue_text.detachNode() for t in self.question_choice_text: t.detachNode() self.camera_rot.setH(np.random.randint(0, 360)) self.cam_spin = 270 self.taskMgr.doMethodLater(self.buffer_time, self.rotate, "rotate") def rotate(self, task): """ Task: rotate camera.""" H = (self.camera_rot.getH() + 1) % 360 self.camera_rot.setH(H) self.cam_spin -= 1 if self.cam_spin == 0: self.toggle_task("show_question") return task.done else: return task.cont def show_question(self, task): for t in self.question_choice_text: t.reparentTo(self.text_parent) for key in self.question_keys: self.accept(key, self.record_response, [key]) def record_response(self, key): for k in self.question_keys: self.ignore(k) for i, t in enumerate(self.question_choice_text): if i != (int(key) - 1): t.detachNode() self.toggle_task("physics") def physics(self, task): """ Task: simulate physics.""" # Elapsed time. dt = self._get_elapsed() - self.old_elapsed # Update amount of time simulated so far. self.old_elapsed += dt # Step the physics dt time. size_sub = self.bbase.sim_par["size_sub"] n_subs = int(dt / size_sub) self.bbase.step(dt, n_subs, size_sub) if self.old_elapsed >= self.feedback_time: self.toggle_task("show_trial") return task.done else: return task.cont
class DirectionExperiment(ViewTowers): def __init__(self, *args, **kwargs): ViewTowers.__init__(self, *args, **kwargs) # ignore keys set by viewer for key in self.getAllAccepting(): if key in ("s", "escape"): continue self.ignore(key) self.permanent_events = self.getAllAccepting() # global variables self.text_bg = (1, 1, 1, 0.7) self.font = self.loader.loadFont("cmr12.egg") self.question = "Use the mouse to indicate the direction that " "the tower will fall." self.feedback_time = 3.0 self.buffer_time = 0.75 # create text self.create_all_text() # create direction line self.line = LineSegs() self.line_node = None self.angle = None alight = AmbientLight("alight3") alight.setColor((0.8, 0.8, 0.8, 1)) self.line_light = self.lights.attachNewNode(alight) def place_camera(self): self.cameras.setPos(0, -12, 2.5) self.look_at.setPos(0, 0, 1.5) self.cameras.lookAt(self.look_at) def run(self): # Show the start screen self.toggle_task("show_start_screen") # Call parent's run(). ShowBase.run(self) def create_all_text(self): self.continue_text = OnscreenText( **{ "text": ( "In a moment, you will be asked the question displayed on " "the left. When you are ready, press the spacebar to begin." ), "style": 1, "fg": (0.75, 0, 0, 1), "bg": self.text_bg, "pos": (0.4, 0.4), "align": TextNode.ACenter, "scale": 0.08, "font": self.font, "wordwrap": 20, } ) self.text_parent = self.continue_text.getParent() self.continue_text.detachNode() xpos = -1.25 self.question_text = OnscreenText( **{ "text": self.question, "style": 1, "fg": (0, 0, 0.8, 1), "bg": self.text_bg, "pos": ((xpos + 0.05), 0.8), "align": TextNode.ALeft, "scale": 0.075, "font": self.font, "wordwrap": 35, } ) self.trials_remaining_text = OnscreenText( **{ "text": "", "style": 1, "fg": (0, 0, 0, 1), "bg": self.text_bg, "pos": (-xpos, -0.95), "align": TextNode.ARight, "scale": 0.05, "font": self.font, } ) def show_start_screen(self, task): self.continue_text.reparentTo(self.text_parent) self.accept("space", self.toggle_task, ["show_trial"]) def show_trial(self, task): if self.line_node is not None: self.line_node.removeNode() self.line_node = None if self.sso is None: self.goto_sso(0) elif self.ssos.index(self.sso) == (self.n_ssos - 1): self.exit() else: self.next() n = self.n_ssos - self.ssos.index(self.sso) self.trials_remaining_text.setText("Trials remaining: %d" % n) self.continue_text.detachNode() self.camera_rot.setH(np.random.randint(0, 360)) self.cam_spin = 270 self.taskMgr.doMethodLater(self.buffer_time, self.rotate, "rotate") def rotate(self, task): """ Task: rotate camera.""" H = (self.camera_rot.getH() + 1) % 360 self.camera_rot.setH(H) self.cam_spin -= 1 if self.cam_spin == 0: self.toggle_task("show_question") return task.done else: return task.cont def show_question(self, task): self.toggle_task("draw_direction") self.accept("mouse1", self.record_response) def record_response(self): self.ignore("mouse1") self.taskMgr.remove("draw_direction") self.toggle_task("physics") def physics(self, task): """ Task: simulate physics.""" # Elapsed time. dt = self._get_elapsed() - self.old_elapsed # Update amount of time simulated so far. self.old_elapsed += dt # Step the physics dt time. size_sub = self.bbase.sim_par["size_sub"] n_subs = int(dt / size_sub) self.bbase.step(dt, n_subs, size_sub) if self.old_elapsed >= self.feedback_time: self.toggle_task("show_trial") return task.done else: return task.cont def draw_direction(self, task): if self.mouseWatcherNode.hasMouse(): cv = self._get_collision(self.floor) cv = cv / np.linalg.norm(cv) self.angle = np.arctan2(cv[1], cv[0]) sx, sy, sz = self.floor.getScale() / 2.0 gx, gy, gz = self.floor.getPos() gz += sz + 0.01 if self.line_node is not None: self.line_node.removeNode() self.line_node = None self.line.reset() self.line.setColor(1, 1, 1, 1) self.line.setThickness(5) self.line.moveTo(gx, gy, gz) self.line.drawTo(cv[0] * sx, cv[1] * sy, gz) self.line_node = self.render.attachNewNode(self.line.create()) self.line_node.setLight(self.line_light) return task.cont def _get_collision(self, node, debug=False): mx = self.mouseWatcherNode.getMouseX() my = self.mouseWatcherNode.getMouseY() if debug: print "mouse:", (mx, my) # get the origin and direction of the ray extending from the # camera to the mouse pointer cm = np.array(self.cam.getNetTransform().getMat()) cr = CollisionRay() cr.setFromLens(self.cam.node(), (mx, my)) cp = np.hstack([cr.getOrigin(), 1]) cd = np.hstack([cr.getDirection(), 0]) cp = np.dot(cm.T, cp)[:3] cd = np.dot(cm.T, cd)[:3] if cd[2] > -1: cd[2] = -1 if debug: print "direction:", cd print "origin:", cp # point on the plane, z-axis pz = node.getPos(self.render)[2] sz = node.getScale(self.render)[2] / 2.0 p0 = np.array([0, 0, pz + sz]) if debug: print "p0:", p0 # this is the intersection equation that we want to solve, # where s is the point on the line that intersects # e_z(cp + s*cd - p0) = 0 s = (p0[2] - cp[2]) / cd[2] if debug: print "s:", s # transform the collision point from line coordinates to world # coordinates cv = cp + s * cd if debug: print "collision:", cv return cv
class DirectionExperiment(ViewTowers): def __init__(self, *args, **kwargs): ViewTowers.__init__(self, *args, **kwargs) # ignore keys set by viewer for key in self.getAllAccepting(): if key in ("s", "escape"): continue self.ignore(key) self.permanent_events = self.getAllAccepting() # global variables self.text_bg = (1, 1, 1, 0.7) self.font = self.loader.loadFont('cmr12.egg') self.question = ( "Use the mouse to indicate the direction that " "the tower will fall.") self.feedback_time = 3.0 self.buffer_time = 0.75 # create text self.create_all_text() # create direction line self.line = LineSegs() self.line_node = None self.angle = None alight = AmbientLight('alight3') alight.setColor((0.8, 0.8, 0.8, 1)) self.line_light = self.lights.attachNewNode(alight) def place_camera(self): self.cameras.setPos(0, -12, 2.5) self.look_at.setPos(0, 0, 1.5) self.cameras.lookAt(self.look_at) def run(self): # Show the start screen self.toggle_task("show_start_screen") # Call parent's run(). ShowBase.run(self) def create_all_text(self): self.continue_text = OnscreenText(**{ "text": ( "In a moment, you will be asked the question displayed on " "the left. When you are ready, press the spacebar to begin."), "style": 1, "fg": (.75, 0, 0, 1), "bg": self.text_bg, "pos": (.4, .4), "align": TextNode.ACenter, "scale": .08, "font": self.font, "wordwrap": 20 }) self.text_parent = self.continue_text.getParent() self.continue_text.detachNode() xpos = -1.25 self.question_text = OnscreenText(**{ "text": self.question, "style": 1, "fg": (0, 0, .8, 1), "bg": self.text_bg, "pos": ((xpos + .05), .8), "align": TextNode.ALeft, "scale": .075, "font": self.font, "wordwrap": 35}) self.trials_remaining_text = OnscreenText(**{ "text": "", "style": 1, "fg": (0, 0, 0, 1), "bg": self.text_bg, "pos": (-xpos, -.95), "align": TextNode.ARight, "scale": .05, "font": self.font}) def show_start_screen(self, task): self.continue_text.reparentTo(self.text_parent) self.accept("space", self.toggle_task, ["show_trial"]) def show_trial(self, task): if self.line_node is not None: self.line_node.removeNode() self.line_node = None if self.sso is None: self.goto_sso(0) elif self.ssos.index(self.sso) == (self.n_ssos - 1): self.exit() else: self.next() n = self.n_ssos - self.ssos.index(self.sso) self.trials_remaining_text.setText("Trials remaining: %d" % n) self.continue_text.detachNode() self.camera_rot.setH(np.random.randint(0, 360)) self.cam_spin = 270 self.taskMgr.doMethodLater(self.buffer_time, self.rotate, "rotate") def rotate(self, task): """ Task: rotate camera.""" H = (self.camera_rot.getH() + 1) % 360 self.camera_rot.setH(H) self.cam_spin -= 1 if self.cam_spin == 0: self.toggle_task("show_question") return task.done else: return task.cont def show_question(self, task): self.toggle_task("draw_direction") self.accept("mouse1", self.record_response) def record_response(self): self.ignore("mouse1") self.taskMgr.remove("draw_direction") self.toggle_task("physics") def physics(self, task): """ Task: simulate physics.""" # Elapsed time. dt = self._get_elapsed() - self.old_elapsed # Update amount of time simulated so far. self.old_elapsed += dt # Step the physics dt time. size_sub = self.bbase.sim_par["size_sub"] n_subs = int(dt / size_sub) self.bbase.step(dt, n_subs, size_sub) if self.old_elapsed >= self.feedback_time: self.toggle_task("show_trial") return task.done else: return task.cont def draw_direction(self, task): if self.mouseWatcherNode.hasMouse(): cv = self._get_collision(self.floor) cv = cv / np.linalg.norm(cv) self.angle = np.arctan2(cv[1], cv[0]) sx, sy, sz = self.floor.getScale() / 2.0 gx, gy, gz = self.floor.getPos() gz += sz + 0.01 if self.line_node is not None: self.line_node.removeNode() self.line_node = None self.line.reset() self.line.setColor(1, 1, 1, 1) self.line.setThickness(5) self.line.moveTo(gx, gy, gz) self.line.drawTo(cv[0] * sx, cv[1] * sy, gz) self.line_node = self.render.attachNewNode(self.line.create()) self.line_node.setLight(self.line_light) return task.cont def _get_collision(self, node, debug=False): mx = self.mouseWatcherNode.getMouseX() my = self.mouseWatcherNode.getMouseY() if debug: print "mouse:", (mx, my) # get the origin and direction of the ray extending from the # camera to the mouse pointer cm = np.array(self.cam.getNetTransform().getMat()) cr = CollisionRay() cr.setFromLens(self.cam.node(), (mx, my)) cp = np.hstack([cr.getOrigin(), 1]) cd = np.hstack([cr.getDirection(), 0]) cp = np.dot(cm.T, cp)[:3] cd = np.dot(cm.T, cd)[:3] if cd[2] > -1: cd[2] = -1 if debug: print "direction:", cd print "origin:", cp # point on the plane, z-axis pz = node.getPos(self.render)[2] sz = node.getScale(self.render)[2] / 2.0 p0 = np.array([0, 0, pz + sz]) if debug: print "p0:", p0 # this is the intersection equation that we want to solve, # where s is the point on the line that intersects # e_z(cp + s*cd - p0) = 0 s = (p0[2] - cp[2]) / cd[2] if debug: print "s:", s # transform the collision point from line coordinates to world # coordinates cv = cp + s * cd if debug: print "collision:", cv return cv
class StabilityExperiment(ViewTowers): def __init__(self, *args, **kwargs): ViewTowers.__init__(self, *args, **kwargs) # ignore keys set by viewer for key in self.getAllAccepting(): if key in ("s", "escape"): continue self.ignore(key) self.permanent_events = self.getAllAccepting() # global variables self.text_bg = (1, 1, 1, 0.7) self.font = self.loader.loadFont('cmr12.egg') self.question = [ "Will this tower fall?", [[1, "definitely will not fall"], [2, "probably will not fall"], [3, "might not fall"], [4, "don't know"], [5, "might fall"], [6, "probably will fall"], [7, "definitely will fall"]] ] self.question_keys = ["1", "2", "3", "4", "5", "6", "7"] self.choice_text_start = 0.65 self.feedback_time = 3.0 self.buffer_time = 0.75 # create text self.create_all_text() def run(self): # Show the start screen self.toggle_task("show_start_screen") # Call parent's run(). ShowBase.run(self) def create_all_text(self): self.continue_text = OnscreenText( **{ "text": ("In a moment, you will be asked the question displayed on " "the left. When you are ready, press the spacebar to begin." ), "style": 1, "fg": (.75, 0, 0, 1), "bg": self.text_bg, "pos": (.4, .4), "align": TextNode.ACenter, "scale": .08, "font": self.font, "wordwrap": 20 }) self.text_parent = self.continue_text.getParent() self.continue_text.detachNode() xpos = -1.25 skip = .15 self.question_text = OnscreenText( **{ "text": self.question[0], "style": 1, "fg": (0, 0, .8, 1), "bg": self.text_bg, "pos": ((xpos + .05), .8), "align": TextNode.ALeft, "scale": .075, "font": self.font, "wordwrap": 35 }) self.question_choice_text = [] for i in xrange(len(self.question[1])): n = len(self.question[1]) - i - 1 ypos = self.choice_text_start - (skip * n) t1 = OnscreenText( **{ "text": "%s" % self.question[1][i][0], "style": 1, "fg": (0, .1, 0, 1), "bg": self.text_bg, "pos": ((xpos + .1), ypos), "align": TextNode.ALeft, "scale": .075, "font": self.font }) t2 = OnscreenText( **{ "text": "%s" % self.question[1][i][1], "style": 1, "fg": (0, .1, 0, 1), "bg": self.text_bg, "pos": ((xpos + 0.17), ypos), "align": TextNode.ALeft, "scale": .05, "font": self.font }) t = NodePath("choice_%s" % i) t.reparentTo(self.text_parent) t1.reparentTo(t) t2.reparentTo(t) self.question_choice_text.append(t) for t in self.question_choice_text: t.detachNode() self.trials_remaining_text = OnscreenText( **{ "text": "", "style": 1, "fg": (0, 0, 0, 1), "bg": self.text_bg, "pos": (-xpos, -.95), "align": TextNode.ARight, "scale": .05, "font": self.font }) def show_start_screen(self, task): self.continue_text.reparentTo(self.text_parent) for t in self.question_choice_text: t.reparentTo(self.text_parent) self.accept("space", self.toggle_task, ["show_trial"]) def show_trial(self, task): if self.sso is None: self.goto_sso(0) elif self.ssos.index(self.sso) == (self.n_ssos - 1): self.exit() else: self.next() n = self.n_ssos - self.ssos.index(self.sso) self.trials_remaining_text.setText("Trials remaining: %d" % n) self.continue_text.detachNode() for t in self.question_choice_text: t.detachNode() self.camera_rot.setH(np.random.randint(0, 360)) self.cam_spin = 270 self.taskMgr.doMethodLater(self.buffer_time, self.rotate, "rotate") def rotate(self, task): """ Task: rotate camera.""" H = (self.camera_rot.getH() + 1) % 360 self.camera_rot.setH(H) self.cam_spin -= 1 if self.cam_spin == 0: self.toggle_task("show_question") return task.done else: return task.cont def show_question(self, task): for t in self.question_choice_text: t.reparentTo(self.text_parent) for key in self.question_keys: self.accept(key, self.record_response, [key]) def record_response(self, key): for k in self.question_keys: self.ignore(k) for i, t in enumerate(self.question_choice_text): if i != (int(key) - 1): t.detachNode() self.toggle_task("physics") def physics(self, task): """ Task: simulate physics.""" # Elapsed time. dt = self._get_elapsed() - self.old_elapsed # Update amount of time simulated so far. self.old_elapsed += dt # Step the physics dt time. size_sub = self.bbase.sim_par["size_sub"] n_subs = int(dt / size_sub) self.bbase.step(dt, n_subs, size_sub) if self.old_elapsed >= self.feedback_time: self.toggle_task("show_trial") return task.done else: return task.cont