def phi_local(self): theta_z, phi_z = SkyModel.rotate(self.theta_global, self.phi_global, yaw=-self.yaw) theta_z, phi_z = SkyModel.rotate(theta_z, phi_z, pitch=-self.pitch) theta_z, phi_z = SkyModel.rotate(theta_z, phi_z, roll=-self.roll) return (phi_z + np.pi) % (2 * np.pi) - np.pi
def __init__(self, observer=None, polygons=None, width=WIDTH, length=LENGTH, height=HEIGHT, uniform_sky=False, enable_pol_filters=True, day_shift=153, daylight_only=True): """ Creates a world. :param observer: a reference to an observer :type observer: Observer :param polygons: polygons of the objects in the world :type polygons: PolygonList :param width: the width of the world :type width: int :param length: the length of the world :type length: int :param height: the height of the world :type height: int :param uniform_sky: flag that indicates if there is a uniform sky or not :type uniform_sky: bool :param enable_pol_filters: flag to switch on/off the POL filters of the eyes :type enable_pol_filters: bool :param day_shift: the number of days to roll back :type day_shift: int :param daylight_only: bound the time in between 7.30 am and 7.30 pm :type daylight_only: bool """ # normalise world xmax = np.array([polygons.x.max(), polygons.y.max(), polygons.z.max()]).max() # default observer is in Seville (where the data come from) if observer is None: observer = ephem.Observer() observer.lat = '37.392509' observer.lon = '-5.983877' self.day_shift = day_shift self.daylight_only = daylight_only self.__shifted = False observer.date = self.datetime_now(init=True) # create and generate a sky instance self.sky = SkyModel(observer=observer) self.sky.generate() # create a compound eye model for the sky pixels self.eye = None # type: CompoundEye self.__pol_filters = enable_pol_filters # store the polygons and initialise the parameters self.polygons = polygons self.routes = [] self.width = width self.length = length self.height = height self.__normalise_factor = xmax # type: float self.uniform_sky = uniform_sky
def rotate_centre(centre, yaw=0., pitch=0., roll=0.): # centre[[1, 0]] = SkyModel.rotate(centre[1], centre[0], yaw=yaw, pitch=pitch, roll=roll) centre[[1, 0]] = SkyModel.rotate(np.pi / 2 - centre[1], np.pi - centre[0], yaw=yaw, pitch=-pitch, roll=-roll) centre[0] = (2 * np.pi - centre[0]) % (2 * np.pi) - np.pi centre[1] = (3 * np.pi / 2 - centre[1]) % (2 * np.pi) - np.pi centre[2] = (centre[2] + roll + np.pi) % (2 * np.pi) - np.pi return centre
def rotate(self, yaw=0., pitch=0., roll=0.): sky = self.sky # rotate back to the default orientation sky = SkyModel.rotate_sky(sky, yaw=-self.yaw) sky = SkyModel.rotate_sky(sky, pitch=-self.pitch) sky = SkyModel.rotate_sky(sky, roll=-self.roll) # update the facing direction of the eye self.yaw_pitch_roll = self.rotate_centre(self.yaw_pitch_roll, yaw=yaw, pitch=-pitch, roll=roll) # rotate the sky according to the new facing direction sky = SkyModel.rotate_sky(sky, yaw=self.yaw, pitch=self.pitch, roll=self.roll) self.sky.theta_z = sky.theta_z self.sky.phi_z = sky.phi_z self._update_filters()
def __init__(self, ommatidia, central_microvili=(np.pi / 6, np.pi / 18), noise_factor=.1, activate_dop_sensitivity=False): # the eye facing direction self.yaw_pitch_roll = np.zeros(3) # eye specifications (ommatidia topography) self._sky = SkyModel() self.theta_global = ommatidia[:, 0] self.phi_global = ommatidia[:, 1] if ommatidia.shape[1] > 3: self._dop_filter = ommatidia[:, 3] self._aop_filter = ommatidia[:, 2] elif ommatidia.shape[1] > 2: self._aop_filter = ommatidia[:, 2] _, self._dop_filter = get_microvilli_angle( self.theta_global, self.phi_global, theta=central_microvili[0], phi=central_microvili[1], n=noise_factor) else: self._aop_filter, self._dop_filter = get_microvilli_angle( self.theta_global, self.phi_global, theta=central_microvili[0], phi=central_microvili[1], n=noise_factor) if not activate_dop_sensitivity: self._dop_filter[:] = 1. self._active_pol_filters = True self._channel_filters = {} self._update_filters()
class World(object): """ A representation of the world with object (described as polygons) and agents' routes """ def __init__(self, observer=None, polygons=None, width=WIDTH, length=LENGTH, height=HEIGHT, uniform_sky=False, enable_pol_filters=True, day_shift=153, daylight_only=True): """ Creates a world. :param observer: a reference to an observer :type observer: Observer :param polygons: polygons of the objects in the world :type polygons: PolygonList :param width: the width of the world :type width: int :param length: the length of the world :type length: int :param height: the height of the world :type height: int :param uniform_sky: flag that indicates if there is a uniform sky or not :type uniform_sky: bool :param enable_pol_filters: flag to switch on/off the POL filters of the eyes :type enable_pol_filters: bool :param day_shift: the number of days to roll back :type day_shift: int :param daylight_only: bound the time in between 7.30 am and 7.30 pm :type daylight_only: bool """ # normalise world xmax = np.array([polygons.x.max(), polygons.y.max(), polygons.z.max()]).max() # default observer is in Seville (where the data come from) if observer is None: observer = ephem.Observer() observer.lat = '37.392509' observer.lon = '-5.983877' self.day_shift = day_shift self.daylight_only = daylight_only self.__shifted = False observer.date = self.datetime_now(init=True) # create and generate a sky instance self.sky = SkyModel(observer=observer) self.sky.generate() # create a compound eye model for the sky pixels self.eye = None # type: CompoundEye self.__pol_filters = enable_pol_filters # store the polygons and initialise the parameters self.polygons = polygons self.routes = [] self.width = width self.length = length self.height = height self.__normalise_factor = xmax # type: float self.uniform_sky = uniform_sky @property def ratio2meters(self): return self.__normalise_factor # type: float @property def date(self): return self.sky.obs.date.datetime() # type: datetime def enable_pol_filters(self, value): """ :param value: :type value: bool :return: """ self.__pol_filters = value def add_route(self, route): """ Adds an ant-route in the world :param route: the new route :type route: Route :return: None """ self.routes.append(route) def draw_top_view(self, width=None, length=None, height=None): """ Draws a top view of the world and all the added paths in it. :param width: the width of the world :type width: int :param length: the length of the world :type length: int :param height: the height of the world :type height: int :return: an image of the top view """ # set the default values to the dimensions of the world if width is None: width = self.width if length is None: length = self.length if height is None: height = self.height # create new image and drawer image = Image.new("RGB", (width, length), GROUND_COLOUR) draw = ImageDraw.Draw(image) # draw the polygons for p in self.polygons.scale(*((self.ratio2meters,) * 3)): pp = p * [width, length, height] draw.polygon(pp.xy, fill=pp.c_int32) # draw the routes nants = int(np.array([r.agent_no for r in self.routes]).max()) # the ants' ID nroutes = int(np.array([r.route_no for r in self.routes]).max()) # the routes' ID for route in self.routes: # code the routes similarly to the polygons rt = route.scale(*(self.ratio2meters,) * 3) rt = rt * [width, length, height] r, g, b, _ = cmap(float(rt.agent_no) / float(len(self.routes))) draw.line(rt.xy, fill=(int(r * 255), int(g * 255), int(b * 255))) r = 20. for x0, y0, _, phi in rt: x1 = x0 + r * np.sin(phi) y1 = y0 + r * np.cos(phi) draw.line(((x0, y0), (x1, y1)), fill=(int(r * 255), int(g * 255), int(b * 255))) return image def draw_panoramic_view(self, x=None, y=None, z=None, r=0, width=None, length=None, height=None, include_ground=1., include_sky=1., update_sky=True): """ Draws a panoramic view of the world :param x: The x coordinate of the agent in the world :type x: float :param y: The y coordinate of the agent in the world :type y: float :param z: The z coordinate of the agent in the world :type z: float :param r: The orientation of the agent in the world :type r: float :param width: the width of the world :type width: int :param length: the length of the world :type length: int :param height: the height of the world :type height: int :param include_ground: the percentage of the ground to include in the image :type include_ground: float :param include_sky: the percentage of the sky to include in the image :type include_sky: float :param update_sky: flag that specifies if we want to update the sky :type update_sky: bool :return: an image showing the 360 degrees view of the agent """ # set the default values for the dimensions of the world if width is None: width = self.width if length is None: length = self.length if height is None: height = self.height if x is None: x = width / 2. if y is None: y = length / 2. if z is None: z = height / 2. + .06 * height # calculate the number of pixels allocated to the sky (counting from the top border) Z = (include_sky + include_ground) / 2 horizon = int(height * include_sky / (2 * Z)) # create ommatidia positions with respect to the resolution # (this is for the sky drawing on the panoramic images) thetas = np.linspace(np.pi/2 * include_sky, 0, horizon, endpoint=False) phis = np.linspace(-np.pi, np.pi, width, endpoint=False) thetas, phis = np.meshgrid(thetas, phis) ommatidia = np.array([thetas.flatten(), phis.flatten()]).T image = Image.new("RGB", (width, height), rgb2gbuv(GROUND_COLOUR)) draw = ImageDraw.Draw(image) if self.uniform_sky: draw.rectangle((0, 0, width, horizon), fill=rgb2gbuv(SKY_COLOUR, 255)) else: # create a compound eye model for the sky pixels # self.eye = CompoundEye(ommatidia, # central_microvili=(0., 0.), # noise_factor=.1, # activate_dop_sensitivity=True) self.eye = AntEye(ommatidia) self.eye.activate_pol_filters(self.__pol_filters) self.eye.sky = self.sky if update_sky: self.sky.obs.date = self.datetime_now() self.sky.generate() self.eye.rotate(yaw=-r) pix = image.load() for i, c in enumerate(self.eye.L): pix[i // horizon, i % horizon] = tuple(np.int32(255 * c)) # rotation matrix of the POV orientation R = np.array([ [np.cos(r), -np.sin(r), 0], [np.sin(r), np.cos(r), 0], [0, 0, 1] ]) thetas, phis, rhos = [], [], [] # code position for meters to pixel-space pos = np.array([x, y, z]) / self.ratio2meters pos *= np.array([width, length, height / Z]) for p in self.polygons.scale(*((self.ratio2meters,) * 3)): # code polygons' points from meters to pixels pp = p * [width, length, height / Z] # type: Polygon # and then into spherical coordinates xyz = np.array(pp.xyz) - pos theta, phi, rho = vec2sph(xyz.dot(R).T) thetas.append(theta) phis.append(phi) rhos.append(rho) # code spherical elevation to pixel height thetas = (height / Z) * ((((np.pi/2 - np.array(thetas)) % np.pi) / np.pi) - (1 - include_sky) / 2.) phis = width * ((np.pi + np.array(phis)) % (2 * np.pi)) / (2 * np.pi) rhos = la.norm(np.array(rhos), axis=-1) ind = np.argsort(rhos)[::-1] for theta, phi, c in zip(thetas[ind], phis[ind], self.polygons.c_int32[ind]): if phi.max() - phi.min() < width/2: # normal conditions p = tuple((b, a) for a, b in zip(theta, phi)) draw.polygon(p, fill=rgb2gbuv(c)) else: # in case that the object is on the edge of the screen phi0, phi1 = phi.copy(), phi.copy() phi0[phi < width/2] += width phi1[phi >= width/2] -= width p = tuple((b, a) for a, b in zip(theta, phi0)) draw.polygon(p, fill=rgb2gbuv(c)) p = tuple((b, a) for a, b in zip(theta, phi1)) draw.polygon(p, fill=rgb2gbuv(c)) # draw visible polygons return image def datetime_now(self, init=False): date = shifted_datetime(self.day_shift, lower_limit=None, upper_limit=None) if init: date_shift = shifted_datetime(self.day_shift, lower_limit=7.5, upper_limit=19.5) if date_shift.day != date.day: self.__shifted = True if self.__shifted: date += timedelta(hours=12) return date
s.rotate(yaw=np.pi / 6) # observer.date = datetime(2018, 6, 21, 8 + i, 0, 0) # s.sky.obs = observer # break if __name__ == "__main__2__": import matplotlib.pyplot as plt from sky import ChromaticitySkyModel, get_seville_observer from datetime import datetime s = CompassSensor(nb_lenses=12, fov=np.pi / 6) p = np.zeros(hp.nside2npix(s.nside)) i = hp.ang2pix(s.nside, s.theta, s.phi) # default observer is in Seville (where the data come from) observer = get_seville_observer() observer.date = datetime.now() # create and generate a sky instance sky = SkyModel(observer=observer, nside=1) sky.generate() s.sky = sky p[i] = s.L # p[i] = s.DOP # p[i] = np.rad2deg(s.AOP) p_i_max = p[i].max() p_i_min = p[i].min() p[i] = (p[i] - p_i_min) / (p_i_max - p_i_min) hp.orthview(p, rot=(0, 90, 0)) plt.show()