Source code for BaseMod.geo.geoHistory

import numpy as np
from PySide6.QtCore import QPoint, QRect

from BaseMod.geo.geoUtils import geo_save, geo_undo
from RWS.Modify import HistoryElement
from RWS.Utils import draw_line, draw_ellipse

nearpoints = [QPoint(-1, 0), QPoint(0, -1), QPoint(1, 0), QPoint(0, 1)]
# ^ i  have no clue what this does. Stack overflow told me to do so


[docs] class GEChange(HistoryElement):
[docs] def __init__(self, history, replace, layers: [bool, bool, bool]): super().__init__(history) self.history = history self.replace = replace self.layers = layers self.before = [] self.module = history.level.viewport.modulenames["geo"]
[docs] def redraw(self): for i, l in enumerate(self.layers): if not l: continue self.module.get_layer(i).redraw()
[docs] class GERectChange(GEChange):
[docs] def __init__(self, history, rect: QRect, replace, layers: [bool, bool, bool], hollow=False): super().__init__(history, replace, layers) self.rect = rect self.hollow = hollow x_range = np.arange(self.rect.x(), self.rect.x() + self.rect.width()) y_range = np.arange(self.rect.y(), self.rect.y() + self.rect.height()) # if this works im buying all the lotery tickets #Vectorized loops: np.arange is used for x_range and y_range for faster looping over grid coordinates. for x in x_range: for y in y_range: for i, l in enumerate(self.layers): if not l or not self.history.level.inside(QPoint(x, y)): continue if self.ishollow(x, y): continue block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(x, y, i)) self.before.append(save) self.history.level.l_geo.setlevelgeo(x, y, i, block) t = self.module.get_layer(i) t.draw_geo(x, y, True, self.inborder(x, y)) self.redraw()
#change to make new branch
[docs] def inborder(self, x, y): return (x == self.rect.x() or y == self.rect.y() or x == self.rect.x() + self.rect.width() - 1 or y == self.rect.y() + self.rect.height() - 1)
[docs] def ishollow(self, x, y): if self.hollow and self.inborder(x, y): return False return self.hollow
[docs] def undo_changes(self): c = 0 x_range = np.arange(self.rect.x(), self.rect.x() + self.rect.width()) y_range = np.arange(self.rect.y(), self.rect.y() + self.rect.height()) for x in x_range: for y in y_range: for i, l in enumerate(self.layers): if not l or not self.history.level.inside(QPoint(x, y)): continue if self.ishollow(x, y): continue block = geo_undo(self.replace, self.history.level.l_geo.getlevelgeo(x, y, i), self.before[c]) self.history.level.l_geo.setlevelgeo(x, y, i, block) self.module.get_layer(i).draw_geo(x, y, True, self.inborder(x, y)) c += 1 # c++ almost self.redraw()
[docs] def redo_changes(self): x_range = np.arange(self.rect.x(), self.rect.x() + self.rect.width()) y_range = np.arange(self.rect.y(), self.rect.y() + self.rect.height()) for x in x_range: # ? okay for y in y_range: for i, l in enumerate(self.layers): if not l or not self.history.level.inside(QPoint(x, y)): continue if self.ishollow(x, y): continue block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(x, y, i)) self.history.level.l_geo.setlevelgeo(x, y, i, block) t = self.module.get_layer(i) t.draw_geo(x, y, True, self.inborder(x, y)) self.redraw()
[docs] class GEEllipseChange(GEChange):
[docs] def __init__(self, history, rect: QRect, replace, layers: [bool, bool, bool], hollow=False): super().__init__(history, replace, layers) self.rect = rect self.hollow = hollow self.area = np.ones((self.history.level.level_width, self.history.level.level_height), dtype=bool) #Replaced the 2D lists with NumPy arrays draw_ellipse(self.rect, self.hollow, self.drawpoint) self.redraw()
[docs] def drawpoint(self, pos: QPoint, saveblock=True): if not self.area[pos.x(), pos.y()] and saveblock: return self.area[pos.x(), pos.y()] = False for i, l in enumerate(self.layers): if not l: continue block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(pos.x(), pos.y(), i)) if saveblock: self.before.append([pos, i, save]) self.history.level.l_geo.setlevelgeo(pos.x(), pos.y(), i, block) t = self.module.get_layer(i) t.draw_geo(pos.x(), pos.y(), True)
[docs] def drawpointredo(self, pos): self.drawpoint(pos, False)
[docs] def undo_changes(self): for i in self.before: point, layer, save = i block = geo_undo(self.replace, self.history.level.l_geo.getlevelgeo(point.x(), point.y(), layer), save) self.history.level.l_geo.setlevelgeo(point.x(), point.y(), layer, block) self.module.get_layer(layer).draw_geo(point.x(), point.y(), True) self.redraw()
[docs] def redo_changes(self): draw_ellipse(self.rect, self.hollow, self.drawpointredo) self.redraw()
[docs] class GEPointChange(GEChange):
[docs] def __init__(self, history, start: QPoint, replace: [int, bool], layers: [bool, bool, bool]): super().__init__(history, replace, layers) self.positions: list[QPoint] = [] self.start: QPoint = start self.before = {} self.paintpoint(start) self.redraw()
[docs] def paintpoint(self, pos): for i, l in enumerate(self.layers): if not l: continue if not self.history.level.inside(pos): continue if self.before.get((pos, i), None) is not None: continue block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(pos.x(), pos.y(), i)) self.before[(pos, i)] = save self.history.level.l_geo.setlevelgeo(pos.x(), pos.y(), i, block) t = self.module.get_layer(i) t.draw_geo(pos.x(), pos.y(), True)
[docs] def add_move(self, position): start = self.start if len(self.positions) > 0: start = self.positions[-1] self.positions.append(position) points = [] draw_line(start, position, lambda p: points.append(p)) points.pop(0) for point in points: self.paintpoint(point) self.redraw()
[docs] def undo_changes(self): # removing placed cells with replaced ones for k, v in self.before.items(): block = geo_undo(self.replace, self.history.level.l_geo.getlevelgeo(k[0].x(), k[0].y(), k[1]), v) self.history.level.l_geo.setlevelgeo(k[0].x(), k[0].y(), k[1], block) t = self.module.get_layer(k[1]) t.draw_geo(k[0].x(), k[0].y(), True) self.redraw()
[docs] def redo_changes(self): # re-adding replace cell for k, v in self.before.items(): block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(k[0].x(), k[0].y(), k[1])) self.history.level.l_geo.setlevelgeo(k[0].x(), k[0].y(), k[1], block) t = self.module.get_layer(k[1]) t.draw_geo(k[0].x(), k[0].y(), True) self.redraw()
[docs] class GEBrushChange(GEChange):
[docs] def __init__(self, history, start: QPoint, replace: [int, bool], layers: [bool, bool, bool], brushsize: int): super().__init__(history, replace, layers) self.start = start self.brushsize = brushsize self.area = np.ones((self.history.level.level_width, self.history.level.level_height), dtype=bool) self.lastpos = start self.paint_sphere(start, self.paintpoint) self.redraw()
[docs] def paintpoint(self, pos: QPoint): if not self.history.level.inside(pos) or not self.area[pos.x(), pos.y()]: return for i, l in enumerate(self.layers): if not l: continue self.area[pos.x(), pos.y()] = False block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(pos.x(), pos.y(), i)) self.before.append([pos, i, save]) self.history.level.l_geo.setlevelgeo(pos.x(), pos.y(), i, block) t = self.module.get_layer(i) t.draw_geo(pos.x(), pos.y(), True)
[docs] def paint_sphere(self, pos, callback): point = QPoint(self.brushsize // 2, self.brushsize // 2) rect = QRect(pos - point, pos + point) draw_ellipse(rect, False, callback)
[docs] def add_move(self, position): points = [] draw_line(self.lastpos, position, lambda p: points.append(p)) points.pop(0) for point in points: self.paint_sphere(point, self.paintpoint) self.lastpos = position self.redraw()
[docs] def undo_changes(self): for i in self.before: point, layer, save = i block = geo_undo(self.replace, self.history.level.l_geo.getlevelgeo(point.x(), point.y(), layer), save) self.history.level.l_geo.setlevelgeo(point.x(), point.y(), layer, block) self.module.get_layer(layer).draw_geo(point.x(), point.y(), True) self.redraw()
[docs] def redo_changes(self): for i in self.before: pos, layer, _ = i block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(pos.x(), pos.y(), layer)) self.history.level.l_geo.setlevelgeo(pos.x(), pos.y(), layer, block) t = self.module.get_layer(layer) t.draw_geo(pos.x(), pos.y(), True) self.redraw()
[docs] class GEFillChange(GEChange):
[docs] def __init__(self, history, start: QPoint, replace: [int, bool], layers: [bool, bool, bool]): super().__init__(history, replace, layers) self.area = np.ones((3, self.history.level.level_width, self.history.level.level_height), dtype=bool) self.start: QPoint = start self.before = [[], [], []] self.replacefrom = [self.history.level.l_geo.getlevelgeo(start.x(), start.y(), 0)[0], self.history.level.l_geo.getlevelgeo(start.x(), start.y(), 1)[0], self.history.level.l_geo.getlevelgeo(start.x(), start.y(), 2)[0]] for i, l in enumerate(self.layers): if not l: continue self.drawpoint(start, i) self.dobrush() self.redraw()
[docs] def dobrush(self, save=True): lastlen = 9999 while True: for i, l in enumerate(self.layers): if not l: continue for item in range(len(self.before[i])): pos, _, val = self.before[i][item] if not val: continue for p in nearpoints: newpos = pos + p if not self.history.level.inside(newpos) or not self.area[i][newpos.x(), newpos.y()]: continue self.area[i][newpos.x(), newpos.y()] = False if self.history.level.l_geo.getlevelgeo(newpos.x(), newpos.y(), i)[0] != self.replacefrom[i]: continue self.drawpoint(newpos, i, save) self.before[i][item][2] = False newlen = sum([len(i) for i in self.before]) if newlen == lastlen: break lastlen = newlen self.redraw()
[docs] def drawpoint(self, pos: QPoint, layer: int, saveblock=True): block, save = geo_save(self.replace, self.history.level.l_geo.getlevelgeo(pos.x(), pos.y(), layer)) if saveblock: self.before[layer].append([pos, save, True]) self.history.level.l_geo.setlevelgeo(pos.x(), pos.y(), layer, block) self.module.get_layer(layer).draw_geo(pos.x(), pos.y(), True)
[docs] def undo_changes(self): for i, l in enumerate(self.before): for item in l: point, save, _ = item block = geo_undo(self.replace, self.history.level.l_geo.getlevelgeo(point.x(), point.y(), i), save) self.history.level.l_geo.setlevelgeo(point.x(), point.y(), i, block) self.module.get_layer(i).draw_geo(point.x(), point.y(), True) self.redraw()
[docs] def redo_changes(self): for i, l in enumerate(self.before): for item in l: point, save, _ = item self.drawpoint(point, i, False) self.redraw()
[docs] class LevelResizedGeo(HistoryElement):
[docs] def __init__(self, history, newrect: QRect): super().__init__(history) self.newrect = newrect self.oldblocks = None self.oldstack = None self.redo_changes()
[docs] def undo_changes(self): self.level.l_geo.blocks = np.copy(self.oldblocks) self.level.l_geo.stack = np.copy(self.oldstack)
[docs] def redo_changes(self): newshape = np.zeros((self.newrect.width(), self.newrect.height(), 3), np.uint8) newshapestack = np.zeros((self.newrect.width(), self.newrect.height(), 3), np.uint16) self.oldblocks = np.copy(self.level.l_geo.blocks) self.oldstack = np.copy(self.level.l_geo.stack) with np.nditer(newshape, flags=['multi_index'], op_flags=['writeonly']) as it: for x in it: if it.multi_index[0] < -self.newrect.x() or it.multi_index[1] < -self.newrect.y(): x[...] = 1 newshapestack[*it.multi_index] = 0 continue newpoints = [it.multi_index[0] + self.newrect.x(), it.multi_index[1] + self.newrect.y()] if newpoints[0] >= self.level.l_geo.blocks.shape[0] or newpoints[1] >= self.level.l_geo.blocks.shape[1]: x[...] = 1 newshapestack[*it.multi_index] = 0 continue x[...] = self.level.l_geo.blocks[newpoints[0], newpoints[1], it.multi_index[2]] newshapestack[*it.multi_index] = self.level.l_geo.stack[newpoints[0], newpoints[1], it.multi_index[2]] self.level.l_geo.blocks = newshape self.level.l_geo.stack = newshapestack