class Rect(GraphicalObject): """ Rectangle class representing a rectangle with a border. """ def __init__(self, x, y): super().__init__('rect', x, y) self._width = 1 self._height = 1 self._group = InstructionGroup() self._rec_color = Color(1.0, 1.0, 1.0, 1.0) self._rec = Rectangle(pos=(x, y), size=(self._width, self._height)) # self._x, self._y | self._x + self._width, self._y | self._x + self._width, self._y + self._height | # self._x, self._y + self._height self._group.add(self._rec_color) self._group.add(self._rec) """ Draws rectangle on canvas argument """ def draw(self, canvas): canvas.add(self._group) def resize(self, x, y): self._rec.size = x - self._x, y - self._y def get_bounding_box(self): return self._x, self._y, self._width, self._height def is_within(self, x, y): pass
def group(self, color): rgb = InstructionGroup() color = Color(1, 1, 0) xyz = color rgb.add(xyz) rgb.add(Rectangle(pos=self.pos, size=self.size) ) return rgb
class BillboardDisplay(InstructionGroup): def __init__(self, pos, texture, size_x=1.0, size_y=1.0, intensity=1.0, Tr=1.0): super(BillboardDisplay, self).__init__() self.intensity = intensity self.Tr = Tr self.translate = Translate() self.rotate_azi = Rotate(origin=(0,0,0), axis=(0,1,0)) self.rotate_ele = Rotate(origin=(0,0,0), axis=(1,0,0)) self.scale = Scale() self.color_instruction = InstructionGroup() self.mesh = Mesh( texture=texture, vertices=rectangle_nurb.vertices, indices=rectangle_nurb.indices, fmt=rectangle_nurb.vertex_format, mode='triangles' ) self.add(PushMatrix()) self.add(self.translate) self.add(self.rotate_azi) self.add(self.rotate_ele) self.add(self.scale) self.add(self.color_instruction) self.add(self.mesh) self.add(PopMatrix()) self.set_color(intensity=intensity, Tr=Tr) self.set_size(size_x, size_y) self.set_pos(pos) self.set_texture(texture) def set_texture(self, texture): self.texture = texture self.mesh.texture = texture def set_rotate(self, angles): self.rotate_azi.angle = angles[0] * 180/np.pi self.rotate_ele.angle = angles[1] * 180/np.pi def set_size(self, size_x, size_y): self.scale.xyz = (size_x, size_y, 1) def set_pos(self, pos): self.translate.xyz = pos def set_color(self, intensity=1.0, Tr=1.0): self.color_instruction.clear() self.color_instruction.add( ChangeState( Kd=(0.6, 0.6, 0.6), Ka=(0.8, 0.8, 0.8), Ks=(0.9, 0.9, 0.9), Tr=Tr, Ns=1.0, intensity=intensity ) )
def group(self, color): rgb = InstructionGroup() color = Color(1, 1, 0) xyz = color rgb.add(xyz) rgb.add(Rectangle(pos=self.pos, size=self.size)) return rgb
class Piece(Button): index = ListProperty(None) color = StringProperty('blank') board_size = NumericProperty(None) is_dead = BooleanProperty(False) marker = None def place_piece(self, color): if color is None: self.color = 'blank' else: self.color = str(color) def update_marker(self, color): if color is None: if self.marker is not None: self.canvas.remove(self.marker) else: self.marker = InstructionGroup() self.marker.add( kColor(*((0, 0, 0) if color == Color.black else (1, 1, 1)))) self.marker.add( Rectangle(pos=(self.pos[0] + (self.size[0] / 4) * 1.5, self.pos[1] + (self.size[1] / 4) * 1.5), size=(self.size[0] / 4, self.size[1] / 4))) self.canvas.add(self.marker)
def drawCrossLine(self, aIndex): """ """ dataNum = len(self.minTimeList) if dataNum == 0: return if aIndex >= dataNum: index = dataNum - 1 elif aIndex < 0: index = 0 else: index = aIndex self.crossLineIndex = index if self.infoFunc == None: self._showInfo(index) else: self.infoFunc(self.minTimeList[index]) groupStr = self.instGroup + "cross_line" self.canvas.remove_group(groupStr) instg = InstructionGroup(group=groupStr) color = Color() color.rgba = self.CROSS_LINE_COLOR instg.add(color) x1 = self.start_xaxis + index * self.xscale y1 = self.volume_yaxis x2 = self.start_xaxis + index * self.xscale y2 = self.volume_yaxis + self.crossLine_height instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def _drawLine(self, aValue, dispIdx, isLastFlag): """ """ groupStr = self.instGroup if isLastFlag == True: groupStr += "_lastData" else: groupStr += "_curvData" instg = InstructionGroup(group=groupStr) color = Color() if aValue > 0: color.rgba = self.UP_COLOR else: color.rgba = self.DOWN_COLOR instg.add(color) x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) + self.tickGap y1 = self.chartPos[1] + self.baseYPos rectHeight = abs(aValue) * self.yscale if aValue < 0: y1 = y1 - rectHeight instg.add(Rectangle(pos=(x1,y1), size=(self.tickWide, rectHeight))) self.canvas.add(instg)
class MyWidget(Widget): undolist = [] objects = [] drawing = False def on_touch_up(self, touch): self.drawing = False def on_touch_move(self, touch): if self.drawing: self.points.append(touch.pos) self.obj.children[-1].points = self.points else: self.drawing = True self.points = [touch.pos] self.obj = InstructionGroup() self.obj.add(Color(1, 1, 1)) self.obj.add(Line()) self.objects.append(self.obj) self.canvas.add(self.obj) def undo(self): item = self.objects.pop(-1) self.undolist.append(item) self.canvas.remove(item) def redo(self): item = self.undolist.pop(-1) self.objects.append(item) self.canvas.add(item)
def group(self, color): rgb = InstructionGroup() color = Color(1, 0, 0) xyz = color rgb.add(xyz) radius = sqrt(sqrt(sum([x * x for x in self.size]))) rgb.add(Line(circle=(self.pos[0], self.pos[1], radius))) return rgb
def group(self, color): rgb = InstructionGroup() color = Color(1, 0, 0) xyz = color rgb.add(xyz) radius = sqrt(sqrt(sum([x*x for x in self.size]))) rgb.add(Line(circle=(self.pos[0], self.pos[1], radius ) ) ) return rgb
class NurbDisplay(InstructionGroup): def __init__(self, nurb, pos, size=1.0, color=(0.0, 1.0, 0.0), tr=1.0, intensity=1.0): super(NurbDisplay, self).__init__() self.color = color self.tr = tr self.intensity = intensity self.translate = Translate() self.scale = Scale() self.color_instruction = InstructionGroup() self.add(PushMatrix()) self.add(self.translate) self.add(self.scale) self.add(self.color_instruction) self.add(self.make_mesh(nurb)) self.add(PopMatrix()) self.set_color() self.set_size(size) self.set_pos(pos) def make_mesh(self, m): return Mesh(vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles') def set_size(self, size): self.scale.xyz = (size, size, size) def set_pos(self, pos): self.translate.xyz = pos def set_color(self, color=None, tr=None, intensity=None): if tr is not None: self.tr = tr if intensity is not None: self.intensity = intensity if color is not None: self.color = color self.color_instruction.clear() self.color_instruction.add( ChangeState(Kd=self.color, Ka=self.color, Ks=(0.3, 0.3, 0.3), Tr=self.tr, Ns=1.0, intensity=self.intensity))
def __init__(self, **kwargs): super(SimulationWidget, self).__init__(**kwargs) self.nest_radius = 3 self.old_window_size_x = 0 self.old_window_size_y = 0 self.cells = [[0 for y in range(HEIGHT)] for x in range(WIDTH + 1)] x, y = Window.size self.spacing_x = x / WIDTH self.spacing_y = y / HEIGHT self.meter_width = x / 2 self.meter_bar = InstructionGroup() self.meter_bar.add(Color(1, 1, 1)) self.meter_bar.add( RoundedRectangle(pos=[ x / 2 - self.meter_width / 2, y - self.meter_height * 0.9 ], size=[self.meter_width, self.meter_height / 3])) self.meter_indicator.source = os.path.join(ROOT_PATH, "indicator.png") self.meter_backdrop.source = os.path.join(ROOT_PATH, "indicator_backdrop.png") self.meter_backdrop.pos = [ x / 2 - self.meter_backdrop.size[0] / 2, y - self.meter_height * 1.2 ] self.meter_indicator.pos = [ x / 2 - self.meter_indicator.size[0] / 2, y - self.meter_height * 1.2 ] self.meter_backdrop.size = [self.meter_height, self.meter_height] self.meter_indicator.size = [self.meter_height, self.meter_height] self.meter_backdrop.color = interpolate_color(self.p1_color, self.p2_color, 0.5) self.sides = InstructionGroup() self.sides.add(Color(rgb=self.p1_color)) self.sides.add(Rectangle(pos=[0, 0], size=[self.bar_width, y])) self.sides.add(Color(rgb=self.p2_color)) self.sides.add( Rectangle(pos=[x - self.bar_width, 0], size=[self.bar_width, y])) x = 0 y = -1 count = 0 for i in range(0, len(WORLD_DATA), INTS_PER_FIELD): x = (i - (count * INTS_PER_FIELD) + count) % WIDTH count += 1 if x % WIDTH == 0: y += 1 y_inverted = HEIGHT - y - 1 g = InstructionGroup() g.add(Color(0, 0, 0, 1)) # black g.add( Rectangle(pos=(x * self.spacing_x, y_inverted * self.spacing_y), size=(self.spacing_x, self.spacing_y))) self.ids["grid_layout"].canvas.add(g) self.cells[x][y_inverted] = g self.ids["grid_layout"].canvas.add(self.sides) self.ids["grid_layout"].canvas.add(self.meter_bar)
class NurbDisplay(InstructionGroup): def __init__(self, nurb, pos, size=1.0, color=(0.0,1.0,0.0), tr=1.0, intensity=1.0): super(NurbDisplay, self).__init__() self.color = color self.tr = tr self.intensity = intensity self.translate = Translate() self.scale = Scale() self.color_instruction = InstructionGroup() self.add(PushMatrix()) self.add(self.translate) self.add(self.scale) self.add(self.color_instruction) self.add(self.make_mesh(nurb)) self.add(PopMatrix()) self.set_color() self.set_size(size) self.set_pos(pos) def make_mesh(self, m): return Mesh( vertices=m.vertices, indices=m.indices, fmt=m.vertex_format, mode='triangles' ) def set_size(self, size): self.scale.xyz = (size, size, size) def set_pos(self, pos): self.translate.xyz = pos def set_color(self, color=None, tr=None, intensity=None): if tr is not None: self.tr = tr if intensity is not None: self.intensity = intensity if color is not None: self.color = color self.color_instruction.clear() self.color_instruction.add( ChangeState( Kd=self.color, Ka=self.color, Ks=(0.3, 0.3, 0.3), Tr=self.tr, Ns=1.0, intensity=self.intensity ) )
class Cell(Widget): def __init__(self, i, text, **kwargs): super(Cell, self).__init__(**kwargs) self.ig = InstructionGroup() self.rect = Rectangle() self.text = text self.color = Color(0.2, 0.2, 0.2 * i) self.ig.add(self.color) self.ig.add(self.rect)
class MyWidget(Widget): undolist = [] objects = [] drawing = False eraser = False def on_touch_up(self, touch): self.drawing = False def on_touch_move(self, touch): if self.eraser == False: if self.drawing: self.points.append(touch.pos) self.obj.children[-1].points = self.points else: self.drawing = True self.points = [touch.pos] print(self.points) self.obj = InstructionGroup() self.obj.add(Color(0, 0, 0)) self.obj.add(Line(width=2.5)) self.objects.append(self.obj) self.canvas.add(self.obj) else: for obj in self.objects: for point in obj.children[-1].points: # if point. templine = Line(width=2.5, points=[touch.pos]) if point == (templine.points[0], templine.points[1]): print(obj.children[-1].points) self.canvas.remove(obj) obj.children[-1].points.remove(point) print(obj.children[-1].points) self.canvas.add(obj) def toggleEraser(self): if self.eraser == False: print("Eraser on") self.eraser = True else: print("Eraser off") self.eraser = False def undo(self): item = self.objects.pop(-1) self.undolist.append(item) self.canvas.remove(item) def redo(self): item = self.undolist.pop(-1) self.objects.append(item) self.canvas.add(item)
class BeatBar(FloatLayout): num_beats = NumericProperty(4) def __init__(self, **kwargs): super().__init__(**kwargs) self.beatmarkers = InstructionGroup() for i in range(self.num_beats): beatmarker = BeatMarker() self.beatmarkers.add(beatmarker) self.canvas.add(self.beatmarkers) def on_num_beats(self, instance, num_beats): while num_beats > len(self.beatmarkers.children): beatmarker = BeatMarker() self.beatmarkers.add(beatmarker) while num_beats < len(self.beatmarkers.children): self.beatmarkers.children.pop() self.update_beatmarkers() def on_size(self, *args): self.update_beatmarkers() def on_pos(self, *args): # Needed for slide up menu. self.update_beatmarkers() def update_beatmarkers(self): target_ratio = self.num_beats / 1 aspect_ratio = self.width / self.height percent_radius = 0.6 # circle shouldn't take up the whole square if aspect_ratio > target_ratio: side = self.height r = side / 2 * percent_radius rdiff = side / 2 - r dx = (self.width - (self.num_beats * side)) / 2 cx, cy = self.x + dx + rdiff, self.y + rdiff step_x = side for beatmarker in self.beatmarkers.children: beatmarker.pos = [cx, cy] beatmarker.size = [2*r, 2*r] cx += step_x else: side = self.width / self.num_beats r = side / 2 * percent_radius rdiff = side / 2 - r dy = (self.height - side) / 2 cx, cy = self.x + rdiff, self.y + dy + rdiff step_x = side for beatmarker in self.beatmarkers.children: beatmarker.pos = [cx, cy] beatmarker.size = [2*r, 2*r] cx += step_x
def drawVolumeGraph(self, data, curIndex): instg = InstructionGroup(group="data") volume = data.get("vol") color = Color() color.rgba = self.VOLUME_COLOR instg.add(color) x1 = int(self.pos[0] + self.shift_left + curIndex * self.xscale) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.shift_left + curIndex * self.xscale) y2 = int(self.pos[1] + self.shift_bottom + volume * self.vscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
class BackgroundLabel(Label): def __init__(self, **kwargs): super(BackgroundLabel, self).__init__(**kwargs) self.IG = InstructionGroup() self.background_color = (0, 0, 0, 1) self.color = (1, 1, 1, 1) def Set_Background_Color(self): self.opacity = 1 self.IG.clear() self.IG.add(Color(rgba=(self.background_color))) self.IG.add(Rectangle(size=(self.size), pos=(self.pos))) self.canvas.before.add(self.IG)
async def draw_rect(self, touch): from kivy.graphics import Line, Color, Rectangle, InstructionGroup from kivy.utils import get_random_color inst_group = InstructionGroup() self.canvas.add(inst_group) inst_group.add(Color(*get_random_color())) line = Line(width=2) inst_group.add(line) ox, oy = self.to_local(*touch.opos) on_touch_move_was_fired = False async for __ in ak.rest_of_touch_moves(self, touch): # Don't await anything during this async-for-loop on_touch_move_was_fired = True x, y = self.to_local(*touch.pos) min_x = min(x, ox) min_y = min(y, oy) max_x = max(x, ox) max_y = max(y, oy) line.rectangle = [min_x, min_y, max_x - min_x, max_y - min_y] if on_touch_move_was_fired: inst_group.add(Color(*get_random_color(alpha=.3))) inst_group.add( Rectangle( pos=(min_x, min_y), size=( max_x - min_x, max_y - min_y, ), )) else: self.canvas.remove(inst_group)
def drawCrossLine(self, index): if self.dataList == None or index >= len(self.dataList): return data = self.dataList[index] price = data.get("price") color = Color() color.rgba = self.CROSS_LINE_COLOR self.canvas.remove_group("cross_line") instg = InstructionGroup(group="cross_line") instg.add(color) x1 = int(self.pos[0] + self.shift_left + index * self.xscale) y1 = self.pos[1] + self.shift_bottom x2 = int(self.pos[0] + self.shift_left + index * self.xscale) y2 = self.pos[1] + self.height - self.shift_top instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) instg = InstructionGroup(group="cross_line") instg.add(color) x1 = self.pos[0] + self.shift_left y1 = int(self.pos[1] + self.shift_bottom + (price - self.min_price) * self.yscale) x2 = self.pos[0] + self.width - self.shift_right y2 = int(self.pos[1] + self.shift_bottom + (price - self.min_price) * self.yscale) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def drawCordFrame(self): # 畫一條橫線 instg = InstructionGroup(group="frame") frameColor = Color() frameColor.rgba = self.FRAME_COLOR instg.add(frameColor) x1 = int(self.pos[0] + self.shift_left) y1 = int(self.pos[1] + self.shift_bottom) x2 = int(self.pos[0] + self.width - self.shift_right) y2 = int(self.pos[1] + self.shift_bottom) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) # 畫一條豎線 instg = InstructionGroup(group="frame") instg.add(frameColor) center_pos = int(self.pillarPoint / 2) self.center_xpos = int(self.pos[0] + self.shift_left + (self.min_tickNum * -1) * self.pillarSumPoint + self.ycordWidth + center_pos) x1 = self.center_xpos y1 = int(self.pos[1] + self.shift_bottom) x2 = self.center_xpos y2 = int(self.pos[1] + self.height - self.shift_top) instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
async def draw_rect(self, touch): from kivy.graphics import Line, Color, Rectangle, InstructionGroup from kivy.utils import get_random_color inst_group = InstructionGroup() self.canvas.add(inst_group) inst_group.add(Color(*get_random_color())) line = Line(width=2) inst_group.add(line) ox, oy = x, y = self.to_local(*touch.opos) async for __ in ak.rest_of_touch_moves(self, touch, stop_dispatching=True): # Don't await anything during the iteration x, y = self.to_local(*touch.pos) min_x, max_x = (x, ox) if x < ox else (ox, x) min_y, max_y = (y, oy) if y < oy else (oy, y) line.rectangle = ( min_x, min_y, max_x - min_x, max_y - min_y, ) if x == ox and y == oy: self.canvas.remove(inst_group) else: inst_group.add(Color(*get_random_color(alpha=.3))) inst_group.add( Rectangle( pos=(min_x, min_y), size=( max_x - min_x, max_y - min_y, ), ))
def __get_dbg_aabb_gfx(self): if self.__dbg_aabb is None: c = Color(0.8, 0.8, 0.8, 0.3) r = Rectangle() group = InstructionGroup() for instruction in (c, r): group.add(instruction) def update_r(_, ((left, bottom), (right, top))): r.pos = (left, bottom) r.size = (right - left, top - bottom) self.bind(aabb=update_r) update_r(None, self.aabb) self.__dbg_aabb = group
def __get_dbg_viewport_gfx(self): if self.__dbg_viewport is None: c = Color(1, 1, 1, 0.5) r = Rectangle() group = InstructionGroup() for instruction in (c, r): group.add(instruction) def update_r(_, __): r.pos = self.viewport_pos r.size = self.viewport_size self.bind(viewport_pos=update_r, viewport_size=update_r) update_r(None, None) self.__dbg_viewport = group return self.__dbg_viewport
def _drawVolumeLine(self, aDict, aIdx, isLastFlag): groupStr = self.instGroup if isLastFlag == True: groupStr += "volume_lastData" else: groupStr += "volume_curvData" instg = InstructionGroup(group=groupStr) color = Color() color.rgba = self.VOLUME_COLOR instg.add(color) x1 = self.start_xaxis + aIdx * self.xscale y1 = self.volume_yaxis x2 = x1 y2 = self.volume_yaxis + aDict.get("Vol") * self.volume_yscale instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def draw_line_preview(self, points, close): try: if len(self.lines) > 1: item = self.lines.pop(0) self.canvas.remove(item) line = InstructionGroup() line.add( Color(self.tool_color[0], self.tool_color[1], self.tool_color[2], self.tool_color[3])) line.add( Line(points=(points), width=(self.tool_size / 2), close=close)) self.lines.append(line) self.canvas.add(line) except: pass
def draw_fig(self): #traverse points to draw line of figure coords = [] for p in self.points_as_added: coords.append(p.a_point_x) coords.append(p.a_point_y) self.canvas.remove(self.line_draw) new_line = InstructionGroup() new_line.add( Color(rose_50[0], rose_50[1], rose_50[2], rose_50[3], mode='rgba')) new_line.add(Line(points=coords, close=True, width=2)) self.line_draw = new_line self.canvas.add(self.line_draw) return
class NoteDisplay(InstructionGroup): def __init__(self, note_data, planes, ac): super(NoteDisplay, self).__init__() self.note = note_data self.planes = sorted(planes) self.ac = ac self.sound_count = 0 self.past_me = False self.sounds = [] self.sound_group = InstructionGroup() self.color = COLORS[self.note.pitch % 12] self.intensity = self.note.velocity self.texture_indices = [(self.color, i) for i in range(100) +list(reversed(xrange(1,101)))] self.texture_frame = np.random.randint(len(self.texture_indices)) self.billboard = BillboardDisplay(self.pos_from_tick(ac.tick), texture=textures[self.texture_indices[0]], size_x=2.0, size_y=2.0, intensity=self.intensity) self.add(self.sound_group) self.add(self.billboard) def pos_from_tick(self, tick): z = - (self.note.tick - tick) * config['UNITS_PER_TICK'] x = config['LINE_SPACING'] * self.note.x y = config['LINE_SPACING'] * self.note.y return (x, y, z) def set_pos(self, pos): self.billboard.set_pos(pos) def sound(self, tick, pos): # Play Sound self.ac.play_note(tick, self.note, pos) # Render Sound exp_time = max(self.note.duration * 60 / (480 * self.ac.scheduler.cond.bpm), 0.2) sound_display = SoundDisplay(pos, exp_time, self) self.sounds.append(sound_display) self.sound_group.add(sound_display) def on_update(self, dt, tick, angles): self.texture_frame += 1 self.billboard.set_texture(textures[self.texture_indices[int(self.texture_frame) % len(self.texture_indices)]]) self.billboard.set_rotate(angles) for s in self.sounds: if not s.on_update(dt, tick, angles): self.sounds.remove(s) self.sound_group.remove(s)
def drawCrossLine(self, aIndex): """ """ dataNum = len(self.dataDict) if dataNum == 0: return if aIndex >= self.dispMax: index = self.dispMax - 1 elif aIndex >= self.dispNum: index = self.dispNum - 1 elif aIndex < 0: index = 0 else: index = aIndex self.crossLineIndex = index if self.infoFunc == None: self._showInfo(index) else: aKey = self.keyList[self.scopeIdx[0] + index] aDict = self.dataDict.get(aKey) refDict = {} for aKey in aDict.keys(): refDict[aKey] = aDict.get(aKey) refDict["TechType"] = self.techType self.infoFunc(refDict) if self.isDrawCrossLine == False: return groupStr = self.instGroup + "cross_line" self.canvas.remove_group(groupStr) color = Color() color.rgba = self.CROSS_LINE_COLOR instg = InstructionGroup(group=groupStr) instg.add(color) x1 = self.chartPos[0] + (index + 1) * (self.tickWide + self.tickGap) - self.backGap y1 = self.chartPos[1] x2 = x1 y2 = self.chartPos[1] + self.chartSize[1] instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg) aKey = self.keyList[self.scopeIdx[0] + index] aDict = self.dataDict.get(aKey) instg = InstructionGroup(group=groupStr) instg.add(color) x1 = self.chartPos[0] y1 = self.chartPos[1] + (aDict.get("VOL") - self.lowestValue) * self.yscale x2 = self.chartPos[0] + self.chartSize[0] y2 = y1 instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
class MyWidget(Widget): def __init__(self, **kwargs): super(MyWidget, self).__init__(**kwargs) self.ig = InstructionGroup() self.line = Line(points=[100, 200, 300, 400]) self.ig.add(self.line) self.canvas.add(self.ig) Thread(target=self.draw).start() def draw(self): while True: self.line.points = [randint(0,400) for i in range(4)] time.sleep(0.5)
class ErrorPiece(Piece): def __init__(self, **kwargs): super(ErrorPiece, self).__init__(**kwargs) self.highlight = False def on_parent(self, *args): if self.parent: Clock.schedule_interval(self.update, .5) def on_keypress(self, keyboard, keycode, text, modifiers): return True def do_layout(self, *args): super(ErrorPiece, self).do_layout(*args) self.update() def update(self, *args): if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() if self.highlight: for child in self.children[:]: self.outline.add(Color(1, .2, .2, .8)) self.outline.add(Line( points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5 )) if self.canvas.before: self.canvas.before.add(self.outline) self.highlight = False else: self.canvas.before.remove(self.outline) self.highlight = True
class KidDrawingScreen(Screen): undolist = [] objects = [] drawing = False def on_touch_up(self, touch): self.drawing = False def on_touch_down(self, touch): super(KidDrawingScreen, self).on_touch_down(touch) with self.canvas: Color(random(), random(), random()) #색 랜덤으로 바꾸기 self.line = Line(points=[touch.pos[0], touch.pos[1]], width=2) #포인터 위치 지정 def on_touch_move(self, touch): if self.drawing: self.points.append(touch.pos) self.obj.children[-1].points = self.points else: self.drawing = True self.points = [touch.pos] self.obj = InstructionGroup() self.obj.add(Color(random(), random(), random())) self.obj.add(Line(width=2)) self.objects.append(self.obj) self.canvas.add(self.obj) def undo(self): if len(self.objects) != 0: item = self.objects.pop(-1) self.undolist.append(item) self.canvas.remove(item) def clear_canvas( self ): # 캔퍼스를 지우는 기능. 캔퍼스는 투명도 0으로 만드어놨기때문에 보이지는 않지만, 지우는 기능은 가능하다. self.canvas.clear() def Ss(self): timestr = time.strftime("%Y%m%d_%H%M%S") self.export_to_png(f"{dirname(__file__)}\draw\IMG_" + timestr + ".png")
def __init__(self, **kwargs): super(ResizableCursor, self).__init__(**kwargs) self.size_hint = (None, None) self.pos_hint = (None, None) self.source = '' self.rect = Rectangle(pos=(-9998,-9998), size=(1, 1)) self.size = (dp(22), dp(22)) self.pos = [-9998, -9998] # Makes an instruction group with a rectangle and # loads an image inside it # Binds its properties to mouse positional changes and events triggered instr = InstructionGroup() instr.add(self.rect) self.canvas.after.add(instr) self.bind(pos=lambda obj, val: setattr(self.rect, 'pos', val)) self.bind(source=lambda obj, val: setattr(self.rect, 'source', val)) self.bind(hidden=lambda obj, val: self.on_mouse_move(Window.mouse_pos)) Window.bind(mouse_pos=lambda obj, val: self.on_mouse_move(val))
def __init__(self, **kwargs): super(ResizeCursor, self).__init__(**kwargs) self.size_hint = (None, None) self.pos_hint = (None, None) self.source = '' self.rect = Rectangle(pos=(-9998, -9998), size=(1, 1)) self.size = (dp(22), dp(22)) self.pos = [-9998, -9998] # Makes an instruction group with a rectangle and # loads an image inside it # Binds its properties to mouse positional changes and events triggered instr = InstructionGroup() instr.add(self.rect) self.canvas.after.add(instr) self.bind(pos=lambda obj, val: setattr(self.rect, 'pos', val)) self.bind(source=lambda obj, val: setattr(self.rect, 'source', val)) self.bind(hidden=lambda obj, val: self.on_mouse_move(Window.mouse_pos)) Window.bind(mouse_pos=lambda obj, val: self.on_mouse_move(val))
def selection(widget, select=False): """Emphasizes the widget adding a clear transparent background. Args: widget (Widget): the widget to apply selection to select (bool, optional): Apply selection. Defaults to False. """ group = len(widget.canvas.get_group('sel')) > 0 if not group: sel = InstructionGroup(group='sel') sel.add(Color(1, 1, 1, 0.3)) sel.add(Rectangle(pos=widget.pos, size=widget.size)) with widget.canvas: if select and not group: widget.canvas.add(sel) elif not select and group: widget.canvas.remove_group('sel') else: pass # Nothing to do here!
class ErrorPiece(Piece): def __init__(self, **kwargs): super(ErrorPiece, self).__init__(**kwargs) self.highlight = False def on_parent(self, *args): if self.parent: Clock.schedule_interval(self.update, .5) def on_keypress(self, keyboard, keycode, text, modifiers): return True def do_layout(self, *args): super(ErrorPiece, self).do_layout(*args) self.update() def update(self, *args): if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() if self.highlight: for child in self.children[:]: self.outline.add(Color(1, .2, .2, .8)) self.outline.add( Line(points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5)) if self.canvas.before: self.canvas.before.add(self.outline) self.highlight = False else: self.canvas.before.remove(self.outline) self.highlight = True
def _drawLine(self, preValue, aValue, dispIdx, isLastFlag): """ 繪製曲線 """ groupStr = self.instGroup if isLastFlag == True: groupStr += "_lastData" else: groupStr += "_curvData" instg = InstructionGroup(group=groupStr) color = Color() color.rgba = self.CURV_COLOR instg.add(color) #(self.tickWide + self.tickGap)代表顯示一筆資料,在x軸方向所需的總點數 x1 = self.chartPos[0] + dispIdx * (self.tickWide + self.tickGap) - self.backGap y1 = self.chartPos[1] + (preValue - self.lowestValue) * self.yscale x2 = x1 + (self.tickWide + self.tickGap) y2 = self.chartPos[1] + (aValue - self.lowestValue) * self.yscale instg.add(Line(points=(x1, y1, x2, y2), width=1)) self.canvas.add(instg)
def __get_dbg_origin_gfx(self): if self.__dbg_origin is None: c1 = Color(1, 0, 0, 0.5) r1 = Rectangle() c2 = Color(0, 1, 0, 0.5) r2 = Rectangle() c3 = Color(0, 0, 1, 0.5) e = Ellipse() group = InstructionGroup() for instruction in (c1, r1, c2, r2, c3, e): group.add(instruction) def update_geom(_, (w, h)): r1.size = (w, 0.1 * h) r2.size = (0.1 * w, h) e.size = (0.5 * w, 0.5 * h) e.pos = (0.25 * w, 0.25 * h) self.bind(viewport_size=update_geom) update_geom(None, self.size) self.__dbg_origin = group
class PrinterAnimation(RelativeLayout): padding = NumericProperty(40) printer_actual_dimensions = ListProperty([10, 10, 80]) printer_current_actual_height = NumericProperty(0.0) print_area_height = NumericProperty(1) print_area_width = NumericProperty(1) print_area_left = NumericProperty(0) print_area_bottom = NumericProperty(40) container_padding = NumericProperty(0) container_left = NumericProperty(0) container_width = NumericProperty(0) container_bottom = NumericProperty(0) container_height = NumericProperty(0) laser_size = ListProperty([40, 40]) resin_height = NumericProperty(20) water_height = NumericProperty(20) scale = NumericProperty(1.0) resin_color = ListProperty([0.0, 0.8, 0.0, 0.6]) water_color = ListProperty([0.2, 0.2, 1.0, 0.6]) container_color = ListProperty([1.0, 1.0, 1.0, 1.0]) laser_color_edge2 = ListProperty([0.0, 0.0, 0.5, 1.0]) laser_color_edge = ListProperty([0.0, 0.0, 1.0, 1.0]) laser_color = ListProperty([0.7, 1.0, 1.0, 1.0]) drip_history = ListProperty() laser_points = ListProperty() middle_x = NumericProperty(52) laser_pos = NumericProperty(60) laser_speed = NumericProperty(1) refresh_rate = NumericProperty(1.0) def __init__(self, **kwargs): super(PrinterAnimation, self).__init__(**kwargs) self.drip_time_range = 5 self.waiting_for_drips = True self.refresh_rate = App.get_running_app().refresh_rate self._gl_setup() self.axis_history = [] self.drips = 0 self.line_x = [] self.line_y = [] self.last_height = 0.0 self.min_height = 0.0 self.last_x_min = 0.0 self.last_x_max = 1.0 self.is_on_canvas = False def on_printer_actual_dimensions(self, instance, value): self.min_height = self.printer_actual_dimensions[2] / 400.0 self.on_size(None) def _gl_setup(self): self.drip_texture = CoreImage("resources/images/drop.png", mipmap=True).texture self.drips_instruction = InstructionGroup() self.model_instruction = InstructionGroup() print(self.canvas.children) # self.canvas.add(self.drips_instruction) # self.canvas.add(self.model_instruction) def on_size(self, *largs): bounds_y = (self.height * 0.7) - self.resin_height bounds_x = self.width - (self.padding * 2) printer_x = self.printer_actual_dimensions[0] printer_y = self.printer_actual_dimensions[2] self.laser_pos = self.width / 2 self.scale = min(bounds_y / printer_y, bounds_x / printer_x) Logger.info("Scale: {}".format(self.scale)) self.print_area_width = printer_x * self.scale self.print_area_height = printer_y * self.scale def redraw(self, key): self._draw_drips() self._draw_laser() self._draw_model() if not self.is_on_canvas: self.canvas.insert(4, self.drips_instruction) self.canvas.insert(4, self.model_instruction) self.is_on_canvas = True Clock.unschedule(self.redraw) Clock.schedule_once(self.redraw, self.refresh_rate) def animation_start(self, *args): Clock.unschedule(self.redraw) self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] Clock.schedule_once(self.redraw, self.refresh_rate) def animation_stop(self): Clock.unschedule(self.redraw) self.axis_history = [] self.line_x = [] self.line_y = [] self.last_height = 0 self.min_height = 0.0 self.laser_points = [] self.drip_history = [] def _draw_drips(self): self.drips_instruction.clear() self.drips_instruction.add(Color(1, 1, 1, 1)) top = time.time() bottom = top - self.drip_time_range drips_in_history = len(self.drip_history) for (index, drip_time) in zip(range(drips_in_history, 0, -1), self.drip_history): if drip_time > bottom: time_ago = top - drip_time y_pos_percent = (self.drip_time_range - time_ago) / self.drip_time_range drip_pos_y = (self.height * y_pos_percent) + self.padding xoff = 10 + math.sin((len(self.drip_history) - index) / (2 * math.pi)) * 20 self.drips_instruction.add(Rectangle(size=[12, 16], pos=[self.print_area_left + xoff, drip_pos_y], texture=self.drip_texture)) def _draw_laser(self): if self.waiting_for_drips: self.laser_points = [] else: x_min = self.print_area_left + (self.last_x_min * self.print_area_width) x_max = self.print_area_left + (self.last_x_max * self.print_area_width) if (self.laser_pos >= x_max): self.laser_pos = x_max self.laser_speed = abs(self.laser_speed) * -1 if (self.laser_pos <= x_min): self.laser_pos = x_min self.laser_speed = abs(self.laser_speed) self.laser_pos += self.laser_speed laser_x = self.laser_pos self.laser_points = [self.middle_x, self.height - self.padding, laser_x, self.water_height + self.print_area_bottom + self.resin_height] def _draw_model(self): if self.axis_history: model_height = self.axis_history[-1][2] if model_height > (self.last_height + self.min_height) or not self.line_x: x1, y1, x2, y2 = self._get_pixels(self.axis_history[-1]) self.last_x_min = x1 self.last_x_max = x2 self.line_x.insert(0, x1) self.line_x.append(x2) self.line_y.insert(0, y1) self.line_y.append(y2) self.last_height = model_height points = [] for idx in range(0, len(self.line_x)): x = int(self.print_area_left + (self.line_x[idx] * self.print_area_width)) y = int(self.print_area_bottom + self.resin_height + (self.line_y[idx] * self.print_area_height)) - 2 points.append(x) points.append(y) self.model_instruction.clear() self.model_instruction.add(Color(rgba=(1.0, 0.0, 0.0, 1.0))) self.model_instruction.add(Line(points=points, width=2, close=True)) def _get_pixels(self, data): pixel_height = data[2] / self.printer_actual_dimensions[2] pixel_pos_min = (data[0][0] + (self.printer_actual_dimensions[1] / 2.0)) / self.printer_actual_dimensions[1] pixel_pos_max = (data[0][1] + (self.printer_actual_dimensions[1] / 2.0)) / self.printer_actual_dimensions[1] return [pixel_pos_min, pixel_height, pixel_pos_max, pixel_height]
class CanvasWidget(FloatLayout): canvas_size = ObjectProperty((512, 512)) scale = NumericProperty(1) texture = ObjectProperty() touch_type = 'move' current_color = [0,0,0,1] @property def scaled_size(self): w, h = self.canvas_size return (w * self.scale, h * self.scale) def __init__(self, **kwargs): super(CanvasWidget, self).__init__(**kwargs) self.size = (512, 512) self._keyboard = Window.request_keyboard(self._keyboard_closed, self) self._keyboard.bind(on_key_down=self._on_keyboard_down) self.img = Image.open('test.png') self.img = self.img = self.img.transpose(Image.FLIP_TOP_BOTTOM) self.texture = Texture.create(size=(512,512)) self.texture.mag_filter = 'nearest' size = 512*512*3 buf = [] for r,g,b,a in self.img.getdata(): buf.extend([r,g,b,a]) #buf = [int(x*255/size) for x in range(size)] #buf = self._flatten_list(self.pixels) self.arr = array('B', buf) self.texture.blit_buffer(self.arr, colorfmt='rgba', bufferfmt='ubyte') with self.canvas: self.test = InstructionGroup() #self.test.add(Color(1, 1, 0, mode='rgb')) self.test.add(Rectangle(texture=self.texture, pos=self.pos, size=self.size, group='heh')) #self.bind(texture=self.on_texture_update) self.bind(pos=self.on_texture_update) self.bind(size=self.on_texture_update) def on_texture_update(self, instance=None, value=None): print('on_texture_update') for inst in self.test.get_group('heh'): if hasattr(inst, 'pos'): inst.pos = self.pos if hasattr(inst, 'size'): inst.size = self.size #self.canvas.clear() #with self.canvas: # Color(1, 1, 0, mode='rgb') # #Rectangle(texture=self.texture, pos=self.pos, size=self.size) # Rectangle(pos=self.pos, size=self.size) def _keyboard_closed(self): self._keyboard.unbind(on_key_down=self._on_keyboard_down) self._keyboard = None def _on_keyboard_down(self, keyboard, keycode, text, modifiers): if keycode[1] == 'q': self.touch_type = 'move' elif keycode[1] == 'w': self.touch_type = 'draw' elif keycode[1] == 'e': r = random.random() g = random.random() b = random.random() print(self.parent.parent.ids.palette.add_color([r,g,b,1])) def on_touch_down(self, touch): if touch.button == 'scrolldown': print('Zoomin\' in') self.set_scale(self.scale * 1.2, touch.pos) elif touch.button == 'scrollup': print('Zoomin\' out') self.set_scale(self.scale / 1.2, touch.pos) else: if self.touch_type == 'draw': x,y = self.project(touch.pos) r,g,b,a = self.current_color self.update_pixel(int(x), int(y), r, g, b, a) self.refresh() touch.grab(self) return True def on_touch_move(self, touch): if touch.grab_current == self: if self.touch_type == 'move': x, y = self.pos dx, dy = touch.dpos self.pos = (x+dx, y+dy) elif self.touch_type == 'draw': x,y = self.project(touch.pos) px, py = self.project(touch.ppos) #self.update_pixel(int(x), int(y), 255, 0, 100, 100) r,g,b,a = self.current_color self.draw_line(px, py, x, y, r,g,b,a) return True def set_color(self, color): self.current_color = color def on_touch_up(self, touch): if touch.grab_current == self: touch.ungrab(self) return True def update_pixel(self, x, y, r, g, b, a): w,h = self.canvas_size index = int((y * w * 4) + 4 * x) self.arr[index] = int(r*255) self.arr[index+1] = int(g*255) self.arr[index+2] = int(b*255) self.arr[index+3] = int(a*255) self.texture.blit_buffer(self.arr, colorfmt='rgba', bufferfmt='ubyte') print('PIXEL: %s,%s' % (int(x), int(y))) def refresh(self): self.canvas.ask_update() def draw_line(self, x0, y0, x1, y1, r,g,b,a): self.update_pixel(int(x0),int(y0),r,g,b,a) self.update_pixel(int(x1),int(y1),r,g,b,a) print('LINE: %s, %s -> %s, %s' % (x0,y0,x1,y1)) x0, y0, x1, y1 = int(x0), int(y0), int(x1), int(y1) steep = abs(y1-y0) > abs(x1-x0) if steep: x0, y0 = y0, x0 x1, y1 = y1, x1 if x0 > x1: x0, x1 = x1, x0 y0, y1 = y1, y0 deltax = x1-x0 deltay = abs(y1-y0) error = int(deltax / 2) ystep = 0 y = y0 if y0 < y1: ystep = 1 else: ystep = -1 for x in range(x0,x1): if steep: self.update_pixel(y, x, r,g,b,a) else: self.update_pixel(x, y, r,g,b,a) error -= deltay if error < 0: y = y + ystep error = error + deltax self.refresh() def redraw_canvas(self): arr = array('B', self.buf) self.texture.blit_buffer(arr, colorfmt='rgba', bufferfmt='ubyte') def is_moveable(self): w, h = self.size return w > Window.size[0] and h > Window.size[1] def set_scale(self, scale, pivot): delta_scale = self.scale - scale prev_w, prev_h = self.size c_w, c_h = self.canvas_size self.scale = scale w, h = (c_w * self.scale, c_h * self.scale) self.size = (w, h) dw = w - prev_w dh = h - prev_h px, py = pivot x, y = self.pos ratio_x = abs(px - x) / w ratio_y = abs(py - y) / h after_x = dw * ratio_x after_y = dh * ratio_y print('current', ratio_x, ratio_y) #self.center = (x - (ax-px)*scale, y - (ay-py)*scale) #if not self.is_moveable(): # self.center = Window.center #else: x,y = self.pos self.pos = (x - after_x, y - after_y) def project(self, point): px,py = point x, y = self.pos ratio = self.canvas_size[0]/self.size[0] return (ratio*(px-x), ratio*(py-y)) def _flatten_list(self, lst): return list(itertools.chain.from_iterable(lst)) def resize(self): print('Resize %s' % self.size) def redraw_region(region=None): # This will redraw a region of the canvas by iterating over # a box of pixels in the pixel map and then drawing a # rectangle for each of them. Every time something is drawn # the rectangle dimensions containing the shape will be sent # through a callback to this function pass
class DisplayController(object): def __init__(self, width, height, canvas, ac, eye_pos, eye_angle): super(DisplayController, self).__init__() self.width = width self.height = height self.canvas = canvas self.eye_pos = eye_pos self.eye_angle = eye_angle self.ac = ac self.canvas.shader.source = resource_find('data/simple.glsl') self.all_notes = [] self.future_notes = {} self.past_notes = {} self.ticks = [] # self.planes = range(0, 10 * config['PLANE_SPACING'], config['PLANE_SPACING']) self.planes = [] self.lines = [] self.past_displays = InstructionGroup() self.future_displays = InstructionGroup() self.plane_displays = InstructionGroup() self.line_displays = InstructionGroup() self.fixed_x = Translate(0, 0, 0) self.fixed_y = Translate(0, 0, 0) self.fixed_z = Translate(0, 0, 0) self.fixed_azi = Rotate(origin=(0, 0, 0), axis=(0, 1, 0)) self.fixed_ele = Rotate(origin=(0, 0, 0), axis=(1, 0, 0)) self.alpha_callback = Callback(self.alpha_sample_callback) self.disable_alpha_callback = Callback(self.disable_alpha_sample_callback) self.alpha_instruction = InstructionGroup() self.alpha_disable_instruction = InstructionGroup() self.alpha_sample_enable = False self.canvas.add(Callback(self.setup_gl_context)) self.canvas.add(self.alpha_instruction) self.canvas.add(PushMatrix()) self.canvas.add(UpdateNormalMatrix()) self.canvas.add(PushMatrix()) self.canvas.add(self.fixed_z) self.canvas.add(self.line_displays) self.canvas.add(PopMatrix()) self.canvas.add(PushMatrix()) self.canvas.add(self.past_displays) self.canvas.add(self.future_displays) self.canvas.add(PopMatrix()) self.canvas.add(PushMatrix()) # self.canvas.add(self.fixed_x) # self.canvas.add(self.fixed_y) self.canvas.add(self.plane_displays) self.canvas.add(PopMatrix()) # self.canvas.add(PushMatrix()) # self.canvas.add(self.fixed_x) # self.canvas.add(self.fixed_y) # self.canvas.add(self.fixed_z) # self.canvas.add(Plane(-config['SELF_PLANE_DISTANCE'], size=0.1, color=(0x20/255., 0xD8/255., 0xE9/255.), tr=0.2)) # self.canvas.add(PopMatrix()) self.canvas.add(PopMatrix()) self.canvas.add(self.alpha_disable_instruction) self.canvas.add(Callback(self.reset_gl_context)) self.draw_planes() def add_notes(self, note_data): s = config['LINE_SPACING'] for nd in note_data: if (nd.x, nd.y) not in self.lines and float(nd.x).is_integer() and float(nd.y).is_integer(): self.line_displays.add(Line(nd.x * s, nd.y * s, color=(0.7, 0.5, 0.0))) self.lines.append((nd.x, nd.y)) self.all_notes.extend(note_data) self.all_notes.sort(key=lambda n:n.tick) self.ticks = map(lambda n:n.tick, self.all_notes) def draw_planes(self): for p in self.planes: self.plane_displays.add(Plane(p, color=(0xE9/255., 0xD8/255., 0x3C/255.))) def setup_gl_context(self, *args): gl.glEnable(gl.GL_DEPTH_TEST) def toggle_alpha_sample(self): if self.alpha_sample_enable: self.alpha_instruction.remove(self.alpha_callback) self.alpha_disable_instruction.remove(self.disable_alpha_callback) self.alpha_sample_enable = False else: self.alpha_instruction.add(self.alpha_callback) self.alpha_disable_instruction.add(self.disable_alpha_callback) self.alpha_sample_enable = True def alpha_sample_callback(self, *args): gl.glEnable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE) def reset_gl_context(self, *args): gl.glDisable(gl.GL_DEPTH_TEST) def disable_alpha_sample_callback(self, *args): gl.glDisable(gl.GL_SAMPLE_ALPHA_TO_COVERAGE) def get_look_at(self, x, y, z, azi, ele): dx = - np.sin(azi) * np.cos(ele) dy = np.sin(ele) dz = - np.cos(azi) * np.cos(ele) # Not sure why up has to just be up... upx, upy, upz = (0, 1, 0) mat = Matrix() mat = mat.look_at(x, y, z, x + dx, y + dy, z + dz, upx, upy, upz) return mat def update_camera(self, pos, angle): self.eye_pos = pos self.eye_angle = angle x, y, z = pos azi, ele = angle asp = self.width / float(self.height) mat = self.get_look_at(x, y, z, azi, ele) proj = Matrix() proj.perspective(30, asp, 1, 100) self.canvas['projection_mat'] = proj self.canvas['modelview_mat'] = mat self.fixed_x.x = x self.fixed_y.y = y self.fixed_z.z = z self.fixed_azi.angle = azi * 180/np.pi self.fixed_ele.angle = ele * 180/np.pi def get_notes_in_range(self, start_tick, end_tick): l = bisect.bisect_left(self.ticks, start_tick) r = bisect.bisect_left(self.ticks, end_tick) if r <= 0: return [] return self.all_notes[l:r] def on_update(self, tick): self_plane_z = self.eye_pos[2] - config['SELF_PLANE_DISTANCE'] eye_tick = tick + ( - self.eye_pos[2] / config['UNITS_PER_TICK']) dt = kivyClock.frametime future_range = self.get_notes_in_range(eye_tick, eye_tick + config['VISIBLE_TICK_RANGE']) past_range = self.get_notes_in_range(eye_tick - config['VISIBLE_TICK_RANGE'], eye_tick) # COMPLEX LOGIC TO MAINTAIN LISTS OF VISIBLE NOTES ORDERED BY DISTANCE FROM CAMERA # far future <-> future # future <-> past # past <-> far past # far future -> future fftof = list(x for x in future_range if x not in self.past_notes and x not in self.future_notes) # future -> far future ftoff = list(x for x in self.future_notes if x not in future_range and x not in past_range) # future -> past ftop = list(x for x in past_range if x in self.future_notes) # past -> future ptof = list(x for x in future_range if x in self.past_notes) # past -> far past ptofp = list(x for x in self.past_notes if x not in future_range and x not in past_range) # far past -> past fptop = list(x for x in past_range if x not in self.past_notes and x not in self.future_notes) # handle ff -> f for nd in sorted(fftof, key=lambda n: n.tick): ndisp = NoteDisplay(nd, self.planes, self.ac) self.future_displays.insert(0, ndisp) self.future_notes[nd] = ndisp # handle f -> ff for nd in ftoff: ndisp = self.future_notes[nd] self.future_displays.remove(ndisp) del self.future_notes[nd] # handle f -> p for nd in sorted(ftop, key=lambda n: n.tick): ndisp = self.future_notes[nd] self.future_displays.remove(ndisp) self.past_displays.add(ndisp) self.past_notes[nd] = ndisp del self.future_notes[nd] # handle p -> f for nd in sorted(ptof, key=lambda n: -n.tick): ndisp = self.past_notes[nd] self.past_displays.remove(ndisp) self.future_displays.add(ndisp) self.future_notes[nd] = ndisp del self.past_notes[nd] # handle p -> fp for nd in ptofp: ndisp = self.past_notes[nd] self.past_displays.remove(ndisp) del self.past_notes[nd] # handle fp -> p for nd in sorted(fptop, key=lambda n: -n.tick): ndisp = NoteDisplay(nd, self.planes, self.ac) self.past_displays.insert(0, ndisp) self.past_notes[nd] = ndisp for s in self.future_notes.values() + self.past_notes.values(): pos = s.pos_from_tick(tick) s.set_pos(pos) s.on_update(dt, eye_tick, self.eye_angle) if s.past_me and pos[2] < self_plane_z - 0.5 * config['SELF_PLANE_DISTANCE']: s.past_me = False if pos[2] > self_plane_z and not s.past_me: s.sound(tick, pos) s.past_me = True Logger.debug('Number of notes: %s' % (len(self.future_notes) + len(self.past_notes)))
def move(self,*dt): self.canvas.clear() self.canvas.add(self.foodblue) x,y = self.snake[-1] if abs(self.snake[-1][0] -self.food.pos[0])<10 and abs(self.snake[-1][1] -self.food.pos[1])<10:#吃到食物 x,y = self.snake[-1] if self.keyboard.direction == "left": for i in range(1,11): x1,y1 = x-i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "right": for i in range(1,11): x1,y1 = x+i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "up": for i in range(1,11): x1,y1 = x,y+i self.snake.append((x1,y1)) elif self.keyboard.direction == "down": for i in range(1,11): x1,y1 = x,y-i self.snake.append((x1,y1)) self.foods() else: if self.keyboard.direction == "left": x,y = x-1,y if x < self.rangeSnake[0] : self.gameover() for a,b in self.snake: if x >a and x-a<10 and abs(b-y)<10: self.gameover() break elif self.keyboard.direction == "right": x,y = x+1,y if x+10 > self.rangeSnake[2]: self.gameover() for a,b in self.snake: if a>x and a-x < 10 and abs(b-y)< 10: self.gameover() break elif self.keyboard.direction == "up": x,y = x,y+1 if y+10 >self.rangeSnake[3]: self.gameover() for a,b in self.snake: if b>y and b-y < 10 and abs(x-a)<10: self.gameover() break elif self.keyboard.direction == "down": x,y = x,y-1 if y < self.rangeSnake[1]: self.gameover() for a,b in self.snake: if y >b and y-b>10 and abs(x-a)<10: self.gameover() break self.snake.append((x,y)) del self.snake[0] for i in self.snake: snake = InstructionGroup() snake.add(Color(0, 0, 1, 1)) snake.add(Rectangle(pos=i, size=(10,10))) self.canvas.add(snake)
class TextureStack(Widget): """Several textures superimposed on one another, and possibly offset by some amount. In 2D games where characters can wear different clothes or hold different equipment, their graphics are often composed of several graphics layered on one another. This widget simplifies the management of such compositions. """ texs = ListProperty() """Texture objects""" offxs = ListProperty() """x-offsets. The texture at the same index will be moved to the right by the number of pixels in this list. """ offys = ListProperty() """y-offsets. The texture at the same index will be moved upward by the number of pixels in this list. """ group = ObjectProperty() """My ``InstructionGroup``, suitable for addition to whatever ``canvas``.""" def _get_offsets(self): return zip(self.offxs, self.offys) def _set_offsets(self, offs): offxs = [] offys = [] for x, y in offs: offxs.append(x) offys.append(y) self.offxs, self.offys = offxs, offys offsets = AliasProperty( _get_offsets, _set_offsets, bind=('offxs', 'offys') ) """List of (x, y) tuples by which to offset the corresponding texture.""" _texture_rectangles = DictProperty({}) """Private. Rectangle instructions for each of the textures, keyed by the texture. """ def __init__(self, **kwargs): """Make triggers and bind.""" kwargs['size_hint'] = (None, None) self.translate = Translate(0, 0) self.group = InstructionGroup() super().__init__(**kwargs) self.bind(offxs=self.on_pos, offys=self.on_pos) def on_texs(self, *args): """Make rectangles for each of the textures and add them to the canvas.""" if not self.canvas or not self.texs: Clock.schedule_once(self.on_texs, 0) return texlen = len(self.texs) # Ensure each property is the same length as my texs, padding # with 0 as needed for prop in ('offxs', 'offys'): proplen = len(getattr(self, prop)) if proplen > texlen: setattr(self, prop, getattr(self, prop)[:proplen-texlen]) if texlen > proplen: propval = list(getattr(self, prop)) propval += [0] * (texlen - proplen) setattr(self, prop, propval) self.group.clear() self._texture_rectangles = {} w = h = 0 (x, y) = self.pos self.translate.x = x self.translate.y = y self.group.add(PushMatrix()) self.group.add(self.translate) for tex, offx, offy in zip(self.texs, self.offxs, self.offys): rect = Rectangle( pos=(offx, offy), size=tex.size, texture=tex ) self._texture_rectangles[tex] = rect self.group.add(rect) tw = tex.width + offx th = tex.height + offy if tw > w: w = tw if th > h: h = th self.size = (w, h) self.group.add(PopMatrix()) self.canvas.add(self.group) def on_pos(self, *args): """Translate all the rectangles within this widget to reflect the widget's position. """ (x, y) = self.pos self.translate.x = x self.translate.y = y def clear(self): """Clear my rectangles and ``texs``.""" self.group.clear() self._texture_rectangles = {} self.texs = [] self.size = [1, 1] def insert(self, i, tex): """Insert the texture into my ``texs``, waiting for the creation of the canvas if necessary. """ if not self.canvas: Clock.schedule_once( lambda dt: self.insert(i, tex), 0) return self.texs.insert(i, tex) def append(self, tex): """``self.insert(len(self.texs), tex)``""" self.insert(len(self.texs), tex) def __delitem__(self, i): """Remove a texture and its rectangle""" tex = self.texs[i] try: rect = self._texture_rectangles[tex] self.canvas.remove(rect) del self._texture_rectangles[tex] except KeyError: pass del self.texs[i] def __setitem__(self, i, v): """First delete at ``i``, then insert there""" if len(self.texs) > 0: self._no_upd_texs = True self.__delitem__(i) self._no_upd_texs = False self.insert(i, v) def pop(self, i=-1): """Delete the texture at ``i``, and return it.""" return self.texs.pop(i)
class Main(FloatLayout): snake = ListProperty([(0,0)]) rangeSnake = ListProperty([0,0,Window.width,Window.height]) startSpeed = NumericProperty(30) def __init__(self, **kwargs): super(Main, self).__init__(**kwargs) self.keyboard = Controls() self.count = 0 self.bind(size=self.up,pos=self.up) def up(self,*args): self.rangeSnake[0] = self.pos[0] self.rangeSnake[1] = self.pos[1] self.rangeSnake[2] = self.pos[0] + self.size[0] self.rangeSnake[3] = self.pos[1] + self.size[1] self.snake[0] = self.pos def start(self,*dt): self.canvas.clear() Clock.unschedule(self.move) self.food() Clock.schedule_interval(self.move,1./(self.startSpeed+self.count)) def restart(self, *dt): self.canvas.clear() self.clear_widgets() Clock.unschedule(self.move) self.foods() self.snake = [ self.pos] self.keyboard.direction = "right" Clock.schedule_interval(self.move,1./(self.startSpeed+self.count)) def stop(self,*dt): Clock.unschedule(self.move) def continue_move(self): Clock.unschedule(self.move) Clock.schedule_interval(self.move,1./(self.startSpeed+self.count)) def food(self,*args): self.foodblue = InstructionGroup() self.foodblue.add(Color(1, 0, 0, 1)) x = random.randint(int(self.rangeSnake[0]), int(self.rangeSnake[2]-10)) y = random.randint(int(self.rangeSnake[1]), int(self.rangeSnake[3]-10)) self.food = Rectangle(pos=(x,y), size=(10,10)) self.foodblue.add(self.food) def foods(self): self.count += 1 x = random.randint(int(self.rangeSnake[0]), int(self.rangeSnake[2]-10)) y = random.randint(int(self.rangeSnake[1]), int(self.rangeSnake[3]-10)) for a,b in self.snake: if x > a+10 or y >b+10 or x < a- 10 or y<b-10: pass else: self.foods() return self.food.pos = (x,y) def move(self,*dt): self.canvas.clear() self.canvas.add(self.foodblue) x,y = self.snake[-1] if abs(self.snake[-1][0] -self.food.pos[0])<10 and abs(self.snake[-1][1] -self.food.pos[1])<10:#吃到食物 x,y = self.snake[-1] if self.keyboard.direction == "left": for i in range(1,11): x1,y1 = x-i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "right": for i in range(1,11): x1,y1 = x+i,y self.snake.append((x1,y1)) elif self.keyboard.direction == "up": for i in range(1,11): x1,y1 = x,y+i self.snake.append((x1,y1)) elif self.keyboard.direction == "down": for i in range(1,11): x1,y1 = x,y-i self.snake.append((x1,y1)) self.foods() else: if self.keyboard.direction == "left": x,y = x-1,y if x < self.rangeSnake[0] : self.gameover() for a,b in self.snake: if x >a and x-a<10 and abs(b-y)<10: self.gameover() break elif self.keyboard.direction == "right": x,y = x+1,y if x+10 > self.rangeSnake[2]: self.gameover() for a,b in self.snake: if a>x and a-x < 10 and abs(b-y)< 10: self.gameover() break elif self.keyboard.direction == "up": x,y = x,y+1 if y+10 >self.rangeSnake[3]: self.gameover() for a,b in self.snake: if b>y and b-y < 10 and abs(x-a)<10: self.gameover() break elif self.keyboard.direction == "down": x,y = x,y-1 if y < self.rangeSnake[1]: self.gameover() for a,b in self.snake: if y >b and y-b>10 and abs(x-a)<10: self.gameover() break self.snake.append((x,y)) del self.snake[0] for i in self.snake: snake = InstructionGroup() snake.add(Color(0, 0, 1, 1)) snake.add(Rectangle(pos=i, size=(10,10))) self.canvas.add(snake) def gameover(self): Clock.unschedule(self.move) btn = Button(text="Game is over",size_hint=(1,1),pos_hint={"center_x":.5,"center_y":.5}) self.add_widget(btn) btn.bind(on_release=self.restart )
class LinePlot(Widget): viewport = ListProperty(None) line_width = NumericProperty(5.) line_color = ListProperty([0,.8,1]) border_width = NumericProperty(5) border_color = ListProperty([.3,.3,.3]) flattened_points = ListProperty(None) tick_distance_x = NumericProperty(None) tick_distance_y = NumericProperty(None) tick_color = ListProperty([.3,.3,.3]) select_circle = ListProperty([0,0,0]) def __init__(self, points, **kwargs): # calculate some basic information about the data self.points = points self.points_x = zip(*points)[0] self.points_y = zip(*points)[1] # if we could figure out how to draw an arbitrary number of ticks in kv, this would be cleaner self.ticks = InstructionGroup() self.tick_translate = Translate() super(LinePlot, self).__init__(**kwargs) self.canvas.insert(0, self.ticks) self.viewport = (min(self.points_x), min(self.points_y), max(self.points_x), max(self.points_y)) # recalculate viewport when size changes def on_size(self, instance, value): self.on_viewport(None, self.viewport) def on_pos(self, instance, value): self.tick_translate.xy = self.x, self.y def on_viewport(self, instance, value): if value is None or len(value) != 4: return print value self.vp_width_convert = float(self.width)/(value[2] - value[0]) self.vp_height_convert = float(self.height)/(value[3] - value[1]) # calculate the actual display points based on the viewport and self.size self.display_points = [self.to_display_point(*p) for p in self.points if value[0] <= p[0] <= value[2] and value[1] <= p[1] <= value[3]] self.flattened_points = [item for sublist in self.display_points for item in sublist] self.draw_ticks() # it would be real nice if we could figure out how to do this in kv def draw_ticks(self): self.ticks.clear() self.ticks.add(Color(*self.tick_color, mode='rgb')) self.ticks.add(PushMatrix()) self.ticks.add(self.tick_translate) if self.tick_distance_x is not None: first_x_tick = self.tick_distance_x*(int(self.viewport[0]/self.tick_distance_x) + 1) for x in drange(first_x_tick, self.viewport[2], self.tick_distance_x): start = self.to_display_point(x, self.viewport[1]) stop = self.to_display_point(x, self.viewport[3]) self.ticks.add(Line(points=[start[0], start[1], stop[0], stop[1]])) if self.tick_distance_y is not None: first_y_tick = self.tick_distance_y*(int(self.viewport[1]/self.tick_distance_y) + 1) for y in drange(first_y_tick, self.viewport[3], self.tick_distance_y): start = self.to_display_point(self.viewport[0], y) stop = self.to_display_point(self.viewport[2], y) self.ticks.add(Line(points=[start[0], start[1], stop[0], stop[1]])) self.ticks.add(PopMatrix()) def to_display_point(self, x, y): return (self.vp_width_convert*(x-self.viewport[0]), self.vp_height_convert*(y-self.viewport[1])) def select_point(self, x, y): # get point from self.displaypoints that is closest to x distances = [abs((x - self.x) - d[0]) for d in self.display_points] idx = min(xrange(len(distances)),key=distances.__getitem__) self.select_circle = [self.display_points[idx][0], self.display_points[idx][1], 20] return self.points[idx] def to_xy(self, x, y): xt = (x - self.x)/self.vp_width_convert+self.viewport[0] yt = (y - self.y)/self.vp_height_convert+self.viewport[1] return (xt, yt)
class Piece(SparseGridLayout, TetrisAware): map = ListProperty([]) def __init__(self, color=(1, 1, 1, 1), **kwargs): self.color = color self.size_hint = (None, None) super(SparseGridLayout, self).__init__(**kwargs) self.bind(map=self.on_map) self.keyboard = App.get_running_app().keyboard self.keyboard.bind( on_key_down=self.on_keypress, on_key_up=self.on_keyrelease ) self.base_delay = self.keyboard.repeat_delay self.base_speed = self.keyboard.repeat_speed self.vertical = False """ One may wonder, when entering the realms of Piece.update(), "what exactly is delay_lambda?". It is what makes a piece remain controllable after having touched the ground, for a static duration (.5). It is checked in move() and rotate() - if check_lock notices the Piece isn't right above the ground anymore, it triggers "normal" gravity back by calling on_parent. Finally, the lock timeout is necessarily called after the static duration (.5), to lock the piece if its height hasn't changed (we discard the false-positive if it has). """ self.delay_lambda = None def on_parent(self, *args): if self.parent: level = self.parent.parent.level Clock.schedule_interval( self.update, .5 * (.75 + (.05 * (4 - (level % 4)))) ** level ) def on_map(self, instance, value): current_child = 0 for y in range(len(self.map)): for x in range(len(self.map[y])): if self.map[y][x] == 'x': if len(self.children) < sum(line.count('x') for line in self.map): self.add_widget(Block(coords=(x, y), color=self.color)) else: self.children[current_child].coords = (x, y) current_child += 1 self.do_layout() def update(self, *args): if not self.parent: Clock.unschedule(self.update) self.keyboard_closed() return if self.tetris_coords[1] == 0 or self.collide_piece('down'): self.do_layout() self.remove_children() self.keyboard_closed() self.parent.check_line() self.parent.parent.spawn.new_piece() if self.parent: self.parent.remove_widget(self) else: self.tetris_coords[1] -= 1 self.check_lock(retrigger=True) def check_lock(self, retrigger=False): if not self.delay_lambda and (self.tetris_coords[1] == 0 or self.collide_piece('down')): self.trigger_lock() elif self.delay_lambda and (self.tetris_coords[1] > 0 and not self.collide_piece('down')): self.reset_lock() elif retrigger and self.delay_lambda: Clock.unschedule(self.delay_lambda) self.trigger_lock() def trigger_lock(self): Clock.unschedule(self.update) y = self.tetris_coords[1] self.delay_lambda = lambda *args: self.lock_timeout(y) Clock.schedule_once(self.delay_lambda, .5) def reset_lock(self): self.on_parent() Clock.unschedule(self.delay_lambda) self.delay_lambda = None def lock_timeout(self, y): if self.tetris_coords[1] == y: self.update() self.on_parent() self.delay_lambda = None def remove_children(self): for child in self.children[:]: child.pos_hint = {} self.remove_widget(child) self.parent.add_widget(child) def collide_piece(self, direction='down', map=[], coords=[]): if self.parent: for child in self.parent.children: if hasattr(child, 'tetris_coords') and child != self: if direction == 'cw' or direction == 'ccw': for y in range(len(map)): for x in range(len(map[y])): if map[y][x] == 'x': if coords[0] + x == child.tetris_coords[0]\ and coords[1] + y == child.tetris_coords[1]: return True else: for own_child in self.children: if direction == 'down': if own_child.tetris_coords[1] - 1 == child.tetris_coords[1]\ and own_child.tetris_coords[0] == child.tetris_coords[0]: return True if direction == 'left': if own_child.tetris_coords[0] - 1 == child.tetris_coords[0]\ and own_child.tetris_coords[1] == child.tetris_coords[1]: return True if direction == 'right': if own_child.tetris_coords[0] + 1 == child.tetris_coords[0]\ and own_child.tetris_coords[1] == child.tetris_coords[1]: return True if direction == 'current': if own_child.tetris_coords[0] == child.tetris_coords[0]\ and own_child.tetris_coords[1] == child.tetris_coords[1]: return True return False def on_tetris_coords(self, *args): if hasattr(self, 'map') and self.parent: if self.tetris_coords[0] < 0: self.tetris_coords[0] = 0 if self.tetris_coords[0] + len(self.map[0]) > self.parent.cols: self.tetris_coords[0] = self.parent.cols - len(self.map[0]) if self.tetris_coords[1] < 0: self.tetris_coords[1] = 0 if self.tetris_coords[1] + len(self.map) > self.parent.rows: self.tetris_coords[1] = self.parent.rows - len(self.map) if hasattr(self.parent, 'coord_to_pos'): self.pos = self.parent.coord_to_pos(*self.tetris_coords) for child in self.children: child.tetris_coords = [self.tetris_coords[0] + child.col, self.tetris_coords[1] + child.row] def do_layout(self, *args): super(Piece, self).do_layout(*args) if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) self.outline = InstructionGroup() for child in self.children: self.outline.add(Color(.5, .8, 1, .8)) self.outline.add(Line( points=[ child.x - 1, child.y - 1, child.right + 1, child.y - 1, child.right + 1, child.top + 1, child.x - 1, child.top + 1 ], close=True, width=1.5 )) if self.canvas.before: self.canvas.before.add(self.outline) if len(self.children) == 0: if hasattr(self, 'outline'): self.canvas.before.remove(self.outline) def move(self, direction): if direction == 'left' and not self.collide_piece('left'): self.tetris_coords[0] -= 1 if direction == 'right' and not self.collide_piece('right'): self.tetris_coords[0] += 1 if direction == 'down': self.keyboard.repeat_delay = 0 self.keyboard.repeat_speed /= 4 self.update() self.check_lock() def rotate(self, **kwargs): direction = 'ccw' if 'direction' in kwargs: direction = kwargs['direction'] new_map = self.rotate_map(direction) new_coords = self.rotate_coords(new_map) if self.collide_piece(direction, new_map, new_coords): return self.vertical = not self.vertical self.map = new_map self.tetris_coords = new_coords self.check_lock() def rotate_map(self, direction): new_map = zip(*self.map[::-1]) if direction == 'cw': for i in range(2): new_map = zip(*new_map[::-1]) return new_map def rotate_coords(self, new_map): map_diff = [ len(self.map[0]) - len(new_map[0]), len(self.map) - len(new_map) ] for i in range(len(map_diff)): if self.vertical: map_diff[i] = floor(map_diff[i] / 2.) else: map_diff[i] = ceil(map_diff[i] / 2.) return self.tetris_coords[0] + map_diff[0], self.tetris_coords[1] + map_diff[1] def on_keypress(self, keyboard, key, keycode, modifiers): self.reset_keyboard_repeat() if key == 113: # 'q' on qwerty self.rotate(direction='ccw') elif key == 101: # 'e' self.rotate(direction='cw') elif key == 97: # 'a' on qwerty self.move('left') elif key == 100: # 'd' self.move('right') elif key == 115: # 's' self.move('down') elif key == 122: # 'z' on qwerty self.rotate(direction='ccw') elif key == 120: # 'x' self.rotate(direction='cw') elif key == 276: # left arrow self.move('left') elif key == 275: # right arrow self.move('right') elif key == 273: # up arrow self.rotate(direction='ccw') elif key == 274: # down arrow self.move('down') else: return True return False def on_keyrelease(self, keyboard, keycode): self.reset_keyboard_repeat() def reset_keyboard_repeat(self): self.keyboard.repeat_delay = self.base_delay self.keyboard.repeat_speed = self.base_speed def keyboard_closed(self): self.reset_keyboard_repeat() self.keyboard.unbind( on_key_down=self.on_keypress, on_key_up=self.on_keyrelease )