279 lines
11 KiB
Python
279 lines
11 KiB
Python
from trackdirect.parser.policies.PacketOrderPolicy import PacketOrderPolicy
|
|
from trackdirect.parser.policies.PacketMaxSpeedPolicy import PacketMaxSpeedPolicy
|
|
|
|
|
|
class PacketMapIdPolicy():
|
|
"""PacketMapIdPolicy tries to find the best mapId for the current packet
|
|
"""
|
|
|
|
def __init__(self, packet, prevPacket):
|
|
"""The __init__ method.
|
|
|
|
Args:
|
|
packet (Packet): Packet that we want analyze
|
|
"""
|
|
self.packet = packet
|
|
self.prevPacket = prevPacket
|
|
self.hasKillCharacter = False
|
|
# Marker will be confirmed when we receive the third packet
|
|
self.markerCounterConfirmLimit = 3
|
|
|
|
# Results
|
|
self.mapId = None
|
|
self.markerId = None
|
|
self.isReplacingPrevPacket = False
|
|
self.isConfirmingPrevPacket = False
|
|
self.isKillingPrevPacket = False
|
|
|
|
def enableHavingKillCharacter(self):
|
|
"""Treat this packet as having a kill character
|
|
"""
|
|
self.hasKillCharacter = True
|
|
|
|
def getMapId(self):
|
|
"""Returns the map id that corresponds to the found marker id
|
|
|
|
Returns:
|
|
int
|
|
"""
|
|
self._findMapId()
|
|
return self.mapId
|
|
|
|
def getMarkerId(self):
|
|
"""Returns the found marker id
|
|
|
|
Returns:
|
|
int
|
|
"""
|
|
self._findMapId()
|
|
return self.markerId
|
|
|
|
def isReplacingPreviousPacket(self):
|
|
"""Returns true if packet replaces previous packet
|
|
|
|
Returns:
|
|
boolean
|
|
"""
|
|
self._findMapId()
|
|
return self.isReplacingPrevPacket
|
|
|
|
def isConfirmingPreviousPacket(self):
|
|
"""Returns true if packet confirmes previous packet
|
|
|
|
Returns:
|
|
boolean
|
|
"""
|
|
self._findMapId()
|
|
return self.isConfirmingPrevPacket
|
|
|
|
def isKillingPreviousPacket(self):
|
|
"""Returns true if packet kills previous packet
|
|
|
|
Returns:
|
|
boolean
|
|
"""
|
|
self._findMapId()
|
|
return self.isKillingPrevPacket
|
|
|
|
def _findMapId(self):
|
|
"""Find a suitable marker id for the current packet and set correponding attribute (and related attributes)
|
|
"""
|
|
if (self.mapId is None):
|
|
packetOrderPolicy = PacketOrderPolicy()
|
|
if (self.packet.sourceId == 2 and len(self.packet.stationIdPath) > 0):
|
|
# A CWOP-station is allways sending directly
|
|
self.mapId = 16
|
|
self.markerId = 1
|
|
elif (not self._isPacketOnMap()):
|
|
self.mapId = 10
|
|
self.markerId = 1
|
|
elif (packetOrderPolicy.isPacketInWrongOrder(self.packet, self.prevPacket)):
|
|
self.mapId = 6
|
|
self.markerId = 1
|
|
elif (self._isFaultyGpsPosition()):
|
|
self._findMapIdForFaultyGpsPosition()
|
|
elif (self.packet.isMoving == 1):
|
|
self._findMapIdForMovingStation()
|
|
else:
|
|
self._findMapIdForStationaryStation()
|
|
|
|
def _isPacketOnMap(self):
|
|
"""Returns true if current packet will be on map
|
|
|
|
Returns:
|
|
boolean
|
|
"""
|
|
if (self.packet.latitude is not None
|
|
and self.packet.longitude is not None
|
|
and type(self.packet.latitude) == float
|
|
and type(self.packet.longitude) == float
|
|
and self.packet.sourceId != 3
|
|
and self.packet.mapId in [1, 5, 7, 9]):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def _findMapIdForStationaryStation(self):
|
|
"""Find a suitable marker id for the current packet (assumes it is a stationary station) and set correponding attribute (and related attributes)
|
|
"""
|
|
if (self.prevPacket.isExistingObject()
|
|
and self.packet.isPostitionEqual(self.prevPacket)
|
|
and self.packet.isSymbolEqual(self.prevPacket)
|
|
and self.packet.isMoving == self.prevPacket.isMoving
|
|
and self.prevPacket.mapId in [1, 7]):
|
|
# Same position and same symbol
|
|
self.mapId = 1
|
|
self.markerId = self.prevPacket.markerId
|
|
if (self.hasKillCharacter):
|
|
# This station we can actually kill (it's stationary), let the markerId be
|
|
self.mapId = 14
|
|
|
|
# Also mark this to replace previous packet
|
|
self.isReplacingPrevPacket = True
|
|
elif (self.hasKillCharacter):
|
|
# We found nothing to kill
|
|
self.markerId = 1
|
|
self.mapId = 4
|
|
else:
|
|
# Seems to be a new stationary station (or at least a new symbol for an existing station)
|
|
self.mapId = 1
|
|
self.markerId = None
|
|
|
|
def _findMapIdForMovingStation(self):
|
|
"""Find a suitable marker id for the current packet (assumes it is a moving station) and set correponding attribute (and related attributes)
|
|
"""
|
|
if (self.hasKillCharacter):
|
|
# Makes no sense in handling kill characters for moving
|
|
self.mapId = 4
|
|
self.markerId = 1
|
|
|
|
elif (self.prevPacket.isExistingObject()
|
|
and self.prevPacket.isMoving == 1
|
|
and self.prevPacket.mapId in [1, 7]):
|
|
calculatedDistance = self.packet.getDistance(
|
|
self.prevPacket.latitude, self.prevPacket.longitude)
|
|
calculatedSpeed = self.packet.getCalculatedSpeed(self.prevPacket)
|
|
packetMaxSpeedPolicy = PacketMaxSpeedPolicy()
|
|
maxSpeed = packetMaxSpeedPolicy.getMaxLikelySpeed(
|
|
self.packet, self.prevPacket)
|
|
# distance is likely if distance is shorter than 50km (map performance is bad with to long polylines)
|
|
absoluteMaxDistance = 50000
|
|
# speed may be likely but if it is faster than absoluteMaxSpeed we create a new marker any way
|
|
absoluteMaxSpeed = 2000
|
|
|
|
if (self.packet.isPostitionEqual(self.prevPacket)):
|
|
# Same position
|
|
self._findMapIdForMovingStationWithSamePosition()
|
|
|
|
elif (calculatedDistance < 5000 and calculatedSpeed <= absoluteMaxSpeed):
|
|
# Distance is very short (shorter than 5km)
|
|
self._findMapIdForMovingStationWithLikelySpeed()
|
|
|
|
elif (calculatedSpeed <= maxSpeed and calculatedSpeed <= absoluteMaxSpeed and calculatedDistance <= absoluteMaxDistance):
|
|
# Speed and distance is likely
|
|
self._findMapIdForMovingStationWithLikelySpeed()
|
|
|
|
elif (calculatedSpeed <= maxSpeed and calculatedDistance > absoluteMaxDistance):
|
|
# Speed is likly but distance is to long or speed is very fast
|
|
self._findMapIdForMovingStationWithToLongDistance()
|
|
|
|
else:
|
|
# No suitable marker id
|
|
self.mapId = 7
|
|
self.markerId = None
|
|
else:
|
|
if (self.prevPacket.isExistingObject()
|
|
and self.prevPacket.isMoving == 0
|
|
and self.packet.isSymbolEqual(self.prevPacket)):
|
|
# We previously made a mistake, previous packet should have been marked as moving, just mark previous as abnormal (ghost marker)
|
|
self.isKillingPrevPacket = True
|
|
|
|
# Seems to be a new station
|
|
self.mapId = 1
|
|
self.markerId = None
|
|
|
|
def _findMapIdForMovingStationWithToLongDistance(self):
|
|
"""Sets a suitable marker id for the current packet based on prevPacket and assumes that distance is to long between them
|
|
"""
|
|
if (self.prevPacket.markerCounter == 1):
|
|
# Previous packet is not related to any previous and it is not related to this, mark it as abnormal
|
|
self.isKillingPrevPacket = True
|
|
|
|
# This is kind of a special case, we have no requirements on the previous packet
|
|
# Station is either sending few packets or is moving very fast, we accept everything as long as speed is likely
|
|
# Create new marker
|
|
self.mapId = 1
|
|
self.markerId = None
|
|
|
|
def _findMapIdForMovingStationWithLikelySpeed(self):
|
|
"""Sets a suitable marker id for the current packet based on prevPacket and assumes that speed is likly
|
|
"""
|
|
self.markerId = self.prevPacket.markerId
|
|
if (self.prevPacket.mapId == 1
|
|
or (self.prevPacket.markerCounter + 1) >= self.markerCounterConfirmLimit):
|
|
self.mapId = 1
|
|
else:
|
|
self.mapId = self.prevPacket.mapId
|
|
|
|
if (self.mapId == 1
|
|
and self.prevPacket.mapId == 7):
|
|
# To mark a previous packet as confirmed is not important since client should handle it anyway when a connected packet that is confirmed is recived
|
|
# But we do it when possible to make things easier for the client (currently we are not doiong it if several previous packets is unconfirmed)
|
|
self.isConfirmingPrevPacket = True
|
|
|
|
def _findMapIdForMovingStationWithSamePosition(self):
|
|
"""Sets a suitable marker id for the current packet based on prevPacket and assumes that position is equal
|
|
"""
|
|
# Also mark this to replace previous packet
|
|
# If this packet is converted to a 12 it will be treated as confirmed in history
|
|
# (we kind of assumes that markerCounterConfirmLimit == 2, maybe a TODO?)
|
|
self.markerId = self.prevPacket.markerId
|
|
self.isReplacingPrevPacket = True
|
|
if (self.prevPacket.mapId == 1
|
|
or (self.prevPacket.markerCounter + 1) >= self.markerCounterConfirmLimit):
|
|
self.mapId = 1
|
|
else:
|
|
self.mapId = self.prevPacket.mapId
|
|
|
|
def _findMapIdForFaultyGpsPosition(self):
|
|
"""Sets a suitable marker id for the current packet based on prevPacket and assumes that gps position is faulty (mapId 5)
|
|
"""
|
|
if (self.hasKillCharacter):
|
|
# No point in killing a ghost-marker
|
|
self.mapId = 4
|
|
self.markerId = 1
|
|
elif (self.prevPacket.mapId == self.mapId
|
|
and self.packet.isPostitionEqual(self.prevPacket)
|
|
and self.packet.isSymbolEqual(self.prevPacket)):
|
|
# Same mapId and position and same symbol
|
|
# Also mark this to replace previous packet
|
|
self.isReplacingPrevPacket = True
|
|
self.mapId = 5 # it is still 5
|
|
self.markerId = self.prevPacket.markerId
|
|
else:
|
|
# Seems to be a new stationary station (or at least a new symbol for an existing station)
|
|
self.mapId = 5
|
|
self.markerId = None
|
|
|
|
def _isFaultyGpsPosition(self):
|
|
"""Parse the packet and modify the mapId attribute if position is faulty
|
|
"""
|
|
packetlatCmp = int(round(self.packet.latitude*100000))
|
|
packetlngCmp = int(round(self.packet.longitude*100000))
|
|
|
|
if (packetlatCmp == int(0) and packetlngCmp == int(0)):
|
|
return True
|
|
|
|
if (packetlatCmp == int(1*100000) and packetlngCmp == int(1*100000)):
|
|
return True
|
|
|
|
if (packetlatCmp == int(36*100000) and packetlngCmp == int(136*100000)):
|
|
# Some gps units seems to use this position as default until they find the real position
|
|
# Maybe it is the position of a gps manufacturer?
|
|
return True
|
|
|
|
if (packetlatCmp == int(-48*100000) and packetlngCmp == int(0)):
|
|
# Some gps units seems to use this position as default until they find the real position
|
|
return True
|
|
return False
|