diff --git a/navipy/database/__init__.py b/navipy/database/__init__.py index abeb5ad155bf9cd5e024a90b93426617e3c844bf..431b5253ef1203a851fc0c4c7ddf020779b2a4a6 100644 --- a/navipy/database/__init__.py +++ b/navipy/database/__init__.py @@ -7,10 +7,10 @@ import numpy as np import pandas as pd import sqlite3 import io -import warnings from navipy.scene import is_numeric_array, check_scene import navipy.maths.constants as mconst from navipy.tools.trajectory import Trajectory +from navipy.scene import __spherical_indeces__ import logging @@ -151,12 +151,12 @@ class DataBase(): self._logger.exception(msg) raise NameError(msg) - azimuth = np.linspace(-180, 180, 360) - elevation = np.linspace(-90, 90, 180) + azimuth = np.deg2rad(np.linspace(-180, 180, 360)) + elevation = np.deg2rad(np.linspace(-90, 90, 180)) [ma, me] = np.meshgrid(azimuth, elevation) self.viewing_directions = np.zeros((ma.shape[0], ma.shape[1], 2)) - self.viewing_directions[..., 0] = me - self.viewing_directions[..., 1] = ma + self.viewing_directions[..., __spherical_indeces__['elevation']] = me + self.viewing_directions[..., __spherical_indeces__['azimuth']] = ma def table_exist(self, tablename): """ @@ -465,6 +465,7 @@ class DataBaseLoad(DataBase): R,G,B or D (Distance)' self._logger.exception(msg) raise ValueError(msg) + self.__convention = None @property def create(self): @@ -491,6 +492,35 @@ class DataBaseLoad(DataBase): toyield.drop('id', inplace=True) yield toyield + @property + def rotation_convention(self): + """ Return the convention in the database + + The database can technically contains more than one convention. + Although it is discourage to do so, it is not forbidden. + + If more than one convention is found in the database, this function + will issue awarning when more than one convention is present in the database. + """ + posorient = pd.read_sql_query( + "select * from position_orientation;", self.db) + posorient.set_index('id', inplace=True) + if self.__convention is None: + if 'rotconv_id' in posorient.columns: + rotconv = posorient.loc[:, 'rotconv_id'] + if np.all(rotconv == rotconv.iloc[0]): + self.__convention = rotconv + else: + self._logger.warning( + 'More than one convention have been found in database') + self.__convention = None + else: + self._logger.warning("you are loading a database with old\ + conventions, it will be transformed\ + automatically into the new one") + self.__convention = 'rxyz' + return self.__convention + @property def posorients(self): """Return the position orientations of all points in the \ @@ -501,20 +531,9 @@ class DataBaseLoad(DataBase): posorient = pd.read_sql_query( "select * from position_orientation;", self.db) posorient.set_index('id', inplace=True) - if 'rotconv_id' in posorient.columns: - rotconv = posorient.loc[:, 'rotconv_id'] - if np.all(rotconv == rotconv.iloc[0]): - posorients = Trajectory( - rotconv.iloc[0], indeces=posorient.index) - posorients.from_dataframe(posorient) - else: - posorients = posorient - else: - warnings.warn("you are loading a database with old\ - conventions, it will be transformed\ - automatically into the new one") + if self.rotation_convention is not None: posorients = Trajectory() - posorients.from_dataframe(posorient, rotconv='rxyz') + posorients.from_dataframe(posorient, rotconv=self.__convention) return posorients @property diff --git a/navipy/models/hafner_2000.py b/navipy/models/hafner_2000.py index 4e72a80611e84f07dae822323f49333a6a55d3e2..3c94b921d17c379fc4430e082c89fd6b27524b1c 100644 --- a/navipy/models/hafner_2000.py +++ b/navipy/models/hafner_2000.py @@ -1,6 +1,8 @@ from navipy import Brain from navipy.processing.pcode import apcv, skyline import pandas as pd +import numpy as np +from navipy.scene import __spherical_indeces__ # 0) Define a class heriting from Brain @@ -24,8 +26,10 @@ def processing(scene, viewing_directions, channel): scene[..., 3, :] = 1/scene[..., 3, :] # Calculate the skyline scene = skyline(scene) - - comanv = apcv(scene, viewing_directions) + # skyline viewing direction + viewdir = viewing_directions[1, ...][np.newaxis, ...] + viewdir[..., __spherical_indeces__['elevation']] = 0 + comanv = apcv(scene, viewdir) return comanv[..., channel, :] @@ -34,6 +38,7 @@ def comparing(current, memory): homing vector = current vector - memory vector """ + return current-memory class ASVBrain(Brain): @@ -53,9 +58,10 @@ class ASVBrain(Brain): self.vision.viewing_directions, self.channel) homing_vector = comparing(current, self.memory) + homing_vector = np.squeeze(homing_vector) indeces = [('location', 'dx'), ('location', 'dy'), ('location', 'dz'), (convention, 'dalpha_0'), (convention, 'dalpha_1'), (convention, 'dalpha_2')] velocity = pd.Series(data=0, index=pd.MultiIndex.from_tuples(indeces)) - velocity['location'] = homing_vector + velocity.loc['location'] = homing_vector return velocity diff --git a/navipy/moving/agent.py b/navipy/moving/agent.py index baa501a962b92702d257ac483165d9531363d27c..0c4775cf34c9da016efae9c6f380156ed5f65675 100644 --- a/navipy/moving/agent.py +++ b/navipy/moving/agent.py @@ -28,6 +28,7 @@ import multiprocessing from multiprocessing import Queue, JoinableQueue, Process import inspect import navipy.moving.maths as navimomath +from navipy.database import DataBaseLoad version = float(nx.__version__) @@ -52,25 +53,33 @@ class AbstractAgent(): def __init__(self, convention='rzyx'): self._brain = DefaultBrain() self._alter_posorientvel = defaultcallback - tuples = [('location', 'x'), ('location', 'y'), - ('location', 'z'), (convention, 'alpha_0'), - (convention, 'alpha_1'), (convention, 'alpha_2')] + tuples = [('location', 'x'), + ('location', 'y'), + ('location', 'z'), + (convention, 'alpha_0'), + (convention, 'alpha_1'), + (convention, 'alpha_2')] index = pd.MultiIndex.from_tuples(tuples, names=['position', 'orientation']) self._posorient_col = index - tuples_vel = [('location', 'x'), ('location', 'y'), - ('location', 'z'), (convention, 'alpha_0'), - (convention, 'alpha_1'), (convention, 'alpha_2'), - ('location', 'dx'), ('location', 'dy'), - ('location', 'dz'), (convention, 'dalpha_0'), - (convention, 'dalpha_1'), (convention, 'dalpha_2')] + tuples_vel = [('location', 'dx'), + ('location', 'dy'), + ('location', 'dz'), + (convention, 'dalpha_0'), + (convention, 'dalpha_1'), + (convention, 'dalpha_2')] index_vel = pd.MultiIndex.from_tuples(tuples_vel, names=['position', 'orientation']) + tuples_posvel = tuples + tuples_posvel.extend(tuples_vel) + index_posvel = pd.MultiIndex.from_tuples(tuples_posvel, + names=['position', + 'orientation']) self._velocity_col = index_vel - self._posorient_vel_col = self._velocity_col.copy() + self._posorient_vel_col = index_posvel self._posorient_vel = pd.Series( index=self._posorient_vel_col, data=np.nan) @@ -105,6 +114,15 @@ class AbstractAgent(): self._posorient_vel.loc[self._velocity_col] = \ velocity.loc[self._velocity_col] + @property + def posorient_vel(self): + return self._posorient_vel.copy() + + @posorient_vel.setter + def posorient_vel(self, posorient_vel): + self.posorient = posorient_vel + self.velocity = posorient_vel + @property def brain(self): return inspect.getsourcelines(self._brain) @@ -176,11 +194,14 @@ GridAgent is a close loop agent here its position is snap to a grid. """ - def __init__(self, brain, convention, + def __init__(self, brain, posorients_queue=None, results_queue=None): - if convention is None: - raise Exception("convention must be set") + if not isinstance(brain.renderer, DataBaseLoad): + msg = 'GridAgent only works with a brain having ' + msg += 'a renderer of type DataBaseLoad' + raise TypeError(msg) + convention = brain.renderer.rotation_convention if (posorients_queue is not None) and (results_queue is not None): multiprocessing.Process.__init__(self) AbstractAgent.__init__(self, convention) @@ -283,14 +304,19 @@ the agent motion, or """ - def __init__(self, brain): + def __init__(self, brain, mode_of_motion): self._brain = copy.copy(brain) # Init the graph self._graph = nx.DiGraph() + if not isinstance(self._brain.renderer, DataBaseLoad): + msg = 'GraphAgent only works with a brain having ' + msg += 'a renderer of type DataBaseLoad' + raise TypeError(msg) for row_id, posor in self._brain.posorients.iterrows(): posor.name = row_id self._graph.add_node(row_id, posorient=posor) + self.mode_of_motion = mode_of_motion @property def graph(self): diff --git a/navipy/moving/maths.py b/navipy/moving/maths.py index 55389c762ea1d37fa746d49f06d5f03437e77f9e..d2d14da2e6a292cdf839eb4a2f1cd18d6d5441cf 100644 --- a/navipy/moving/maths.py +++ b/navipy/moving/maths.py @@ -49,7 +49,7 @@ def next_pos(motion_vec, move_mode, move_param=None): # speed in spherical coord epsilon = np.arctan2(speed['location']['dz'], np.sqrt(speed['location']['dx']**2 + - speed['location']['dy']**2)) + speed['location']['dy']**2)) phi = np.arctan2(speed['location']['dy'], speed['location']['dx']) radius = np.sqrt(np.sum(speed**2)) if np.isclose(radius, 0): @@ -88,15 +88,9 @@ def next_pos(motion_vec, move_mode, move_param=None): else: raise ValueError('grid_mode is not supported') toreturn = motion_vec - toreturn['location']['x'] = (toreturn['location']['x'] + - speed['location']['dx']) - toreturn['location']['y'] = (toreturn['location']['y'] + - speed['location']['dy']) - toreturn['location']['z'] = (toreturn['location']['z'] + - speed['location']['dz']) - # toreturn.loc[['x', 'y', 'z']] += speed.rename({'dx': 'x', - # 'dy': 'y', - # 'dz': 'z'}) * scaling + toreturn.loc[('location', 'x')] += speed['location']['dx'] + toreturn.loc[('location', 'y')] += speed['location']['dy'] + toreturn.loc[('location', 'z')] += speed['location']['dz'] return toreturn @@ -110,9 +104,9 @@ def closest_pos(pos, positions): """ euclidian_dist = np.sqrt( - (pos['location']['x'] - positions['location']['x'])**2 - + (pos['location']['y'] - positions['location']['y'])**2 - + (pos['location']['z'] - positions['location']['z'])**2) + (pos['location']['x'] - positions['location']['x'])**2 + + (pos['location']['y'] - positions['location']['y'])**2 + + (pos['location']['z'] - positions['location']['z'])**2) return positions.loc[euclidian_dist.idxmin()]