diff --git a/gui/builtinGraphs/__init__.py b/gui/builtinGraphs/__init__.py
index 82c10e1f7..6f55feae6 100644
--- a/gui/builtinGraphs/__init__.py
+++ b/gui/builtinGraphs/__init__.py
@@ -1,9 +1,7 @@
# noinspection PyUnresolvedReferences
from gui.builtinGraphs import ( # noqa: E402,F401
fitDamageStats,
- # fitDmgVsTime,
fitShieldRegen,
fitCapRegen,
fitMobility,
- fitWarpTime
-)
+ fitWarpTime)
diff --git a/gui/builtinGraphs/base.py b/gui/builtinGraphs/base.py
index adb6e624d..b6cc457f3 100644
--- a/gui/builtinGraphs/base.py
+++ b/gui/builtinGraphs/base.py
@@ -232,13 +232,12 @@ class FitGraph(metaclass=ABCMeta):
def _getPoints(self, mainParam, miscParams, xSpec, ySpec, fit, tgt):
try:
- fullGetter, singleGetter, cacheGetter = self._getters[(xSpec.handle, ySpec.handle)]
+ getterClass = self._getters[(xSpec.handle, ySpec.handle)]
except KeyError:
return [], []
else:
- return fullGetter(
- self, cacheGetter=cacheGetter, singleGetter=singleGetter,
- mainParam=mainParam, miscParams=miscParams, fit=fit, tgt=tgt)
+ getter = getterClass(graph=self)
+ return getter.getRange(mainParam=mainParam, miscParams=miscParams, fit=fit, tgt=tgt)
_denormalizers = {}
@@ -249,11 +248,52 @@ class FitGraph(metaclass=ABCMeta):
values = [denormalizer(v, fit, tgt) for v in values]
return values
- def _iterLinear(self, valRange, segments=200):
+
+class PointGetter(metaclass=ABCMeta):
+
+ def __init__(self, graph):
+ self.graph = graph
+
+ @abstractmethod
+ def getRange(self, mainParam, miscParams, fit, tgt):
+ raise NotImplementedError
+
+ @abstractmethod
+ def getPoint(self, mainParam, miscParams, fit, tgt, cache=None):
+ raise NotImplementedError
+
+
+class SmoothPointGetter(PointGetter, metaclass=ABCMeta):
+
+ def __init__(self, graph, baseResolution=200):
+ super().__init__(graph)
+ self._baseResolution = baseResolution
+
+ def getRange(self, mainParam, miscParams, fit, tgt):
+ xs = []
+ ys = []
+ commonData = self._getCommonData(miscParams=miscParams, fit=fit, tgt=tgt)
+ for x in self._iterLinear(mainParam[1]):
+ y = self._calculatePoint(
+ mainParam=x, miscParams=miscParams,
+ fit=fit, tgt=tgt, commonData=commonData)
+ xs.append(x)
+ ys.append(y)
+ return xs, ys
+
+ def getPoint(self, mainParam, miscParams, fit, tgt):
+ commonData = self._getCommonData(miscParams=miscParams, fit=fit, tgt=tgt)
+ y = self._calculatePoint(
+ mainParam=mainParam, miscParams=miscParams,
+ fit=fit, tgt=tgt, commonData=commonData)
+ return mainParam, y
+
+ def _iterLinear(self, valRange):
rangeLow = min(valRange)
rangeHigh = max(valRange)
- # Amount is amount of ranges between points here, not amount of points
- step = (rangeHigh - rangeLow) / segments
+ # Resolution defines amount of ranges between points here,
+ # not amount of points
+ step = (rangeHigh - rangeLow) / self._baseResolution
if step == 0 or math.isnan(step):
yield rangeLow
else:
@@ -264,6 +304,13 @@ class FitGraph(metaclass=ABCMeta):
yield current
current += step
+ def _getCommonData(self, miscParams, fit, tgt):
+ return {}
+
+ @abstractmethod
+ def _calculatePoint(self, mainParam, miscParams, fit, tgt, commonData):
+ raise NotImplementedError
+
class FitDataCache:
diff --git a/gui/builtinGraphs/fitWarpTime.py b/gui/builtinGraphs/fitWarpTime.py
deleted file mode 100644
index da9bc9bca..000000000
--- a/gui/builtinGraphs/fitWarpTime.py
+++ /dev/null
@@ -1,189 +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 math
-
-from eos.const import FittingModuleState
-from service.const import GraphCacheCleanupReason
-from .base import FitGraph, XDef, YDef, Input, FitDataCache
-
-
-AU_METERS = 149597870700
-
-
-class FitWarpTimeGraph(FitGraph):
-
- def __init__(self):
- super().__init__()
- self._subspeedCache = SubwarpSpeedCache()
-
- def _clearInternalCache(self, reason, extraData):
- if reason in (GraphCacheCleanupReason.fitChanged, GraphCacheCleanupReason.fitRemoved):
- self._subspeedCache.clearForFit(extraData)
- elif reason == GraphCacheCleanupReason.graphSwitched:
- self._subspeedCache.clearAll()
-
- # UI stuff
- internalName = 'warpTimeGraph'
- name = 'Warp Time'
- xDefs = [
- XDef(handle='distance', unit='AU', label='Distance', mainInput=('distance', 'AU')),
- XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km'))]
- yDefs = [
- YDef(handle='time', unit='s', label='Warp time')]
- inputs = [
- Input(handle='distance', unit='AU', label='Distance', iconID=1391, defaultValue=20, defaultRange=(0, 50)),
- Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=1000, defaultRange=(150, 5000))]
- srcExtraCols = ('WarpSpeed', 'WarpDistance')
-
- # Calculation stuff
- _normalizers = {
- ('distance', 'AU'): lambda v, fit, tgt: v * AU_METERS,
- ('distance', 'km'): lambda v, fit, tgt: v * 1000}
- _limiters = {
- 'distance': lambda fit, tgt: (0, fit.maxWarpDistance * AU_METERS)}
- _denormalizers = {
- ('distance', 'AU'): lambda v, fit, tgt: v / AU_METERS,
- ('distance', 'km'): lambda v, fit, tgt: v / 1000}
-
- def _distance2timeCache(self, miscParams, fit, tgt):
- return {
- 'subwarpSpeed': self._subspeedCache.getSubwarpSpeed(fit),
- 'warpSpeed': fit.warpSpeed}
-
- def _distance2timeFull(self, cacheGetter, singleGetter, mainParam, miscParams, fit, tgt):
- xs = []
- ys = []
- cache = cacheGetter(self, miscParams=miscParams, fit=fit, tgt=tgt)
- for distance in self._iterLinear(mainParam[1]):
- time = singleGetter(
- self, cacheGetter=cacheGetter, mainParam=distance, miscParams=miscParams,
- fit=fit, tgt=tgt, cache=cache)
- xs.append(distance)
- ys.append(time)
- return xs, ys
-
- def _distance2timeSingle(self, cacheGetter, mainParam, miscParams, fit, tgt, cache=None):
- if cache is None:
- cache = cacheGetter(self, miscParams=miscParams, fit=fit, tgt=tgt)
- time = calculate_time_in_warp(
- max_subwarp_speed=cache['subwarpSpeed'],
- max_warp_speed=cache['warpSpeed'],
- warp_dist=mainParam)
- return time
-
- _getters = {
- ('distance', 'time'): (_distance2timeFull, _distance2timeSingle, _distance2timeCache)}
-
-
-class SubwarpSpeedCache(FitDataCache):
-
- def getSubwarpSpeed(self, fit):
- try:
- subwarpSpeed = self._data[fit.ID]
- except KeyError:
- modStates = {}
- disallowedGroups = (
- # Active modules which affect ship speed and cannot be used in warp
- 'Propulsion Module',
- 'Mass Entanglers',
- 'Cloaking Device',
- # Those reduce ship speed to 0
- 'Siege Module',
- 'Super Weapon',
- 'Cynosural Field Generator',
- 'Clone Vat Bay',
- 'Jump Portal Generator')
- for mod in fit.modules:
- if mod.item is not None and mod.item.group.name in disallowedGroups and mod.state >= FittingModuleState.ACTIVE:
- modStates[mod] = mod.state
- mod.state = FittingModuleState.ONLINE
- projFitStates = {}
- for projFit in fit.projectedFits:
- projectionInfo = projFit.getProjectionInfo(fit.ID)
- if projectionInfo is not None and projectionInfo.active:
- projFitStates[projectionInfo] = projectionInfo.active
- projectionInfo.active = False
- projModStates = {}
- for mod in fit.projectedModules:
- if not mod.isExclusiveSystemEffect and mod.state >= FittingModuleState.ACTIVE:
- projModStates[mod] = mod.state
- mod.state = FittingModuleState.ONLINE
- projDroneStates = {}
- for drone in fit.projectedDrones:
- if drone.amountActive > 0:
- projDroneStates[drone] = drone.amountActive
- drone.amountActive = 0
- projFighterStates = {}
- for fighter in fit.projectedFighters:
- if fighter.active:
- projFighterStates[fighter] = fighter.active
- fighter.active = False
- fit.calculateModifiedAttributes()
- subwarpSpeed = fit.ship.getModifiedItemAttr('maxVelocity')
- self._data[fit.ID] = subwarpSpeed
- for projInfo, state in projFitStates.items():
- projInfo.active = state
- for mod, state in modStates.items():
- mod.state = state
- for mod, state in projModStates.items():
- mod.state = state
- for drone, amountActive in projDroneStates.items():
- drone.amountActive = amountActive
- for fighter, state in projFighterStates.items():
- fighter.active = state
- fit.calculateModifiedAttributes()
- return subwarpSpeed
-
-
-# Taken from https://wiki.eveuniversity.org/Warp_time_calculation#Implementation
-# with minor modifications
-# Warp speed in AU/s, subwarp speed in m/s, distance in m
-def calculate_time_in_warp(max_warp_speed, max_subwarp_speed, warp_dist):
-
- if warp_dist == 0:
- return 0
-
- k_accel = max_warp_speed
- k_decel = min(max_warp_speed / 3, 2)
-
- warp_dropout_speed = max_subwarp_speed / 2
- max_ms_warp_speed = max_warp_speed * AU_METERS
-
- accel_dist = AU_METERS
- decel_dist = max_ms_warp_speed / k_decel
-
- minimum_dist = accel_dist + decel_dist
-
- cruise_time = 0
-
- if minimum_dist > warp_dist:
- max_ms_warp_speed = warp_dist * k_accel * k_decel / (k_accel + k_decel)
- else:
- cruise_time = (warp_dist - minimum_dist) / max_ms_warp_speed
-
- accel_time = math.log(max_ms_warp_speed / k_accel) / k_accel
- decel_time = math.log(max_ms_warp_speed / warp_dropout_speed) / k_decel
-
- total_time = cruise_time + accel_time + decel_time
- return total_time
-
-
-FitWarpTimeGraph.register()
diff --git a/gui/builtinGraphs/fitWarpTime/__init__.py b/gui/builtinGraphs/fitWarpTime/__init__.py
new file mode 100644
index 000000000..860a43eb2
--- /dev/null
+++ b/gui/builtinGraphs/fitWarpTime/__init__.py
@@ -0,0 +1 @@
+import gui.builtinGraphs.fitWarpTime.graph # noqa: E402,F401
diff --git a/gui/builtinGraphs/fitWarpTime/getter.py b/gui/builtinGraphs/fitWarpTime/getter.py
new file mode 100644
index 000000000..89c181460
--- /dev/null
+++ b/gui/builtinGraphs/fitWarpTime/getter.py
@@ -0,0 +1,74 @@
+# =============================================================================
+# 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 math
+
+from gui.builtinGraphs.base import SmoothPointGetter
+
+
+AU_METERS = 149597870700
+
+
+class Distance2TimeGetter(SmoothPointGetter):
+
+ def _getCommonData(self, miscParams, fit, tgt):
+ return {
+ 'subwarpSpeed': self.graph._subspeedCache.getSubwarpSpeed(fit),
+ 'warpSpeed': fit.warpSpeed}
+
+ def _calculatePoint(self, mainParam, miscParams, fit, tgt, commonData):
+ time = calculate_time_in_warp(
+ max_subwarp_speed=commonData['subwarpSpeed'],
+ max_warp_speed=commonData['warpSpeed'],
+ warp_dist=mainParam)
+ return time
+
+
+# Taken from https://wiki.eveuniversity.org/Warp_time_calculation#Implementation
+# with minor modifications
+# Warp speed in AU/s, subwarp speed in m/s, distance in m
+def calculate_time_in_warp(max_warp_speed, max_subwarp_speed, warp_dist):
+
+ if warp_dist == 0:
+ return 0
+
+ k_accel = max_warp_speed
+ k_decel = min(max_warp_speed / 3, 2)
+
+ warp_dropout_speed = max_subwarp_speed / 2
+ max_ms_warp_speed = max_warp_speed * AU_METERS
+
+ accel_dist = AU_METERS
+ decel_dist = max_ms_warp_speed / k_decel
+
+ minimum_dist = accel_dist + decel_dist
+
+ cruise_time = 0
+
+ if minimum_dist > warp_dist:
+ max_ms_warp_speed = warp_dist * k_accel * k_decel / (k_accel + k_decel)
+ else:
+ cruise_time = (warp_dist - minimum_dist) / max_ms_warp_speed
+
+ accel_time = math.log(max_ms_warp_speed / k_accel) / k_accel
+ decel_time = math.log(max_ms_warp_speed / warp_dropout_speed) / k_decel
+
+ total_time = cruise_time + accel_time + decel_time
+ return total_time
diff --git a/gui/builtinGraphs/fitWarpTime/graph.py b/gui/builtinGraphs/fitWarpTime/graph.py
new file mode 100644
index 000000000..986c6da0a
--- /dev/null
+++ b/gui/builtinGraphs/fitWarpTime/graph.py
@@ -0,0 +1,66 @@
+# =============================================================================
+# 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 .
+# =============================================================================
+
+
+from service.const import GraphCacheCleanupReason
+from gui.builtinGraphs.base import FitGraph, XDef, YDef, Input
+from .getter import Distance2TimeGetter, AU_METERS
+from .subwarpCache import SubwarpSpeedCache
+
+
+class FitWarpTimeGraph(FitGraph):
+
+ def __init__(self):
+ super().__init__()
+ self._subspeedCache = SubwarpSpeedCache()
+
+ def _clearInternalCache(self, reason, extraData):
+ if reason in (GraphCacheCleanupReason.fitChanged, GraphCacheCleanupReason.fitRemoved):
+ self._subspeedCache.clearForFit(extraData)
+ elif reason == GraphCacheCleanupReason.graphSwitched:
+ self._subspeedCache.clearAll()
+
+ # UI stuff
+ internalName = 'warpTimeGraph'
+ name = 'Warp Time'
+ xDefs = [
+ XDef(handle='distance', unit='AU', label='Distance', mainInput=('distance', 'AU')),
+ XDef(handle='distance', unit='km', label='Distance', mainInput=('distance', 'km'))]
+ yDefs = [
+ YDef(handle='time', unit='s', label='Warp time')]
+ inputs = [
+ Input(handle='distance', unit='AU', label='Distance', iconID=1391, defaultValue=20, defaultRange=(0, 50)),
+ Input(handle='distance', unit='km', label='Distance', iconID=1391, defaultValue=1000, defaultRange=(150, 5000))]
+ srcExtraCols = ('WarpSpeed', 'WarpDistance')
+
+ # Calculation stuff
+ _normalizers = {
+ ('distance', 'AU'): lambda v, fit, tgt: v * AU_METERS,
+ ('distance', 'km'): lambda v, fit, tgt: v * 1000}
+ _limiters = {
+ 'distance': lambda fit, tgt: (0, fit.maxWarpDistance * AU_METERS)}
+ _denormalizers = {
+ ('distance', 'AU'): lambda v, fit, tgt: v / AU_METERS,
+ ('distance', 'km'): lambda v, fit, tgt: v / 1000}
+
+ _getters = {
+ ('distance', 'time'): Distance2TimeGetter}
+
+
+FitWarpTimeGraph.register()
diff --git a/gui/builtinGraphs/fitWarpTime/subwarpCache.py b/gui/builtinGraphs/fitWarpTime/subwarpCache.py
new file mode 100644
index 000000000..2eabb9be7
--- /dev/null
+++ b/gui/builtinGraphs/fitWarpTime/subwarpCache.py
@@ -0,0 +1,82 @@
+# =============================================================================
+# 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 .
+# =============================================================================
+
+
+from eos.const import FittingModuleState
+from gui.builtinGraphs.base import FitDataCache
+
+
+class SubwarpSpeedCache(FitDataCache):
+
+ def getSubwarpSpeed(self, fit):
+ try:
+ subwarpSpeed = self._data[fit.ID]
+ except KeyError:
+ modStates = {}
+ disallowedGroups = (
+ # Active modules which affect ship speed and cannot be used in warp
+ 'Propulsion Module',
+ 'Mass Entanglers',
+ 'Cloaking Device',
+ # Those reduce ship speed to 0
+ 'Siege Module',
+ 'Super Weapon',
+ 'Cynosural Field Generator',
+ 'Clone Vat Bay',
+ 'Jump Portal Generator')
+ for mod in fit.modules:
+ if mod.item is not None and mod.item.group.name in disallowedGroups and mod.state >= FittingModuleState.ACTIVE:
+ modStates[mod] = mod.state
+ mod.state = FittingModuleState.ONLINE
+ projFitStates = {}
+ for projFit in fit.projectedFits:
+ projectionInfo = projFit.getProjectionInfo(fit.ID)
+ if projectionInfo is not None and projectionInfo.active:
+ projFitStates[projectionInfo] = projectionInfo.active
+ projectionInfo.active = False
+ projModStates = {}
+ for mod in fit.projectedModules:
+ if not mod.isExclusiveSystemEffect and mod.state >= FittingModuleState.ACTIVE:
+ projModStates[mod] = mod.state
+ mod.state = FittingModuleState.ONLINE
+ projDroneStates = {}
+ for drone in fit.projectedDrones:
+ if drone.amountActive > 0:
+ projDroneStates[drone] = drone.amountActive
+ drone.amountActive = 0
+ projFighterStates = {}
+ for fighter in fit.projectedFighters:
+ if fighter.active:
+ projFighterStates[fighter] = fighter.active
+ fighter.active = False
+ fit.calculateModifiedAttributes()
+ subwarpSpeed = fit.ship.getModifiedItemAttr('maxVelocity')
+ self._data[fit.ID] = subwarpSpeed
+ for projInfo, state in projFitStates.items():
+ projInfo.active = state
+ for mod, state in modStates.items():
+ mod.state = state
+ for mod, state in projModStates.items():
+ mod.state = state
+ for drone, amountActive in projDroneStates.items():
+ drone.amountActive = amountActive
+ for fighter, state in projFighterStates.items():
+ fighter.active = state
+ fit.calculateModifiedAttributes()
+ return subwarpSpeed