class Segment(waves.Segment, heat_map.Segment): def __init__(self, *args): waves.Segment.__init__(self, *args) heat_map.Segment.__init__(self, *args) self._amp_smoother = Smoother(response_factor=2.5) def relative_size(self): age = self.age() if age > (self.duration - self._fade_time): return 1 - sigmoid(1 - (self.duration - age) / self._fade_time) else: self._amp_smoother.smooth( max([abs(value) for value in self.waveform]), self.visualizer.time_increment) return sigmoid(pow(max(self._amp_smoother.value(), 0), 0.25))
class Ancestry(visualizer.Visualizer, AncestryPlotter): def __init__(self, tr_log, pieces, args): visualizer.Visualizer.__init__(self, args) AncestryPlotter.__init__(self, tr_log.total_file_size(), tr_log.lastchunktime(), args) self._unfold_function = getattr(self, "_unfold_%s" % args.unfold) self._pre_render() self._autozoom = (args.geometry == CIRCLE and self.args.autozoom) if self._autozoom: self._max_pxy = 0 self._zoom_smoother = Smoother() @staticmethod def add_parser_arguments(parser): AncestryPlotter.add_parser_arguments(parser) visualizer.Visualizer.add_parser_arguments(parser) parser.add_argument("-z", dest="timefactor", type=float, default=1.0) def _pre_render(self): print "pre-rendering..." self._timeline = [] for piece in pieces: self.add_piece(piece["id"], piece["t"], piece["begin"], piece["end"]) frame = {"t": piece["t"], "tracker": copy.deepcopy(self._tracker), "num_pieces": self._num_pieces} self._timeline.append(frame) print "ok" def InitGL(self): visualizer.Visualizer.InitGL(self) glClearColor(0.0, 0.0, 0.0, 0.0) def ReSizeGLScene(self, width, height): visualizer.Visualizer.ReSizeGLScene(self, width, height) self._size = min(width, height) - 2*MARGIN AncestryPlotter.set_size(self, self._size, self._size) def render(self): glTranslatef(MARGIN + (self.width - self._size)/2, MARGIN, 0) glLineWidth(LINE_WIDTH * self.width) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glColor3f(1,1,1) self._unfold_function(self.current_time() * self.args.timefactor) frame = self._frame_at_cursor() self._activate_frame(frame) if self._autozoom: self._zoom = self._zoom_smoother.value() if self._zoom is None: self._zoom = 0.0 else: self._zoom = 1.0 self.plot() if self._autozoom: if self._max_pxy == 0: zoom = 0.5 else: zoom = 0.5 + self.cursor_t/self._duration * 0.5 / self._max_pxy self._zoom_smoother.smooth(zoom, self.time_increment) def _unfold_backward(self, t): self._cursor_t = self._duration - t % self._duration def _unfold_forward(self, t): self._cursor_t = t % self._duration def _frame_at_cursor(self): for frame in self._timeline: if frame["t"] >= self._cursor_t: return frame return self._timeline[-1] def _activate_frame(self, frame): self._num_pieces = frame["num_pieces"] self._tracker = frame["tracker"] # def _follow_piece(self, piece): # if len(piece.growth) > 0: # path = [(piece.t, # (piece.begin + piece.end) / 2)] # for older_version in reversed(piece.growth): # path.append((older_version.t, # (older_version.begin + older_version.end) / 2)) # self.draw_path(path) # for parent in piece.parents.values(): # if self.min_t < parent.t < self.max_t: # self._connect_child_and_parent( # piece.t, (piece.begin + piece.end) / 2, # parent.t, (parent.begin + parent.end) / 2) # self._follow_piece(parent) # else: # if self.args.unfold == BACKWARD: # t = self.cursor_t - pow(self.cursor_t - parent.t, 0.7) # else: # t = self.cursor_t # self._connect_child_and_parent( # piece.t, (piece.begin + piece.end) / 2, # t, (parent.begin + parent.end) / 2) def _rect_position(self, t, byte_pos): x = float(byte_pos) / self._total_size * self._width y = (1 - t / self._duration) * self._height return x, y def _circle_position(self, t, byte_pos): angle = float(byte_pos) / self._total_size * 2*math.pi rel_t = 1 - t / self._duration px = rel_t * math.cos(angle) py = rel_t * math.sin(angle) x = self._width / 2 + (px * self._zoom) * self._width / 2 y = self._height / 2 + (py * self._zoom) * self._height / 2 if self._autozoom: self._max_pxy = max([self._max_pxy, abs(px), abs(py)]) return x, y def draw_path(self, points): glBegin(GL_LINE_STRIP) for (t, b) in points: x, y = self._position(t, b) glVertex2f(x, y) glEnd() def draw_curve(self, x1, y1, x2, y2): control_points = [ Vector2d(x1, y1), Vector2d(x1 + (x2 - x1) * 0.3, y1), Vector2d(x1 + (x2 - x1) * 0.7, y2), Vector2d(x2, y2) ] bezier = make_bezier([(p.x, p.y) for p in control_points]) points = bezier(CURVE_PRECISION) glBegin(GL_LINE_STRIP) for x, y in points: glVertex2f(x, y) glEnd()
class Ancestry(visualizer.Visualizer, AncestryPlotter): def __init__(self, tr_log, pieces, args): visualizer.Visualizer.__init__(self, args) AncestryPlotter.__init__(self, tr_log.total_file_size(), tr_log.lastchunktime(), args) if args.unfold == BACKWARD: for piece in pieces: self.add_piece(piece["id"], piece["t"], piece["begin"], piece["end"]) elif args.unfold == FORWARD: self._remaining_pieces = copy.copy(pieces) self._autozoom = (args.geometry == CIRCLE and self.args.autozoom) if self._autozoom: self._max_pxy = 0 self._zoom_smoother = Smoother() if args.node_style == CIRCLE: self._node_plot_method = self._draw_node_circle self._nodes = {} else: self._node_plot_method = None if args.node_size_envelope: attack, decay, sustain = args.node_size_envelope.split(",") self._node_size_envelope = AdsrEnvelope( attack, decay, sustain, args.node_size_envelope_slope) else: self._node_size_envelope = None if args.sway_envelope: attack, decay, sustain = args.sway_envelope.split(",") self._sway_envelope = AdsrEnvelope(attack, decay, sustain) else: self._sway_envelope = None @staticmethod def add_parser_arguments(parser): AncestryPlotter.add_parser_arguments(parser) visualizer.Visualizer.add_parser_arguments(parser) parser.add_argument("-z", dest="timefactor", type=float, default=1.0) def InitGL(self): visualizer.Visualizer.InitGL(self) glClearColor(0.0, 0.0, 0.0, 0.0) if self.args.node_style == CIRCLE: self._node_circle_lists = [] for n in range(0, NODE_SIZE_PRECISION): display_list = self.new_display_list_id() self._node_circle_lists.append(display_list) glNewList(display_list, GL_COMPILE) self._render_node_circle(0, 0, n) glEndList() def ReSizeGLScene(self, width, height): visualizer.Visualizer.ReSizeGLScene(self, width, height) self._size = min(width, height) - 2*MARGIN AncestryPlotter.set_size(self, self._size, self._size) def render(self): glTranslatef(MARGIN + (self.width - self._size)/2, MARGIN, 0) glLineWidth(self.args.line_width) glEnable(GL_LINE_SMOOTH) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glColor3f(1,1,1) if self.args.unfold == BACKWARD: self._cursor_t = self._duration - self._adjusted_current_time() % self._duration elif self.args.unfold == FORWARD: if self.args.ff: self._add_oldest_remaining_piece() else: while (len(self._remaining_pieces) > 0 and self._remaining_pieces[0]["t"] <= self._adjusted_current_time()): self._add_oldest_remaining_piece() if self._autozoom: self._zoom = self._zoom_smoother.value() if self._zoom is None: self._zoom = 0.0 else: self._zoom = 1.0 self.plot() if self._autozoom: if self._max_pxy == 0: zoom = 0.5 else: zoom = 0.5 + self._cursor_t/self._duration * 0.5 / self._max_pxy self._zoom_smoother.smooth(zoom, self.time_increment) def _add_oldest_remaining_piece(self): piece = self._remaining_pieces.pop(0) self.add_piece(piece["id"], piece["t"], piece["begin"], piece["end"]) def finished(self): return self.current_time() > (self._duration / self.args.timefactor + SUSTAIN_TIME) def _adjusted_current_time(self): return self.current_time() * self.args.timefactor def _follow_piece(self, piece, child=None): self._update_and_draw_node(piece, piece.t, (piece.begin + piece.end) / 2) if len(piece.growth) > 0: path = [(piece.t, (piece.begin + piece.end) / 2)] for older_version in reversed(piece.growth): if self.args.unfold == FORWARD or self._cursor_t < older_version.t: path.append((older_version.t, (older_version.begin + older_version.end) / 2)) self.draw_path(piece, path) self._update_and_draw_node(piece, path[-1][0], path[-1][1]) for parent in piece.parents.values(): if self.args.unfold == FORWARD or self._cursor_t < parent.t: self._connect_generations(parent, piece, child) self._follow_piece(parent, piece) else: if self.args.unfold == BACKWARD: t = self._cursor_t - pow(self._cursor_t - parent.t, 0.7) else: t = self._cursor_t self._connect_generations(parent, piece, child, t) self._update_and_draw_node(parent, t, (parent.begin + parent.end) / 2) def _rect_position(self, t, byte_pos): x = float(byte_pos) / self._total_size * self._width y = (1 - t / self._duration) * self._height return Vector2d(x, y) def _circle_position(self, t, byte_pos): angle = float(byte_pos) / self._total_size * 2*math.pi rel_t = 1 - t / self._duration px = rel_t * math.cos(angle) py = rel_t * math.sin(angle) x = self._width / 2 + (px * self._zoom) * self._width / 2 y = self._height / 2 + (py * self._zoom) * self._height / 2 if self._autozoom: self._max_pxy = max([self._max_pxy, abs(px), abs(py)]) return Vector2d(x, y) def draw_path(self, piece, points): if self.args.sway: piece_sway_magnitude = self._sway_magnitude(piece) glBegin(GL_LINE_STRIP) n = 0 for (t, b) in points: x, y = self._position(t, b) if self.args.sway: magnitude = (1 - float(n) / len(points)) * piece_sway_magnitude x += piece.sway.sway.x * magnitude * self._size y += piece.sway.sway.y * magnitude * self._size n += 1 glVertex2f(x, y) glEnd() def draw_curve(self, x1, y1, x2, y2): control_points = [ Vector2d(x1, y1), Vector2d(x1 + (x2 - x1) * 0.3, y1), Vector2d(x1 + (x2 - x1) * 0.7, y2), Vector2d(x2, y2) ] bezier = make_bezier([(p.x, p.y) for p in control_points]) points = bezier(CURVE_PRECISION) glBegin(GL_LINE_STRIP) for x, y in points: glVertex2f(x, y) glEnd() def draw_line(self, x1, y1, x2, y2): glBegin(GL_LINES) glVertex2f(x1, y1) glVertex2f(x2, y2) glEnd() def _update_and_draw_node(self, piece, t, b): if self.args.sway: self._update_sway(piece) if self._node_plot_method: self._node_plot_method(piece, t, b) def _update_sway(self, piece): if not hasattr(piece, "sway"): piece.sway = Sway(self.args.sway_magnitude) piece.sway.update(self.time_increment) def _draw_node_circle(self, piece, t, b): age = self._age(piece) size = self._node_size(age) cx, cy = self._position(t, b) if self.args.sway: piece_sway_magnitude = self._sway_magnitude(piece) cx += piece.sway.sway.x * piece_sway_magnitude * self._size cy += piece.sway.sway.y * piece_sway_magnitude * self._size glPushMatrix() glTranslatef(cx, cy, 0) glCallList(self._node_circle_lists[size]) glPopMatrix() def _age(self, piece): try: appearance_time = piece.appearance_time except AttributeError: appearance_time = piece.appearance_time = self._adjusted_current_time() return self._adjusted_current_time() - appearance_time def _node_size(self, age): if self._node_size_envelope: return int(self._node_size_envelope.value(age) * (NODE_SIZE_PRECISION-1)) else: return NODE_SIZE_PRECISION-1 def _sway_magnitude(self, piece): age = self._age(piece) if self._sway_envelope: return self._sway_envelope.value(age) else: return 1 def _render_node_circle(self, cx, cy, size): # glColor3f(0,0,0) # self._render_filled_circle(cx, cy, size) # glColor3f(1,1,1) # self._render_circle_outline(cx, cy, size) # glColor3f(1,1,1) # self._render_filled_circle(cx, cy, size) glColor3f(1,1,1) glEnable(GL_POINT_SMOOTH) radius = max(self.args.node_size * self.width * size / (NODE_SIZE_PRECISION-1), 0.1) glPointSize(radius * 2) glBegin(GL_POINTS) glVertex2f(cx, cy) glEnd() def _render_filled_circle(self, cx, cy, size): glBegin(GL_TRIANGLE_FAN) glVertex2f(cx, cy) angle = 0 radius = self.args.node_size * self.width * size / (NODE_SIZE_PRECISION-1) while angle < 2*math.pi: x = cx + math.cos(angle) * radius y = cy + math.sin(angle) * radius glVertex2f(x, y) angle += 0.1 x = cx + math.cos(0) * radius y = cy + math.sin(0) * radius glVertex2f(x, y) glEnd() def _render_circle_outline(self, cx, cy, size): glBegin(GL_LINE_STRIP) angle = 0 radius = self.args.node_size * self.width * size / (NODE_SIZE_PRECISION-1) while angle < 2*math.pi: x = cx + math.cos(angle) * radius y = cy + math.sin(angle) * radius glVertex2f(x, y) angle += 0.1 glEnd()