NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

hexMap.py (31268B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\mapView\hexagonal\hexMap.py
      2 from __future__ import print_function
      3 import math
      4 import logging
      5 from carbon.common.script.util.timerstuff import AutoTimer
      6 from carbonui.primitives.base import ScaleDpi, ReverseScaleDpi
      7 from carbonui.primitives.fill import Fill
      8 from carbonui.primitives.sprite import Sprite
      9 from carbonui.primitives.vectorlinetrace import VectorLineTrace
     10 from carbonui.primitives.container import Container
     11 from eve.client.script.ui.control.eveLabel import EveLabelSmall
     12 from eve.client.script.ui.shared.mapView.hexagonal import hexUtil
     13 import carbonui.const as uiconst
     14 import geo2
     15 from eve.client.script.ui.shared.mapView.hexagonal.hexMapLine import HexMapLine
     16 from evePathfinder.core import EvePathfinderCore
     17 from evePathfinder.eveMapWrapper import EveMapWrapper
     18 from evePathfinder.pathfinder import ClientPathfinder
     19 from evePathfinder.stateinterface import StandardPathfinderInterface
     20 import trinity
     21 import pyEvePathfinder
     22 from eve.common.script.sys.idCheckers import IsConstellation, IsRegion
     23 from eve.client.script.ui.shared.mapView.hexagonal.hexMapUtil import GetHexMapSizeForObject, GetPlotDataForObject, PrepareCombinedMap
     24 from carbonui.uicore import uicore
     25 logger = logging.getLogger(__name__)
     26 
     27 class HexMap(Container):
     28     default_align = uiconst.TOPLEFT
     29     default_state = uiconst.UI_PICKCHILDREN
     30     isChild = False
     31     isCombinedMap = False
     32     isFlatTop = True
     33     editMode = False
     34     parentMap = None
     35     gridSprite = None
     36     _morphGlobalScaling = 0.0
     37     _morphGlobalScalingValues = None
     38     globalScaling = 1.0
     39     localScaling = 1.0
     40     mapsize = 3
     41     setMapSize = None
     42     objectID = None
     43     objectData = None
     44     objectByID = None
     45     connectionsByID = None
     46     hexGridConnectionsByID = {}
     47     markersByID = None
     48     colorsInverted = False
     49     slotsByPosition = None
     50     hexGridSize = 48.0
     51     sizeUnscaled = None
     52     outline = None
     53 
     54     def ApplyAttributes(self, attributes):
     55         self.parentMap = attributes.parentMap
     56         self.isChild = bool(self.parentMap)
     57         self.editMode = attributes.editMode
     58         self.hexGridSize = attributes.hexGridSize or self.hexGridSize
     59         self.setMapSize = attributes.setMapSize
     60         if self.parentMap:
     61             self.colorsInverted = not self.parentMap.colorsInverted
     62         Container.ApplyAttributes(self, attributes)
     63         if self.colorsInverted:
     64             self.mainColor = (0, 0, 0, 1)
     65             self.blockColor = (0.75, 0.75, 0.75, 1)
     66         else:
     67             self.mainColor = (0.75, 0.75, 0.75, 1)
     68             self.blockColor = (0, 0, 0, 1)
     69         Fill(parent=self, align=uiconst.CENTER, pos=(0, 0, 10, 2), color=(1, 0, 0, 1))
     70         Fill(parent=self, align=uiconst.CENTER, pos=(0, 0, 2, 10), color=(1, 0, 0, 1))
     71 
     72     def Close(self, *args):
     73         Container.Close(self, *args)
     74         self.parentMap = None
     75 
     76     @apply
     77     def morphGlobalScaling():
     78 
     79         def fget(self):
     80             return self._morphGlobalScaling
     81 
     82         def fset(self, value):
     83             if value != self._morphGlobalScaling:
     84                 self._morphGlobalScaling = value
     85                 self.globalScaling = value
     86                 w = self.sizeUnscaled[0] * value
     87                 h = self.sizeUnscaled[1] * value
     88                 if self._morphGlobalScalingValues:
     89                     preMouse, preAbs, parentAbsolute = self._morphGlobalScalingValues
     90                     pl, pt, pw, ph = preAbs
     91                     proportionalX = (preMouse[0] - pl) / float(pw)
     92                     proportionalY = (preMouse[1] - pt) / float(ph)
     93                     left = preMouse[0] - parentAbsolute[0] - proportionalX * w
     94                     top = preMouse[1] - parentAbsolute[1] - proportionalY * h
     95                 else:
     96                     left = self.left
     97                     top = self.top
     98                 self.pos = (left,
     99                  top,
    100                  w,
    101                  h)
    102                 self.TraverseHexMap()
    103 
    104         return property(**locals())
    105 
    106     def UpdateChildren(self):
    107         pass
    108 
    109     def TraverseHexMap(self, viewportRect = None, scaling = None):
    110         if not self.parent:
    111             return
    112         if scaling is None:
    113             scaling = self.globalScaling
    114         self.globalScaling = scaling
    115         if self.objectByID:
    116             if viewportRect is None:
    117                 viewportRect = (self.left,
    118                  self.top,
    119                  ReverseScaleDpi(self.parent.displayWidth),
    120                  ReverseScaleDpi(self.parent.displayHeight))
    121             else:
    122                 vX, vY, vW, vH = viewportRect
    123                 viewportRect = (vX + self.left,
    124                  vY + self.top,
    125                  vW,
    126                  vH)
    127             for objectID, hexCell in self.objectByID.iteritems():
    128                 hexCell.TraverseHexCell(viewportRect, self.globalScaling * self.localScaling)
    129 
    130             self.UpdateJumpLines()
    131 
    132     def UpdateAlignment(self, budgetLeft = 0, budgetTop = 0, budgetWidth = 0, budgetHeight = 0, updateChildrenOnly = False):
    133         ret = Container.UpdateAlignment(self, budgetLeft, budgetTop, budgetWidth, budgetHeight, updateChildrenOnly)
    134         return ret
    135 
    136     @apply
    137     def displayRect():
    138         fget = Container.displayRect.fget
    139 
    140         def fset(self, value):
    141             pW, pH = self._displayWidth, self._displayHeight
    142             displayX, displayY, displayWidth, displayHeight = value
    143             self._displayX = int(round(displayX))
    144             self._displayY = int(round(displayY))
    145             self._displayWidth = int(round(displayX + displayWidth)) - self._displayX
    146             self._displayHeight = int(round(displayY + displayHeight)) - self._displayY
    147             ro = self.renderObject
    148             if ro:
    149                 ro.displayX = self._displayX
    150                 ro.displayY = self._displayY
    151                 ro.displayWidth = self._displayWidth
    152                 ro.displayHeight = self._displayHeight
    153             if self._displayWidth != pW or self._displayHeight != pH:
    154                 if self._backgroundlist and len(self.background):
    155                     self.UpdateBackgrounds()
    156                 if self.outline:
    157                     self.DrawOutline()
    158                 if self.gridSprite:
    159                     baseCellSize = hexUtil.hex_slot_size(self.isFlatTop, self.hexGridSize)
    160                     tileTextureWidth = 288.0
    161                     tileTextureHeight = 333.0
    162                     textureScaling = tileTextureHeight / baseCellSize[1]
    163                     self.gridSprite.rectSecondary = ((self.sizeUnscaled[0] * 2 % (self.hexGridSize * 6) - self.hexGridSize) * textureScaling + self.hexGridSize * textureScaling * 0.75,
    164                      0.0,
    165                      tileTextureWidth / self.globalScaling / self.localScaling * textureScaling * 0.5,
    166                      tileTextureHeight / self.globalScaling / self.localScaling * textureScaling * 0.5)
    167 
    168         return property(**locals())
    169 
    170     def FlushMap(self):
    171         if self.objectByID:
    172             for each in self.objectByID.values():
    173                 each.Close()
    174 
    175         if self.connectionsByID:
    176             for each in self.connectionsByID.values():
    177                 each.Close()
    178 
    179         if self.hexGridConnectionsByID:
    180             for line1, line2 in self.hexGridConnectionsByID.values():
    181                 line1.Close()
    182                 line2.Close()
    183 
    184         if self.markersByID:
    185             for each in self.markersByID.values():
    186                 each.Close()
    187 
    188         self.objectByID = {}
    189         self.connectionsByID = {}
    190         self.hexGridConnectionsByID = {}
    191         self.markersByID = {}
    192         self.slotsByPosition = {}
    193 
    194     def GetVectorBetweenObjectsOnSameLevel(self, fromObjectID, toObjectID, parentObjectID, i = 0):
    195         plotData = GetPlotDataForObject(parentObjectID, ignoreFixed=False)
    196         if fromObjectID in plotData:
    197             column1, row1 = plotData[fromObjectID]
    198             fromPos = hexUtil.hex_slot_center_position(column1, row1, self.isFlatTop, self.hexGridSize)
    199         elif self.parentMap and fromObjectID in self.parentMap.markersByID:
    200             fromPos = self.parentMap.markersByID[fromObjectID].unscaledPosition
    201         else:
    202             return
    203         if toObjectID in plotData:
    204             column2, row2 = plotData[toObjectID]
    205             toPos = hexUtil.hex_slot_center_position(column2, row2, self.isFlatTop, self.hexGridSize)
    206         elif self.parentMap and toObjectID in self.parentMap.markersByID:
    207             toPos = self.parentMap.markersByID[toObjectID].unscaledPosition
    208         else:
    209             return
    210         diffVec = geo2.Vec2Subtract(toPos, fromPos)
    211         diffVec = geo2.Vec2Scale(diffVec, 100000000000.0)
    212         cornerPoints = []
    213         for i in xrange(6):
    214             if self.isFlatTop:
    215                 outlineRad = self.width * 0.5
    216                 angle = 2.0 * math.pi / 6.0 * i
    217             else:
    218                 outlineRad = self.height * 0.5
    219                 angle = 2.0 * math.pi / 6.0 * (i + 0.5)
    220             x_i = outlineRad * math.cos(angle)
    221             y_i = outlineRad * math.sin(angle)
    222             cornerPoints.append((x_i, y_i))
    223 
    224         for i in xrange(6):
    225             p1 = cornerPoints[i]
    226             p2 = cornerPoints[i - 1]
    227             crossPoint = hexUtil.intersect_line_segments((p1, p2), ((0.0, 0.0), diffVec))
    228             if crossPoint:
    229                 return crossPoint
    230 
    231     def LoadExitPoints(self, exitData, parentID):
    232         for exitID in exitData:
    233             if self.objectID not in exitID:
    234                 continue
    235             a, b = exitID
    236             if a == self.objectID:
    237                 toID = b
    238             else:
    239                 toID = a
    240             crossPoint = self.GetVectorBetweenObjectsOnSameLevel(self.objectID, toID, parentID)
    241             if IsRegion(toID):
    242                 color = (1, 0, 0, 1)
    243             elif IsConstellation(toID):
    244                 color = (0, 1, 0, 1)
    245             else:
    246                 color = (0, 0, 1, 1)
    247             if crossPoint:
    248                 marker = self.AddMarker(toID, crossPoint[0], crossPoint[1], color=color, size=8)
    249                 marker.state = uiconst.UI_NORMAL
    250                 marker.hint = '%s' % toID
    251 
    252     def LoadMapData(self, objectID, loadLayout = True, ignoreFixedLayout = None, loadCombined = False):
    253         if objectID not in uicore.mapObjectDataByID:
    254             return
    255         loadCombined = loadCombined or settings.user.ui.Get('mapLoadCombined', 0)
    256         if loadCombined and IsRegion(objectID):
    257             self.isCombinedMap = True
    258             layoutData, connectionData, exitConnectionData, size = PrepareCombinedMap(objectID)
    259             objectData = layoutData.keys()
    260             plotData = layoutData
    261         else:
    262             self.isCombinedMap = False
    263             objectData = uicore.mapObjectDataByID[objectID]
    264             connectionData = uicore.mapConnectionDataByID.get(objectID, [])
    265             plotData = GetPlotDataForObject(objectID, ignoreFixedLayout)
    266             if plotData:
    267                 size = GetHexMapSizeForObject(objectID)
    268             else:
    269                 size = 10
    270             exitConnectionData = []
    271         self.objectID = objectID
    272         self.exitConnectionData = exitConnectionData
    273         self.FlushMap()
    274         from eve.client.script.ui.shared.mapView.hexagonal.hexCell import HexCell
    275         for childObjectID in objectData:
    276             hexCell = HexCell(parent=self, hexGrid=self, hexSize=self.hexGridSize * 0.5, hexGridSize=self.hexGridSize, opacity=1.0, state=uiconst.UI_NORMAL, isFlatTop=self.isFlatTop, editMode=self.editMode, idx=0)
    277             hexCell.OnMouseWheelCallback = self.OnMouseWheel
    278             hexCell.OnDragCallback = self.OnHexCellDrag
    279             hexCell.OnDragEndCallback = self.OnHexCellEndDrag
    280             hexCell.renderObject.pickRadius = -1
    281             hexCell.objectID = childObjectID
    282             self.objectByID[childObjectID] = hexCell
    283 
    284         if loadLayout:
    285             if plotData:
    286                 try:
    287                     for _objectID in objectData:
    288                         hexCell = self.objectByID[_objectID]
    289                         col, row = plotData[_objectID]
    290                         hexCell.MoveToCR(col, row)
    291 
    292                 except KeyError as e:
    293                     if ignoreFixedLayout is None:
    294                         return self.LoadMapData(objectID, ignoreFixedLayout=True)
    295                     return
    296 
    297             else:
    298                 return
    299             self.SetMapSize(size)
    300         loadExitpoints = settings.user.ui.Get('mapDebugShowExitPoints', 0)
    301         if loadExitpoints:
    302             self.DrawOutline()
    303             parentID = uicore.mapObjectParentByID.get(self.objectID, None)
    304             if parentID and parentID in uicore.mapConnectionDataByID:
    305                 parentConnections = uicore.mapConnectionDataByID[parentID]
    306                 self.LoadExitPoints(parentConnections, parentID)
    307         loadHexLines = settings.user.ui.Get('mapDebugLoadHexLines', 0)
    308         self.LoadConnections(connectionData, createHexLines=loadHexLines)
    309         self.LoadConnections(self.exitConnectionData, createHexLines=loadHexLines)
    310         if loadHexLines:
    311             self.UpdateJumpLines(refreshLayout=True)
    312         if not self.isChild:
    313             self.TraverseHexMap()
    314 
    315     def LoadConnections(self, connectionData, createHexLines = False):
    316         for fromID, toID in connectionData:
    317             if (fromID, toID) in self.connectionsByID or (toID, fromID) in self.connectionsByID:
    318                 continue
    319             self.connectionsByID[fromID, toID] = VectorLineTrace(parent=self)
    320             if createHexLines and fromID in self.objectByID and toID in self.objectByID:
    321                 self.hexGridConnectionsByID[fromID, toID] = (HexMapLine(parent=self), HexMapLine(parent=self))
    322 
    323     def GetCurrentLayout(self):
    324         layoutByObjectID = {}
    325         for objectID, uiObject in self.objectByID.iteritems():
    326             layoutByObjectID[objectID] = uiObject.GetGridPosition()
    327 
    328         return layoutByObjectID
    329 
    330     def GetOccupiedSlots(self):
    331         occupied = []
    332         for objectID, uiObject in self.objectByID.iteritems():
    333             if uiObject.GetGridPosition():
    334                 occupied.append(uiObject.GetGridPosition())
    335 
    336         return occupied
    337 
    338     def GetAxialCoordinateFromMousePosition(self):
    339         absLeft, absTop, absWidth, absHeight = self.GetAbsolute()
    340         pickX, pickY = uicore.uilib.x - absLeft - absWidth / 2, uicore.uilib.y - absTop - absHeight / 2
    341         return self.GetAxialCoordinateFromUIPosition(pickX, pickY)
    342 
    343     def GetAxialCoordinateFromUIPosition(self, x, y):
    344         px_hx = hexUtil.pixel_to_hex(x, y, self.hexGridSize, isFlatTop=self.isFlatTop)
    345         ax_cu = hexUtil.axial_to_cube_coordinate(*px_hx)
    346         ax_cu_rounded = hexUtil.hex_round(*ax_cu)
    347         if self.isFlatTop:
    348             cu_ax = hexUtil.cube_to_odd_q_axial_coordinate(*ax_cu_rounded)
    349         else:
    350             cu_ax = hexUtil.cube_to_odd_r_axial_coordinate(*ax_cu_rounded)
    351         return cu_ax
    352 
    353     def OnHexCellDrag(self, *args):
    354         self.TraverseHexMap()
    355 
    356     def OnHexCellEndDrag(self, hexCell, *args):
    357         if self.globalScaling != 1.0:
    358             return
    359         CR = self.GetAxialCoordinateFromMousePosition()
    360         hexCell.MoveToCR(*CR)
    361         self.UpdateJumpLines(refreshLayout=True)
    362         self.TraverseHexMap()
    363         if not self.isCombinedMap:
    364             positions = {}
    365             for objectID, hexCell in self.objectByID.iteritems():
    366                 positions[objectID] = hexCell.GetGridPosition()
    367 
    368             handmade = settings.user.ui.Get('mapHexLayout', {})
    369             handmade[self.objectID] = positions
    370             settings.user.ui.Set('mapHexLayout', handmade)
    371 
    372     def OnMouseWheel(self, dz, *args):
    373         if self.isChild:
    374             return
    375         preAbsolute = self.GetAbsolute()
    376         parentAbsolute = self.parent.GetAbsolute()
    377         preMouse = (uicore.uilib.x, uicore.uilib.y)
    378         if dz < 0:
    379             globalScaling = min(8192.0, self.globalScaling * 4)
    380         else:
    381             globalScaling = max(0.125, self.globalScaling / 4)
    382         self._morphGlobalScalingValues = (preMouse, preAbsolute, parentAbsolute)
    383         uicore.animations.MorphScalar(self, 'morphGlobalScaling', startVal=self.globalScaling, endVal=globalScaling, duration=0.5)
    384 
    385     def OnMouseDown(self, mouseButton, *args):
    386         if self.isChild:
    387             return
    388         if self.editMode:
    389             ctrl = uicore.uilib.Key(uiconst.VK_CONTROL)
    390             if ctrl:
    391                 positions = {}
    392                 for objectID, hexCell in self.objectByID.iteritems():
    393                     positions[objectID] = hexCell.GetGridPosition()
    394 
    395                 print(self.objectID, ':', positions)
    396                 print('----')
    397                 print(sorted(positions.values()))
    398         self.initDragData = (self.left,
    399          self.top,
    400          uicore.uilib.x,
    401          uicore.uilib.y)
    402         self.dragThread = AutoTimer(1, self.DragMap)
    403 
    404     def OnMouseUp(self, mouseButton, *args):
    405         if self.isChild:
    406             return
    407 
    408     def DragMap(self):
    409         if not uicore.uilib.leftbtn:
    410             self.dragThread = None
    411         initLeft, initTop, initMouseX, initMouseY = self.initDragData
    412         dX = initMouseX - uicore.uilib.x
    413         dY = initMouseY - uicore.uilib.y
    414         parentWidth = ScaleDpi(self.parent.displayWidth)
    415         parentHeight = ScaleDpi(self.parent.displayHeight)
    416         w, h = self.width, self.height
    417         self.left = min(parentWidth / 2, max(parentWidth / 2 - w, initLeft - dX))
    418         self.top = min(parentHeight / 2, max(parentHeight / 2 - h, initTop - dY))
    419         self.TraverseHexMap()
    420 
    421     def UpdateJumpLines(self, refreshLayout = False):
    422         if self.markersByID:
    423             for markerID, marker in self.markersByID.iteritems():
    424                 marker.left = marker.unscaledPosition[0] * self.globalScaling * self.localScaling
    425                 marker.top = marker.unscaledPosition[1] * self.globalScaling * self.localScaling
    426 
    427         if self.connectionsByID:
    428             for (fromID, toID), line in self.connectionsByID.iteritems():
    429                 if fromID < 1000:
    430                     continue
    431                 line.Flush()
    432                 isExit = False
    433                 lineColor = self.mainColor
    434                 fromObj = self.objectByID.get(fromID, None)
    435                 if fromObj is None and fromID in self.markersByID:
    436                     fromObj = self.markersByID.get(fromID, None)
    437                     isExit = True
    438                     lineColor = (1, 0, 0, 1)
    439                 toObj = self.objectByID.get(toID, None)
    440                 if toObj is None and toID in self.markersByID:
    441                     toObj = self.markersByID.get(toID, None)
    442                     isExit = True
    443                     lineColor = (1, 0, 0, 1)
    444                 if fromObj and toObj:
    445                     p1, p2 = self.ApplyLineMargin((fromObj.left + self.width / 2.0, fromObj.top + self.height / 2.0), (toObj.left + self.width / 2.0, toObj.top + self.height / 2.0), fromObj.hexSize * self.globalScaling * self.localScaling, toObj.hexSize * self.globalScaling * self.localScaling)
    446                     if p1 and p2:
    447                         line.AddPoint(p1, getattr(line, 'lineColor', lineColor))
    448                         line.AddPoint(p2, getattr(line, 'lineColor', lineColor))
    449 
    450         if self.hexGridConnectionsByID:
    451             if refreshLayout:
    452                 self.RefreshHexGridConnectionsLayout()
    453             for (fromID, toID), lines in self.hexGridConnectionsByID.iteritems():
    454                 line, line2 = lines
    455                 line.Flush()
    456                 line2.Flush()
    457                 if line.positionsUnscaled:
    458                     line.display = True
    459                     line.display = True
    460                     line.lineWidth = line.lineWidthUnscaled * self.globalScaling * self.localScaling
    461                     line2.lineWidth = line.lineWidth * 1.6
    462                     line.AddPoints(line.positionsUnscaled, scaling=self.globalScaling * self.localScaling)
    463                     line2.AddPoints(line.positionsUnscaled, scaling=self.globalScaling * self.localScaling)
    464                 else:
    465                     line.display = False
    466                     line.display = False
    467 
    468     def ApplyLineMargin(self, p1, p2, radius1, radius2):
    469         v = geo2.Vec2Subtract(p1, p2)
    470         vn = geo2.Vec2Normalize(v)
    471         l = geo2.Vec2Length(v)
    472         if not l:
    473             return (None, None)
    474         s = (radius1 + radius2) / l
    475         mp1 = geo2.Vec2Subtract(p1, geo2.Vec2Scale(vn, radius1))
    476         mp2 = geo2.Vec2Add(p2, geo2.Vec2Scale(vn, radius2))
    477         return (mp1, mp2)
    478 
    479     def SetMapSize(self, size):
    480         size = self.setMapSize or size
    481         size += size & 1
    482         self.mapsize = size
    483         baseSize = hexUtil.hex_slot_size(self.isFlatTop, self.hexGridSize * size)
    484         if baseSize != (self.width, self.height):
    485             self.sizeUnscaled = baseSize
    486             self.morphGlobalScaling = 0.0
    487             self.morphGlobalScaling = 1.0
    488 
    489     def DrawOutline(self):
    490         if self.outline:
    491             outline = self.outline
    492         else:
    493             outline = VectorLineTrace(parent=self, lineWidth=2)
    494             outline.isLoop = True
    495             self.outline = outline
    496         outline.Flush()
    497         for i in xrange(6):
    498             if self.isFlatTop:
    499                 outlineRad = self.displayWidth * 0.5
    500                 angle = 2.0 * math.pi / 6.0 * i
    501             else:
    502                 outlineRad = self.displayHeight * 0.5
    503                 angle = 2.0 * math.pi / 6.0 * (i + 0.5)
    504             x_i = ReverseScaleDpi(self.displayWidth * 0.5 + outlineRad * math.cos(angle))
    505             y_i = ReverseScaleDpi(self.displayHeight * 0.5 + outlineRad * math.sin(angle))
    506             outline.AddPoint((x_i, y_i), (1, 0, 0, 0.8))
    507 
    508     def AddMarker(self, markerID, x, y, color = (1, 1, 1, 0.5), size = 10):
    509         marker = Container(parent=self, align=uiconst.CENTER, pos=(x,
    510          y,
    511          size,
    512          size), idx=0)
    513         marker.markerID = markerID
    514         self.markersByID[markerID] = marker
    515         marker.unscaledPosition = (x, y)
    516         marker.hexSize = 1
    517         Fill(bgParent=marker, color=color)
    518         return marker
    519 
    520     def PreparePathFinder(self):
    521         xStep, yStep = hexUtil.hex_slot_size(self.isFlatTop, self.hexGridSize / 2.0)
    522         xRange = int(self.width / xStep)
    523         yRange = int(self.height / yStep)
    524         xRange = xRange - xRange % 3 + 3
    525         yRange = yRange - yRange % 3 + 3
    526         pathMap = EveMapWrapper()
    527         pathMap.add_region(-1)
    528         pathMap.add_constellation(-2, -1)
    529         self.pathMap = pathMap
    530         pathfinderCore = pathMap.create_core()
    531         pathfinderState = HexMapPathfinderInterface()
    532         self.avoidPathFinderState = HexMapPathfinderInterface()
    533 
    534         def ConvertPathFinderIDMock(ret):
    535             return ret
    536 
    537         self.pathfinderHandler = ClientPathfinder(pathfinderCore, pathfinderState, self.avoidPathFinderState, ConvertPathFinderIDMock, ConvertPathFinderIDMock)
    538         self.avoidPathFinderState.blockedSpots = []
    539         self.avoidPathFinderState.usedSpots = []
    540         if getattr(self, 'pathFindingPairs', None):
    541             for i in xrange(yRange * xRange):
    542                 pathMap.add_solar_system(i, -2, -1)
    543 
    544             self.AddToPathFinding(self.pathFindingPairs)
    545             return
    546         self.column_row_to_pathfinder = column_row_to_pathfinder = {}
    547         self.pathfinder_to_xy = pathfinder_to_xy = []
    548         self.pathfinderIndexGrid = indexGrid = []
    549         self.pathFindingPairs = pathFindingPairs = set()
    550         self.pathFindingPairSequence = pathFindingPairSequence = {}
    551         showDebug = not self.isChild and settings.user.ui.Get('mapDebugSubdivision', 0)
    552         self.pathfinderSize = (xRange, yRange)
    553         i = 0
    554         for y in xrange(yRange):
    555             row = []
    556             indexGrid.append(row)
    557             yOdd = y & 1
    558             for x in xrange(xRange):
    559                 row.append(i)
    560                 posX = x * xStep
    561                 posY = y * yStep
    562                 if y % 2:
    563                     posX += xStep / 2
    564                 isPrimary = not (x - yOdd + self.mapsize / 2 % 3) % 3
    565                 if isPrimary:
    566                     px_hx = hexUtil.pixel_to_hex(posX - self.width / 2, posY - self.height / 2, self.hexGridSize, isFlatTop=self.isFlatTop)
    567                     ax_cu = hexUtil.axial_to_cube_coordinate(*px_hx)
    568                     ax_cu_rounded = hexUtil.hex_round(*ax_cu)
    569                     cu_ax = hexUtil.cube_to_odd_q_axial_coordinate(*ax_cu_rounded)
    570                     column_row_to_pathfinder[cu_ax] = i
    571                 for cMod, rMod in ((-1, 0), (-1 + yOdd, -1), (yOdd, -1)):
    572                     cIndex = x + cMod
    573                     rIndex = y + rMod
    574                     if rIndex >= 0 and cIndex >= 0:
    575                         try:
    576                             pathFindingPairs.add((i, indexGrid[rIndex][cIndex]))
    577                         except IndexError:
    578                             pass
    579 
    580                 if showDebug:
    581                     if isPrimary:
    582                         textColor = (1, 0, 0, 1)
    583                     else:
    584                         textColor = (0, 1, 0, 1)
    585                     EveLabelSmall(parent=self, text=str(i), left=posX - self.width / 2, top=posY - self.height / 2, align=uiconst.CENTER, color=textColor)
    586                 pathfinder_to_xy.append((posX, posY))
    587                 pathMap.add_solar_system(i, -2, -1)
    588                 i += 1
    589 
    590         self.AddToPathFinding(self.pathFindingPairs, showDebug)
    591 
    592     def RefreshHexGridConnectionsLayout(self):
    593         self.PreparePathFinder()
    594         busyPrimary = [ each.GetGridPosition() for objectID, each in self.objectByID.iteritems() ]
    595         self.avoidPathFinderState.usedSpots = []
    596         if self.hexGridConnectionsByID:
    597             connectionIDs = self.hexGridConnectionsByID.keys()
    598             unresolved = self.UpdateHexGridConnections(connectionIDs, busyPrimary)
    599             if unresolved:
    600                 self.LoadExtraPrimaryConnections()
    601                 unresolved = self.UpdateHexGridConnections(unresolved[:], busyPrimary)
    602                 if unresolved:
    603                     print('STILL UNRESOLVED !!!!', len(unresolved))
    604 
    605     def LoadExtraPrimaryConnections(self):
    606         print('LoadExtraPrimaryConnections')
    607         xRange, yRange = self.pathfinderSize
    608         indexGrid = self.pathfinderIndexGrid
    609         pathFindingPairs = set()
    610         showDebug = False
    611         i = 0
    612         for y in xrange(yRange):
    613             yOdd = y & 1
    614             for x in xrange(xRange):
    615                 isPrimary = not (x - yOdd + self.mapsize / 2 % 3) % 3
    616                 if isPrimary:
    617                     for cMod, rMod in ((-2 + yOdd, -1), (0, -2), (1 + yOdd, -1)):
    618                         cIndex = x + cMod
    619                         rIndex = y + rMod
    620                         if rIndex >= 0 and cIndex >= 0:
    621                             try:
    622                                 fromIndex, toIndex = i, indexGrid[rIndex][cIndex]
    623                                 pathFindingPairs.add((fromIndex, toIndex))
    624                                 fromIndex, toIndex = sorted((fromIndex, toIndex))
    625                                 if rMod == 0:
    626                                     self.pathFindingPairSequence[fromIndex, toIndex] = range(fromIndex, toIndex + 1)
    627                             except IndexError:
    628                                 pass
    629 
    630                 i += 1
    631 
    632         self.AddToPathFinding(pathFindingPairs, showDebug, groupID=-1)
    633 
    634     def AddToPathFinding(self, pathFindingPairs, showDebug = False, groupID = 0, debugColor = None):
    635         pathfinder_to_xy = self.pathfinder_to_xy
    636         for _p1, _p2 in pathFindingPairs:
    637             self.pathMap.add_jump(_p1, _p2, groupID)
    638             self.pathMap.add_jump(_p2, _p1, groupID)
    639             if (showDebug or debugColor) and not self.isChild:
    640                 self._DebugDrawLine(pathfinder_to_xy[_p1], pathfinder_to_xy[_p2], debugColor or (1, 0, 0, 0.5))
    641 
    642         self.pathMap.finalize()
    643 
    644     def UpdateHexGridConnections(self, connectionIDs, busyPrimary, lineColor = None):
    645         column_row_to_pathfinder = self.column_row_to_pathfinder
    646         pathfinder_to_xy = self.pathfinder_to_xy
    647         unresolvedConnections = []
    648         for fromID, toID in connectionIDs:
    649             fromObj = self.objectByID.get(fromID, None) or self.markersByID.get(fromID, None)
    650             toObj = self.objectByID.get(toID, None) or self.markersByID.get(toID, None)
    651             if not hasattr(fromObj, 'GetGridPosition'):
    652                 continue
    653             if not hasattr(toObj, 'GetGridPosition'):
    654                 continue
    655             cr1 = fromObj.GetGridPosition()
    656             cr2 = toObj.GetGridPosition()
    657             self.avoidPathFinderState.blockedSpots = [ column_row_to_pathfinder[cr] for cr in busyPrimary if cr not in (cr1, cr2) ]
    658             line, line2 = self.hexGridConnectionsByID[fromID, toID]
    659             path = self.pathfinderHandler.GetAutopilotPathBetween(column_row_to_pathfinder[cr1], column_row_to_pathfinder[cr2])
    660             if not path:
    661                 unresolvedConnections.append((fromID, toID))
    662                 line.positionsUnscaled = None
    663                 line2.positionsUnscaled = None
    664                 if (fromID, toID) in self.connectionsByID:
    665                     self.connectionsByID[fromID, toID].lineColor = (1, 0, 0, 1)
    666                 continue
    667             if (fromID, toID) in self.connectionsByID:
    668                 self.connectionsByID[fromID, toID].lineColor = (0, 0, 0, 0)
    669             line.lineColor = lineColor or self.mainColor
    670             line.lineWidthUnscaled = 4.0
    671             line2.lineColor = self.blockColor
    672             line.positionsUnscaled = []
    673             for i, pointIndex in enumerate(path):
    674                 self.avoidPathFinderState.usedSpots.append(pointIndex)
    675                 try:
    676                     nextPointIndex = path[i + 1]
    677                     jumpKey1 = (pointIndex, nextPointIndex)
    678                     jumpKey2 = (nextPointIndex, pointIndex)
    679                     occupy = self.pathFindingPairSequence.get(jumpKey1, None) or self.pathFindingPairSequence.get(jumpKey2, None)
    680                     if occupy:
    681                         for each in occupy:
    682                             if each not in self.avoidPathFinderState.usedSpots:
    683                                 self.avoidPathFinderState.usedSpots.append(each)
    684 
    685                 except IndexError:
    686                     pass
    687 
    688                 pos = pathfinder_to_xy[pointIndex]
    689                 line.positionsUnscaled.append(pos)
    690 
    691         return unresolvedConnections
    692 
    693     def _DebugDrawLine(self, p1, p2, color = (1, 0, 0, 0.8), margin = 10):
    694         if margin:
    695             p1, p2 = self.ApplyLineMargin(p1, p2, margin, margin)
    696         line = VectorLineTrace(parent=self, lineWidth=1, idx=0)
    697         x1, y1 = p1
    698         x2, y2 = p2
    699         line.AddPoint((x1, y1), color)
    700         line.AddPoint((x2, y2), color)
    701         return line
    702 
    703 
    704 class HexMapPathfinderInterface(StandardPathfinderInterface):
    705 
    706     def __init__(self):
    707         StandardPathfinderInterface.__init__(self)
    708         self.blockedSpots = []
    709         self.usedSpots = []
    710 
    711     def GetAvoidanceList(self):
    712         return self.blockedSpots + self.usedSpots
    713 
    714     def GetSecurityPenalty(self):
    715         return 0.0