Source code for morse.core.zone

import logging
logger = logging.getLogger("morse." + __name__)
from morse.core import mathutils
import morse.core.object
from sys import float_info

[docs]class Zone: """ Creates a named zone in the 3D environment. This can be used by components via the :py:class:morse.core.ZoneManagerto trigger specific behaviours when the component is inside the zone. The main method is the contains one, which allow to decide if a point is part of a zone (and so potentially to trigger some behaviour). Note that for simplicity, we currently assume the zone axis follows the world axis. """ def __init__(self, obj): self.name = obj.name self.type = obj['Type'] self.obj = obj mesh = obj.meshes[0] # Get list of unique vertexes vertexes_ = set() for v_index in range(24): vertex = mesh.getVertex(0, v_index) vertexes_.add(vertex.getXYZ()[:]) vertexes = [mathutils.Vector(p) for p in vertexes_] # Compute range self._min_values = [float_info.max, float_info.max, float_info.max] self._max_values = [-float_info.max, -float_info.max, -float_info.max] for i in range(len(vertexes)): for j in range(3): # XXX Here, we assume there is no rotation vertexes[i][j] = vertexes[i][j] * obj.worldScale[j] + obj.worldPosition[j] if self._min_values[j] > vertexes[i][j]: self._min_values[j] = vertexes[i][j] if self._max_values[j] < vertexes[i][j]: self._max_values[j] = vertexes[i][j]
[docs] def contains(self, pos): """ Verify if a pos (represented by a vector) is contained in the zone The implementation assumes that the zone is a rectangle, with axis following world axis. """ res = True for i in range(3): res = res and pos[i] >= self._min_values[i] res = res and pos[i] <= self._max_values[i] return res
[docs]class ZoneManager: """ Handle the different zones, allowing to search for them 'efficiently' (at least in an abstract way) """ def __init__(self): self.all_zones = {} self.zones_by_type = {}
[docs] def add(self, obj): new_zone = Zone(obj) logger.info("Adding zone %s of type %s" % (new_zone.name, new_zone.type)) self.all_zones[new_zone.name] = new_zone zone_type = self.zones_by_type.get(new_zone.type, None) if not zone_type: self.zones_by_type[new_zone.type] = {} zone_type = self.zones_by_type[new_zone.type] zone_type[new_zone.name] = new_zone
def _get_subset(self, name = None, type = None): search_list = self.all_zones if name: if name in self.all_zones: search_list = {name: [self.all_zones[name]]} else: search_list = {} if type: if type in self.zones_by_type: search_list = self.zones_by_type[type] else: search_list = {} return search_list
[docs] def is_in(self, obj_or_pos, name = None, type = None): """ Determine if obj_or_pos is in a zone If :param obj_or_pos: is a :py:class:morse.core.object.Object, consider the position of the object. Otherwise, assume it is a position. If a :param name: is precised, check only if this specific zone contains the position If a :param type: is precised, only search in the zone of this type. """ pos = obj_or_pos if (isinstance(obj_or_pos, morse.core.object.Object)): pos = obj_or_pos.position_3d.translation search_list = self._get_subset(name, type) for zone in search_list.values(): if zone.contains(pos): return True return False
[docs] def contains(self, obj_or_pos, name = None, type = None): """ Determine which zone(s) contain(s) the position pos If :param obj_or_pos: is a :py:class:morse.core.object.Object, consider the position of the object. Otherwise, assume it is a position. If a :param name: is precised, check only if this specific zone contains the position If a :param type: is precised, only search in the zone of this type. The method returns the list of zones containing the position, considering the previous limitation """ pos = obj_or_pos if (isinstance(obj_or_pos, morse.core.object.Object)): pos = obj_or_pos.position_3d.translation search_list = self._get_subset(name, type) res = [] for zone in search_list.values(): if zone.contains(pos): res.append(zone) return res