From fb5eb220fd81612d7347a641380ab820d5248bd4 Mon Sep 17 00:00:00 2001 From: DarkPhoenix Date: Fri, 17 May 2019 17:48:20 +0300 Subject: [PATCH] Rework graph interfaces again --- eos/graph/__init__.py | 18 ++++- eos/graph/fitCapAmountVsTime.py | 18 +---- eos/graph/fitCapRegenVsCapPerc.py | 18 +---- eos/graph/fitDistanceVsTime.py | 17 +++++ eos/graph/fitMobilityVsTime.py | 40 ----------- eos/graph/fitSpeedVsTime.py | 14 ++++ gui/builtinGraphs/fitCapAmountVsTime.py | 10 ++- gui/builtinGraphs/fitCapRegenVsCapPerc.py | 10 ++- gui/builtinGraphs/fitMobilityVsTime.py | 19 +++--- gui/builtinGraphs/fitSpeedTime.py | 81 ----------------------- gui/graph.py | 11 ++- gui/graphFrame.py | 16 +++-- 12 files changed, 89 insertions(+), 183 deletions(-) create mode 100644 eos/graph/fitDistanceVsTime.py delete mode 100644 eos/graph/fitMobilityVsTime.py create mode 100644 eos/graph/fitSpeedVsTime.py delete mode 100644 gui/builtinGraphs/fitSpeedTime.py diff --git a/eos/graph/__init__.py b/eos/graph/__init__.py index 77a348e88..59fd0dc61 100644 --- a/eos/graph/__init__.py +++ b/eos/graph/__init__.py @@ -47,5 +47,19 @@ class Graph(metaclass=ABCMeta): yield current current += step - def clearCache(self, fitID): - self.cache.clear() + def clearCache(self, fitID=None): + if fitID is None: + self.cache.clear() + elif fitID in self.cache: + del self.cache[fitID] + + +class SmoothGraph(Graph, metaclass=ABCMeta): + + def getPlotPoints(self, fit, extraData, xRange, xAmount): + xs = [] + ys = [] + for x in self._xIter(xRange, xAmount): + xs.append(x) + ys.append(self.getYForX(fit, extraData, x)) + return xs, ys diff --git a/eos/graph/fitCapAmountVsTime.py b/eos/graph/fitCapAmountVsTime.py index 1b9c25995..16627617d 100644 --- a/eos/graph/fitCapAmountVsTime.py +++ b/eos/graph/fitCapAmountVsTime.py @@ -1,23 +1,11 @@ import math -from eos.graph import Graph +from eos.graph import SmoothGraph -class FitCapAmountVsTimeGraph(Graph): +class FitCapAmountVsTimeGraph(SmoothGraph): - def getPlotPoints(self, fit, extraData, xRange, xAmount): - xs = [] - ys = [] - for x in self._xIter(xRange, xAmount): - xs.append(x) - ys.append(self.calc(fit, x)) - return xs, {'capAmount': ys} - - def getYForX(self, fit, extraData, x): - return {'capAmount': self.calc(fit, x)} - - @staticmethod - def calc(fit, time): + def getYForX(self, fit, extraData, time): if time < 0: return 0 maxCap = fit.ship.getModifiedItemAttr('capacitorCapacity') diff --git a/eos/graph/fitCapRegenVsCapPerc.py b/eos/graph/fitCapRegenVsCapPerc.py index 81776637f..ff686abea 100644 --- a/eos/graph/fitCapRegenVsCapPerc.py +++ b/eos/graph/fitCapRegenVsCapPerc.py @@ -1,23 +1,11 @@ import math -from eos.graph import Graph +from eos.graph import SmoothGraph -class FitCapRegenVsCapPercGraph(Graph): +class FitCapRegenVsCapPercGraph(SmoothGraph): - def getPlotPoints(self, fit, extraData, xRange, xAmount): - xs = [] - ys = [] - for x in self._xIter(xRange, xAmount): - xs.append(x) - ys.append(self.calc(fit, x)) - return xs, {'capRegen': ys} - - def getYForX(self, fit, extraData, x): - return {'capRegen': self.calc(fit, x)} - - @staticmethod - def calc(fit, perc): + def getYForX(self, fit, extraData, perc): maxCap = fit.ship.getModifiedItemAttr('capacitorCapacity') regenTime = fit.ship.getModifiedItemAttr('rechargeRate') / 1000 currentCap = maxCap * perc / 100 diff --git a/eos/graph/fitDistanceVsTime.py b/eos/graph/fitDistanceVsTime.py new file mode 100644 index 000000000..dcc5ce506 --- /dev/null +++ b/eos/graph/fitDistanceVsTime.py @@ -0,0 +1,17 @@ +import math + +from eos.graph import SmoothGraph + + +class FitDistanceVsTimeGraph(SmoothGraph): + + def getYForX(self, fit, extraData, time): + maxSpeed = fit.ship.getModifiedItemAttr('maxVelocity') + mass = fit.ship.getModifiedItemAttr('mass') + agility = fit.ship.getModifiedItemAttr('agility') + # Definite integral of: + # https://wiki.eveuniversity.org/Acceleration#Mathematics_and_formulae + distance_t = maxSpeed * time + (maxSpeed * agility * mass * math.exp((-time * 1000000) / (agility * mass)) / 1000000) + distance_0 = maxSpeed * 0 + (maxSpeed * agility * mass * math.exp((-0 * 1000000) / (agility * mass)) / 1000000) + distance = distance_t - distance_0 + return distance diff --git a/eos/graph/fitMobilityVsTime.py b/eos/graph/fitMobilityVsTime.py deleted file mode 100644 index fc6ad2a08..000000000 --- a/eos/graph/fitMobilityVsTime.py +++ /dev/null @@ -1,40 +0,0 @@ -import math - -from eos.graph import Graph - - -class FitMobilityVsTimeGraph(Graph): - - def getPlotPoints(self, fit, extraData, xRange, xAmount): - xs = [] - ysSpeed = [] - ysDistance = [] - for x in self._xIter(xRange, xAmount): - xs.append(x) - ysSpeed.append(self.calcSpeed(fit, x)) - ysDistance.append(self.calcDistance(fit, x)) - return xs, {'speed': ysSpeed, 'distance': ysDistance} - - def getYForX(self, fit, extraData, x): - return {'speed': self.calcSpeed(fit, x), 'distance': self.calcDistance(fit, x)} - - @staticmethod - def calcSpeed(fit, time): - maxSpeed = fit.ship.getModifiedItemAttr('maxVelocity') - mass = fit.ship.getModifiedItemAttr('mass') - agility = fit.ship.getModifiedItemAttr('agility') - # https://wiki.eveuniversity.org/Acceleration#Mathematics_and_formulae - speed = maxSpeed * (1 - math.exp((-time * 1000000) / (agility * mass))) - return speed - - @staticmethod - def calcDistance(fit, time): - maxSpeed = fit.ship.getModifiedItemAttr('maxVelocity') - mass = fit.ship.getModifiedItemAttr('mass') - agility = fit.ship.getModifiedItemAttr('agility') - # Definite integral of: - # https://wiki.eveuniversity.org/Acceleration#Mathematics_and_formulae - distance_t = maxSpeed * time + (maxSpeed * agility * mass * math.exp((-time * 1000000) / (agility * mass)) / 1000000) - distance_0 = maxSpeed * 0 + (maxSpeed * agility * mass * math.exp((-0 * 1000000) / (agility * mass)) / 1000000) - distance = distance_t - distance_0 - return distance diff --git a/eos/graph/fitSpeedVsTime.py b/eos/graph/fitSpeedVsTime.py new file mode 100644 index 000000000..ea19a310a --- /dev/null +++ b/eos/graph/fitSpeedVsTime.py @@ -0,0 +1,14 @@ +import math + +from eos.graph import SmoothGraph + + +class FitSpeedVsTimeGraph(SmoothGraph): + + def getYForX(self, fit, extraData, time): + maxSpeed = fit.ship.getModifiedItemAttr('maxVelocity') + mass = fit.ship.getModifiedItemAttr('mass') + agility = fit.ship.getModifiedItemAttr('agility') + # https://wiki.eveuniversity.org/Acceleration#Mathematics_and_formulae + speed = maxSpeed * (1 - math.exp((-time * 1000000) / (agility * mass))) + return speed diff --git a/gui/builtinGraphs/fitCapAmountVsTime.py b/gui/builtinGraphs/fitCapAmountVsTime.py index f5729f9ed..00e30c537 100644 --- a/gui/builtinGraphs/fitCapAmountVsTime.py +++ b/gui/builtinGraphs/fitCapAmountVsTime.py @@ -18,6 +18,8 @@ # ============================================================================= +from collections import OrderedDict + from eos.graph.fitCapAmountVsTime import FitCapAmountVsTimeGraph as EosGraph from gui.graph import Graph, XDef, YDef @@ -31,15 +33,11 @@ class FitCapAmountVsTimeGraph(Graph): @property def xDef(self): - return XDef(handle='time', inputDefault='0-300', inputLabel='Time (seconds)', inputIconID=1392, axisLabel='Time, s') + return XDef(inputDefault='0-300', inputLabel='Time (seconds)', inputIconID=1392, axisLabel='Time, s') @property def yDefs(self): - return [YDef(handle='capAmount', switchLabel='Cap amount', axisLabel='Cap amount, GJ')] - - def getPlotPoints(self, fit, extraData, xRange, xAmount): - xRange = self.parseRange(xRange) - return self.eosGraph.getPlotPoints(fit, extraData, xRange, xAmount) + return OrderedDict([('capAmount', YDef(switchLabel='Cap amount', axisLabel='Cap amount, GJ', eosGraph='eosGraph'))]) FitCapAmountVsTimeGraph.register() diff --git a/gui/builtinGraphs/fitCapRegenVsCapPerc.py b/gui/builtinGraphs/fitCapRegenVsCapPerc.py index 8431a7e29..41396f498 100644 --- a/gui/builtinGraphs/fitCapRegenVsCapPerc.py +++ b/gui/builtinGraphs/fitCapRegenVsCapPerc.py @@ -18,6 +18,8 @@ # ============================================================================= +from collections import OrderedDict + from eos.graph.fitCapRegenVsCapPerc import FitCapRegenVsCapPercGraph as EosGraph from gui.graph import Graph, XDef, YDef @@ -31,15 +33,11 @@ class FitCapRegenVsCapPercGraph(Graph): @property def xDef(self): - return XDef(handle='percentage', inputDefault='0-100', inputLabel='Cap Amount (percent)', inputIconID=1668, axisLabel='Cap amount, %') + return XDef(inputDefault='0-100', inputLabel='Cap Amount (percent)', inputIconID=1668, axisLabel='Cap amount, %') @property def yDefs(self): - return [YDef(handle='capRegen', switchLabel='Cap regen', axisLabel='Cap regen, GJ/s')] - - def getPlotPoints(self, fit, extraData, xRange, xAmount): - xRange = self.parseRange(xRange) - return self.eosGraph.getPlotPoints(fit, extraData, xRange, xAmount) + return OrderedDict([('capRegen', YDef(switchLabel='Cap regen', axisLabel='Cap regen, GJ/s', eosGraph='eosGraph'))]) FitCapRegenVsCapPercGraph.register() diff --git a/gui/builtinGraphs/fitMobilityVsTime.py b/gui/builtinGraphs/fitMobilityVsTime.py index e5836497a..24c237b27 100644 --- a/gui/builtinGraphs/fitMobilityVsTime.py +++ b/gui/builtinGraphs/fitMobilityVsTime.py @@ -17,7 +17,11 @@ # along with pyfa. If not, see . # ============================================================================= -from eos.graph.fitMobilityVsTime import FitMobilityVsTimeGraph as EosGraph + +from collections import OrderedDict + +from eos.graph.fitDistanceVsTime import FitDistanceVsTimeGraph as EosGraphDistance +from eos.graph.fitSpeedVsTime import FitSpeedVsTimeGraph as EosGraphSpeed from gui.graph import Graph, XDef, YDef @@ -26,19 +30,18 @@ class FitMobilityVsTimeGraph(Graph): name = 'Mobility vs Time' def __init__(self): - self.eosGraph = EosGraph() + self.eosGraphSpeed = EosGraphSpeed() + self.eosGraphDistance = EosGraphDistance() @property def xDef(self): - return XDef(handle='time', inputDefault='0-80', inputLabel='Time (seconds)', inputIconID=1392, axisLabel='Time, s') + return XDef(inputDefault='0-80', inputLabel='Time (seconds)', inputIconID=1392, axisLabel='Time, s') @property def yDefs(self): - return [YDef(handle='speed', switchLabel='Speed', axisLabel='Speed, m/s'), YDef(handle='distance', switchLabel='Distance', axisLabel='Distance, m')] - - def getPlotPoints(self, fit, extraData, xRange, xAmount): - xRange = self.parseRange(xRange) - return self.eosGraph.getPlotPoints(fit, extraData, xRange, xAmount) + return OrderedDict([ + ('speed', YDef(switchLabel='Speed', axisLabel='Speed, m/s', eosGraph='eosGraphSpeed')), + ('distance', YDef(switchLabel='Distance', axisLabel='Distance, m', eosGraph='eosGraphDistance'))]) FitMobilityVsTimeGraph.register() diff --git a/gui/builtinGraphs/fitSpeedTime.py b/gui/builtinGraphs/fitSpeedTime.py deleted file mode 100644 index 68a0cc36c..000000000 --- a/gui/builtinGraphs/fitSpeedTime.py +++ /dev/null @@ -1,81 +0,0 @@ -# ============================================================================= -# Copyright (C) 2010 Diego Duclos -# -# This file is part of pyfa. -# -# pyfa 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. -# -# pyfa 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 pyfa. If not, see . -# ============================================================================= - -import gui.mainFrame -from eos.graph import Data -from eos.graph.fitSpeedTime import FitSpeedTimeGraph as EosFitSpeedTimeGraph -from gui.bitmap_loader import BitmapLoader -from gui.graph import Graph -from service.attribute import Attribute - - -class FitSpeedTimeGraph(Graph): - - propertyLabelMap = {"time": "Time (seconds)"} - - defaults = EosFitSpeedTimeGraph.defaults.copy() - - def __init__(self): - Graph.__init__(self) - self.defaults["time"] = "0-80" - self.name = "Speed vs Time" - self.eosGraph = None - self.mainFrame = gui.mainFrame.MainFrame.getInstance() - - def getFields(self): - return self.defaults - - def getLabels(self): - return self.propertyLabelMap - - def getIcons(self): - iconFile = Attribute.getInstance().getAttributeInfo('duration').iconID - bitmap = BitmapLoader.getBitmap(iconFile, "icons") - return {"time": bitmap} - - def getPoints(self, fit, fields): - eosGraph = getattr(self, "eosGraph", None) - if eosGraph is None or eosGraph.fit != fit: - eosGraph = self.eosGraph = EosFitSpeedTimeGraph(fit) - - eosGraph.clearData() - variable = None - for fieldName, value in fields.items(): - d = Data(fieldName, value) - if not d.isConstant(): - if variable is None: - variable = fieldName - else: - # We can't handle more then one variable atm, OOPS FUCK OUT - return False, "Can only handle 1 variable" - - eosGraph.setData(d) - - if variable is None: - return False, "No variable" - - x = [] - y = [] - for point, val in eosGraph.getIterator(): - x.append(point[variable]) - y.append(val) - return x, y - - -FitSpeedTimeGraph.register() diff --git a/gui/graph.py b/gui/graph.py index 3d02915b8..7b75d4688 100644 --- a/gui/graph.py +++ b/gui/graph.py @@ -44,7 +44,7 @@ class Graph(metaclass=ABCMeta): @property def extraInputs(self): - return () + return {} @property @abstractmethod @@ -55,6 +55,11 @@ class Graph(metaclass=ABCMeta): def redrawOnEffectiveChange(self): return False + def getPlotPoints(self, fit, extraData, xRange, xAmount, yType): + xRange = self.parseRange(xRange) + graph = getattr(self, self.yDefs[yType].eosGraph, None) + return graph.getPlotPoints(fit, extraData, xRange, xAmount) + def parseRange(self, string): m = re.match('\s*(?P\d+(\.\d+)?)\s*(-\s*(?P\d+(\.\d+)?))?', string) if m is None: @@ -67,8 +72,8 @@ class Graph(metaclass=ABCMeta): return (float(first), float(second)) -XDef = namedtuple('XDef', ('handle', 'inputDefault', 'inputLabel', 'inputIconID', 'axisLabel')) -YDef = namedtuple('YDef', ('handle', 'switchLabel', 'axisLabel')) +XDef = namedtuple('XDef', ('inputDefault', 'inputLabel', 'inputIconID', 'axisLabel')) +YDef = namedtuple('YDef', ('switchLabel', 'axisLabel', 'eosGraph')) ExtraInput = namedtuple('ExtraInput', ('handle', 'inputDefault', 'inputLabel', 'inputIconID')) diff --git a/gui/graphFrame.py b/gui/graphFrame.py index cf03d203a..dcbf9b884 100644 --- a/gui/graphFrame.py +++ b/gui/graphFrame.py @@ -244,9 +244,9 @@ class GraphFrame(wx.Frame): self.fields.clear() # Setup textboxes - for fieldDef in (view.xDef, *view.extraInputs): + for fieldHandle, fieldDef in (('x', view.xDef), *view.extraInputs.items()): textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0) - self.fields[fieldDef.handle] = textBox + self.fields[fieldHandle] = textBox textBox.Bind(wx.EVT_TEXT, self.onFieldChanged) sizer.Add(textBox, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3) if fieldDef.inputDefault is not None: @@ -293,14 +293,16 @@ class GraphFrame(wx.Frame): min_y = 0 max_y = 0 - xRange = values[view.xDef.handle] - extraInputs = {i.handle: values[i.handle] for i in view.extraInputs} - chosenY = view.yDefs[0].handle + xRange = values['x'] + extraInputs = {ih: values[ih] for ih in view.extraInputs} + chosenY = None + for handle in view.yDefs: + chosenY = handle + break for fit in self.fits: try: - xs, ys = view.getPlotPoints(fit, extraInputs, xRange, 100) - ys = ys[chosenY] + xs, ys = view.getPlotPoints(fit, extraInputs, xRange, 100, chosenY) min_y = min(min_y, min(ys, default=0)) max_y = max(max_y, max(ys, default=0))