import math
class CEntity(object):
def __init__(self,cid,x,y,radius):
self.cid = cid
self.x = x
self.y = y
self.radius = radius
self.xpre = None
self.xnext = None
self.ypre = None
self.ynext = None
self.watcher = set([]) #观察者集合(关注当前对象的集合)
self.maker = set([]) #被观察者集合(当前对象关注的集合)
def __str__(self):
return "[%s:(%s-%s-%s) w:%s m:%s]" % (self.cid,self.x,self.y,self.radius,self.watcher,str(self.maker))
def xsee(self,entity):
return math.fabs(self.x - entity.x) <= self.radius
def ysee(self,entity):
return math.fabs(self.y - entity.y) <= self.radius
def see(self,entity):
return self.xsee(entity) and self.ysee(entity)
def getWatcherSet(self):
return self.watcher
def addWatcher(self,cid):
self.watcher.add(cid)
def delWatcher(self,cid):
if cid not in self.watcher:
return
self.watcher.remove(cid)
def getMakerSet(self):
return self.maker
def addMaker(self,cid):
self.maker.add(cid)
def delMaker(self,cid):
if cid not in self.maker:
return
self.maker.remove(cid)
class CScene(object):
def __init__(self):
self.dstmax = 10
self.m_mapEntity = {}
self.head = CEntity(-1,0,0,0)
self.tail = CEntity(-2,0,0,0)
self.head.xnext = self.tail
self.head.ynext = self.tail
self.tail.xpre = self.head
self.tail.ypre = self.head
def addEntity(self,entity):
cur = self.head.xnext
while(cur != None):
if entity.x < cur.x or cur == self.tail:
pre = cur.xpre
pre.xnext = entity
entity.xnext = cur
cur.xpre = entity
entity.xpre = pre
break
cur = cur.xnext
cur = self.head.ynext
while(cur != None):
if entity.y < cur.y or cur == self.tail:
entity.ynext = cur
entity.ypre = cur.ypre
cur.ypre.ynext = entity
cur.ypre = entity
break
cur = cur.ynext
def delEntity(self,entity):
if entity == self.head or entity == self.tail:
return
entity.xpre.xnext = entity.xnext
entity.xnext.xpre = entity.xpre
entity.ypre.ynext = entity.ynext
entity.ynext.ypre = entity.ypre
entity.xpre = None
entity.xnext = None
entity.ypre = None
entity.ynext = None
pass
def add(self,cid,x,y,distance = 2):
target = self.m_mapEntity.get(cid,None)
if target:
return
target = CEntity(cid,x,y,distance)
self.m_mapEntity[cid] = target
self.addEntity(target)
#target能看到的对象集合
makermap = self.getMakers(target)
for entity in makermap.values():
target.addMaker(entity.cid)
entity.addWatcher(target.cid)
print("notify{0} event:{1}enter".format(target,entity)) #通知target,entity进入视野范围
#能看到cur的对象集合
watchers = self.getWatchers(target,self.dstmax)
for entity in watchers.values():
target.addWatcher(entity.cid)
entity.addMaker(target.cid)
print("notify{0} event:{1}enter".format(entity,target)) #通知entity,cur进入视野范围
print("add entity {0}".format(target))
def move(self,cid,x,y):
target = self.m_mapEntity.get(cid,None)
if not target:
return
self.updateEntityPosition(target,x,y)
#target移动 关注target的对象(watcher列表)也会变化
curwatcherset = target.getWatcherSet()
watchers = self.getWatchers(target,self.dstmax)
newwatcherset = set(watchers.keys())
outsets = curwatcherset - newwatcherset
insets = newwatcherset - curwatcherset
movesets = curwatcherset & newwatcherset
for outcid in outsets:
entity = self.m_mapEntity.get(outcid,None)
if not entity:
continue
target.delWatcher(outcid)
entity.delMaker(cid)
print("notify{0} event:{1}leave".format(entity,target)) #通知entity,target离开视野范围
for incid in insets:
entity = self.m_mapEntity.get(incid,None)
if not entity:
continue
target.addWatcher(incid)
entity.addMaker(cid)
print("notify{0} event:{1}enter".format(entity,target)) #通知entity,target进入视野范围
for movecid in movesets:
entity = self.m_mapEntity.get(movecid,None)
if not entity:
continue
print("notify{0} event:{1}move".format(entity,target)) #通知entity,target移动了
#target移动 target关注的对象(maker列表)也会变化
makers = self.getMakers(target)
curmakerset = target.getMakerSet()
newmakerset = set(makers.keys())
outsets = curmakerset - newmakerset
insets = newmakerset - curmakerset
movesets = curmakerset & newmakerset
for outcid in outsets:
entity = self.m_mapEntity.get(outcid,None)
if not entity:
continue
target.delMaker(outcid)
entity.delWatcher(cid)
print("notitfy{0} event:{1}leave".format(target,entity)) #通知target,entity离开视野
for incid in insets:
entity = self.m_mapEntity.get(incid,None)
if not entity:
continue
target.addMaker(incid)
entity.addWatcher(cid)
print("notify{0} event:{1}enter".format(target,entity)) #通知target,entity进入视野
#不同notify movesets集合的节点target移动了
print("move entity {0}".format(target))
def leave(self,cid):
target = self.m_mapEntity.get(cid,None)
if not target:
return
curwatcherset = target.getWatcherSet()
for outcid in curwatcherset:
entity = self.m_mapEntity.get(outcid,None)
if not entity:
continue
entity.delMaker(outcid)
print("notify{0} event:{1}leave".format(entity,target))
curmakerset = target.getMakerSet()
for outcid in curmakerset:
entity = self.m_mapEntity.get(outcid,None)
if not entity:
continue
entity.delWatcher(outcid)
#删除watcher即可 不用notify
self.delEntity(target)
self.m_mapEntity.pop(cid,None)
print("leave entity {0}".format(target))
target = None
#pentity周围 pentity可见的对象
def getMakers(self,pentity):
maker = {}
if pentity == None:
return maker
cur = pentity.xnext
while(cur != self.tail):
if pentity.xsee(cur) and pentity.ysee(cur):
maker[cur.cid] = cur
else:
if pentity.xsee(cur) == False:
break
cur = cur.xnext
cur = pentity.xpre
while(cur != self.head):
if pentity.xsee(cur) and pentity.ysee(cur):
maker[cur.cid] = cur
else:
if pentity.xsee(cur) == False:
break
cur = cur.xpre
return maker
#pentity周围 dstMax范围内 哪些对象可见pentity
def getWatchers(self,pentity,dstMax):
watcher = {}
if pentity == None:
return watcher
cur = pentity.xnext
while(cur != self.tail):
if cur.xsee(pentity) and cur.ysee(pentity):
watcher[cur.cid] = cur
else:
if cur.x - pentity.x > dstMax:
break
cur = cur.xnext
cur = pentity.xpre
while(cur != self.head):
if cur.xsee(pentity) and cur.ysee(pentity):
watcher[cur.cid] = cur
else:
if pentity.x - cur.x > dstMax:
break
cur = cur.xpre
return watcher
def updateEntityPosition(self,pentity,x,y):
self.delEntity(pentity)
pentity.x = x
pentity.y = y
self.addEntity(pentity)
def dump(self):
cur = self.head
while(cur != None):
print("xlist:",cur)
cur = cur.xnext
cur = self.head
while(cur != None):
print("ylist:",cur)
cur = cur.ynext
def main():
scene = CScene()
import random
for i in range(5):
scene.add(i+ 1,random.randint(1,10),random.randint(1,10),random.randint(3,6))
scene.dump()
print("#####################################")
for i in range(3):
scene.move(random.randint(1,5),random.randint(1,10),random.randint(1,10))
scene.dump()
if __name__ == '__main__':
main()
随机增加5个点(x,y,radius)
1:3-3-6
2:10-6-4
3:2-2-3
4:1-10-4
5:1-7-5
将节点4(1-10-4) 移动到 (4-8-8)
将节点4 (4-8-4) 移动到 (7-6-4)
将节点2 (10-6-4) 移动到 (9-10-4)