Example #1
0
class OrientedPoint(Point):
    """Implementation of the Scenic class ``OrientedPoint``.

	The default mutator for `OrientedPoint` adds Gaussian noise to ``heading``
	with a standard deviation given by the ``headingStdDev`` property, then
	applies the mutator for `Point`.

	Properties:
		heading (float; dynamic): Heading of the `OrientedPoint`. Default value 0
			(North).
		viewAngle (float): View cone angle for ``can see`` operator. Default
		  value :math:`2\\pi`.
	"""
    heading: PropertyDefault((), {'dynamic'}, lambda self: 0)
    viewAngle: math.tau

    mutator: PropertyDefault({'headingStdDev'}, {'additive'},
                             lambda self: HeadingMutator(self.headingStdDev))
    headingStdDev: math.radians(5)

    @cached_property
    def visibleRegion(self):
        return SectorRegion(self.position, self.visibleDistance, self.heading,
                            self.viewAngle)

    def relativize(self, vec):
        pos = self.relativePosition(vec)
        return OrientedPoint(position=pos, heading=self.heading)

    def relativePosition(self, vec):
        return self.position.offsetRotated(self.heading, vec)

    def toHeading(self) -> float:
        return self.heading
Example #2
0
class OrientedPoint(Point):
    heading: 0
    viewAngle: math.tau

    mutator: PropertyDefault({'headingStdDev'}, {'additive'},
                             lambda self: HeadingMutator(self.headingStdDev))
    headingStdDev: math.radians(5)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.heading = toScalar(self.heading,
                                f'"heading" of {self} not a scalar')
        self.visibleRegion = SectorRegion(self.position, self.visibleDistance,
                                          self.heading, self.viewAngle)

    def relativize(self, vec):
        pos = self.relativePosition(vec)
        return OrientedPoint(position=pos, heading=self.heading)

    def relativePosition(self, x, y=None):
        vec = x if y is None else Vector(x, y)
        pos = self.position.offsetRotated(self.heading, vec)
        return OrientedPoint(position=pos, heading=self.heading)

    def toHeading(self):
        return self.heading
Example #3
0
class Point(Constructible):
    """Implementation of the Scenic class ``Point``.

	The default mutator for `Point` adds Gaussian noise to ``position`` with
	a standard deviation given by the ``positionStdDev`` property.

	Attributes:
		position (`Vector`): Position of the point. Default value is the origin.
		visibleDistance (float): Distance for ``can see`` operator. Default value 50.
		width (float): Default value zero (only provided for compatibility with
		  operators that expect an `Object`).
		height (float): Default value zero.
	"""
    position: Vector(0, 0)
    width: 0
    height: 0
    visibleDistance: 50

    mutationEnabled: False
    mutator: PropertyDefault({'positionStdDev'}, {'additive'},
                             lambda self: PositionMutator(self.positionStdDev))
    positionStdDev: 1

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.position = toVector(self.position,
                                 f'"position" of {self} not a vector')
        self.corners = (self.position, )
        self.visibleRegion = CircularRegion(self.position,
                                            self.visibleDistance)

    def toVector(self):
        return self.position.toVector()

    def canSee(self, other):  # TODO improve approximation?
        for corner in other.corners:
            if self.visibleRegion.containsPoint(corner):
                return True
        return False

    def sampleGiven(self, value):
        sample = super().sampleGiven(value)
        if self.mutationEnabled:
            for mutator in self.mutator:
                if mutator is None:
                    continue
                sample, proceed = mutator.appliedTo(sample)
                if not proceed:
                    break
        return sample

    # Points automatically convert to Vectors when needed
    def __getattr__(self, attr):
        if hasattr(Vector, attr):
            return getattr(self.toVector(), attr)
        else:
            raise AttributeError(
                f"'{type(self).__name__}' object has no attribute '{attr}'")
Example #4
0
    def defaults(cla):  # TODO improve so this need only be done once?
        # find all defaults provided by the class or its superclasses
        allDefs = collections.defaultdict(list)
        for sc in inspect.getmro(cla):
            if hasattr(sc, '__annotations__'):
                for prop, value in sc.__annotations__.items():
                    allDefs[prop].append(PropertyDefault.forValue(value))

        # resolve conflicting defaults
        resolvedDefs = {}
        for prop, defs in allDefs.items():
            primary, rest = defs[0], defs[1:]
            spec = primary.resolveFor(prop, rest)
            resolvedDefs[prop] = spec
        return resolvedDefs
Example #5
0
    def __init_subclass__(cls):
        # find all defaults provided by the class or its superclasses
        allDefs = collections.defaultdict(list)
        for sc in inspect.getmro(cls):
            if hasattr(sc, '__annotations__'):
                for prop, value in sc.__annotations__.items():
                    allDefs[prop].append(PropertyDefault.forValue(value))

        # resolve conflicting defaults
        resolvedDefs = {}
        for prop, defs in allDefs.items():
            primary, rest = defs[0], defs[1:]
            spec = primary.resolveFor(prop, rest)
            resolvedDefs[prop] = spec
        cls.defaults = resolvedDefs
Example #6
0
class Point(Constructible):
    position: Vector(0, 0)
    width: 0
    height: 0
    visibleDistance: 50

    mutationEnabled: False
    mutator: PropertyDefault({'positionStdDev'}, {'additive'},
                             lambda self: PositionMutator(self.positionStdDev))
    positionStdDev: 1

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.position = toVector(self.position,
                                 f'"position" of {self} not a vector')
        self.corners = (self.position, )
        self.visibleRegion = CircularRegion(self.position,
                                            self.visibleDistance)

    def toVector(self):
        return self.position.toVector()

    def canSee(self, other):  # TODO improve approximation?
        for corner in other.corners:
            if self.visibleRegion.containsPoint(corner):
                return True
        return False

    def sampleGiven(self, value):
        sample = super().sampleGiven(value)
        if self.mutationEnabled:
            for mutator in self.mutator:
                if mutator is None:
                    continue
                sample, proceed = mutator.appliedTo(sample)
                if not proceed:
                    break
        return sample

    # Points automatically convert to Vectors when needed
    def __getattr__(self, attr):
        if hasattr(Vector, attr):
            return getattr(self.toVector(), attr)
        else:
            raise AttributeError(
                f"'{type(self).__name__}' object has no attribute '{attr}'")
Example #7
0
    def __init_subclass__(cls):
        super().__init_subclass__()
        # find all defaults provided by the class or its superclasses
        allDefs = collections.defaultdict(list)
        for sc in cls.__mro__:
            if issubclass(sc, _Constructible) and hasattr(
                    sc, '__annotations__'):
                for prop, value in sc.__annotations__.items():
                    allDefs[prop].append(PropertyDefault.forValue(value))

        # resolve conflicting defaults and gather dynamic properties
        resolvedDefs = {}
        dyns = []
        for prop, defs in allDefs.items():
            primary, rest = defs[0], defs[1:]
            spec = primary.resolveFor(prop, rest)
            resolvedDefs[prop] = spec

            if any(defn.isDynamic for defn in defs):
                dyns.append(prop)
        cls._defaults = resolvedDefs
        cls._dynamicProperties = tuple(dyns)
Example #8
0
class OrientedPoint(Point):
    """Implementation of the Scenic class ``OrientedPoint``.

	The default mutator for `OrientedPoint` adds Gaussian noise to ``heading``
	with a standard deviation given by the ``headingStdDev`` property, then
	applies the mutator for `Point`.

	Attributes:
		heading (float): Heading of the `OrientedPoint`. Default value 0 (North).
		viewAngle (float): View cone angle for ``can see`` operator. Default
		  value :math:`2\\pi`.
	"""
    heading: 0
    viewAngle: math.tau

    mutator: PropertyDefault({'headingStdDev'}, {'additive'},
                             lambda self: HeadingMutator(self.headingStdDev))
    headingStdDev: math.radians(5)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.heading = toScalar(self.heading,
                                f'"heading" of {self} not a scalar')
        self.visibleRegion = SectorRegion(self.position, self.visibleDistance,
                                          self.heading, self.viewAngle)

    def relativize(self, vec):
        pos = self.relativePosition(vec)
        return OrientedPoint(position=pos, heading=self.heading)

    def relativePosition(self, x, y=None):
        vec = x if y is None else Vector(x, y)
        pos = self.position.offsetRotated(self.heading, vec)
        return OrientedPoint(position=pos, heading=self.heading)

    def toHeading(self):
        return self.heading
Example #9
0
def to_annotations(model_desc: t.Dict[str, t.Any], input_dir: str,
                   models_dir: str):
    typ = ModelTypes[model_desc['type']]
    name = model_desc['name']
    annotations = {
        'gz_name': name,
        'type': typ,
    }
    if typ == ModelTypes.MISSION_ONLY:
        annotations.update({
            'width': model_desc.get('width', 0.00001),
            'length': model_desc.get('length', 0.00001)
        })

    elif typ == ModelTypes.CUSTOM_MODEL:
        dir_path = os.path.join(input_dir, models_dir)
        dir_path = os.path.join(dir_path, name)
        url = model_desc.get('url', '')
    elif typ in [ModelTypes.GAZEBO_MODEL, ModelTypes.GAZEBO_DB_MODEL]:
        # TODO we need to download files from gazebo repo
        # and do the same as CUSTOM_MODEL
        dir_path, gazebo_db = gazebo_dir_and_path(
            os.path.join(input_dir, models_dir), name)
        annotations[
            'type'] = ModelTypes.GAZEBO_DB_MODEL if gazebo_db else ModelTypes.GAZEBO_MODEL
        url = ''

    if typ != ModelTypes.MISSION_ONLY:
        sdf_path = handle_path(dir_path, url)
        info = process_sdf(dir_path, sdf_path)
        if not model_desc.get('dynamic_size', info.dynamic_size):
            annotations.update({
                'length': info.length,
                'width': info.width,
                'height': info.height
            })
        else:
            annotations.update({
                'length':
                Range(info.length / 2, info.length * 2),
                'width':
                Range(info.width / 2, info.width * 2),
                'height':
                Range(info.height / 2, info.height * 2),
                'dynamic_size':
                info.dynamic_size,
                'o_length':
                info.length / info.orig_scale[1],
                'o_width':
                info.width / info.orig_scale[0],
                'o_height':
                info.height / info.orig_scale[2]
            })
            if info.eq_width_length:
                annotations['width'] = PropertyDefault(
                    ('length', ), {}, lambda self: self.length)

    if 'z' in model_desc:
        annotations['z'] = model_desc['z']
    if 'heading' in model_desc:
        annotations['heading'] = model_desc['heading']
    if 'dynamic_size' in model_desc:
        annotations['dynamic_size'] = model_desc['dynamic_size']
    annotations['allowCollisions'] = model_desc.get('allow_collisions', False)
    return annotations
Example #10
0
class Object(OrientedPoint, _RotatedRectangle):
    """Implementation of the Scenic class ``Object``.

	This is the default base class for Scenic classes.

	Properties:
		width (float): Width of the object, i.e. extent along its X axis.
		  Default value 1.
		length (float): Length of the object, i.e. extent along its Y axis.
		  Default value 1.
		allowCollisions (bool): Whether the object is allowed to intersect
		  other objects. Default value ``False``.
		requireVisible (bool): Whether the object is required to be visible
		  from the ``ego`` object. Default value ``True``.
		regionContainedIn (`Region` or ``None``): A `Region` the object is
		  required to be contained in. If ``None``, the object need only be
		  contained in the scenario's workspace.
		cameraOffset (`Vector`): Position of the camera for the ``can see``
		  operator, relative to the object's ``position``. Default ``0 @ 0``.

		speed (float; dynamic): Speed in dynamic simulations. Default value 0.
		velocity (`Vector`; *dynamic*): Velocity in dynamic simulations. Default value is
			the velocity determined by ``self.speed`` and ``self.heading``.
		angularSpeed (float; *dynamic*): Angular speed in dynamic simulations. Default
			value 0.

		behavior: Behavior for dynamic agents, if any (see :ref:`dynamics`). Default
			value ``None``.
	"""
    width: 1
    length: 1

    allowCollisions: False
    requireVisible: True
    regionContainedIn: None
    cameraOffset: Vector(0, 0)

    velocity: PropertyDefault(
        ('speed', 'heading'), {'dynamic'},
        lambda self: Vector(0, self.speed).rotatedBy(self.heading))
    speed: PropertyDefault((), {'dynamic'}, lambda self: 0)
    angularSpeed: PropertyDefault((), {'dynamic'}, lambda self: 0)

    behavior: None
    lastActions: None

    def __new__(cls, *args, **kwargs):
        obj = super().__new__(cls)
        # The _dynamicProxy attribute stores a mutable copy of the object used during
        # simulations, intercepting all attribute accesses to the original object;
        # we set this attribute very early to prevent problems during unpickling.
        object.__setattr__(obj, '_dynamicProxy', obj)
        return obj

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.hw = hw = self.width / 2
        self.hl = hl = self.length / 2
        self.radius = hypot(hw, hl)  # circumcircle; for collision detection
        self.inradius = min(hw, hl)  # incircle; for collision detection

        self._relations = []

    def _specify(self, prop, value):
        # Normalize types of some built-in properties
        if prop == 'behavior':
            import scenic.syntax.veneer as veneer  # TODO improve?
            value = toType(value, veneer.Behavior,
                           f'"behavior" of {self} not a behavior')
        super()._specify(prop, value)

    def _register(self):
        import scenic.syntax.veneer as veneer  # TODO improve?
        veneer.registerObject(self)

    def __getattribute__(self, name):
        proxy = object.__getattribute__(self, '_dynamicProxy')
        return object.__getattribute__(proxy, name)

    def __setattr__(self, name, value):
        proxy = object.__getattribute__(self, '_dynamicProxy')
        object.__setattr__(proxy, name, value)

    def __delattr__(self, name):
        proxy = object.__getattribute__(self, '_dynamicProxy')
        object.__delattr__(proxy, name)

    @cached_property
    def left(self):
        return self.relativize(Vector(-self.hw, 0))

    @cached_property
    def right(self):
        return self.relativize(Vector(self.hw, 0))

    @cached_property
    def front(self):
        return self.relativize(Vector(0, self.hl))

    @cached_property
    def back(self):
        return self.relativize(Vector(0, -self.hl))

    @cached_property
    def frontLeft(self):
        return self.relativize(Vector(-self.hw, self.hl))

    @cached_property
    def frontRight(self):
        return self.relativize(Vector(self.hw, self.hl))

    @cached_property
    def backLeft(self):
        return self.relativize(Vector(-self.hw, -self.hl))

    @cached_property
    def backRight(self):
        return self.relativize(Vector(self.hw, -self.hl))

    @cached_property
    def visibleRegion(self):
        camera = self.position.offsetRotated(self.heading, self.cameraOffset)
        return SectorRegion(camera, self.visibleDistance, self.heading,
                            self.viewAngle)

    @cached_property
    def corners(self):
        hw, hl = self.hw, self.hl
        return (self.relativePosition(Vector(hw, hl)),
                self.relativePosition(Vector(-hw, hl)),
                self.relativePosition(Vector(-hw, -hl)),
                self.relativePosition(Vector(hw, -hl)))

    def show(self, workspace, plt, highlight=False):
        if needsSampling(self):
            raise RuntimeError('tried to show() symbolic Object')
        pos = self.position
        spos = workspace.scenicToSchematicCoords(pos)

        if highlight:
            # Circle around object
            rad = 1.5 * max(self.width, self.length)
            c = plt.Circle(spos, rad, color='g', fill=False)
            plt.gca().add_artist(c)
            # View cone
            ha = self.viewAngle / 2.0
            camera = self.position.offsetRotated(self.heading,
                                                 self.cameraOffset)
            cpos = workspace.scenicToSchematicCoords(camera)
            for angle in (-ha, ha):
                p = camera.offsetRadially(20, self.heading + angle)
                edge = [cpos, workspace.scenicToSchematicCoords(p)]
                x, y = zip(*edge)
                plt.plot(x, y, 'b:')

        corners = [
            workspace.scenicToSchematicCoords(corner)
            for corner in self.corners
        ]
        x, y = zip(*corners)
        color = self.color if hasattr(self, 'color') else (1, 0, 0)
        plt.fill(x, y, color=color)

        frontMid = averageVectors(corners[0], corners[1])
        baseTriangle = [frontMid, corners[2], corners[3]]
        triangle = [averageVectors(p, spos, weight=0.5) for p in baseTriangle]
        x, y = zip(*triangle)
        plt.fill(x, y, "w")
        plt.plot(x + (x[0], ), y + (y[0], ), color="k", linewidth=1)
Example #11
0
class Point(_Constructible):
    """Implementation of the Scenic base class ``Point``.

	The default mutator for `Point` adds Gaussian noise to ``position`` with
	a standard deviation given by the ``positionStdDev`` property.

	Properties:
		position (`Vector`; dynamic): Position of the point. Default value is the origin.
		visibleDistance (float): Distance for ``can see`` operator. Default value 50.
		width (float): Default value zero (only provided for compatibility with
		  operators that expect an `Object`).
		length (float): Default value zero.

	.. note::

		If you're looking into Scenic's internals, note that `Point` is actually a
		subclass of the internal Python class `_Constructible`.
	"""
    position: PropertyDefault((), {'dynamic'}, lambda self: Vector(0, 0))
    width: 0
    length: 0
    visibleDistance: 50

    mutationEnabled: False
    mutator: PropertyDefault({'positionStdDev'}, {'additive'},
                             lambda self: PositionMutator(self.positionStdDev))
    positionStdDev: 1

    @cached_property
    def visibleRegion(self):
        return CircularRegion(self.position, self.visibleDistance)

    @cached_property
    def corners(self):
        return (self.position, )

    def toVector(self) -> Vector:
        return self.position

    def canSee(self, other) -> bool:  # TODO improve approximation?
        for corner in other.corners:
            if self.visibleRegion.containsPoint(corner):
                return True
        return False

    def sampleGiven(self, value):
        sample = super().sampleGiven(value)
        if self.mutationEnabled:
            for mutator in self.mutator:
                if mutator is None:
                    continue
                sample, proceed = mutator.appliedTo(sample)
                if not proceed:
                    break
        return sample

    # Points automatically convert to Vectors when needed
    def __getattr__(self, attr):
        if hasattr(Vector, attr):
            return getattr(self.toVector(), attr)
        else:
            raise AttributeError(
                f"'{type(self).__name__}' object has no attribute '{attr}'")