Add vector class

This commit is contained in:
DarkPhoenix
2019-06-13 13:20:04 +03:00
parent 6003302e10
commit c85b6e4a36

View File

@@ -17,9 +17,9 @@
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
import math
import os
import traceback
from itertools import chain
# noinspection PyPackageRequirements
import wx
@@ -52,7 +52,7 @@ try:
graphFrame_enabled = True
mplImported = True
except ImportError as e:
pyfalog.warning("Matplotlib failed to import. Likely missing or incompatible version.")
pyfalog.warning('Matplotlib failed to import. Likely missing or incompatible version.')
mpl_version = -1
Patch = mpl = Canvas = Figure = None
graphFrame_enabled = False
@@ -60,7 +60,7 @@ except ImportError as e:
except Exception:
# We can get exceptions deep within matplotlib. Catch those. See GH #1046
tb = traceback.format_exc()
pyfalog.critical("Exception when importing Matplotlib. Continuing without importing.")
pyfalog.critical('Exception when importing Matplotlib. Continuing without importing.')
pyfalog.critical(tb)
mpl_version = -1
Patch = mpl = Canvas = Figure = None
@@ -79,13 +79,13 @@ class GraphFrame(wx.Frame):
self.legendFix = False
if not graphFrame_enabled:
pyfalog.warning("Matplotlib is not enabled. Skipping initialization.")
pyfalog.warning('Matplotlib is not enabled. Skipping initialization.')
return
try:
cache_dir = mpl._get_cachedir()
except:
cache_dir = os.path.expanduser(os.path.join("~", ".matplotlib"))
cache_dir = os.path.expanduser(os.path.join('~', '.matplotlib'))
cache_file = os.path.join(cache_dir, 'fontList.cache')
@@ -97,15 +97,15 @@ class GraphFrame(wx.Frame):
graphFrame_enabled = True
if int(mpl.__version__[0]) < 1:
pyfalog.warning("pyfa: Found matplotlib version {} - activating OVER9000 workarounds".format(mpl.__version__))
pyfalog.warning("pyfa: Recommended minimum matplotlib version is 1.0.0")
pyfalog.warning('pyfa: Found matplotlib version {} - activating OVER9000 workarounds'.format(mpl.__version__))
pyfalog.warning('pyfa: Recommended minimum matplotlib version is 1.0.0')
self.legendFix = True
mplImported = True
wx.Frame.__init__(self, parent, title="pyfa: Graph Generator", style=style, size=(520, 390))
wx.Frame.__init__(self, parent, title='pyfa: Graph Generator', style=style, size=(520, 390))
i = wx.Icon(BitmapLoader.getBitmap("graphs_small", "gui"))
i = wx.Icon(BitmapLoader.getBitmap('graphs_small', 'gui'))
self.SetIcon(i)
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.CreateStatusBar()
@@ -153,7 +153,7 @@ class GraphFrame(wx.Frame):
ctrlPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
viewOptSizer = wx.BoxSizer(wx.VERTICAL)
self.showY0Cb = wx.CheckBox(self.graphCtrlPanel, wx.ID_ANY, "Always show Y = 0", wx.DefaultPosition, wx.DefaultSize, 0)
self.showY0Cb = wx.CheckBox(self.graphCtrlPanel, wx.ID_ANY, 'Always show Y = 0', wx.DefaultPosition, wx.DefaultSize, 0)
self.showY0Cb.SetValue(self.showY0)
self.showY0Cb.Bind(wx.EVT_CHECKBOX, self.OnShowY0Update)
viewOptSizer.Add(self.showY0Cb, 0, wx.LEFT | wx.TOP | wx.RIGHT | wx.EXPAND, 5)
@@ -203,7 +203,7 @@ class GraphFrame(wx.Frame):
self.SetMinSize(self.GetSize())
def handleDrag(self, type, fitID):
if type == "fit":
if type == 'fit':
self.AppendFitToList(fitID)
def closeEvent(self, event):
@@ -321,15 +321,15 @@ class GraphFrame(wx.Frame):
if fieldDef.inputDefault is not None:
inputDefault = fieldDef.inputDefault
if not isinstance(inputDefault, str):
inputDefault = ("%f" % inputDefault).rstrip("0")
if inputDefault[-1:] == ".":
inputDefault += "0"
inputDefault = ('%f' % inputDefault).rstrip('0')
if inputDefault[-1:] == '.':
inputDefault += '0'
textBox.ChangeValue(inputDefault)
imgLabelSizer = wx.BoxSizer(wx.HORIZONTAL)
if fieldDef.inputIconID:
icon = BitmapLoader.getBitmap(fieldDef.inputIconID, "icons")
icon = BitmapLoader.getBitmap(fieldDef.inputIconID, 'icons')
if icon is not None:
static = wx.StaticBitmap(self.graphCtrlPanel)
static.SetBitmap(icon)
@@ -343,7 +343,7 @@ class GraphFrame(wx.Frame):
def delayedDraw(self, event=None):
self.drawTimer.Stop()
self.drawTimer.Start(Fit.getInstance().serviceFittingOptions["marketSearchDelay"], True)
self.drawTimer.Start(Fit.getInstance().serviceFittingOptions['marketSearchDelay'], True)
def draw(self, event=None):
global mpl_version
@@ -356,7 +356,7 @@ class GraphFrame(wx.Frame):
# todo: FIX THIS, see #1430. draw() is not being unbound properly when the window closes, this is an easy fix,
# but not a proper solution
if not self:
pyfalog.warning("GraphFrame handled event, however GraphFrame no longer exists. Ignoring event")
pyfalog.warning('GraphFrame handled event, however GraphFrame no longer exists. Ignoring event')
return
values = self.getValues()
@@ -396,8 +396,8 @@ class GraphFrame(wx.Frame):
self.subplot.plot(xs, ys)
legend.append('{} ({})'.format(fit.name, fit.ship.item.getShortName()))
except Exception as ex:
pyfalog.warning("Invalid values in '{0}'", fit.name)
self.SetStatusText("Invalid values in '%s'" % fit.name)
pyfalog.warning('Invalid values in "{0}"', fit.name)
self.SetStatusText('Invalid values in "%s"' % fit.name)
self.canvas.draw()
return
@@ -414,7 +414,7 @@ class GraphFrame(wx.Frame):
if mpl_version < 2:
if self.legendFix and len(legend) > 0:
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False)
leg = self.subplot.legend(tuple(legend), 'upper right', shadow=False)
for t in leg.get_texts():
t.set_fontsize('small')
@@ -422,7 +422,7 @@ class GraphFrame(wx.Frame):
l.set_linewidth(1)
elif not self.legendFix and len(legend) > 0:
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False)
leg = self.subplot.legend(tuple(legend), 'upper right', shadow=False, frameon=False)
for t in leg.get_texts():
t.set_fontsize('small')
@@ -431,14 +431,14 @@ class GraphFrame(wx.Frame):
elif mpl_version >= 2:
legend2 = []
legend_colors = {
0: "blue",
1: "orange",
2: "green",
3: "red",
4: "purple",
5: "brown",
6: "pink",
7: "grey",
0: 'blue',
1: 'orange',
2: 'green',
3: 'red',
4: 'purple',
5: 'brown',
6: 'pink',
7: 'grey',
}
for i, i_name in enumerate(legend):
@@ -457,7 +457,7 @@ class GraphFrame(wx.Frame):
l.set_linewidth(1)
self.canvas.draw()
self.SetStatusText("")
self.SetStatusText('')
self.Refresh()
def onFieldChanged(self, event):
@@ -516,13 +516,13 @@ class FitList(wx.Panel):
self.fitList = FitDisplay(self)
self.mainSizer.Add(self.fitList, 1, wx.EXPAND)
fitToolTip = wx.ToolTip("Drag a fit into this list to graph it")
fitToolTip = wx.ToolTip('Drag a fit into this list to graph it')
self.fitList.SetToolTip(fitToolTip)
class FitDisplay(gui.display.Display):
DEFAULT_COLS = ["Base Icon",
"Base Name"]
DEFAULT_COLS = ['Base Icon',
'Base Name']
def __init__(self, parent):
gui.display.Display.__init__(self, parent)
@@ -537,13 +537,216 @@ class TargetList(wx.Panel):
self.targetList = TargetDisplay(self)
self.mainSizer.Add(self.targetList, 1, wx.EXPAND)
fitToolTip = wx.ToolTip("Drag a fit into this list to graph it")
fitToolTip = wx.ToolTip('Drag a fit into this list to graph it')
self.targetList.SetToolTip(fitToolTip)
class TargetDisplay(gui.display.Display):
DEFAULT_COLS = ["Base Icon",
"Base Name"]
DEFAULT_COLS = ['Base Icon',
'Base Name']
def __init__(self, parent):
gui.display.Display.__init__(self, parent)
# class VectorEvent(wx.PyCommandEvent):
# def __init__(self, evtType, id):
# wx.PyCommandEvent.__init__(self, evtType, id)
# self._angle = 0
# self._length = 0
#
# def GetValue(self):
# return self._angle, self._length
#
# def GetAngle(self):
# return self._angle
#
# def GetLength(self):
# return self._length
class VectorPicker(wx.Control):
myEVT_VECTOR_CHANGED = wx.NewEventType()
EVT_VECTOR_CHANGED = wx.PyEventBinder(myEVT_VECTOR_CHANGED, 1)
def __init__(self, *args, **kwargs):
self._label = str(kwargs.pop('label', ''))
self._labelpos = int(kwargs.pop('labelpos', 0))
self._offset = float(kwargs.pop('offset', 0))
self._size = max(0, float(kwargs.pop('size', 50)))
self._fontsize = max(1, float(kwargs.pop('fontsize', 8)))
wx.Control.__init__(self, *args, **kwargs)
self._font = wx.Font(self._fontsize, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
self._angle = 0
self._length = 1
self._left = False
self._right = False
self._tooltip = 'Click to set angle and velocity, right-click for increments; mouse wheel for velocity only'
self.SetToolTip(wx.ToolTip(self._tooltip))
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
def DoGetBestSize(self):
return wx.Size(self._size, self._size)
def AcceptsFocusFromKeyboard(self):
return False
def GetValue(self):
return self._angle, self._length
def GetAngle(self):
return self._angle
def GetLength(self):
return self._length
def SetValue(self, angle=None, length=None):
if angle is not None:
self._angle = min(max(angle, -180), 180)
if length is not None:
self._length = min(max(length, 0), 1)
self.Refresh()
def SetAngle(self, angle):
self.SetValue(angle, None)
def SetLength(self, length):
self.SetValue(None, length)
def OnPaint(self, event):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)
def Draw(self, dc):
width, height = self.GetClientSize()
if not width or not height:
return
dc.SetBackground(wx.Brush(self.GetBackgroundColour(), wx.BRUSHSTYLE_SOLID))
dc.Clear()
dc.SetTextForeground(wx.Colour(0))
dc.SetFont(self._font)
radius = min(width, height) / 2 - 2
dc.SetBrush(wx.WHITE_BRUSH)
dc.DrawCircle(radius + 2, radius + 2, radius)
a = math.radians(self._angle + self._offset)
x = math.sin(a) * radius
y = math.cos(a) * radius
dc.DrawLine(radius + 2, radius + 2, radius + 2 + x * self._length, radius + 2 - y * self._length)
dc.SetBrush(wx.BLACK_BRUSH)
dc.DrawCircle(radius + 2 + x * self._length, radius + 2 - y * self._length, 2)
if self._label:
labelText = self._label
labelTextW, labelTextH = dc.GetTextExtent(labelText)
labelTextX = (radius * 2 + 4 - labelTextW) if (self._labelpos & 1) else 0
labelTextY = (radius * 2 + 4 - labelTextH) if (self._labelpos & 2) else 0
dc.DrawText(labelText, labelTextX, labelTextY)
lengthText = '%d%%' % (100 * self._length,)
lengthTextW, lengthTextH = dc.GetTextExtent(lengthText)
lengthTextX = radius + 2 + x / 2 - y / 3 - lengthTextW / 2
lengthTextY = radius + 2 - y / 2 - x / 3 - lengthTextH / 2
dc.DrawText(lengthText, lengthTextX, lengthTextY)
angleText = '%d\u00B0' % (self._angle,)
angleTextW, angleTextH = dc.GetTextExtent(angleText)
angleTextX = radius + 2 - x / 2 - angleTextW / 2
angleTextY = radius + 2 + y / 2 - angleTextH / 2
dc.DrawText(angleText, angleTextX, angleTextY)
def OnEraseBackground(self, event):
pass
def OnLeftDown(self, event):
self._left = True
self.SetToolTip(None)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnLeftUp)
if not self._right:
self.Bind(wx.EVT_MOTION, self.OnMotion)
if not self.HasCapture():
self.CaptureMouse()
self.HandleMouseEvent(event)
def OnRightDown(self, event):
self._right = True
self.SetToolTip(None)
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnRightUp)
if not self._left:
self.Bind(wx.EVT_MOTION, self.OnMotion)
if not self.HasCapture():
self.CaptureMouse()
self.HandleMouseEvent(event)
def OnLeftUp(self, event):
self.HandleMouseEvent(event)
self.Unbind(wx.EVT_LEFT_UP, handler=self.OnLeftUp)
self.Unbind(wx.EVT_MOUSE_CAPTURE_LOST, handler=self.OnLeftUp)
self._left = False
if not self._right:
self.Unbind(wx.EVT_MOTION, handler=self.OnMotion)
self.SendChangeEvent()
self.SetToolTip(wx.ToolTip(self._tooltip))
if self.HasCapture():
self.ReleaseMouse()
def OnRightUp(self, event):
self.HandleMouseEvent(event)
self.Unbind(wx.EVT_RIGHT_UP, handler=self.OnRightUp)
self.Unbind(wx.EVT_MOUSE_CAPTURE_LOST, handler=self.OnRightUp)
self._right = False
if not self._left:
self.Unbind(wx.EVT_MOTION, handler=self.OnMotion)
self.SendChangeEvent()
self.SetToolTip(wx.ToolTip(self._tooltip))
if self.HasCapture():
self.ReleaseMouse()
def OnMotion(self, event):
self.HandleMouseEvent(event)
event.Skip()
def OnWheel(self, event):
amount = 0.1 * event.GetWheelRotation() / event.GetWheelDelta()
self._length = min(max(self._length + amount, 0.0), 1.0)
self.Refresh()
self.SendChangeEvent()
def HandleMouseEvent(self, event):
width, height = self.GetClientSize()
if width and height:
center = min(width, height) / 2
x, y = event.GetPositionTuple()
x = x - center
y = center - y
angle = self._angle
length = min((x * x + y * y) ** 0.5 / (center - 2), 1.0)
if length < 0.01:
length = 0
else:
angle = ((math.degrees(math.atan2(x, y)) - self._offset + 180) % 360) - 180
if (self._right and not self._left) or event.ShiftDown():
angle = round(angle / 15.0) * 15.0
# floor() for length to make it easier to hit 0%, can still hit 100% outside the circle
length = math.floor(length / 0.05) * 0.05
if (angle != self._angle) or (length != self._length):
self._angle = angle
self._length = length
self.Refresh()
if self._right and not self._left:
self.SendChangeEvent()
def SendChangeEvent(self):
changeEvent = wx.CommandEvent(self.myEVT_VECTOR_CHANGED, self.GetId())
changeEvent._object = self
changeEvent._angle = self._angle
changeEvent._length = self._length
self.GetEventHandler().ProcessEvent(changeEvent)