Esempio n. 1
0
File: init.py Progetto: mzimny/aamks
class OnEnd():
    def __init__(self):  # {{{
        ''' Stuff that happens at the end of the project '''
        self.json = Json()
        self.conf = self.json.read("{}/conf.json".format(
            os.environ['AAMKS_PROJECT']))
        self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        self.project_id = self.conf['project_id']
        self.scenario_id = self.conf['scenario_id']
        self.p = Psql()
        if self.conf['navmesh_debug'] == 1:
            self._navmeshes_for_floors()
        Vis({
            'highlight_geom': None,
            'anim': None,
            'title': "OnEnd()",
            'srv': 1
        })
        self._gearman_register_works()
# }}}

    def _navmeshes_for_floors(self):  # {{{
        navs = {}
        for floor in self.json.readdb('floors_meta').keys():
            z = self.s.query(
                "SELECT name FROM aamks_geom WHERE floor=? AND room_enter='no'",
                (floor, ))
            bypass_rooms = []
            for i in z:
                bypass_rooms.append(i['name'])
            navs[tuple(bypass_rooms)] = Navmesh()
            navs[tuple(bypass_rooms)].build(floor, bypass_rooms)
            navs[tuple(bypass_rooms)].test()
# }}}

    def _gearman_register_works(self):  # {{{
        ''' 
        We only register works. The works will be run by workers registered via
        manager. 
        '''

        if os.environ['AAMKS_USE_GEARMAN'] == '0':
            return

        si = SimIterations(self.project_id, self.scenario_id,
                           self.conf['number_of_simulations'])
        try:
            for i in range(*si.get()):
                worker = "{}/workers/{}".format(os.environ['AAMKS_PROJECT'], i)
                worker = worker.replace("/home", "")
                gearman = "gearman -b -f aRun 'https://www.ctrk.pl:444{}'".format(
                    worker)
                os.system(gearman)
        except Exception as e:
            print('OnEnd: {}'.format(e))
Esempio n. 2
0
class Obstacles():
    def __init__(self):# {{{
        self.json=Json()
        self.conf=self.json.read("{}/conf.json".format(os.environ['AAMKS_PROJECT']))
        self.fire_model=self.conf['fire_model'];
        self.s=Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        self.world_meta=self.json.readdb("world_meta")
        self.floors_meta=self.json.readdb("floors_meta")
        self.floors=self.floors_meta.keys()
        self.walls_width=self.world_meta['walls_width']
        self._create_obstacles('aamks_geom', 'obstacles')
        # TODO: in future we will probably process vertical staircases outside of aamks_geoms db table
        #if self.world_meta['multifloor_building']==1:
        #    self._create_obstacles('world2d', 'world2d_obstacles')
        #exit()

# }}}
    def _create_obstacles(self, tin, tout):# {{{
        ''' 
        Geometry may contain obstacles for modeling machines, FDS walls, bookcases,
        etc. Obstacles are not visible in CFAST.
        '''

        data=OrderedDict()
        for r in self.s.query("SELECT DISTINCT(floor) FROM {}".format(tin)):
            floor=r['floor']
            zz=0
            if tin=='aamks_geom':
                zz=self.floors_meta[floor]['minz_abs']
            data[floor]=[]
            obsts=[]
            for o in self.s.query("SELECT points FROM {} WHERE type_pri='OBST' AND floor=?".format(tin), (floor,)):
                obsts.append(Polygon(json.loads(o['points'])))
                
            obsts+=self._floor2obsts(tin,floor)
            for i in obsts:
                data[floor].append([(int(x),int(y), zz) for x,y in i.exterior.coords])
        self.s.query("CREATE TABLE {} (json)".format(tout))
        self.s.query("INSERT INTO {} VALUES (?)".format(tout), (json.dumps({'obstacles': data}),))
        #self.s.dumpall()
#}}}
    def _floor2obsts(self,tin,floor):# {{{
        ''' 
        For a roomX we create a roomX_ghost, we move it by self.walls_width,
        which must match the width of hvents. Then we create walls via logical
        operations. Finally doors cut the openings in walls.

        '''
        if self.fire_model=='FDS':
            return []

        walls=[]
        for i in self.s.query("SELECT * FROM {} WHERE floor=? AND type_pri='COMPA' ORDER BY name".format(tin), (floor,)):

            walls.append((i['x0']+self.walls_width , i['y0']            , i['x0']+i['width']                  , i['y0']+self.walls_width)                )
            walls.append((i['x0']+i['width']       , i['y0']            , i['x0']+i['width']+self.walls_width , i['y0']+i['depth']+self.walls_width)     )
            walls.append((i['x0']+self.walls_width , i['y0']+i['depth'] , i['x0']+i['width']                  , i['y0']+i['depth']+self.walls_width)     )
            walls.append((i['x0']                  , i['y0']            , i['x0']+self.walls_width            , i['y0']+i['depth']+self.walls_width)     )

        walls_polygons=([box(ii[0],ii[1],ii[2],ii[3]) for ii in set(walls)])

        doors_polygons=[]
        for i in self.s.query("SELECT * FROM {} WHERE floor=? AND type_tri='DOOR' ORDER BY name".format(tin), (floor,)):
            doors_polygons.append(box(i['x0'], i['y0'], i['x0']+i['width'], i['y0']+i['depth']))
            
        obsts=[]
        for wall in walls_polygons:
            for door in doors_polygons:
                wall=wall.difference(door)
            if isinstance(wall, MultiPolygon):
                for i in polygonize(wall):
                    obsts.append(i)
            elif isinstance(wall, Polygon):
                obsts.append(wall)
        return obsts 
Esempio n. 3
0
class EvacMcarlo():
    def __init__(self):# {{{
        ''' Generate montecarlo evac.conf. '''
        self.json=Json()
        self.conf=self.json.read("{}/conf.json".format(os.environ['AAMKS_PROJECT']))
        self.s=Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        self.evacuee_radius=self.json.read('{}/inc.json'.format(os.environ['AAMKS_PATH']))['evacueeRadius']
        self.floors=[z['floor'] for z in self.s.query("SELECT DISTINCT floor FROM aamks_geom ORDER BY floor")]
        self._project_name=os.path.basename(os.environ['AAMKS_PROJECT'])

        si=SimIterations(self.conf['project_id'], self.conf['scenario_id'], self.conf['number_of_simulations'])
        sim_ids=range(*si.get())
        for self._sim_id in sim_ids:
            seed(self._sim_id)
            self._fire_obstacle()
            self._static_evac_conf()
            self._dispatch_evacuees()
            self._make_evac_conf()
        self._evacuees_static_animator()

# }}}
    def _static_evac_conf(self):# {{{
        ''' 
        AAMKS_PROJECT must be propagated to worker environment.
        '''

        self._evac_conf=self.conf
        self._evac_conf['AAMKS_PROJECT']=os.environ['AAMKS_PROJECT']
        self._evac_conf['SIM_ID']=self._sim_id
        self._evac_conf['SERVER']=os.environ['AAMKS_SERVER']
        self._evac_conf['FIRE_ORIGIN']=self.s.query("SELECT name FROM fire_origin WHERE sim_id=?", (self._sim_id,))[0]['name']
# }}}
    def _fire_obstacle(self):# {{{
        '''
        Fire Obstacle prevents humans to walk right through the fire. Currently
        we build the rectangle xx * yy around x,y. Perhaps this size could be
        some function of fire properties.
        '''

        xx=150
        yy=150

        z=self.s.query("SELECT * FROM fire_origin") 
        i=z[0]
        points=[ [i['x']-xx, i['y']-yy, 0], [i['x']+xx, i['y']-yy, 0], [i['x']+xx, i['y']+yy, 0], [i['x']-xx, i['y']+yy, 0], [i['x']-xx, i['y']-yy, 0] ]

        obstacles=self.json.readdb("obstacles")
        obstacles['fire']={ i['floor']: points }
        self.s.query("UPDATE obstacles SET json=?", (json.dumps(obstacles),)) 

# }}}
    def _make_pre_evacuation(self,room,type_sec):# {{{
        ''' 
        An evacuee pre_evacuates from either ordinary room or from the room of
        fire origin; type_sec is for future development.
        '''

        if room != self._evac_conf['FIRE_ORIGIN']:
            pe=self.conf['pre_evac']
        else:
            pe=self.conf['pre_evac_fire_origin']
        return round(lognorm(s=1, loc=pe['mean'], scale=pe['sd']).rvs(), 2)
# }}}
    def _get_density(self,name,type_sec,floor):# {{{
        ''' 
        Special selectors from distributions.json
        First we try to return ROOM_1_2, then ROOM_FLOOR_1, then ROOM
        Concentration comes as m^2, but aamks uses 100 * 100 cm^2 
        '''

        z=self.conf['evacuees_concentration']
        for i in [name, "{}_FLOOR_{}".format(type_sec,floor), type_sec]:
            if i in z.keys():
                return z[i] * 100 * 100
        raise Exception("Cannot determine the density for {}".format(name))

# }}}
    def _evac_rooms(self,floor): # {{{
        '''
        * probabilistic: probabilistic rooms
        * manual: manually asigned evacuees 
        '''

        rooms={}
        probabilistic_rooms={}
        for i in self.s.query("SELECT points, name, type_sec FROM aamks_geom WHERE type_pri='COMPA' AND floor=? ORDER BY global_type_id", (floor,)):
            i['points']=json.loads(i['points'])
            probabilistic_rooms[i['name']]=i

        manual_rooms={}
        for i in self.s.query("SELECT name, x0, y0 FROM aamks_geom WHERE type_pri='EVACUEE' AND floor=?", (floor,)):
            q=(floor,i['x0'], i['y0'], i['x0'], i['y0'])
            x=self.s.query("SELECT name,type_sec FROM aamks_geom WHERE type_pri='COMPA' AND floor=? AND x0<=? AND y0<=? AND x1>=? AND y1>=?", q)[0]
            if not x['name'] in manual_rooms:
                manual_rooms[x['name']]={'type_sec': x['type_sec'], 'positions': [] }
                del probabilistic_rooms[x['name']]
            manual_rooms[x['name']]['positions'].append((i['x0'], i['y0'], x['name']))

        rooms['probabilistic']=probabilistic_rooms
        rooms['manual']=manual_rooms
        return rooms
# }}}
    def _dispatch_evacuees(self):# {{{
        ''' 
        We dispatch the evacuees across the building according to the density
        distribution. 
        '''

        self.dispatched_evacuees=OrderedDict() 
        self.pre_evacuation=OrderedDict() 
        self._make_floor_obstacles()
        for floor in self.floors:
            self.pre_evacuation[floor] = list()
            positions = []
            evac_rooms=self._evac_rooms(floor)
            for name,r in evac_rooms['probabilistic'].items():
                density=self._get_density(r['name'],r['type_sec'],floor)
                room_positions=self._dispatch_inside_polygons(density,r['points'], floor, name)
                positions += room_positions
                for i in room_positions:
                    self.pre_evacuation[floor].append(self._make_pre_evacuation(r['name'], r['type_sec']))
            for name,r in evac_rooms['manual'].items():
                positions += r['positions']
                for i in r['positions']:
                    self.pre_evacuation[floor].append(self._make_pre_evacuation(name, r['type_sec']))
            self.dispatched_evacuees[floor] = positions
# }}}
    def _make_floor_obstacles(self):# {{{
        self._floor_obstacles={}
        for floor in self.floors:
            obsts=[]
            for x in self.json.readdb("obstacles")['obstacles'][floor]:
                obsts.append([(o[0],o[1]) for o in x])
            try:
                obsts.append(self.json.readdb("obstacles")['fire'][floor])
            except:
                pass
            self._floor_obstacles[floor]=unary_union([ Polygon(i) for i in obsts ])
# }}}
    def _dispatch_inside_polygons(self,density,points,floor,name):# {{{
        exterior=Polygon(points)
        exterior_minus_obsts=exterior.difference(self._floor_obstacles[floor])
        walkable=exterior_minus_obsts.buffer(- self.evacuee_radius - 10 )

        bbox=list(walkable.bounds)
        target=int(walkable.area / density)
        positions=[]
        while len(positions) < target:
            x=uniform(bbox[0], bbox[2])
            y=uniform(bbox[1], bbox[3])
            if walkable.intersects(Point(x,y)):
                positions.append((int(x),int(y), name))
        return positions
# }}}
    def _make_evac_conf(self):# {{{
        ''' Write data to sim_id/evac.json. '''

        self._evac_conf['FLOORS_DATA']=OrderedDict()
        for floor in self.floors:
            self._evac_conf['FLOORS_DATA'][floor]=OrderedDict()
            self._evac_conf['FLOORS_DATA'][floor]['NUM_OF_EVACUEES']=len(self.dispatched_evacuees[floor])
            self._evac_conf['FLOORS_DATA'][floor]['EVACUEES']=OrderedDict()
            z=self.s.query("SELECT z0 FROM aamks_geom WHERE floor=?", (floor,))[0]['z0']
            for i,pos in enumerate(self.dispatched_evacuees[floor]):
                e_id='f{}'.format(i)
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]=OrderedDict()
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['ORIGIN']         = (pos[0], pos[1])
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['COMPA']          = (pos[2])
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['PRE_EVACUATION'] = self.pre_evacuation[floor][i]

                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['ALPHA_V']        = round(normal(self.conf['evacuees_alpha_v']['mean']     , self.conf['evacuees_alpha_v']['sd'])     , 2)
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['BETA_V']         = round(normal(self.conf['evacuees_beta_v']['mean']      , self.conf['evacuees_beta_v']['sd'])      , 2)
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['H_SPEED']        = round(normal(self.conf['evacuees_max_h_speed']['mean'] , self.conf['evacuees_max_h_speed']['sd']) , 2)
                self._evac_conf['FLOORS_DATA'][floor]['EVACUEES'][e_id]['V_SPEED']        = round(normal(self.conf['evacuees_max_v_speed']['mean'] , self.conf['evacuees_max_v_speed']['sd']) , 2)

        self.json.write(self._evac_conf, "{}/workers/{}/evac.json".format(os.environ['AAMKS_PROJECT'],self._sim_id))
# }}}
    def _evacuees_static_animator(self):# {{{
        ''' 
        For the animator. We just pick a single, newest sim_id and display
        evacuees init positions. Animator can use it when there are no worker
        provided animations (moving evacuees for specific sim_id). 

        '''

        m={}
        for floor in self.floors:
            m[floor]=self.dispatched_evacuees[floor]
        self.s.query('INSERT INTO dispatched_evacuees VALUES (?)', (json.dumps(m),))
Esempio n. 4
0
class EvacEnv:
    def __init__(self):  # {{{
        self.json = Json()
        self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))

        self.evacuee_radius = self.json.read("{}/inc.json".format(
            os.environ['AAMKS_PATH']))['evacueeRadius']
        time = 1
        self.sim = rvo2.PyRVOSimulator(time, 40, 5, time, time,
                                       self.evacuee_radius, 30)
        self.make_nav("0")
        self._anim = {
            "simulation_id": 1,
            "simulation_time": 20,
            "time_shift": 0,
            "animations": {
                "evacuees": [],
                "rooms_opacity": []
            }
        }
        self._create_agents()
        self._load_obstacles()
        self._run()
        self._write_zip()
        Vis({
            'highlight_geom': None,
            'anim': '1/f1.zip',
            'title': 'x',
            'srv': 1
        })

# }}}

    def make_nav(self, floor):  # {{{
        self.nav = Navmesh()
        self.nav.build(floor)
# }}}

    def _create_agents(self):  # {{{
        z = self.s.query("SELECT * FROM aamks_geom WHERE type_pri='EVACUEE'")
        self.agents = {}
        for i in z:
            aa = i['name']
            self.agents[aa] = {}
            ii = self.sim.addAgent((i['x0'], i['y0']))
            self.agents[aa]['name'] = aa
            self.agents[aa]['id'] = ii
            self.sim.setAgentPrefVelocity(ii, (0, 0))
            self.agents[aa]['behaviour'] = 'random'
            self.agents[aa]['origin'] = (i['x0'], i['y0'])
            self.agents[aa]['target'] = self.nav.room_leaves(
                (i['x0'], i['y0']))['best'][0]
        self._positions()
# }}}

    def _load_obstacles(self):  # {{{
        z = self.json.readdb('obstacles')
        obstacles = z['obstacles']['0']
        for i in obstacles:
            self.sim.addObstacle([(o[0], o[1]) for o in i[:4]])
            self.sim.processObstacles()
# }}}

    def _velocity(self, a):  # {{{
        '''
        radius=3.5 is the condition for the agent to reach the behind-doors target 
        '''

        dx = a['target'][0] - self.sim.getAgentPosition(a['id'])[0]
        dy = a['target'][1] - self.sim.getAgentPosition(a['id'])[1]
        self.sim.setAgentPrefVelocity(a['id'], (dx, dy))
        return sqrt(dx**2 + dy**2)

# }}}

    def _positions(self):  # {{{
        frame = []
        for k, v in self.agents.items():
            pos = [round(i) for i in self.sim.getAgentPosition(v['id'])]
            frame.append([pos[0], pos[1], 0, 0, "N", 1])
        self._anim["animations"]["evacuees"].append({"0": frame})
# }}}

    def _update(self):  # {{{
        for k, v in self.agents.items():
            target_dist = self._velocity(self.agents[k])
            if target_dist <= self.evacuee_radius * 3.5:
                #dd(self.agents[k]['id'], target_dist)
                pass
                #exit()

        self._positions()
# }}}

    def _write_zip(self):  # {{{
        d = "{}/workers/1".format(os.environ['AAMKS_PROJECT'])

        zf = zipfile.ZipFile("{}/f1.zip".format(d), 'w')
        zf.writestr("anim.json", json.dumps(self._anim))
        zf.close()
# }}}

    def _run(self):  # {{{
        for t in range(100):
            self.sim.doStep()
            self._update()
Esempio n. 5
0
class Navmesh: 
    def __init__(self):# {{{
        ''' 
        installer/navmesh_installer.sh installs all the dependencies.

        * navmesh build from the obj geometry file
        thanks to https://github.com/arl/go-detour !

        * navmesh query
        thanks to https://github.com/layzerar/recastlib/ !

        ============================================

        This is how we are supposed to be called:

        nav=Navmesh()
        nav.build(floor)
        nav.nav_query(src, dst)

            or if you want to block r1 and r2 and have the navmeshes named

        navs=dict()
        navs[('r1','r2')]=Navmesh()
        navs[('r1','r2')].build(floor,('r1','r2'))
        navs[('r1','r2')].nav_query(src, dst)

        '''

        self.json=Json()
        self.s=Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        self._test_colors=[ "#f80", "#f00", "#8f0", "#08f" ]
        self.navmesh=OrderedDict()
        self.partition_query={}
        self.evacuee_radius=self.json.read('{}/inc.json'.format(os.environ['AAMKS_PATH']))['evacueeRadius']
# }}}

    def build(self,floor,bypass_rooms=[]):# {{{
        self.floor=floor
        self.bypass_rooms=bypass_rooms
        self._get_name(bypass_rooms)
        file_obj=self._obj_make(bypass_rooms)
        file_nav="{}/{}".format(os.environ['AAMKS_PROJECT'], self.nav_name)
        file_conf="{}/recast.yml".format(os.environ['AAMKS_PROJECT'])
        with open(file_conf, "w") as f: 
            f.write('''\
            cellsize: 0.10
            cellheight: 0.2
            agentheight: 2
            agentradius: 0.30
            agentmaxclimb: 0.1
            agentmaxslope: 45
            regionminsize: 8
            regionmergesize: 20
            edgemaxlen: 12
            edgemaxerror: 1.3
            vertsperpoly: 6
            detailsampledist: 6
            detailsamplemaxerror: 1
            partitiontype: 1
            tilesize: 0
            ''')
        subprocess.call("rm -rf {}; recast --config {} --input {} build {} 1>/dev/null 2>/dev/null".format(file_nav, file_conf, file_obj, file_nav), shell=True)

        try:
            self.NAV = dt.dtLoadSampleTileMesh(file_nav)
        except:
            raise SystemExit("Navmesh: cannot create {}".format(file_nav))
# }}}
    def nav_query(self,src,dst,maxStraightPath=16):# {{{
        '''
        ./Detour/Include/DetourNavMeshQuery.h: maxStraightPath: The maximum number of points the straight path arrays can hold.  [Limit: > 0]
        We set maxStraightPath to a default low value which stops calculations early
        If one needs to get the full path to the destination one must call us with any high value, e.g. 999999999


        '''

        filtr = dt.dtQueryFilter()
        query = dt.dtNavMeshQuery()

        status = query.init(self.NAV, 2048)
        if dt.dtStatusFailed(status):
            return "err", -1, status

        polyPickExt = dt.dtVec3(2.0, 4.0, 2.0)
        startPos = dt.dtVec3(src[0]/100, 1, src[1]/100)
        endPos = dt.dtVec3(dst[0]/100, 1, dst[1]/100)

        status, out = query.findNearestPoly(startPos, polyPickExt, filtr)
        if dt.dtStatusFailed(status):
            return "err", -2, status
        startRef = out["nearestRef"]
        _startPt = out["nearestPt"]

        status, out = query.findNearestPoly(endPos, polyPickExt, filtr)
        if dt.dtStatusFailed(status):
            return "err", -3, status
        endRef = out["nearestRef"]
        _endPt = out["nearestPt"]

        status, out = query.findPath(startRef, endRef, startPos, endPos, filtr, maxStraightPath)
        if dt.dtStatusFailed(status):
            return "err", -4, status
        pathRefs = out["path"]

        status, fixEndPos = query.closestPointOnPoly(pathRefs[-1], endPos)
        if dt.dtStatusFailed(status):
            return "err", -5, status

        status, out = query.findStraightPath(startPos, fixEndPos, pathRefs, maxStraightPath, 0)
        if dt.dtStatusFailed(status):
            return "err", -6, status
        straightPath = out["straightPath"]
        straightPathFlags = out["straightPathFlags"]
        straightPathRefs = out["straightPathRefs"]
        
        path=[]
        for i in straightPath:
            path.append((i[0]*100, i[2]*100))

        if path[0]=="err":
            return None
        else :
            return path
# }}}
    def closest_terminal(self,p0,exit_type):# {{{
        '''
        The shortest polyline defines the closest exit from the floor. 
        dist < 10 test asserts the polyline has min 2 distinct points.

        exit_type: primary | secondary | any
        '''

        if exit_type in ['primary', 'secondary']:
            r=self.s.query("SELECT name,center_x,center_y FROM aamks_geom WHERE terminal_door=? AND floor=?", (exit_type, self.floor))
        else:
            r=self.s.query("SELECT name,center_x,center_y FROM aamks_geom WHERE terminal_door IS NOT NULL AND floor=?", (self.floor,))
        m={}
        closest={ 'len': 999999999, 'name': None, 'x': None, 'y': None }
        for i in r:
            if abs(i['center_x']-p0[0]) < 10 and abs(i['center_y']-p0[1]) < 10: 
                closest={ 'name': i['name'],  'x': i['center_x'], 'y': i['center_y'],'len': 0  }
                return closest
            ll=self.path_length(p0,(i['center_x'],i['center_y']))
            if ll < closest['len']:
                closest={ 'name': i['name'], 'x': i['center_x'], 'y': i['center_y'], 'len': int(ll) }
        return closest
            
# }}}
    def room_leaves(self,ee):# {{{
        self.partition_query[self.floor]=PartitionQuery(self.floor)
        room=self.partition_query[self.floor].xy2room(ee)
        closest={ 'len': 999999999, 'name': None, 'x': None, 'y': None }

        leaves={}
        for door in self._room_exit_doors(room):
            dest=self._move_dest_around_door({'e': ee, 'door': door, 'room': room})
            ll=self.path_length(ee,dest)
            leaves[ll]=(dest, door['name'])

        best_point, best_name=leaves[min(leaves.keys())]
        best_path=self.nav_query(ee, best_point)
        candidates={'best_point': best_point, 'best_name': best_name, 'best_path': best_path, 'all': list(leaves.values())}
        return candidates

# }}}
    def path_length(self, src, dst):# {{{
        return LineString(self.nav_query(src, dst, 300)).length 
# }}}
    def nav_plot_path(self,points,ddgeoms,style={}):# {{{
        ss={ "strokeColor": "#fff", "strokeWidth": 14  , "opacity": 0.5 }
        for m,n in style.items():
            ss[m]=n
        ddgeoms.add({'floor': self.floor, 'type': 'path', "g": { "points": points } , 'style': ss } )
# }}}
    def test(self):# {{{
        self.conf=self.json.read("{}/conf.json".format(os.environ['AAMKS_PROJECT']))
        agents_pairs=4
        ee=self.s.query("SELECT name,x0,y0 FROM aamks_geom WHERE type_pri='EVACUEE' AND floor=? ORDER BY global_type_id LIMIT ?", (self.floor, agents_pairs*2))
        if len(ee) == 0: return
        evacuees=list(self._chunks(ee,2))
        self._test_evacuees_pairs(evacuees)
        if self.conf['fire_model'] != 'FDS':
            self._test_room_leaves((ee[0]['x0'], ee[0]['y0']))
        Vis({'highlight_geom': None, 'anim': None, 'title': 'Nav {} test'.format(self.nav_name), 'srv': 1})

# }}}

    def _bricked_wall(self, bypass_rooms=[]):# {{{
        '''
        For navmesh we may wish to turn some doors into bricks.
        '''

        bricked_wall=[]

        if len(bypass_rooms) > 0 :
            floors_meta=json.loads(self.s.query("SELECT json FROM floors_meta")[0]['json'])
            elevation=floors_meta[self.floor]['minz_abs']
            where=" WHERE "
            where+=" vent_from_name="+" OR vent_from_name=".join([ "'{}'".format(i) for i in bypass_rooms])
            where+=" OR vent_to_name="+" OR vent_to_name=".join([ "'{}'".format(i) for i in bypass_rooms])
            bypass_doors=self.s.query("SELECT name,x0,y0,x1,y1 FROM aamks_geom {}".format(where))

            for i in bypass_doors:
                bricked_wall.append([[i['x0'],i['y0'],elevation], [i['x1'],i['y0'],elevation], [i['x1'],i['y1'],elevation], [i['x0'],i['y1'],elevation], [i['x0'],i['y0'],elevation]])

        bricked_wall+=self.json.readdb("obstacles")['obstacles'][self.floor]
        try:
            bricked_wall.append(self.json.readdb("obstacles")['fire'][self.floor])
        except:
            pass

        return bricked_wall

# }}}
    def _obj_platform(self):# {{{
        z=self.s.query("SELECT x0,y0,x1,y1 FROM aamks_geom WHERE type_pri='COMPA' AND floor=?", (self.floor,))
        platforms=[]
        for i in z:
            platforms.append([ (i['x1'], i['y1']), (i['x1'], i['y0']), (i['x0'], i['y0']), (i['x0'], i['y1']) ])
        return platforms

# }}}
    def _obj_elem(self,face,z):# {{{
        elem=''
        elem+="o Face{}\n".format(self._obj_num)
        for verts in face[:4]:
            elem+="v {}\n".format(" ".join([ str(i/100) for i in [verts[0], z, verts[1]]]))
        elem+="f {}\n\n".format(" ".join([ str(4*self._obj_num+i)+"//1" for i in [1,2,3,4]]))
        self._obj_num+=1
        return elem
# }}}
    def _obj_make(self,bypass_rooms):# {{{
        ''' 
        1. Create obj file from aamks geometries.
        2. Build navmesh with golang, obj is input
        3. Query navmesh with python
        4. bypass_rooms are the rooms excluded from navigation

        99 is the z-dim in cm

        '''

        z=self._bricked_wall(bypass_rooms)
        obj='';
        self._obj_num=0;
        for face in z:
            obj+=self._obj_elem(face,99)
        for face in self._obj_platform():
            obj+=self._obj_elem(face,0)
        
        path="{}/{}.obj".format(os.environ['AAMKS_PROJECT'], self.nav_name)
        with open(path, "w") as f: 
            f.write(obj)
        return path

# }}}
    def _chunks(self,l, n):# {{{
        """Yield successive n-sized chunks from l."""
        for i in range(0, len(l), n):
            yield l[i:i + n]
# }}}
    def _get_name(self,bypass_rooms=[]):# {{{
        brooms=''
        if len(bypass_rooms)>0:
            brooms="-"+"-".join(bypass_rooms)
        self.nav_name="{}{}.nav".format(self.floor,brooms)

# }}}

    def _hole_connected_rooms(self): # {{{
        ''' 
        room A may be hole-connected to room B which may be hole-connnected to
        room C and so on -- recursion
        '''

        if self._hole_count == len(self._hole_rooms):
            return 
        else:
            self._hole_count=len(self._hole_rooms)
            tt=copy.deepcopy(self._hole_rooms)
            for room in self._hole_rooms.keys():
                for i in self.s.query("SELECT vent_from_name,vent_to_name FROM aamks_geom WHERE type_sec='HOLE' AND (vent_from_name=? OR vent_to_name=?)", (room, room)):
                    tt[i['vent_from_name']]=1
                    tt[i['vent_to_name']]=1
            self._hole_rooms=copy.deepcopy(tt)
            return self._hole_connected_rooms()
# }}}
    def _room_exit_doors(self,room): # {{{
        ''' 
        An agents is found in room A. If room A is connected to room B via a
        hole, then we are looking for way out via doors in the "merged" AB
        room. 

        room A may be hole-connected to room B which may be hole-connnected to
        room C and so on, hence recursive _hole_connected_rooms() need to
        calculate _hole_rooms
        '''

        self._hole_rooms={room: 1}
        self._hole_count=0
        self._hole_connected_rooms()
        doors={}
        for rr in self._hole_rooms.keys():
            z=self.s.query("SELECT name, type_sec, x0, y0, x1, y1, center_x, center_y, is_vertical FROM aamks_geom WHERE type_sec='DOOR' AND (vent_from_name=? OR vent_to_name=?)", (rr, rr))
            for d in z:
                doors[d['name']]=d
        return list(doors.values())
# }}}
    def _move_dest_around_door(self,data):# {{{
        '''
        For the hole-connnected rooms the dest point must be calculated
        relative to the ROOM (inside, outside). It won't do relative to the
        EVACUEE position (left, right, above, below). 
        '''
        top_right=self.partition_query[self.floor].xy2room([data['door']['x1'], data['door']['y0']])

        #print(data['door']['name'], top_right, [data['door']['x1'], data['door']['y0']])
        if data['door']['is_vertical']==1:
            if top_right in self._hole_rooms.keys():
                dest=(data['door']['center_x'] - self.evacuee_radius*4, data['door']['center_y'])
            else:
                dest=(data['door']['center_x'] + self.evacuee_radius*4, data['door']['center_y'])
        else:
            if top_right in self._hole_rooms.keys():
                dest=(data['door']['center_x'], data['door']['center_y'] + self.evacuee_radius*4)
            else:
                dest=(data['door']['center_x'], data['door']['center_y'] - self.evacuee_radius*4)

        return dest
# }}}

    def _test_evacuees_pairs(self,evacuees):# {{{
        ddgeoms=DDgeoms()
        ddgeoms.open()
        for x,i in enumerate(evacuees):
            src=(i[0]['x0'], i[0]['y0'])
            dst=(i[1]['x0'], i[1]['y0'])
            color=self._test_colors[x] if x <= len(self._test_colors) else "#fff"
            ddgeoms.add({'floor': self.floor, 'type': 'circle', "g": { 'p0': src, "radius": 30 }, "style": { "fillColor": color , "opacity": 1 }})
            ddgeoms.add({'floor': self.floor, 'type': 'circle', "g": { 'p0': dst, "radius": 30 }, "style": { "fillColor": color , "opacity": 1 }})
            self.nav_plot_path(self.nav_query(src, dst, 300),ddgeoms,style={ 'strokeColor': color } )
        ddgeoms.write()
# }}}
    def _test_room_leaves(self,ee):# {{{
        ''' 
        radius=3.5 is the condition for the agent to reach the behind-doors target 
        '''

        ddgeoms=DDgeoms()
        ddgeoms.open()

        mm=self.room_leaves(ee)
        for dest in mm['all']:
            ddgeoms.add({'floor': self.floor, 'type': 'circle', "g": { "p0": dest[0], "radius": self.evacuee_radius*3.5 }, "style": { "fillColor": "#f80", "opacity": 0.3 }} )
            ddgeoms.add({'floor': self.floor, 'type': 'circle', "g": { "p0": dest[0], "radius": self.evacuee_radius*0.5 }, "style": { "fillColor": "#f80", "opacity": 0.5 }} )

        ddgeoms.add({'floor': self.floor, 'type': 'circle', "g": { "p0": mm['best_point'], "radius": self.evacuee_radius*3.5 }, "style": { "fillColor": "#f80", "opacity": 0.3 }} )
        ddgeoms.add({'floor': self.floor, 'type': 'circle', "g": { "p0": mm['best_point'], "radius": self.evacuee_radius*0.5 }, "style": { "fillColor": "#f80", "opacity": 0.5 }} )

        self.nav_plot_path(mm['best_path'], ddgeoms, style={ "strokeColor": "#f80", "strokeWidth": 6 } )
        ddgeoms.write()
Esempio n. 6
0
class Navmesh:
    def __init__(self):  # {{{
        ''' 
        installer/navmesh_installer.sh installs all the dependencies.

        * navmesh build from the obj geometry file
        thanks to https://github.com/arl/go-detour !

        * navmesh query
        thanks to https://github.com/layzerar/recastlib/ !

        ============================================

        This is how we are supposed to be called:

        nav=Navmesh()
        nav.build(floor)
        nav.query([(1300,600), (3100,1800)])

            or if you want to block r1 and r2 and have the navmeshes named

        navs=dict()
        navs[('r1','r2')]=Navmesh()
        navs[('r1','r2')].build(floor,('r1','r2'))
        navs[('r1','r2')].query([(1300,600), (3100,1800)])

        '''

        self.json = Json()
        self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        self.navmesh = OrderedDict()
# }}}

    def _bricked_wall(self, floor, bypass_rooms=[]):  # {{{
        '''
        For navmesh we may wish to turn some doors into bricks.
        '''

        bricked_wall = []

        if len(bypass_rooms) > 0:
            floors_meta = json.loads(
                self.s.query("SELECT json FROM floors_meta")[0]['json'])
            elevation = floors_meta[floor]['minz_abs']
            where = " WHERE "
            where += " vent_from_name=" + " OR vent_from_name=".join(
                ["'{}'".format(i) for i in bypass_rooms])
            where += " OR vent_to_name=" + " OR vent_to_name=".join(
                ["'{}'".format(i) for i in bypass_rooms])
            bypass_doors = self.s.query(
                "SELECT name,x0,y0,x1,y1 FROM aamks_geom {}".format(where))

            for i in bypass_doors:
                bricked_wall.append([[i['x0'], i['y0'], elevation],
                                     [i['x1'], i['y0'], elevation],
                                     [i['x1'], i['y1'], elevation],
                                     [i['x0'], i['y1'], elevation],
                                     [i['x0'], i['y0'], elevation]])

        bricked_wall += self.json.readdb("obstacles")['obstacles'][floor]
        try:
            bricked_wall.append(self.json.readdb("obstacles")['fire'][floor])
        except:
            pass

        return bricked_wall

# }}}

    def _obj_platform(self, floor):  # {{{
        z = self.s.query(
            "SELECT x0,y0,x1,y1 FROM aamks_geom WHERE type_pri='COMPA' AND floor=?",
            (floor, ))
        platforms = []
        for i in z:
            platforms.append([(i['x1'], i['y1']), (i['x1'], i['y0']),
                              (i['x0'], i['y0']), (i['x0'], i['y1'])])
        return platforms

# }}}

    def _obj_elem(self, face, z):  # {{{
        elem = ''
        elem += "o Face{}\n".format(self._obj_num)
        for verts in face[:4]:
            elem += "v {}\n".format(" ".join(
                [str(i / 100) for i in [verts[0], z, verts[1]]]))
        elem += "f {}\n\n".format(" ".join(
            [str(4 * self._obj_num + i) + "//1" for i in [1, 2, 3, 4]]))
        self._obj_num += 1
        return elem
# }}}

    def _obj_make(self, floor, bypass_rooms):  # {{{
        ''' 
        1. Create obj file from aamks geometries.
        2. Build navmesh with golang, obj is input
        3. Query navmesh with python
        4. bypass_rooms are the rooms excluded from navigation

        99 is the z-dim in cm

        '''

        z = self._bricked_wall(floor, bypass_rooms)
        obj = ''
        self._obj_num = 0
        for face in z:
            obj += self._obj_elem(face, 99)
        for face in self._obj_platform(floor):
            obj += self._obj_elem(face, 0)

        path = "{}/{}.obj".format(os.environ['AAMKS_PROJECT'], self.nav_name)
        with open(path, "w") as f:
            f.write(obj)
        return path

# }}}

    def _navmesh_vis(self, navmesh_paths, colors):  # {{{
        j = Json()
        z = j.read('{}/dd_geoms.json'.format(os.environ['AAMKS_PROJECT']))
        for cc, path in enumerate(navmesh_paths):
            for i, p in enumerate(path):
                try:
                    z[self.floor]['lines'].append({
                        "xy": (path[i][0], path[i][1]),
                        "x1":
                        path[i + 1][0],
                        "y1":
                        path[i + 1][1],
                        "strokeColor":
                        colors[cc],
                        "strokeWidth":
                        14,
                        "opacity":
                        0.5
                    })
                except:
                    pass

        j.write(z, '{}/dd_geoms.json'.format(os.environ['AAMKS_PROJECT']))
# }}}

    def _chunks(self, l, n):  # {{{
        """Yield successive n-sized chunks from l."""
        for i in range(0, len(l), n):
            yield l[i:i + n]
# }}}

    def _get_name(self, floor, bypass_rooms=[]):  # {{{
        brooms = ''
        if len(bypass_rooms) > 0:
            brooms = "-" + "-".join(bypass_rooms)
        self.nav_name = "{}{}.nav".format(floor, brooms)

# }}}

    def test(self):  # {{{
        agents_pairs = 6
        colors = [
            "#f80", "#f00", "#8f0", "#08f", "#f0f", "#f8f", "#0ff", "#ff0"
        ]
        navmesh_paths = []

        z = self.json.read('{}/dd_geoms.json'.format(
            os.environ['AAMKS_PROJECT']))
        evacuees = self.s.query(
            "SELECT x0,y0 FROM aamks_geom WHERE type_pri='EVACUEE' AND floor=? ORDER BY global_type_id LIMIT ?",
            (self.floor, agents_pairs * 2))
        for x, i in enumerate(self._chunks(evacuees, 2)):
            p0 = (i[0]['x0'], i[0]['y0'])
            p1 = (i[1]['x0'], i[1]['y0'])
            z[self.floor]['circles'].append({
                "xy": p0,
                "radius": 30,
                "fillColor": colors[x],
                "opacity": 1
            })
            z[self.floor]['circles'].append({
                "xy": p1,
                "radius": 30,
                "fillColor": colors[x],
                "opacity": 1
            })
            navmesh_paths.append(self.query((p0, p1), 300))
        self.json.write(z,
                        '{}/dd_geoms.json'.format(os.environ['AAMKS_PROJECT']))
        self._navmesh_vis(navmesh_paths, colors)
        Vis({
            'highlight_geom': None,
            'anim': None,
            'title': 'Nav {} test'.format(self.nav_name),
            'srv': 1
        })
# }}}

    def build(self, floor, bypass_rooms=[]):  # {{{
        self.floor = floor
        self.bypass_rooms = bypass_rooms
        self._get_name(floor, bypass_rooms)
        file_obj = self._obj_make(floor, bypass_rooms)
        file_nav = "{}/{}".format(os.environ['AAMKS_PROJECT'], self.nav_name)
        file_conf = "{}/recast.yml".format(os.environ['AAMKS_PROJECT'])
        with open(file_conf, "w") as f:
            f.write('''\
            cellsize: 0.10
            cellheight: 0.2
            agentheight: 2
            agentradius: 0.30
            agentmaxclimb: 0.1
            agentmaxslope: 45
            regionminsize: 8
            regionmergesize: 20
            edgemaxlen: 12
            edgemaxerror: 1.3
            vertsperpoly: 6
            detailsampledist: 6
            detailsamplemaxerror: 1
            partitiontype: 1
            tilesize: 0
            ''')
        subprocess.call(
            "rm -rf {}; recast --config {} --input {} build {} 1>/dev/null 2>/dev/null"
            .format(file_nav, file_conf, file_obj, file_nav),
            shell=True)

        try:
            self.NAV = dt.dtLoadSampleTileMesh(file_nav)
        except:
            raise SystemExit("Navmesh: cannot create {}".format(file_nav))
# }}}

    def query(self, q, maxStraightPath=16):  # {{{
        '''
        ./Detour/Include/DetourNavMeshQuery.h: maxStraightPath: The maximum number of points the straight path arrays can hold.  [Limit: > 0]
        We set maxStraightPath to a default low value which stops calculations early
        If one needs to get the full path to the destination one must call us with any high value, e.g. 999999999
        '''

        filtr = dt.dtQueryFilter()
        query = dt.dtNavMeshQuery()

        status = query.init(self.NAV, 2048)
        if dt.dtStatusFailed(status):
            return "err", -1, status

        polyPickExt = dt.dtVec3(2.0, 4.0, 2.0)
        startPos = dt.dtVec3(q[0][0] / 100, 1, q[0][1] / 100)
        endPos = dt.dtVec3(q[1][0] / 100, 1, q[1][1] / 100)

        status, out = query.findNearestPoly(startPos, polyPickExt, filtr)
        if dt.dtStatusFailed(status):
            return "err", -2, status
        startRef = out["nearestRef"]
        _startPt = out["nearestPt"]

        status, out = query.findNearestPoly(endPos, polyPickExt, filtr)
        if dt.dtStatusFailed(status):
            return "err", -3, status
        endRef = out["nearestRef"]
        _endPt = out["nearestPt"]

        status, out = query.findPath(startRef, endRef, startPos, endPos, filtr,
                                     maxStraightPath)
        if dt.dtStatusFailed(status):
            return "err", -4, status
        pathRefs = out["path"]

        status, fixEndPos = query.closestPointOnPoly(pathRefs[-1], endPos)
        if dt.dtStatusFailed(status):
            return "err", -5, status

        status, out = query.findStraightPath(startPos, fixEndPos, pathRefs,
                                             maxStraightPath, 0)
        if dt.dtStatusFailed(status):
            return "err", -6, status
        straightPath = out["straightPath"]
        straightPathFlags = out["straightPathFlags"]
        straightPathRefs = out["straightPathRefs"]

        path = []
        for i in straightPath:
            path.append((i[0] * 100, i[2] * 100))

        if path[0] == "err":
            return None
        else:
            return path
# }}}

    def closest_terminal(self, p0, exit_type):  # {{{
        '''
        The shortest polyline defines the closest exit from the floor. 
        dist < 10 test asserts the polyline has min 2 distinct points.

        exit_type: primary | secondary | any
        '''

        if exit_type in ['primary', 'secondary']:
            r = self.s.query(
                "SELECT name,center_x,center_y FROM aamks_geom WHERE terminal_door=? AND floor=?",
                (exit_type, self.floor))
        else:
            r = self.s.query(
                "SELECT name,center_x,center_y FROM aamks_geom WHERE terminal_door IS NOT NULL AND floor=?",
                (self.floor, ))
        m = {}
        closest = {'len': 999999999, 'name': None, 'x': None, 'y': None}
        for i in r:
            if abs(i['center_x'] - p0[0]) < 10 and abs(i['center_y'] -
                                                       p0[1]) < 10:
                closest = {
                    'name': i['name'],
                    'x': i['center_x'],
                    'y': i['center_y'],
                    'len': 0
                }
                return closest
            ll = LineString(
                self.query((p0, (i['center_x'], i['center_y'])), 300)).length
            if ll < closest['len']:
                closest = {
                    'name': i['name'],
                    'x': i['center_x'],
                    'y': i['center_y'],
                    'len': int(ll)
                }
        return closest

# }}}

    def closest_room_escape(self, p0, room):  # {{{
        '''
        Evacuee finds himself in a room with smoke and needs to leave urgently
        '''

        r = self.s.query(
            "SELECT name,center_x,center_y FROM aamks_geom WHERE (vent_from_name=? OR vent_to_name=?) AND floor=?",
            (room, room, self.floor))
        m = {}
        closest = {'len': 999999999, 'name': None, 'x': None, 'y': None}
        for i in r:
            if abs(i['center_x'] - p0[0]) < 10 and abs(i['center_y'] -
                                                       p0[1]) < 10:
                closest = {
                    'name': i['name'],
                    'x': i['center_x'],
                    'y': i['center_y'],
                    'len': 0
                }
                return closest
            ll = sqrt((i['center_x'] - p0[0])**2 + (i['center_y'] - p0[1])**2)
            if ll < closest['len']:
                closest = {
                    'name': i['name'],
                    'x': i['center_x'],
                    'y': i['center_y'],
                    'len': int(ll)
                }
        return closest
Esempio n. 7
0
class EvacEnv:
    def __init__(self):  # {{{
        self.Que = Staircase(floors=9)
        self.json = Json()
        self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))

        self.evacuee_radius = self.json.read("{}/inc.json".format(
            os.environ['AAMKS_PATH']))['evacueeRadius']
        time = 1
        #self.sim rvo2.PyRVOSimulator TIME_STEP , NEIGHBOR_DISTANCE , MAX_NEIGHBOR , TIME_HORIZON , TIME_HORIZON_OBSTACLE , RADIUS , MAX_SPEED
        self.sim = rvo2.PyRVOSimulator(time, 40, 5, time, time,
                                       self.evacuee_radius, 30)
        self._anim = {
            "simulation_id": 1,
            "simulation_time": 20,
            "time_shift": 0,
            "animations": {
                "evacuees": [],
                "rooms_opacity": []
            }
        }
        self._create_agents()
        self._load_obstacles()
        Vis({
            'highlight_geom': None,
            'anim': '1/f1.zip',
            'title': 'x',
            'srv': 1
        })
        self.waitings = {}

# }}}

    def _create_agents(self):  # {{{
        #self.s.query("INSERT INTO aamks_geom (name, type_pri, x0, y0) VALUES ('f500', 'EVACUEE', '690', '2300')")
        z = self.s.query("SELECT * FROM aamks_geom WHERE type_pri='EVACUEE'")
        self.agents = {}
        for i in z:
            aa = i['name']
            self.agents[aa] = {}
            ii = self.sim.addAgent((i['x0'], i['y0']))
            self.agents[aa]['name'] = aa
            self.agents[aa]['id'] = ii
            self.sim.setAgentPrefVelocity(ii, (0, 0))
            self.agents[aa]['behaviour'] = 'random'
            self.agents[aa]['origin'] = (i['x0'], i['y0'])
            if int(aa[1:]) < 105:
                self.agents[aa]['target'] = (1010, i['y0'])
            else:
                self.agents[aa]['target'] = (2530, i['y0'])
        self._positions()
# }}}

    def _load_obstacles(self):  # {{{
        z = self.json.readdb('obstacles')
        obstacles = z['obstacles']['0']
        for i in obstacles:
            self.sim.addObstacle([(o[0], o[1]) for o in i[:4]])
            self.sim.processObstacles()
# }}}

    def _velocity(self, a):  # {{{
        '''
        radius=3.5 is the condition for the agent to reach the behind-doors target 
        '''

        dx = a['target'][0] - self.sim.getAgentPosition(a['id'])[0]
        dy = a['target'][1] - self.sim.getAgentPosition(a['id'])[1]
        self.sim.setAgentPrefVelocity(a['id'], (dx, dy))
        if abs(dx) < 60:
            if self.sim.getAgentPosition(a['id'])[1] < 300:
                floor = 8
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 340 and self.sim.getAgentPosition(
                        a['id'])[1] < 640:
                floor = 7
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 680 and self.sim.getAgentPosition(
                        a['id'])[1] < 980:
                floor = 6
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 1020 and self.sim.getAgentPosition(
                        a['id'])[1] < 1320:
                floor = 5
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 1360 and self.sim.getAgentPosition(
                        a['id'])[1] < 1660:
                floor = 4
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 1700 and self.sim.getAgentPosition(
                        a['id'])[1] < 2000:
                floor = 3
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 2040 and self.sim.getAgentPosition(
                        a['id'])[1] < 2340:
                floor = 2
            elif self.sim.getAgentPosition(
                    a['id'])[1] > 2380 and self.sim.getAgentPosition(
                        a['id'])[1] < 2680:
                floor = 1
            else:
                floor = 0
            try:
                if (a['name'], a['id']) not in self.waitings[floor]:
                    self.waitings[floor].append((a['name'], a['id']))
            except:
                self.waitings.setdefault(floor, []).append(
                    (a['name'], a['id']))
        return sqrt(dx**2 + dy**2)
# }}}

    def _positions(self):  # {{{
        frame = []
        for k, v in self.agents.items():
            if self.Que.check_if_in(v['id']):
                pos = self.Que.check_if_in(v['id'])
            else:
                pos = [round(i) for i in self.sim.getAgentPosition(v['id'])]
            frame.append([pos[0], pos[1], 0, 0, "N", 1])
        self._anim["animations"]["evacuees"].append({"0": frame})
# }}}

    def _update(self):  # {{{
        for k, v in self.agents.items():
            target_dist = self._velocity(self.agents[k])
            if target_dist <= self.evacuee_radius * 3.5:
                #dd(self.agents[k]['id'], target_dist)
                pass
                #exit()
        self._positions()


# }}}

    def _write_zip(self):  # {{{
        d = "{}/workers/1".format(os.environ['AAMKS_PROJECT'])
        #dd(self._anim['animations']['evacuees'])

        zf = zipfile.ZipFile("{}/f1.zip".format(d), 'w')
        zf.writestr("anim.json", json.dumps(self._anim))
        zf.close()  # }}}
        #self.json.write(self._anim, "/home/mateusz/Pulpit/praca/anim3.json")
    def _add_to_staircase(self):  # {{{
        try:
            for floor in sorted(self.waitings.keys()):
                #print(floor, len(self.waitings[floor]))
                #liczba oczekujących na danym piętrze
                agentname, agentid = self.waitings[floor][0]
                if self.Que.add_to_queues(floor, agentid):
                    #self.agents[agentname]['target']=(19750, 3570)
                    #self.sim.setAgentPosition(agentid, (1750,3570))
                    self.agents[agentname]['target'] = (19750, 3570)
                    self.sim.setAgentPosition(agentid, (3750, 3570))
                    del self.waitings[floor][0]
                    if len(self.waitings[floor]) == 0:
                        del self.waitings[floor]
        except:
            pass  # }}}

    def _run(self):  # {{{
        x = []  #krok
        y = []  #prędkość w klatce
        xx = []  #gęstość
        yyy = []
        ay = []  #prędkość w klatce i poza
        done = []
        done2 = []
        donex = []
        for t in range(550):
            self.sim.doStep()
            self._update()
            self._add_to_staircase()
            donex.append(t)

            K = [copy.deepcopy(k.counter) for k in self.Que.ques]
            wszyscy = self.Que.total_number_of_people()
            done.append(wszyscy)
            done2.append(self.Que.total_completed())
            wszyscy2 = 0
            for i in self.waitings.values():
                wszyscy2 += len(i)

            self.Que.move()

            J = [j.counter for j in self.Que.ques]
            krok = 0
            stop = 0
            for i in range(len(K)):
                krok += len([
                    x[0] for x, y in zip(K[i].items(), J[i].items())
                    if x[1][2] != y[1][2] and len(y[1]) < 4
                ])
                krok += len([
                    x for x, y in zip(K[i].items(), J[i].items())
                    if len(x[1]) != len(y[1])
                ])
                stop += len([
                    x[0] for x, y in zip(K[i].items(), J[i].items())
                    if x[1][2] == y[1][2] and len(y[1]) < 4
                ])
            if wszyscy > 0:
                a = self.Que.density2(wszyscy)
                xx.append(a)
                y.append(round(krok / wszyscy * 100, 2))
                x.append(t)
                ay.append(round(krok / (wszyscy + wszyscy2) * 100, 2))
                #yy = 0.42*(1/a)**(1/3)
                #yyy.append(yy)
            if wszyscy == 0 and t > 100:
                break
Esempio n. 8
0
class EvacEnv:
    def __init__(self):  # {{{
        self.json = Json()
        self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))

        self.evacuee_radius = self.json.read("{}/inc.json".format(
            os.environ['AAMKS_PATH']))['evacueeRadius']
        time = 1
        #self.sim rvo2.PyRVOSimulator TIME_STEP , NEIGHBOR_DISTANCE , MAX_NEIGHBOR , TIME_HORIZON , TIME_HORIZON_OBSTACLE , RADIUS , MAX_SPEED
        self.sim = rvo2.PyRVOSimulator(time, 40, 5, time, time,
                                       self.evacuee_radius, 30)
        self.door1 = 'd10'
        self.door2 = (6100, 2100)
        self._create_teleports()
        self._create_agents()
        self._load_obstacles()
        self._anim = {
            "simulation_id": 1,
            "simulation_time": 20,
            "time_shift": 0,
            "animations": {
                "evacuees": [],
                "rooms_opacity": []
            }
        }
        self._run()
        self._write_zip()
        Vis({
            'highlight_geom': None,
            'anim': '1/f1.zip',
            'title': 'x',
            'srv': 1
        })

# }}}

    def _create_teleports(self):  # {{{
        '''
        TODO: non-multifloor stairacases cause the need to try/except here. 
        geom.py should handle sX.Y naming better.
        '''
        self._teleport_from = {}
        for i in self.s.query(
                "SELECT name,center_x,center_y,vent_to_name  FROM world2d WHERE vent_to_name LIKE 's%'"
        ):
            target = i['vent_to_name'].replace(".", "|")
            tt = self.s.query("SELECT x0,y0 FROM world2d WHERE name=?",
                              (target, ))
            try:
                #self._teleport_from[(i['name'], (i['center_x'], i['center_y']), i['vent_to_name'])]=(target, (tt[0]['x0'], tt[0]['y0']))
                self._teleport_from[i['name']] = (target,
                                                  (tt[0]['x0'] +
                                                   self.evacuee_radius * 2,
                                                   tt[0]['y0'] +
                                                   self.evacuee_radius * 2))
            except:
                pass
        #dd(self._teleport_from)
# }}}

    def _positions(self):  # {{{
        frame = []
        for k, v in self.agents.items():
            pos = [round(i) for i in self.sim.getAgentPosition(v['id'])]
            frame.append([pos[0], pos[1], 0, 0, "N", 1])
            #print(k,",t:", self.sim.getGlobalTime(), ",pos:", pos, ",v:", [ round(i) for i in self.sim.getAgentVelocity(v['id'])])
        self._anim["animations"]["evacuees"].append(frame)
# }}}

    def _create_agents(self):  # {{{
        door = self.s.query(
            "SELECT center_x, center_y  FROM world2d WHERE name=?",
            (self.door1, ))[0]
        z = self.s.query("SELECT * FROM world2d WHERE type_pri='EVACUEE'")
        self.agents = {}
        for i in z:
            aa = i['name']
            self.agents[aa] = {}
            ii = self.sim.addAgent((i['x0'], i['y0']))
            self.agents[aa]['name'] = aa
            self.agents[aa]['id'] = ii
            self.sim.setAgentPrefVelocity(ii, (200, 0))
            self.agents[aa]['behaviour'] = 'random'
            self.agents[aa]['target'] = (door['center_x'], door['center_y'])
# }}}

    def _load_obstacles(self):  # {{{
        obstacles = self.json.readdb('world2d_obstacles')['points']
        for i in obstacles:
            self.sim.addObstacle([(o[0], o[1]) for o in i[:4]])
            self.sim.processObstacles()
# }}}

    def _velocity(self, a):  # {{{
        x = a['target'][0] - self.sim.getAgentPosition(a['id'])[0]
        y = a['target'][1] - self.sim.getAgentPosition(a['id'])[1]
        if abs(x) + abs(y) < 30:
            self.sim.setAgentPosition(a['id'],
                                      self._teleport_from[self.door1][1])
            a['target'] = self.door2
        else:
            self.sim.setAgentPrefVelocity(a['id'], (x, y))

# }}}

    def _update(self):  # {{{
        for k, v in self.agents.items():
            self._velocity(self.agents[k])
        self._positions()
# }}}

    def _write_zip(self):  # {{{
        d = "{}/workers/1".format(os.environ['AAMKS_PROJECT'])

        zf = zipfile.ZipFile("{}/f1.zip".format(d), 'w')
        zf.writestr("anim.json", json.dumps(self._anim))
        zf.close()
# }}}

    def _run(self):  # {{{
        for t in range(100):
            self.sim.doStep()
            self._update()
Esempio n. 9
0
class CfastPartition():
    def __init__(self, verbose=0): # {{{
        ''' 
        Divide space into cells for smoke conditions queries asked by evacuees.
        A cell may be a square or a rectangle. First divide space into squares
        of self._square_side. Iterate over squares and if any square is crossed by an
        obstacle divide this square further into rectangles. 
        
        In the final structure of partition.json we encode each cell.
        Each cell is sorted by x, which allows quick bisections.

        * In each cell we always encode the first sub-cell - the square itself.
        (2000, 2449): OrderedDict([('x', (2000,)), ('y', (2449,))])

        * Then we can add more sub-cells (rectangles).
        (1600, 2449): OrderedDict([('x', (1600, 1600, 1842, 1842)), ('y', (2449, 2541, 2449, 2541))])

        Partition will be later used for filling the cells with smoke
        conditions. Finally we get a tool for quick altering of the state of an
        evacuee at x,y.

        '''

        self._square_side=300
        self.s=Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        try:
            self.s.query("DROP TABLE cell2compa")
            self.s.query("DROP TABLE query_vertices")
        except:
            pass
        self.s.query("CREATE TABLE cell2compa(json)")
        self.s.query("CREATE TABLE query_vertices(json)")

        self.json=Json() 
        self._cell2compa=OrderedDict()
        self._save=OrderedDict()
        floors=self.json.readdb("floors_meta")
        for floor in floors.keys():
            self._init_space(floor) 
            self._intersect_space() 
            self._optimize(floor)
            self._make_cell2compa(floor)
            if(verbose==1):
                self._plot_space(floor)  # debug
        if(verbose==1):
            Vis(None, 'image', 'partition') # debug
        self._dbsave()
# }}}
    def _init_space(self,floor):# {{{
        ''' Divide floor into squares. Prepare empty rectangles placeholders. '''

        floors=self.json.readdb("floors_meta")
        fdims=floors[floor]

        self.squares=OrderedDict()
        self.rectangles=OrderedDict()
        self.lines=[]

        for i in self.s.query("SELECT * FROM aamks_geom WHERE type_pri='COMPA' AND floor=? ORDER BY x0,y0", (floor,)):
            self.lines.append(LineString([ Point(i['x0'],i['y0']), Point(i['x0'], i['y1'])] ))
            self.lines.append(LineString([ Point(i['x0'],i['y0']), Point(i['x1'], i['y0'])] ))
            self.lines.append(LineString([ Point(i['x1'],i['y1']), Point(i['x0'], i['y1'])] ))
            self.lines.append(LineString([ Point(i['x1'],i['y1']), Point(i['x1'], i['y0'])] ))

        x=int(fdims['xdim']/self._square_side)+1
        y=int(fdims['ydim']/self._square_side)+1
        for v in range(y):
            for i in range(x):
                x_=fdims['minx']+self._square_side*i
                y_=fdims['miny']+self._square_side*v
                xy=(x_, y_)
                self.squares[xy]=box(x_, y_, x_+self._square_side, y_+self._square_side)
                self.rectangles[xy]=[]
# }}}
    def _candidate_intersection(self,id_,points):# {{{
        ''' 
        So there's an intersection "points" of the square and the walls of the
        room. We get 2 points in this call. Should we create a rectangle of any
        of these points? The rectangle is defined by it's (minX,minY) vertex.
        We only accept the points that belong to the square but don't lie on
        the maxX (right) and maxY (top) edges. 
        '''

        right_limit=id_[0]+self._square_side
        top_limit=id_[1]+self._square_side
        for pt in list(zip(points.xy[0], points.xy[1])):
            if right_limit != pt[0] and top_limit != pt[1]:
                self.rectangles[id_].append((int(pt[0]), int(pt[1])))
# }}}
    def _optimize(self, floor):# {{{
        ''' 
        * self.squares (collection of shapely boxen) is not needed anymore
        * self.rectangles must have duplicates removed and must be sorted by x
        * xy_vectors must be of the form: [ [x0,x1,x2,x3], [y0,y1,y2,y3] ]. 

        self._query_vertices are of the form:

        square        : optimized rectangles 
        (1000 , -1000): OrderedDict([('x' , (1000 , 1100)) , ('y' , (-1000 , -1000))])
        (1400 , -1000): OrderedDict([('x' , (1400 , 1500)) , ('y' , (-1000 , -1000))])
        (1800 , -1000): OrderedDict([('x' , (1800 , ))     , ('y' , (-1000 , ))])
        (2200 , -1000): OrderedDict([('x' , (2200 , ))     , ('y' , (-1000 , ))])
        '''

        del(self.squares)

        for id_,rects in self.rectangles.items():
            rects.append(id_)
            self.rectangles[id_]=list(sorted(set(rects)))

        self._query_vertices=OrderedDict()
        for id_,v in self.rectangles.items():
            self._query_vertices[id_]=OrderedDict()
            xy_vectors=list(zip(*self.rectangles[id_]))
            try:
                self._query_vertices[id_]['x']=xy_vectors[0]
                self._query_vertices[id_]['y']=xy_vectors[1]
            except:
                self._query_vertices[id_]['x']=()
                self._query_vertices[id_]['y']=()

        self._save[floor]=OrderedDict()
        self._save[floor]['square_side']=self._square_side
        self._save[floor]['query_vertices']=OrderedDict()
        for k,v in self._query_vertices.items():
            cell_str="{}x{}".format(k[0], k[1])
            self._save[floor]['query_vertices'][cell_str]=v
# }}}
    def _intersect_space(self):# {{{
        ''' 
        We want to further partition the square into rectangles based on obstacles.
        '''

        for line in self.lines: 
            for id_,square in self.squares.items():
                if square.intersects(line):
                    points=square.intersection(line)
                    if points.length>0:
                        self._candidate_intersection(id_,points)
        
# }}}
    def _plot_space(self,floor):# {{{
        ''' 
        Plots the partition on top of the rooms. 
        '''

        z=self.json.read('{}/dd_geoms.json'.format(os.environ['AAMKS_PROJECT']))

        radius=5
        a=self._square_side
        for k,v in self.rectangles.items():
            z[floor]['rectangles'].append( { "xy": k, "width": a , "depth": a , "strokeColor": "#f80" , "strokeWidth": 2 , "opacity": 0.2 } )
            z[floor]['circles'].append(    { "xy": k, "radius": radius , "fillColor": "#fff", "opacity": 0.3 } )
            z[floor]['texts'].append(      { "xy": k, "content": k, "fontSize": 5, "fillColor":"#f0f", "opacity":0.7 })
            for mm in v:
                z[floor]['circles'].append( { "xy": mm, "radius": radius, "fillColor": "#fff", "opacity": 0.3 } )
                z[floor]['texts'].append(   { "xy": mm, "content": mm, "fontSize": 5, "fillColor":"#f0f", "opacity":0.7 })
        self.json.write(z, '{}/dd_geoms.json'.format(os.environ['AAMKS_PROJECT']))
# }}}

    def _make_cell2compa_record(self,cell,floor):# {{{
        cell_str="{}x{}".format(cell[0], cell[1])
        try:
            self._cell2compa[floor][cell_str]=self.s.query("SELECT name from aamks_geom WHERE floor=? AND type_pri='COMPA' AND ?>=x0 AND ?>=y0 AND ?<x1 AND ?<y1", (floor, cell[0], cell[1], cell[0], cell[1]))[0]['name']
        except:
            pass
# }}}
    def _make_cell2compa(self,floor):#{{{
        self._cell2compa[floor]=OrderedDict()
        for k,v in self._query_vertices.items():
            self._make_cell2compa_record(k,floor)
            for pt in list(zip(v['x'], v['y'])):
                self._make_cell2compa_record(pt,floor)
#}}}

    def _dbsave(self):# {{{
        self.s.query('INSERT INTO cell2compa VALUES (?)'     , (json.dumps(self._cell2compa),))
        self.s.query('INSERT INTO query_vertices VALUES (?)' , (json.dumps(self._save),))
Esempio n. 10
0
class World2d():
    ''' World2d is a display of all floors in a single 2d world '''
    def __init__(self):  # {{{
        self.json = Json()
        self.conf = self.json.read("{}/conf.json".format(
            os.environ['AAMKS_PROJECT']))
        self.world_meta = self.json.readdb("world_meta")
        self.s = Sqlite("{}/aamks.sqlite".format(os.environ['AAMKS_PROJECT']))
        self.floors_meta = self.json.readdb("floors_meta")
        self.floors = self.floors_meta.keys()
        self.walls_width = self.world_meta['walls_width']
        self.projections = {'top': dict(), 'side': dict()}
        self._top_projection_make()
        self._top_proj_lines()
        self._meta_translate_y()
        self._world2d_boundaries()
# }}}

    def _top_projection_make(self):  # {{{
        '''
        In world2d we have top and left projections
        '''

        self.projections['top']['padding_rectangle'] = 300
        self.projections['top']['padding_vertical'] = 200
        self.projections['top']['x0'] = self.s.query(
            "SELECT min(x0) AS m FROM aamks_geom"
        )[0]['m'] - self.projections['top']['padding_rectangle']
        self.projections['top']['x1'] = self.s.query(
            "SELECT max(x1) AS m FROM aamks_geom")[0]['m']
# }}}

    def _top_proj_lines(self):  # {{{
        '''
        Helper horizontal lines for Animator: 2, 1, 0
        '''

        lines = OrderedDict()
        absolute = 0
        for floor in list(self.floors_meta.keys())[::-1]:
            if absolute == 0:
                lines[floor] = absolute + self.floors_meta[floor][
                    'ydim'] + self.projections['top']['padding_vertical']
            else:
                lines[floor] = absolute + self.floors_meta[floor][
                    'ydim'] + self.projections['top']['padding_vertical'] * 2
            absolute = lines[floor]
        self.projections['top']['lines'] = lines

# }}}

    def _meta_translate_y(self):  # {{{
        '''
        Calculate translateY (ty). Animator needs this meta info to dynamicaly
        merge floors in world2d view. At some point we will probably introduce
        tx for staircases. 
        '''

        floors_meta = self.json.readdb("floors_meta")

        for floor, line in self.projections['top']['lines'].items():
            self.floors_meta[floor]['ty'] = line - self.projections['top'][
                'padding_vertical'] - self.floors_meta[floor]['maxy']
            self.floors_meta[floor]['tx'] = 0
        self.s.query("UPDATE floors_meta SET json=?",
                     (json.dumps(self.floors_meta), ))

# }}}

    def _world2d_boundaries(self):  # {{{
        m = {}
        m['minx'] = 99999999999
        m['miny'] = 99999999999
        m['maxx'] = -99999999999
        m['maxy'] = -99999999999
        for floor, meta in self.json.readdb("floors_meta").items():
            m['minx'] = min(m['minx'], meta['minx'] + meta['tx'])
            m['miny'] = min(m['miny'], meta['miny'] + meta['ty'])
            m['maxx'] = max(m['maxx'], meta['maxx'] + meta['tx'])
            m['maxy'] = max(m['maxy'], meta['maxy'] + meta['ty'])

        m['xdim'] = m['maxx'] - m['minx']
        m['ydim'] = m['maxy'] - m['miny']
        m['center'] = [
            round(m['minx'] + m['xdim'] / 2),
            round(m['miny'] + m['ydim'] / 2), 0
        ]

        self.world_meta['world2d'] = m
        self.s.query("UPDATE world_meta SET json=?",
                     (json.dumps(self.world_meta), ))