Files
2026-07-16 14:44:33 +08:00

326 lines
11 KiB
Python

# coding=utf-8
import copy
from ..OtherTools import GetDistance
routeControls = {} # 所有路径节点
class ConnectChangedState(object):
"""
当发生连接变化时的状态
"""
DisConnect = 0b00
Connect = 0b01
ConvertConnect = 0b00
ReallyConnect = 0b10
def GetRouteByPosDim(posDim):
# type:(Union[List,Tuple]) -> RouteControl
"""
通过维度坐标获取加载的路径节点
"""
return routeControls.get(posDim)
class RouteControl(object):
"""
路径节点
"""
def __init__(self, posDim):
# type:(Tuple[int,int,int,int]) -> None
self.posDim = posDim
self.connections = [] # 真连接
self.convertConnections = [] # 隐性连接,用于记录哪个路径节点连接与此
routeControls[posDim] = self
def HasConnection(self):
"""
判断是否有方向:自身 -> routeControl的连接
"""
return self.connections.__len__() > 0
def ConnectionChanged(self, routeControl, state):
"""
当连接情况发生改变完成后触发,包括真连接和隐性连接
:param routeControl: 将要变化的路径节点
:param state: ConnectChangedState不同位的不同state
"""
pass
def Destroy(self):
"""
销毁本路径节点
:return:
"""
for routeControl in copy.copy(self.convertConnections):
# 销毁, 不可触发自身连接改变
routeControl.DisConnectBefore(self)
routeControl.connections.remove(self)
self.convertConnections.remove(routeControl)
routeControl.ConnectionChanged(self, ConnectChangedState.ReallyConnect | ConnectChangedState.DisConnect)
for routeControl in copy.copy(self.connections):
# 销毁, 不可触发自身连接改变
self.DisConnectBefore(routeControl)
self.connections.remove(routeControl)
routeControl.convertConnections.remove(self)
routeControl.ConnectionChanged(self, ConnectChangedState.ConvertConnect | ConnectChangedState.DisConnect)
del routeControls[self.posDim]
def DisconnectTo(self, routeControl):
"""
单向取消与路径节点的单向连接, 方向:自身 -> routeControl
:param routeControl:将要取消的路径节点
:return:
"""
if self.IsConnection(routeControl):
self.DisConnectBefore(routeControl)
self.connections.remove(routeControl)
routeControl.convertConnections.remove(self)
self.ConnectionChanged(routeControl, ConnectChangedState.ReallyConnect | ConnectChangedState.DisConnect)
routeControl.ConnectionChanged(self, ConnectChangedState.ConvertConnect | ConnectChangedState.DisConnect)
@staticmethod
def DisconnectBy(routeControl):
"""
单向取消与路径节点的单向连接, 方向: routeControl -> 自身
:param routeControl:将要取消的路径节点
:return:
"""
routeControl.DisconnectTo(routeControl)
def InterDisconnect(self, routeControl):
"""
双向取消与路径节点的连接
:param routeControl:将要取消的路径节点
:return:
"""
self.DisconnectTo(routeControl)
self.DisconnectBy(routeControl)
def IsConnection(self, routeControl):
"""
判断路径节点是否与本路径节点连接
:param routeControl:路径节点
:return:
"""
return routeControl in self.connections
def Connectable(self, routeControl):
"""
在尝试与对方进行连接时触发,方向:自身 -> routeControl
:param routeControl:将要连接的路径节点
:return:是否与对方连接
"""
if abs(GetDistance(self.posDim[:3], routeControl.posDim[:3]) - 1) < 10e-6:
return True
def DisConnectBefore(self, routeControl):
"""
当断开方向为:routeControl -> 自身 连接之前触发
"""
pass
def ConnectBefore(self, routeControl):
"""
当发生方向为:routeControl -> 自身 连接之前触发
"""
pass
def ConnectTo(self, routeControl):
"""
与另外一个路径节点进行单向连接,方向:自身 -> routeControl
如果routeControl不可连接与此, 将无法建立连接
"""
routeControl.ConnectBefore(self)
if self.Connectable(routeControl) and routeControl not in self.connections:
self.connections.append(routeControl)
routeControl.convertConnections.append(self)
self.ConnectionChanged(routeControl, ConnectChangedState.ReallyConnect | ConnectChangedState.Connect)
routeControl.ConnectionChanged(self, ConnectChangedState.ConvertConnect | ConnectChangedState.Connect)
def ConnectBy(self, routeControl):
"""
与另外一个路径节点进行单向连接,方向:routeControl -> 自身
"""
routeControl.ConnectTo(self)
def InterConnect(self, routeControl):
"""
与另外一个路径节点进行双向连接
"""
self.ConnectTo(routeControl)
self.ConnectBy(routeControl)
def ConnectBeside(self):
"""
与周围的可连接的路径节点进行连接
"""
myPosDim = list(self.posDim)
dr = [-1, 1]
posDimBeside = [(myPosDim[0] + x, myPosDim[1], myPosDim[2], myPosDim[3]) for x in dr] + \
[(myPosDim[0], myPosDim[1] + y, myPosDim[2], myPosDim[3]) for y in dr] + \
[(myPosDim[0], myPosDim[1], myPosDim[2] + z, myPosDim[3]) for z in dr]
for posDim in posDimBeside:
routeControl = routeControls.get(posDim)
self.InterConnect(routeControl) if routeControl else 0
def IsFinal(self, *args, **kwargs):
"""
是否为终点
:param args:判断时可能传入的参数
:param kwargs:判断时可能传入的参数
:return:
"""
return self.connections.__len__() == 1
def Finder(routeControl, maxRuntime=10e5):
# type:(RouteControl,int)->List
"""
寻找器,不可跨维度寻找
:param routeControl:起点路径节点
:param maxRuntime:最大运行次数
:return:终点集
"""
destination = [] # 目标集
x = {} # 储存已经寻找过的节点
runTime = 0 # 寻找次数
hand = routeControl.posDim # 运行指针
subRoute = [] # 下一节点
while runTime < maxRuntime:
routeControl = routeControls.get(hand) # type:RouteControl
y = x.get(hand[0], {})
z = y.get(hand[1], {})
# 如果获取错误,或者此节点已被寻找,则尝试下一个分流节点
if routeControl is None or z.get(hand[2], False):
if subRoute.__len__() == 0:
break
hand = subRoute.pop()
continue
# 储存节点
z[hand[2]] = routeControl
y[hand[1]] = z
x[hand[0]] = y
if routeControl.IsFinal():
destination.append(routeControl)
for connection in routeControl.connections:
posDim = connection.posDim
# 判断下一节点是否被储存过
if not x.get(posDim[0], {}).get(posDim[1], {}).get(posDim[2], False):
subRoute.append(connection.posDim)
if subRoute.__len__() == 0:
break
hand = subRoute.pop()
runTime += 1
return destination
def FinderStopWhenFindDestination(routeControl, maxRuntime=10e5):
# type:(RouteControl,int)->List
"""
寻找器,不可跨维度寻找,每个分路遇到终点会停止寻路
:param routeControl:起点路径节点
:param maxRuntime:最大运行次数
:return:终点集
"""
destination = []
x = {}
runTime = 0
hand = routeControl.posDim
subRoute = []
while runTime < maxRuntime:
routeControl = routeControls.get(hand) # type:RouteControl
y = x.get(hand[0], {})
z = y.get(hand[1], {})
if routeControl is None or z.get(hand[2], False):
if subRoute.__len__() == 0:
break
hand = subRoute.pop()
continue
z[hand[2]] = True
y[hand[1]] = z
x[hand[0]] = y
if routeControl.IsFinal():
destination.append(routeControl)
else:
for connection in routeControl.connections:
posDim = connection.posDim
if not x.get(posDim[0], {}).get(posDim[1], {}).get(posDim[2], False):
subRoute.append(connection.posDim)
if subRoute.__len__() == 0:
break
hand = subRoute.pop()
runTime += 1
return destination
def FinderStopSampleNum(routeControl, sampleNum, maxRuntime=10e5):
# type:(RouteControl,int,int)->Dict
"""
寻找器,不可跨维度寻找,每个分路到达sampleNumber时停止寻路
:param routeControl:起点路径节点
:param maxRuntime:最大运行次数
:param sampleNum:距离起点相隔的节点个数
:return:结果集无论是否为终点
"""
destination = {} # 目标集
x = {} # 储存已经寻找过的节点
runTime = 0 # 寻找次数
hand = routeControl.posDim # 运行指针
subRoute = [] # 下一节点
subRouteNum = {} # 下一节点计数
presentNum = 0 # 当前计数
while runTime < maxRuntime:
routeControl = routeControls.get(hand) # type:RouteControl
y = x.get(hand[0], {})
z = y.get(hand[1], {})
# 如果获取错误,或者此节点已被寻找,再或者此时计数大于sampleNum则尝试下一个分流节点
if presentNum >= sampleNum or presentNum == -1 or z.get(hand[2], False) or routeControl is None:
if subRoute.__len__() == 0:
break
hand = subRoute.pop()
continue
# 储存节点
z[hand[2]] = routeControl
y[hand[1]] = z
x[hand[0]] = y
if presentNum > 0:
destination[presentNum] = destination.get(presentNum, [])
destination[presentNum].append(routeControl)
presentNum += 1
for connection in routeControl.connections:
posDim = connection.posDim
# 判断下一节点是否被储存过
if not x.get(posDim[0], {}).get(posDim[1], {}).get(posDim[2], False):
subRoute.append(connection.posDim)
a = subRouteNum.get(posDim[0], {})
subRouteNum[posDim[0]] = a
b = a.get(posDim[1], {})
a[posDim[1]] = b
b[posDim[2]] = presentNum
if subRoute.__len__() == 0:
break
hand = subRoute.pop()
presentNum = subRouteNum.get(hand[0], {}).get(hand[1], {}).get(hand[2], False)
runTime += 1
return destination