diff --git a/Stuff/Modules/cm.py b/Stuff/Modules/cm.py index 0959c73..e803f77 100644 --- a/Stuff/Modules/cm.py +++ b/Stuff/Modules/cm.py @@ -95,40 +95,40 @@ def _setRoomName(self, name): def _processHeader(self, file): for line in file: - if line.count("TrackerVersion") > 0: + if "TrackerVersion" in line: if "iTrack" in line: self.tracker = "iTrack" elif "Tracker" in line: self.tracker = "Tracker" else: self.tracker = "Unknown" - elif line.count("ArenaCenterXY") > 0: + elif "ArenaCenterXY" in line: strg = line.split() for i in range(len(strg)): if strg[i] == "(": pos = i self.centerX = eval(strg[pos+1]) self.centerY = eval(strg[pos+2]) - elif line.count("TrackerResolution_PixPerCM") > 0: + elif "TrackerResolution_PixPerCM" in line: strg = line.split() for i in range(len(strg)): if strg[i] == "(": pos = i self.trackerResolution = eval(strg[pos+1]) - elif line.count("%ReinforcedSector") > 0 and line.count("//") == 0: + elif "%ReinforcedSector" in line and "//" not in line: # needs to be updated for double avoidance strg = line.split() for i in range(len(strg)): if strg[i] == "(": pos = i self._addReinforcedSector(strg, pos) - elif line.count("ArenaDiameter") > 0: + elif "ArenaDiameter" in line: strg = line.split() for i in range(len(strg)): if strg[i] == "(": pos = i self.arenaDiameter = eval(strg[pos+1]) - elif line.count("END_HEADER") > 0: + elif "END_HEADER" in line: break self.radius = max([self.centerX, self.centerY]) @@ -147,7 +147,7 @@ def _processRoomFile(self, infile, endsplit = 7): count = -1 for line in infile: try: - line = list(map(int, line.split()[:endsplit])) + line = list(map(float, line.split()[:endsplit])) # zmenit na int??? float je pro RA self.data.append(line) except Exception: continue @@ -216,7 +216,7 @@ def _processArenaFile(self, infile): count = -1 for line in infile: try: - line = list(map(int, line.split()[:7])) + line = list(map(float, line.split()[:7])) # zmenit na int??? float je pro RA except Exception: continue diff --git a/Stuff/Modules/cmsf.py b/Stuff/Modules/cmsf.py index 0b26023..a2d8a59 100644 --- a/Stuff/Modules/cmsf.py +++ b/Stuff/Modules/cmsf.py @@ -17,11 +17,16 @@ along with Carousel Maze Manager. If not, see . """ +from collections import OrderedDict + + from cm import CM from singleframe import SF class CMSF(SF, CM): + cache = OrderedDict() + def __init__(self, nameA, *_): self.nameA = nameA diff --git a/Stuff/Modules/explorer.py b/Stuff/Modules/explorer.py index b1863e7..fb3f001 100644 --- a/Stuff/Modules/explorer.py +++ b/Stuff/Modules/explorer.py @@ -92,9 +92,19 @@ def __init__(self, root): self.timeLabFrame = ttk.Labelframe(self, text = "Time") self.timeLabFrame.root = self self.timeFrame = TimeFrame(self.timeLabFrame, onChange = True) - arenaText = "Arena frame" if m.mode == "CM" else "Animation" + if m.mode == "CM": + arenaText = "Arena frame" + elif m.mode == "RA": + arenaText = "Room frame" + else: + arenaText = "Animation" self.arenaFrame = ttk.LabelFrame(self, text = arenaText) - roomText = "Room frame" if m.mode == "CM" else "Track" + if m.mode == "CM": + roomText = "Room frame" + elif m.mode == "RA": + roomText = "Robot frame" + else: + roomText = "Track" self.roomFrame = ttk.LabelFrame(self, text = roomText) self.speedScaleFrame = ttk.Frame(self) self.speedScaleFrame.rowconfigure(0, weight = 1) @@ -221,7 +231,7 @@ def __init__(self, root): self.showShocks.grid(column = 1, row = 1, padx = 3, pady = 2, sticky = (N, W)) self.showTail.grid(column = 1, row = 2, padx = 3, pady = 2, sticky = (N, W)) - if m.mode == "CM": + if m.files == "pair": self.showAnimation.grid(column = 0, row = 0, padx = 2, pady = 1, sticky = (N, W)) self.showTrack.grid(column = 0, row = 1, padx = 2, pady = 1, sticky = (N, W)) @@ -484,16 +494,30 @@ def changedTime(self, value, unit = "0-100"): if self.showTailVar.get(): self._createTail(curLine) + Ax, Ay = curLine[self.cm.indices] + Ax *= self.scale + Ay *= self.scale + if m.mode == "CM": - Ax, Ay = curLine[7:9] Rx, Ry = curLine[2:4] - self.roomCanv.coords("ratR", (Rx + self.ld, Ry + self.ld,\ - Rx + self.ur, Ry + self.ur)) + Rx *= self.scale + Ry *= self.scale + self.roomCanv.coords("ratR", (Rx + 16, Ry + 16, Rx + 24, Ry + 24)) self.roomCanv.lift("ratR") - else: - Ax, Ay = curLine[2:4] - self.arenaCanv.coords("ratA", (Ax + self.ld, Ay + self.ld,\ - Ax + self.ur, Ay + self.ur)) + elif m.mode == "RA": + Rx, Ry = curLine[2:4] + Rx *= self.scale + Ry *= self.scale + self.arenaCanv.coords("robotA", (Rx + 16, Ry + 16, Rx + 24, Ry + 24)) + self.roomCanv.coords("ratR", ((Ax - Rx)/2 + 146, (Ay - Ry)/2 + 146, + (Ax - Rx)/2 + 154, (Ay - Ry)/2 + 154)) + r = self.cm.sectorRadius * self.scale + self.arenaCanv.coords("shockZoneA", (Rx + 20 - r, Ry + 20 - r, Rx + 20 + r, Ry + 20 + r)) + self.arenaCanv.lift("robotA") + self.arenaCanv.lift("shockZoneA") + self.roomCanv.lift("ratR") + + self.arenaCanv.coords("ratA", (Ax + 16, Ay + 16, Ax + 24, Ay + 24)) self.arenaCanv.lift("ratA") self._setShockColor(curLine) @@ -512,7 +536,7 @@ def changedTime(self, value, unit = "0-100"): def _updateDefaultParameters(self, time): - indices = slice(7, 9) if m.mode == "CM" else slice(2, 4) + indices = self.cm.indices x0, y0 = self.cm.data[0][indices] dist = 0 entrances = 0 @@ -592,6 +616,15 @@ def _setShockColor(self, curLine): if (m.mode == "CM" and curLine[6] > 0) or (m.mode == "MWM" and curLine[-1] > 0): self.roomCanv.itemconfigure("ratR", fill = "red", outline = "red") self.shock = True + elif m.mode == "RA": + if curLine[6] > 0: + self.arenaCanv.itemconfigure("ratA", fill = "red", outline = "red") + self.roomCanv.itemconfigure("ratR", fill = "red", outline = "red") + self.shock = True + else: + self.arenaCanv.itemconfigure("ratA", fill = "black", outline = "black") + self.roomCanv.itemconfigure("ratR", fill = "black", outline = "black") + self.shock = False else: self.roomCanv.itemconfigure("ratR", fill = "black", outline = "black") self.shock = False @@ -643,33 +676,32 @@ def initializeFile(self, filename, new = True, timeReset = True): if not successful: return - r = self.cm.radius - self.r = r + self.scale = 130 / self.cm.radius self.shock = False self.arenaCanv.delete("all") self.roomCanv.delete("all") if m.mode != "OF": - self.arenaCanv.create_oval(150 - r, 150 - r, 150 + r, 150 + r, outline = "black",\ + self.arenaCanv.create_oval(20, 20, 280, 280, outline = "black", width = 2, tags = "arenaAF") - self.roomCanv.create_oval(150 - r, 150 - r, 150 + r, 150 + r, outline = "black",\ + self.roomCanv.create_oval(20, 20, 280, 280, outline = "black", width = 2, tags = "arenaRF") else: - self.arenaCanv.create_rectangle(150 - r, 150 - r, 150 + r, 150 + r, - outline = "black", width = 2, tags = "arenaAF") - self.roomCanv.create_rectangle(150 - r, 150 - r, 150 + r, 150 + r, outline = "black", + self.arenaCanv.create_rectangle(20, 20, 280, 280, outline = "black", + width = 2, tags = "arenaAF") + self.roomCanv.create_rectangle(20, 20, 280, 280, outline = "black", width = 2, tags = "arenaRF") - if self.cm.centerAngle: + if self.cm.centerAngle or m.mode == "RA": self._createShockSector() self.maxTime = min([self.cm.data[-1][1], eval(self.timeFrame.timeVar.get()) * 60000]) self.minTime = max([self.cm.data[0][1], eval(self.timeFrame.startTimeVar.get()) * 60000]) - if self.showTrackVar.get() or m.mode != "CM": + if self.showTrackVar.get() or m.files != "pair": self._drawTrack() - if not self.showTrackVar.get() or m.mode != "CM": + if not self.showTrackVar.get() or m.files != "pair": self._initializeAnimation() self._setParameterDisplays(timeReset) @@ -724,22 +756,28 @@ def _createShockSector(self): self.width = self.cm.width a1 = radians(self.angle - (self.width / 2)) a2 = radians(self.angle + (self.width / 2)) - Sx1, Sy1 = 150 + (cos(a1) * self.r), 150 - (sin(a1) * self.r) - Sx2, Sy2 = 150 + (cos(a2) * self.r), 150 - (sin(a2) * self.r) + Sx1, Sy1 = 150 + (cos(a1) * 130), 150 - (sin(a1) * 130) + Sx2, Sy2 = 150 + (cos(a2) * 130), 150 - (sin(a2) * 130) self.roomCanv.create_line((Sx1, Sy1, 150, 150, Sx2, Sy2), fill = "red", width = 2,\ tags = "shockZone") elif m.mode == "MWM": - x = self.cm.platformX + 150 - self.r - y = self.cm.platformY + 150 - self.r + x = self.cm.platformX + 20 + y = self.cm.platformY + 20 r = self.cm.platformRadius self.arenaCanv.create_oval(x - r, y - r, x + r, y + r, outline = "red", width = 2, tags = "platformAF") self.roomCanv.create_oval(x - r, y - r, x + r, y + r, outline = "red", - width = 2, tags = "platformRF") + width = 2, tags = "platformRF") + elif m.mode == "RA": + r = self.cm.sectorRadius * self.scale / 2 + self.roomCanv.create_oval(150 - r, 150 - r, 150 + r, 150 + r, outline = "red", + width = 2, tags = "shockZoneR") + self.roomCanv.create_oval(146, 146, 154, 154, outline = "green", fill = "green", + width = 2, tags = "robotR") + def _drawTrack(self): - r = self.r if m.mode == "CM": data = [line[2:4] + line[6:9] for line in self.cm.data if self.minTime <= line[1] <= self.maxTime] @@ -756,20 +794,18 @@ def _drawTrack(self): arena.append(line[3:5]) last[1] = count prev = line - self.arenaCanv.create_line(([item + 150 - r for line in arena for item in line]), + self.arenaCanv.create_line(([item + 20 for line in arena for item in line]), fill = "black", width = 2) - self.roomCanv.create_line(([item + 150 - r for line in room for item in line]), + self.roomCanv.create_line(([item + 20 for line in room for item in line]), fill = "black", width = 2) if self.showShocksVar.get(): shocks = [line[2:4] for count, line in enumerate(self.cm.data) if self.minTime <= line[1] <= self.maxTime and line[6] > 0 and self.cm.data[count - 1][6] <= 0] - self.ld = 150 - r - 4 - self.ur = 150 - r + 4 for shock in shocks: - self.roomCanv.create_oval(shock[0] + self.ld, shock[1] + self.ld, - shock[0] + self.ur, shock[1] + self.ur, + self.roomCanv.create_oval(shock[0] + 16, shock[1] + 16, + shock[0] + 24, shock[1] + 24, outline = "red", width = 3) else: data = [line[2:4] for line in self.cm.data if self.minTime <= line[1] <= self.maxTime] @@ -781,12 +817,11 @@ def _drawTrack(self): points.append(line) last = count prev = line - self.roomCanv.create_line(([item + 150 - r for line in points for item in line]), + self.roomCanv.create_line(([item + 20 for line in points for item in line]), fill = "black", width = 2) def _initializeAnimation(self): - r = self.r # initial position for line in self.cm.data: if line[1] < self.minTime: @@ -800,27 +835,34 @@ def _initializeAnimation(self): return # makes 'the rat' (i.e. two black points) - self.ld = 150 - r - 4 # 4 is size of the rat dot - self.ur = 150 - r + 4 - - if m.mode == "CM": + if m.files == "pair": Rx, Ry = curLine[2:4] - Ax, Ay = curLine[7:9] - else: - Ax, Ay = curLine[2:4] + Rx *= self.scale + Ry *= self.scale + + Ax, Ay = curLine[self.cm.indices] + Ax *= self.scale + Ay *= self.scale if self.showTailVar.get(): - self.arenaCanv.create_line((Ax + 149 - r, Ay + 149 - r, Ax + 151 - r, - Ay + 151 - r), fill = "blue", width = 2, - tag = "trailA") + self.arenaCanv.create_line((Ax + 19, Ay + 19, Ax + 21, Ay + 21), fill = "blue", + width = 2, tag = "trailA") if m.mode == "CM": - self.roomCanv.create_line((Rx + 149 - r, Ry + 149 - r, Rx + 151 - r, Ry + 151 - r), + self.roomCanv.create_line((Rx + 19, Ry + 19, Rx + 21, Ry + 21), fill = "blue", width = 2, tag = "trailR") - self.roomCanv.create_oval(Rx + self.ld, Ry + self.ld, Rx + self.ur, Ry + self.ur, + self.roomCanv.create_oval(Rx + 16, Ry + 16, Rx + 24, Ry + 24, fill = "black", tags = "ratR") - - self.arenaCanv.create_oval(Ax + self.ld, Ay + self.ld, Ax + self.ur, Ay + self.ur, + elif m.mode == "RA": + self.roomCanv.create_oval(Ax - Rx + 146, Ay - Ry + 146, Ax - Rx + 154, Ay - Ry + 154, + fill = "black", tags = "ratR") + self.arenaCanv.create_oval(Rx + 16, Ry + 16, Rx + 24, Ry + 24, outline = "green", + fill = "green", tags = "robotA") + r = self.cm.sectorRadius * self.scale + self.arenaCanv.create_oval(Rx + 20 - r, Ry + 20 - r, Rx + 20 + r, Ry + 20 + r, + outline = "red", tags = "shockZoneA", width = 2) + + self.arenaCanv.create_oval(Ax + 16, Ay + 16, Ax + 24, Ay + 24, fill = "black", tags = "ratA") self._setShockColor(curLine) diff --git a/Stuff/Modules/filestorage.py b/Stuff/Modules/filestorage.py index a05ea96..e703b35 100644 --- a/Stuff/Modules/filestorage.py +++ b/Stuff/Modules/filestorage.py @@ -136,14 +136,14 @@ def tag(self, file): def pairFiles(self, files): "checks pairing of files and puts pairs in arenafiles and pairedfiles" - if ("arena" in files[0] or "Arena" in files[0]) and\ - ("room" in files[1] or "Room" in files[1]): + if (m.pairing[m.mode][0].lower() in files[0] or m.pairing[m.mode][0] in files[0]) and\ + (m.pairing[m.mode][1].lower() in files[1] or m.pairing[m.mode][1] in files[1]): self.pairedfiles[files[0]] = files[1] self.wrongfiles.remove(files[0]) self.wrongfiles.remove(files[1]) self.arenafiles.append(files[0]) - elif ("arena" in files[1] or "Arena" in files[1]) and\ - ("room" in files[0] or "Room" in files[0]): + elif (m.pairing[m.mode][0].lower() in files[1] or m.pairing[m.mode][0] in files[1]) and\ + (m.pairing[m.mode][1].lower() in files[0] or m.pairing[m.mode][1] in files[0]): self.pairedfiles[files[1]] = files[0] self.wrongfiles.remove(files[0]) self.wrongfiles.remove(files[1]) @@ -661,12 +661,15 @@ def loadFromLogFun(self): arenafile = file else: arenafile = file - if "Arena" in basename(arenafile): + if m.pairing[m.mode][0] in basename(arenafile): splitName = os.path.split(arenafile) - roomfile = os.path.join(splitName[0], splitName[1].replace("Arena", "Room")) - elif "arena" in basename(arenafile): + roomfile = os.path.join(splitName[0], splitName[1].replace(m.pairing[m.mode][0], + m.pairing[m.mode][1])) + elif m.pairing[m.mode][0].lower() in basename(arenafile): splitName = os.path.split(arenafile) - roomfile = os.path.join(splitName[0], splitName[1].replace("arena", "room")) + roomfile = os.path.join(splitName[0], + splitName[1].replace(m.pairing[m.mode][0].lower(), + m.pairing[m.mode][1].lower())) # sorting existing and non-existing files if os.path.isfile(arenafile): if m.files == "one" or os.path.isfile(roomfile): diff --git a/Stuff/Modules/mode.py b/Stuff/Modules/mode.py index b8a94be..ee69beb 100644 --- a/Stuff/Modules/mode.py +++ b/Stuff/Modules/mode.py @@ -24,7 +24,8 @@ from mwm import MWM from of import OF from cmsf import CMSF -from parameters import ParametersCM, ParametersMWM, ParametersOF, ParametersCMSF +from ra import RA +from parameters import ParametersCM, ParametersMWM, ParametersOF, ParametersCMSF, ParametersRA mode = None @@ -42,19 +43,24 @@ dispatch = {"CM": Task(CM, "pair", ParametersCM()), "MWM": Task(MWM, "one", ParametersMWM()), "OF": Task(OF, "one", ParametersOF()), - "CMSF": Task(CMSF, "one", ParametersCMSF())} + "CMSF": Task(CMSF, "one", ParametersCMSF()), + "RA": Task(RA, "pair", ParametersRA())} fullname = OrderedDict() fullname["CM"] = "Carousel maze" fullname["CMSF"] = "Carousel maze (single frame)" fullname["MWM"] = "Morris watter maze" fullname["OF"] = "Open field" +fullname["RA"] = "Robot avoidance" +pairing = {"CM": ("Arena", "Room"), + "RA": ("Rat", "Rob")} # zmenit pokud se bude menit pojmenovani !!! time = {"CM": 20, "MWM": 1, "OF": 10, - "CMSF": 20} + "CMSF": 20, + "RA": 20} # zkontrolovat def changeMode(newMode): diff --git a/Stuff/Modules/parameters.py b/Stuff/Modules/parameters.py index 48f2fdd..294102d 100644 --- a/Stuff/Modules/parameters.py +++ b/Stuff/Modules/parameters.py @@ -206,7 +206,13 @@ def __init__(self): - +class ParametersRA(OrderedDict): + def __init__(self): + super().__init__() + for name, parameter in ParametersCM().items(): + self[name] = parameter +## if name not in ("Room frame filename",): +## self[name] = parameter diff --git a/Stuff/Modules/ra.py b/Stuff/Modules/ra.py new file mode 100644 index 0000000..88f9dc6 --- /dev/null +++ b/Stuff/Modules/ra.py @@ -0,0 +1,95 @@ +""" +Copyright 2013 Štěpán Bahník + +This file is part of Carousel Maze Manager. + +Carousel Maze Manager is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Carousel Maze Manager is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Carousel Maze Manager. If not, see . +""" + +from collections import OrderedDict + +import os + + +from cm import CM + + +class RA(CM): + cache = OrderedDict() + + def __init__(self, nameA, nameR = "auto"): + "class RA represents data from robot avoidance; nameA - rat file; nameR - robot file" + self.nameA = nameA + self.data = [] + self.interpolated = set() + self.indices = slice(7,9) + + # automatic room frame filename creation + self._setRoomName(nameR) + + # in cache? + if (self.nameA, self.nameR) in RA.cache: + self.__dict__ = RA.cache[(self.nameA, self.nameR)] + return + + # processing data from robot frame + with open(self.nameR, "r") as infile: + self._processHeader(infile) + self.radius = self.trackerResolution * self.arenaDiameter * 100 + self._processRoomFile(infile) # robot file generally internally corresponds to roomfile + + # processing data from rat file + with open(self.nameA, "r") as infile: + self._processArenaFile(infile) # rat file generally internally corresponds to arenafile + + # discards missing points from beginning of self.data + self._correctMissingFromBeginning() + + # exception used for example when all lines are wrong (all positions are 0, 0) + if not self.data: + raise Exception("Failure in data initialization.") + + # caching + RA.cache[(self.nameA, self.nameR)] = self.__dict__ + if len(RA.cache) > 10: + CM.cache.popitem(last = False) + + + + def _setRoomName(self, name): # ZMENIT rob na robot??? + if name == "auto": + splitname = os.path.split(self.nameA) + if splitname[1].count("Rat") > 0: + self.nameR = os.path.join(splitname[0], splitname[1].replace("Rat", "Rob")) + elif splitname[1].count("rat") > 0: + self.nameR = os.path.join(splitname[0], splitname[1].replace("rat", "rob")) + else: + raise IOError + else: + self.nameR = name + + + def _addReinforcedSector(self, string, position): + self.sectorRadius = eval(string[position+1]) + + + + def _cacheRemoval(self): + if (self.nameA, self.nameR) in RA.cache: + RA.cache.pop((self.nameA, self.nameR)) + + + def removeReflections(self, *args, bothframes = False, **kwargs): + super().removeReflections(*args, bothframes = bothframes, **kwargs) + diff --git a/Stuff/Modules/recognizefiles.py b/Stuff/Modules/recognizefiles.py index e39aed4..c00fb54 100644 --- a/Stuff/Modules/recognizefiles.py +++ b/Stuff/Modules/recognizefiles.py @@ -40,8 +40,10 @@ def recognizeFiles(filenames): first = filenames.popleft() name = os.path.basename(first) splitName = os.path.split(first) - if "Arena" in name or "arena" in name: - base = splitName[1].replace("Arena", "Room").replace("arena", "room") + if m.pairing[m.mode][0] in name or m.pairing[m.mode][0].lower() in name: + base = splitName[1].replace(m.pairing[m.mode][0], + m.pairing[m.mode][1]).replace(m.pairing[m.mode][0].lower(), + m.pairing[m.mode][1].lower()) roomName = os.path.join(splitName[0], base) if roomName in filenames: arenaFiles.append(first) @@ -50,8 +52,10 @@ def recognizeFiles(filenames): arenaFiles.append(first) else: nonmatchingFiles.append(first) - elif "Room" in name or "room" in name: - base = splitName[1].replace("Room", "Arena").replace("room", "arena") + elif m.pairing[m.mode][1] in name or m.pairing[m.mode][1].lower() in name: + base = splitName[1].replace(m.pairing[m.mode][1], + m.pairing[m.mode][0]).replace(m.pairing[m.mode][1].lower(), + m.pairing[m.mode][0].lower()) arenaName = os.path.join(splitName[0], base) if arenaName in filenames: arenaFiles.append(arenaName) diff --git a/Stuff/Modules/version.py b/Stuff/Modules/version.py index ed8a8c9..bc65f75 100644 --- a/Stuff/Modules/version.py +++ b/Stuff/Modules/version.py @@ -21,7 +21,7 @@ def version(): return ['0', '4', '0'] def date(): - return "18 February 2014" + return "23 April 2014" def copyleft(): return "2013, 2014"