Source code for pymunk
# ----------------------------------------------------------------------------
# pymunk
# Copyright (c) 2007-2012 Victor Blomqvist
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ----------------------------------------------------------------------------
"""
pymunk is a easy-to-use pythonic 2d physics library that can be used whenever
you need 2d rigid body physics from Python.
Homepage: http://www.pymunk.org
This is the main containing module of pymunk. It contains among other things
the very central Space, Body and Shape classes.
When you import this module it will automatically load the chipmunk library
file. As long as you haven't turned off the debug mode a print will show
exactly which Chipmunk library file it loaded. For example::
>>> import pymunk
Loading chipmunk for Windows (32bit) [C:\code\pymunk\chipmunk.dll]
"""
__version__ = "$Id: __init__.py 541 2013-08-22 17:36:25Z<EMAIL_ADDRESS>$"
__docformat__ = "reStructuredText"
__all__ = ["inf", "version", "chipmunk_version"
, "Space", "Body", "Shape", "Circle", "Poly", "Segment"
, "moment_for_circle", "moment_for_poly", "moment_for_segment"
, "moment_for_box", "reset_shapeid_counter"
, "SegmentQueryInfo", "Contact", "Arbiter", "BB"]
import ctypes as ct
import weakref
try:
#Python 2.7+
from weakref import WeakSet
except ImportError:
from .weakrefset import WeakSet
from . import _chipmunk as cp
from . import _chipmunk_ffi as cpffi
from . import util as u
from .vec2d import Vec2d
from pymunk.constraint import *
version = "4.0.0"
"""The release version of this pymunk installation.
Valid only if pymunk was installed from a source or binary
distribution (i.e. not in a checked-out copy from svn).
"""
chipmunk_version = "%sR%s" % (cp.cpVersionString.value.decode(), '3bdf1b7b3c')
"""The Chipmunk version compatible with this pymunk version.
Other (newer) Chipmunk versions might also work if the new version does not
contain any breaking API changes.
This property does not show a valid value in the compiled documentation, only
when you actually import pymunk and do pymunk.chipmunk_version
The string is in the following format:
<cpVersionString>R<svn or github commit of chipmunk>
where cpVersionString is a version string set by Chipmunk and the svn version
corresponds to the svn version of the chipmunk source files included with
pymunk or the github commit hash. If the Chipmunk version is a release then
the second part will be empty
.. note::
This is also the version of the Chipmunk source files included in the
chipmunk_src folder (normally included in the pymunk source distribution).
"""
#inf = float('inf') # works only on python 2.6+
inf = 1e100
"""Infinity that can be passed as mass or inertia to Body.
Useful when you for example want a body that cannot rotate, just set its
moment to inf. Just remember that if two objects with both infinite masses
collides the world might explode. Similary effects can happen with infinite
moment.
.. note::
In previous versions of pymunk you used inf to create static bodies. This
has changed and you should instead do it by invoking the body constructor
without any arguments.
"""
cp.cpEnableSegmentToSegmentCollisions()
[docs]class Space(object):
"""Spaces are the basic unit of simulation. You add rigid bodies, shapes
and joints to it and then step them all forward together through time.
"""
[docs] def __init__(self, iterations=10):
"""Create a new instace of the Space
Its usually best to keep the elastic_iterations setting to 0. Only
change if you have problem with stacking elastic objects on each other.
If that is the case, try to raise it. However, a value other than 0
will affect other parts, most importantly you wont get reliable
total_impulse readings from the `Arbiter` object in collsion callbacks!
:Parameters:
iterations : int
Number of iterations to use in the impulse solver to solve
contacts.
"""
self._space = cp.cpSpaceNew()
self._space.contents.iterations = iterations
self._static_body = Body()
self._handlers = {} # To prevent the gc to collect the callbacks.
self._default_handler = None
self._post_step_callbacks = {}
self._post_callback_keys = {}
self._post_last_callback_key = 0
self._removed_shapes = {}
self._shapes = {}
self._bodies = set()
self._constraints = set()
self._locked = False
self._add_later = set()
self._remove_later = set()
def _get_shapes(self):
return list(self._shapes.values())
shapes = property(_get_shapes,
doc="""A list of all the shapes added to this space (both static and non-static)""")
def _get_bodies(self):
return list(self._bodies)
bodies = property(_get_bodies,
doc="""A list of the bodies added to this space""")
def _get_constraints(self):
return list(self._constraints)
constraints = property(_get_constraints,
doc="""A list of the constraints added to this space""")
def _get_static_body(self):
"""A convenience static body already added to the space"""
return self._static_body
static_body = property(_get_static_body, doc=_get_static_body.__doc__)
def __del__(self):
try:
cp.cpSpaceFree(self._space)
except:
pass
def _set_iterations(self, iterations):
self._space.contents.iterations = iterations
def _get_iterations(self):
return self._space.contents.iterations
iterations = property(_get_iterations, _set_iterations
, doc="""Number of iterations to use in the impulse solver to solve
contacts.""")
def _set_gravity(self, gravity_vec):
self._space.contents.gravity = gravity_vec
def _get_gravity(self):
return self._space.contents.gravity
gravity = property(_get_gravity, _set_gravity
, doc="""Default gravity to supply when integrating rigid body motions.""")
def _set_damping(self, damping):
self._space.contents.damping = damping
def _get_damping(self):
return self._space.contents.damping
damping = property(_get_damping, _set_damping
, doc="""Damping rate expressed as the fraction of velocity bodies
retain each second.
A value of 0.9 would mean that each body's velocity will drop 10% per
second. The default value is 1.0, meaning no damping is applied.""")
def _set_idle_speed_threshold(self, idle_speed_threshold):
self._space.contents.idleSpeedThreshold = idle_speed_threshold
def _get_idle_speed_threshold(self):
return self._space.contents.idleSpeedThreshold
idle_speed_threshold = property(_get_idle_speed_threshold
, _set_idle_speed_threshold
, doc="""Speed threshold for a body to be considered idle.
The default value of 0 means to let the space guess a good threshold
based on gravity.""")
def _set_sleep_time_threshold(self, sleep_time_threshold):
self._space.contents.sleepTimeThreshold = sleep_time_threshold
def _get_sleep_time_threshold(self):
return self._space.contents.sleepTimeThreshold
sleep_time_threshold = property(_get_sleep_time_threshold
, _set_sleep_time_threshold
, doc="""Time a group of bodies must remain idle in order to fall
asleep.
Enabling sleeping also implicitly enables the the contact graph. The
default value of `inf` disables the sleeping algorithm.""")
def _set_collision_slop(self, collision_slop):
self._space.contents.collisionSlop = collision_slop
def _get_collision_slop(self):
return self._space.contents.collisionSlop
collision_slop = property(_get_collision_slop
, _set_collision_slop
, doc="""Amount of allowed penetration.
Used to reduce oscillating contacts and keep the collision cache warm.
Defaults to 0.1. If you have poor simulation quality, increase this
number as much as possible without allowing visible amounts of
overlap.""")
def _set_collision_bias(self, collision_bias):
self._space.contents.collisionBias = collision_bias
def _get_collision_bias(self):
return self._space.contents.collisionBias
collision_bias = property(_get_collision_bias
, _set_collision_bias
, doc="""Determines how fast overlapping shapes are pushed apart.
Expressed as a fraction of the error remaining after each second.
Defaults to pow(1.0 - 0.1, 60.0) meaning that pymunk fixes 10% of
overlap each frame at 60Hz.""")
def _set_collision_persistence(self, collision_persistence):
self._space.contents.collisionPersistence = collision_persistence
def _get_collision_persistence(self):
return self._space.contents.collisionPersistence
collision_persistence = property(_get_collision_persistence
, _set_collision_persistence
, doc="""Number of frames that contact information should persist.
Defaults to 3. There is probably never a reason to change this value.
""")
def _set_enable_contact_graph(self, enable_contact_graph):
self._space.contents.enableContactGraph = enable_contact_graph
def _get_enable_contact_graph(self):
return self._space.contents.enableContactGraph
enable_contact_graph = property(_get_enable_contact_graph
, _set_enable_contact_graph
, doc="""Rebuild the contact graph during each step.
Must be enabled to use the get_arbiter() function on Body
Disabled by default for a small performance boost. Enabled implicitly
when the sleeping feature is enabled.
""")
[docs] def add(self, *objs):
"""Add one or many shapes, bodies or joints to the space
Unlike Chipmunk and earlier versions of pymunk its now allowed to add
objects even from a callback during the simulation step. However, the
add will not be performed until the end of the step.
"""
if self._locked:
self._add_later.add(objs)
return
for o in objs:
if isinstance(o, Body):
self._add_body(o)
elif isinstance(o, Shape):
self._add_shape(o)
elif isinstance(o, Constraint):
self._add_constraint(o)
else:
for oo in o:
self.add(oo)
[docs] def remove(self, *objs):
"""Remove one or many shapes, bodies or constraints from the space
Unlike Chipmunk and earlier versions of pymunk its now allowed to
remove objects even from a callback during the simulation step.
However, the removal will not be performed until the end of the step.
.. Note::
When removing objects from the space, make sure you remove any
other objects that reference it. For instance, when you remove a
body, remove the joints and shapes attached to it.
"""
if self._locked:
self._remove_later.add(objs)
return
for o in objs:
if isinstance(o, Body):
self._remove_body(o)
elif isinstance(o, Shape):
self._remove_shape(o)
elif isinstance(o, Constraint):
self._remove_constraint(o)
else:
for oo in o:
self.remove(oo)
def _add_shape(self, shape):
"""Adds a shape to the space"""
assert shape._hashid_private not in self._shapes, "shape already added to space"
self._shapes[shape._hashid_private] = shape
cp.cpSpaceAddShape(self._space, shape._shape)
def _add_body(self, body):
"""Adds a body to the space"""
assert body not in self._bodies, "body already added to space"
body._space = weakref.proxy(self)
self._bodies.add(body)
cp.cpSpaceAddBody(self._space, body._body)
def _add_constraint(self, constraint):
"""Adds a constraint to the space"""
assert constraint not in self._constraints, "constraint already added to space"
self._constraints.add(constraint)
cp.cpSpaceAddConstraint(self._space, constraint._constraint)
def _remove_shape(self, shape):
"""Removes a shape from the space"""
self._removed_shapes[shape._hashid_private] = shape
del self._shapes[shape._hashid_private]
cp.cpSpaceRemoveShape(self._space, shape._shape)
def _remove_body(self, body):
"""Removes a body from the space"""
body._space = None
self._bodies.remove(body)
cp.cpSpaceRemoveBody(self._space, body._body)
def _remove_constraint(self, constraint):
"""Removes a constraint from the space"""
self._constraints.remove(constraint)
cp.cpSpaceRemoveConstraint(self._space, constraint._constraint)
[docs] def reindex_static(self):
"""Update the collision detection info for the static shapes in the
space. You only need to call this if you move one of the static shapes.
"""
cp.cpSpaceReindexStatic(self._space)
[docs] def reindex_shape(self, shape):
"""Update the collision detection data for a specific shape in the
space.
"""
cp.cpSpaceReindexShape(self._space, shape._shape)
[docs] def step(self, dt):
"""Update the space for the given time step. Using a fixed time step is
highly recommended. Doing so will increase the efficiency of the
contact persistence, requiring an order of magnitude fewer iterations
to resolve the collisions in the usual case."""
self._locked = True
cp.cpSpaceStep(self._space, dt)
self._removed_shapes = {}
self._post_step_callbacks = {}
self._post_callback_keys = {}
self._post_last_callback_key = 0
self._locked = False
for objs in self._add_later:
self.add(objs)
self._add_later.clear()
for objs in self._remove_later:
self.remove(objs)
self._remove_later.clear()
[docs] def add_collision_handler(self, a, b, begin=None, pre_solve=None, post_solve=None, separate=None, *args, **kwargs):
"""Add a collision handler for given collision type pair.
Whenever a shapes with collision_type a and collision_type b collide,
these callbacks will be used to process the collision.
None can be provided for callbacks you do not wish to implement,
however pymunk will call it's own default versions for these and not
the default ones you've set up for the Space. If you need to fall back
on the space's default callbacks, you'll have to provide them
individually to each handler definition.
:Parameters:
a : int
Collision type of the first shape
b : int
Collision type of the second shape
begin : ``func(space, arbiter, *args, **kwargs) -> bool``
Collision handler called when two shapes just started touching
for the first time this step. Return false from the callback
to make pymunk ignore the collision or true to process it
normally. Rejecting a collision from a begin() callback
permanently rejects the collision until separation. Pass
`None` if you wish to use the pymunk default.
pre_solve : ``func(space, arbiter, *args, **kwargs) -> bool``
Collision handler called when two shapes are touching. Return
false from the callback to make pymunk ignore the collision or
true to process it normally. Additionally, you may override
collision values such as `Arbiter.elasticity` and
`Arbiter.friction` to provide custom friction or elasticity
values. See `Arbiter` for more info. Pass `None` if you wish
to use the pymunk default.
post_solve : ``func(space, arbiter, *args, **kwargs)``
Collsion handler called when two shapes are touching and their
collision response has been processed. You can retrieve the
collision force at this time if you want to use it to
calculate sound volumes or damage amounts. Pass `None` if you
wish to use the pymunk default.
separate : ``func(space, arbiter, *args, **kwargs)``
Collision handler called when two shapes have just stopped
touching for the first time this frame. Pass `None` if you
wish to use the pymunk default.
args
Optional parameters passed to the collision handler functions.
kwargs
Optional keyword parameters passed on to the collision handler
functions.
"""
_functions = self._collision_function_helper(begin, pre_solve, post_solve, separate, *args, **kwargs)
self._handlers[(a, b)] = _functions
cp.cpSpaceAddCollisionHandler(self._space, a, b,
_functions[0], _functions[1], _functions[2], _functions[3], None)
[docs] def set_default_collision_handler(self, begin=None, pre_solve=None, post_solve=None, separate=None, *args, **kwargs):
"""Register a default collision handler to be used when no specific
collision handler is found. If you do nothing, the space will be given
a default handler that accepts all collisions in begin() and
pre_solve() and does nothing for the post_solve() and separate()
callbacks.
:Parameters:
begin : ``func(space, arbiter, *args, **kwargs) -> bool``
Collision handler called when two shapes just started touching
for the first time this step. Return False from the callback
to make pymunk ignore the collision or True to process it
normally. Rejecting a collision from a begin() callback
permanently rejects the collision until separation. Pass
`None` if you wish to use the pymunk default.
pre_solve : ``func(space, arbiter, *args, **kwargs) -> bool``
Collision handler called when two shapes are touching. Return
False from the callback to make pymunk ignore the collision or
True to process it normally. Additionally, you may override
collision values such as Arbiter.elasticity and
Arbiter.friction to provide custom friction or elasticity
values. See Arbiter for more info. Pass `None` if you wish to
use the pymunk default.
post_solve : ``func(space, arbiter, *args, **kwargs)``
Collsion handler called when two shapes are touching and their
collision response has been processed. You can retrieve the
collision force at this time if you want to use it to
calculate sound volumes or damage amounts. Pass `None` if you
wish to use the pymunk default.
separate : ``func(space, arbiter, *args, **kwargs)``
Collision handler called when two shapes have just stopped
touching for the first time this frame. Pass `None` if you wish
to use the pymunk default.
args
Optional parameters passed to the collision handler functions.
kwargs
Optional keyword parameters passed on to the collision handler
functions.
"""
_functions = self._collision_function_helper(
begin, pre_solve, post_solve, separate, *args, **kwargs
)
self._default_handler = _functions
cp.cpSpaceSetDefaultCollisionHandler(self._space,
_functions[0], _functions[1], _functions[2], _functions[3], None)
def _collision_function_helper(self, begin, pre_solve, post_solve, separate, *args, **kwargs):
functions = [(begin, cp.cpCollisionBeginFunc)
, (pre_solve, cp.cpCollisionPreSolveFunc)
, (post_solve, cp.cpCollisionPostSolveFunc)
, (separate, cp.cpCollisionSeparateFunc)]
_functions = []
for func, func_type in functions:
if func is None:
_f = ct.cast(ct.POINTER(ct.c_int)(), func_type)
else:
_f = self._get_cf1(func, func_type, *args, **kwargs)
_functions.append(_f)
return _functions
[docs] def remove_collision_handler(self, a, b):
"""Remove a collision handler for a given collision type pair.
:Parameters:
a : int
Collision type of the first shape
b : int
Collision type of the second shape
"""
if (a, b) in self._handlers:
del self._handlers[(a, b)]
cp.cpSpaceRemoveCollisionHandler(self._space, a, b)
def _get_cf1(self, func, function_type, *args, **kwargs):
def cf(_arbiter, _space, _data):
arbiter = Arbiter(_arbiter, self)
return func(self, arbiter, *args, **kwargs)
return function_type(cf)
[docs] def add_post_step_callback(self, callback_function, obj, *args, **kwargs):
"""Add a function to be called last in the next simulation step.
Post step callbacks are registered as a function and an object used as
a key. You can only register one post step callback per object.
This function was more useful with earlier versions of pymunk where
you weren't allowed to use the add and remove methods on the space
during a simulation step. But this function is still available for
other uses and to keep backwards compatibility.
.. Note::
If you remove a shape from the callback it will trigger the
collision handler for the 'separate' event if it the shape was
touching when removed.
:Parameters:
callback_function : ``func(obj, *args, **kwargs)``
The callback function.
obj : Any object
This object is used as a key, you can only have one callback
for a single object. It is passed on to the callback function.
args
Optional parameters passed to the callback function.
kwargs
Optional keyword parameters passed on to the callback function.
:Return:
True if key was not previously added, False otherwise
"""
if obj in self._post_callback_keys:
return False
def cf(_space, key, data):
callback_function(obj, *args, **kwargs)
f = cp.cpPostStepFunc(cf)
self._post_last_callback_key += 1
self._post_callback_keys[obj] = self._post_last_callback_key
self._post_step_callbacks[obj] = f
key = self._post_callback_keys[obj]
return bool(cp.cpSpaceAddPostStepCallback(self._space, f, key, None))
[docs] def point_query(self, point, layers = -1, group = 0):
"""Query space at point filtering out matches with the given layers
and group. Return a list of found shapes.
If you don't want to filter out any matches, use -1 for the layers
and 0 as the group.
:Parameters:
point : (x,y) or `Vec2d`
Define where to check for collision in the space.
layers : int
Only pick shapes matching the bit mask. i.e.
(layers & shape.layers) != 0
group : int
Only pick shapes not in this group.
"""
self.__query_hits = []
def cf(_shape, data):
shape = self._get_shape(_shape)
self.__query_hits.append(shape)
f = cp.cpSpacePointQueryFunc(cf)
cp.cpSpacePointQuery(self._space, point, layers, group, f, None)
return self.__query_hits
[docs] def point_query_first(self, point, layers = -1, group = 0):
"""Query space at point and return the first shape found matching the
given layers and group. Returns None if no shape was found.
:Parameters:
point : (x,y) or `Vec2d`
Define where to check for collision in the space.
layers : int
Only pick shapes matching the bit mask. i.e.
(layers & shape.layers) != 0
group : int
Only pick shapes not in this group.
"""
_shape = cp.cpSpacePointQueryFirst(self._space, point, layers, group)
return self._get_shape(_shape)
def _get_shape(self, _shape):
if not bool(_shape):
return None
hashid_private = _shape.contents.hashid_private
#return self._shapes[hashid_private]
if hashid_private in self._shapes:
shape = self._shapes[hashid_private]
elif hashid_private in self._removed_shapes:
shape = self._removed_shapes[hashid_private]
return shape
[docs] def nearest_point_query(self, point, max_distance, layers = -1, group = 0):
"""Query space at point filtering out matches with the given layers
and group. Return a list of all shapes within max_distance of the point.
If you don't want to filter out any matches, use -1 for the layers
and 0 as the group.
:Parameters:
point : (x,y) or `Vec2d`
Define where to check for collision in the space.
max_distance : int
Maximumm distance of shape from point
layers : int
Only pick shapes matching the bit mask. i.e.
(layers & shape.layers) != 0
group : int
Only pick shapes not in this group.
:Return:
[dict(shape=`Shape`, distance = distance, point = Vec2d)]
"""
self.__query_hits = []
def cf(_shape, distance, point, data):
shape = self._get_shape(_shape)
self.__query_hits.append(dict(shape=shape, distance=distance, point=Vec2d(point)))
f = cp.cpSpaceNearestPointQueryFunc(cf)
cp.cpSpaceNearestPointQuery(self._space, point, max_distance, layers, group, f, None)
return self.__query_hits
[docs] def nearest_point_query_nearest(self, point, max_distance, layers = -1, group = 0):
"""Query space at point filtering out matches with the given layers
and group. Return nearest of all shapes within max_distance of the
point.
If you don't want to filter out any matches, use -1 for the layers
and 0 as the group.
:Parameters:
point : (x,y) or `Vec2d`
Define where to check for collision in the space.
max_distance : int
Maximumm distance of shape from point
layers : int
Only pick shapes matching the bit mask. i.e.
(layers & shape.layers) != 0
group : int
Only pick shapes not in this group.
:Return:
dict(shape=`Shape`, distance = distance, point = Vec2d)
"""
info = cp.cpNearestPointQueryInfo()
info_p = ct.POINTER(cp.cpNearestPointQueryInfo)(info)
_shape = cp.cpSpaceNearestPointQueryNearest(self._space, point, max_distance, layers, group, info_p)
shape = self._get_shape(_shape)
if shape != None:
return dict(shape=shape, point=info.p, distance=info.d)
return None
[docs] def segment_query(self, start, end, layers = -1, group = 0):
"""Query space along the line segment from start to end filtering out
matches with the given layers and group.
Segment queries are like ray casting, but because pymunk uses a
spatial hash to process collisions, it cannot process infinitely
long queries like a ray. In practice this is still very fast and you
don't need to worry too much about the performance as long as you
aren't using very long segments for your queries.
:Return:
[`SegmentQueryInfo`] - One SegmentQueryInfo object for each hit.
"""
self.__query_hits = []
def cf(_shape, t, n, data):
shape = self._get_shape(_shape)
info = SegmentQueryInfo(shape, start, end, t, n)
self.__query_hits.append(info)
f = cp.cpSpaceSegmentQueryFunc(cf)
cp.cpSpaceSegmentQuery(self._space, start, end, layers, group, f, None)
return self.__query_hits
[docs] def segment_query_first(self, start, end, layers = -1, group = 0):
"""Query space along the line segment from start to end filtering out
matches with the given layers and group. Only the first shape
encountered is returned and the search is short circuited.
Returns None if no shape was found.
"""
info = cp.cpSegmentQueryInfo()
info_p = ct.POINTER(cp.cpSegmentQueryInfo)(info)
_shape = cp.cpSpaceSegmentQueryFirst(self._space, start, end, layers, group, info_p)
shape = self._get_shape(_shape)
if shape != None:
return SegmentQueryInfo(shape, start, end, info.t, info.n)
return None
[docs] def bb_query(self, bb, layers = -1, group = 0):
"""Perform a fast rectangle query on the space.
Only the shape's bounding boxes are checked for overlap, not their
full shape. Returns a list of shapes.
"""
self.__query_hits = []
def cf(_shape, data):
shape = self._get_shape(_shape)
self.__query_hits.append(shape)
f = cp.cpSpaceBBQueryFunc(cf)
cp.cpSpaceBBQuery(self._space, bb._bb, layers, group, f, None)
return self.__query_hits
[docs] def shape_query(self, shape):
"""Query a space for any shapes overlapping the given shape
Returns a list of shapes.
"""
self.__query_hits = []
def cf(_shape, points, data):
shape = self._get_shape(_shape)
self.__query_hits.append(shape)
f = cp.cpSpaceShapeQueryFunc(cf)
cp.cpSpaceShapeQuery(self._space, shape._shape, f, None)
return self.__query_hits
[docs]class Body(object):
"""A rigid body
* Use forces to modify the rigid bodies if possible. This is likely to be
the most stable.
* Modifying a body's velocity shouldn't necessarily be avoided, but
applying large changes can cause strange results in the simulation.
Experiment freely, but be warned.
* Don't modify a body's position every step unless you really know what
you are doing. Otherwise you're likely to get the position/velocity badly
out of sync.
"""
[docs] def __init__(self, mass=None, moment=None):
"""Create a new Body
To create a static body, pass in None for mass and moment.
"""
if mass == None and moment == None:
self._body = cp.cpBodyNewStatic()
else:
self._body = cp.cpBodyNew(mass, moment)
self._bodycontents = self._body.contents
self._position_callback = None # To prevent the gc to collect the callbacks.
self._velocity_callback = None # To prevent the gc to collect the callbacks.
self._space = None # Weak ref to the space holding this body (if any)
self._constraints = WeakSet() # weak refs to any constraints attached
self._shapes = WeakSet() # weak refs to any shapes attached
def __del__(self):
try:
cp.cpBodyFree(self._body)
except:
pass
def _set_mass(self, mass):
cp.cpBodySetMass(self._body, mass)
def _get_mass(self):
return self._bodycontents.m
mass = property(_get_mass, _set_mass)
def _set_moment(self, moment):
cp.cpBodySetMoment(self._body, moment)
def _get_moment(self):
return self._bodycontents.i
moment = property(_get_moment, _set_moment)
def _set_angle(self, angle):
cp.cpBodySetAngle(self._body, angle)
def _get_angle(self):
return self._bodycontents.a
angle = property(_get_angle, _set_angle,
doc="""The rotation of the body.
.. Note::
If you get small/no changes to the angle when for example a
ball is "rolling" down a slope it might be because the Circle shape
attached to the body or the slope shape does not have any friction
set.""")
def _get_rotation_vector(self):
return self._bodycontents.rot
rotation_vector = property(_get_rotation_vector)
def _set_torque(self, t):
self._bodycontents.t = t
def _get_torque(self):
return self._bodycontents.t
torque = property(_get_torque, _set_torque)
def _set_position(self, pos):
self._bodycontents.p = pos
def _get_position(self):
return self._bodycontents.p
position = property(_get_position, _set_position)
def _set_velocity(self, vel):
self._bodycontents.v = vel
def _get_velocity(self):
return self._bodycontents.v
velocity = property(_get_velocity, _set_velocity)
def _set_velocity_limit(self, vel):
self._bodycontents.v_limit = vel
def _get_velocity_limit(self):
return self._bodycontents.v_limit
velocity_limit = property(_get_velocity_limit, _set_velocity_limit)
def _set_angular_velocity(self, w):
self._bodycontents.w = w
def _get_angular_velocity(self):
return self._bodycontents.w
angular_velocity = property(_get_angular_velocity, _set_angular_velocity)
def _set_angular_velocity_limit(self, w):
self._bodycontents.w_limit = w
def _get_angular_velocity_limit(self):
return self._bodycontents.w_limit
angular_velocity_limit = property(_get_angular_velocity_limit, _set_angular_velocity_limit)
def _set_force(self, f):
self._bodycontents.f = f
def _get_force(self):
return self._bodycontents.f
force = property(_get_force, _set_force)
def _set_velocity_func(self, func):
"""The velocity callback function. The velocity callback function
is called each time step, and can be used to set a body's velocity.
``func(body, gravity, damping, dt) -> None``
Callback Parameters
body : `Body`
Body that should have its velocity calculated
gravity : `Vec2d`
The gravity vector
damping : float
The damping
dt : float
Delta time since last step.
"""
def _impl(_, gravity, damping, dt):
return func(self, gravity, damping, dt)
self._velocity_callback = cp.cpBodyVelocityFunc(_impl)
self._bodycontents.velocity_func = self._velocity_callback
velocity_func = property(fset=_set_velocity_func,
doc=_set_velocity_func.__doc__)
def _set_position_func(self, func):
"""The position callback function. The position callback function
is called each time step and can be used to update the body's position.
``func(body, dt) -> None``
Callback Parameters
body : `Body`
Body that should have its velocity calculated
dt : float
Delta time since last step.
"""
def _impl(_, dt):
func(self, dt)
return 0
self._position_callback = cp.cpBodyPositionFunc(_impl)
self._bodycontents.position_func = self._position_callback
position_func = property(fset=_set_position_func,
doc=_set_position_func.__doc__)
def _get_kinetic_energy(self):
#todo: use ffi method
#return cp._cpBodyKineticEnergy(self._body)
vsq = self.velocity.dot(self.velocity)
wsq = self.angular_velocity * self.angular_velocity
return (vsq*self.mass if vsq else 0.) + (wsq*self.moment if wsq else 0.)
kinetic_energy = property(_get_kinetic_energy,
doc="""Get the kinetic energy of a body.""")
@staticmethod
[docs] def update_velocity(body, gravity, damping, dt):
"""Default rigid body velocity integration function.
Updates the velocity of the body using Euler integration.
"""
cp.cpBodyUpdateVelocity(body._body, gravity, damping, dt)
@staticmethod
[docs] def update_position(body, dt):
"""Default rigid body position integration function.
Updates the position of the body using Euler integration. Unlike the
velocity function, it's unlikely you'll want to override this
function. If you do, make sure you understand it's source code
(in Chipmunk) as it's an important part of the collision/joint
correction process.
"""
cp.cpBodyUpdatePosition(body._body, dt)
[docs] def apply_impulse(self, j, r=(0, 0)):
"""Apply the impulse j to body at a relative offset (important!) r
from the center of gravity. Both r and j are in world coordinates.
:Parameters:
j : (x,y) or `Vec2d`
Impulse to be applied
r : (x,y) or `Vec2d`
Offset the impulse with this vector
"""
cp.cpBodyApplyImpulse(self._body, j, r)
[docs] def reset_forces(self):
"""Zero both the forces and torques accumulated on body"""
cp.cpBodyResetForces(self._body)
[docs] def apply_force(self, f, r=(0, 0)):
"""Apply (accumulate) the force f on body at a relative offset
(important!) r from the center of gravity.

:Parameters:
f : (x,y) or `Vec2d`
Force in world coordinates
r : (x,y) or `Vec2d`
Offset in world coordinates
"""
cp.cpBodyApplyForce(self._body, f, r)
[docs] def activate(self):
"""Wake up a sleeping or idle body."""
cp.cpBodyActivate(self._body)
[docs] def sleep(self):
"""Force a body to fall asleep immediately."""
cp.cpBodySleep(self._body)
[docs] def sleep_with_group(self, body):
"""Force a body to fall asleep immediately along with other bodies in a group.
"""
cp.cpBodySleepWithGroup(self._body, body._body)
def _is_sleeping(self):
return cpffi.cpBodyIsSleeping(self._body)
is_sleeping = property(_is_sleeping,
doc="""Returns true if the body is sleeping.""")
def _is_rogue(self):
return cpffi.cpBodyIsRogue(self._body)
is_rogue = property(_is_rogue,
doc="""Returns true if the body has not been added to a space.""")
def _is_static(self):
return cpffi.cpBodyIsStatic(self._body)
is_static = property(_is_static,
doc="""Returns true if the body is a static body""")
[docs] def each_arbiter(self, func, *args, **kwargs):
"""Run func on each of the arbiters on this body.
``func(arbiter, *args, **kwargs) -> None``
Callback Parameters
arbiter : `Arbiter`
The Arbiter
args
Optional parameters passed to the callback function.
kwargs
Optional keyword parameters passed on to the callback function.
.. warning::
Do not hold on to the Arbiter after the callback!
"""
def impl(body, _arbiter, _):
arbiter = Arbiter(_arbiter, self._space)
func(arbiter, *args, **kwargs)
return 0
f = cp.cpBodyArbiterIteratorFunc(impl)
cp.cpBodyEachArbiter(self._body, f, None)
def _get_constraints(self):
return set(self._constraints)
constraints = property(_get_constraints,
doc="""Get the constraints this body is attached to.""")
def _get_shapes(self):
return set(self._shapes)
shapes = property(_get_shapes,
doc="""Get the shapes attached to this body.""")
[docs] def local_to_world(self, v):
"""Convert body local coordinates to world space coordinates
:Parameters:
v : (x,y) or `Vec2d`
Vector in body local coordinates
"""
return cpffi.cpBodyLocal2World(self._body, v)
[docs] def world_to_local(self, v):
"""Convert world space coordinates to body local coordinates
:Parameters:
v : (x,y) or `Vec2d`
Vector in world space coordinates
"""
return cpffi.cpBodyWorld2Local(self._body, v)
[docs]class Shape(object):
"""Base class for all the shapes.
You usually dont want to create instances of this class directly but use
one of the specialized shapes instead.
"""
[docs] def __init__(self, shape=None):
self._shape = shape
self._shapecontents = self._shape.contents
self._body = shape.body
self.data = None
def __del__(self):
try:
cp.cpShapeFree(self._shape)
except:
pass
def _get_hashid_private(self):
return self._shapecontents.hashid_private
_hashid_private = property(_get_hashid_private)
def _get_sensor(self):
return bool(self._shapecontents.sensor)
def _set_sensor(self, is_sensor):
self._shapecontents.sensor = is_sensor
sensor = property(_get_sensor, _set_sensor,
doc="""A boolean value if this shape is a sensor or not. Sensors only
call collision callbacks, and never generate real collisions.""")
def _get_collision_type(self):
return self._shapecontents.collision_type
def _set_collision_type(self, t):
self._shapecontents.collision_type = t
collision_type = property(_get_collision_type, _set_collision_type,
doc="""User defined collision type for the shape. See
add_collisionpair_func function for more information on when to use
this property""")
def _get_group(self):
return self._shapecontents.group
def _set_group(self, group):
self._shapecontents.group = group
group = property(_get_group, _set_group,
doc="""Shapes in the same non-zero group do not generate collisions.
Useful when creating an object out of many shapes that you don't want
to self collide. Defaults to 0""")
def _get_layers(self):
return self._shapecontents.layers
def _set_layers(self, layers):
self._shapecontents.layers = layers
layers = property(_get_layers, _set_layers,
doc="""Shapes only collide if they are in the same bit-planes.
i.e. (a.layers & b.layers) != 0. By default, a shape occupies all
32 bit-planes, i.e. layers == -1""")
def _get_elasticity(self):
return self._shapecontents.e
def _set_elasticity(self, e):
self._shapecontents.e = e
elasticity = property(_get_elasticity, _set_elasticity,
doc="""Elasticity of the shape.  However due to
inaccuracies in the simulation using 1.0 or greater is not
recommended.""")
def _get_friction(self):
return self._shapecontents.u
def _set_friction(self, u):
self._shapecontents.u = u
friction = property(_get_friction, _set_friction,
doc="""Friction coefficient. pymunk uses the Coulomb friction model, a
value of 0.0 is frictionless.
A value over 1.0 is perfectly fine.
Some real world example values from wikipedia (Remember that
it is what looks good that is important, not the exact value).
============== ====== ========
Material Other Friction
============== ====== ========
Aluminium Steel 0.61
Copper Steel 0.53
Brass Steel 0.51
Cast iron Copper 1.05
Cast iron Zinc 0.85
Concrete (wet) Rubber 0.30
Concrete (dry) Rubber 1.0
Concrete Wood 0.62
Copper Glass 0.68
Glass Glass 0.94
Metal Wood 0.5
Polyethene Steel 0.2
Steel Steel 0.80
Steel Teflon 0.04
Teflon (PTFE) Teflon 0.04
Wood Wood 0.4
============== ====== ========
""")
def _get_surface_velocity(self):
return self._shapecontents.surface_v
def _set_surface_velocity(self, surface_v):
self._shapecontents.surface_v = surface_v
surface_velocity = property(_get_surface_velocity, _set_surface_velocity,
doc="""The surface velocity of the object. Useful for creating
conveyor belts or players that move around. This value is only used
when calculating friction, not resolving the collision.""")
def _get_body(self):
return self._body
def _set_body(self, body):
if self._body != None:
self._body._shapes.remove(self)
if body != None:
body._shapes.add(self)
self._shapecontents.body = body._body
else:
self._shapecontents.body = None
self._body = body
body = property(_get_body, _set_body,
doc="""The body this shape is attached to. Can be set to None to
indicate that this shape doesnt belong to a body.""")
[docs] def update(self, position, rotation_vector):
"""Update, cache and return the bounding box of a shape with an
explicit transformation.
Useful if you have a shape without a body and want to use it for
querying.
"""
return BB(cp.cpShapeUpdate(self._shape, position, rotation_vector))
[docs] def cache_bb(self):
"""Update and returns the bouding box of this shape"""
return BB(cp.cpShapeCacheBB(self._shape))
def _get_bb(self):
return BB(cpffi.cpShapeGetBB(self._shape))
bb = property(_get_bb, doc="""The bounding box of the shape.
Only guaranteed to be valid after Shape.cache_bb() or Space.step() is
called. Moving a body that a shape is connected to does not update it's
bounding box. For shapes used for queries that aren't attached to bodies,
you can also use Shape.update().
""")
[docs] def point_query(self, p):
"""Check if the given point lies within the shape."""
return bool(cp.cpShapePointQuery(self._shape, p))
[docs] def segment_query(self, start, end):
"""Check if the line segment from start to end intersects the shape.
Return either SegmentQueryInfo object or None
"""
info = cp.cpSegmentQueryInfo()
info_p = ct.POINTER(cp.cpSegmentQueryInfo)(info)
r = cp.cpShapeSegmentQuery(self._shape, start, end, info_p)
if bool(r):
return SegmentQueryInfo(self, start, end, info.t, info.n)
else:
return None
[docs]class Circle(Shape):
"""A circle shape defined by a radius
This is the fastest and simplest collision shape
"""
[docs] def __init__(self, body, radius, offset = (0, 0)):
"""body is the body attach the circle to, offset is the offset from the
body's center of gravity in body local coordinates.
It is legal to send in None as body argument to indicate that this
shape is not attached to a body.
"""
self._body = body
body_body = None if body is None else body._body
if body != None:
body._shapes.add(self)
self._shape = cp.cpCircleShapeNew(body_body, radius, offset)
self._shapecontents = self._shape.contents
self._cs = ct.cast(self._shape, ct.POINTER(cp.cpCircleShape))
[docs] def unsafe_set_radius(self, r):
"""Unsafe set the radius of the circle.
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
cp.cpCircleShapeSetRadius(self._shape, r)
def _get_radius(self):
return cp.cpCircleShapeGetRadius(self._shape)
radius = property(_get_radius, doc="""The Radius of the circle""")
[docs] def unsafe_set_offset(self, o):
"""Unsafe set the offset of the circle.
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
cp.cpCircleShapeSetOffset(self._shape, o)
def _get_offset (self):
return cp.cpCircleShapeGetOffset(self._shape)
offset = property(_get_offset, doc="""Offset. (body space coordinates)""")
[docs]class Segment(Shape):
"""A line segment shape between two points
This shape can be attached to moving bodies, but don't currently generate
collisions with other line segments. Can be beveled in order to give it a
thickness.
It is legal to send in None as body argument to indicate that this
shape is not attached to a body.
"""
[docs] def __init__(self, body, a, b, radius):
"""Create a Segment
:Parameters:
body : `Body`
The body to attach the segment to
a : (x,y) or `Vec2d`
The first endpoint of the segment
b : (x,y) or `Vec2d`
The second endpoint of the segment
radius : float
The thickness of the segment
"""
self._body = body
body_body = None if body is None else body._body
if body != None:
body._shapes.add(self)
self._shape = cp.cpSegmentShapeNew(body_body, a, b, radius)
self._shapecontents = self._shape.contents
[docs] def unsafe_set_a(self, a):
"""Set the first of the two endpoints for this segment
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
ct.cast(self._shape, ct.POINTER(cp.cpSegmentShape)).contents.a = a
def _get_a(self):
return ct.cast(self._shape, ct.POINTER(cp.cpSegmentShape)).contents.a
a = property(_get_a,
doc="""The first of the two endpoints for this segment""")
[docs] def unsafe_set_b(self, b):
"""Set the second of the two endpoints for this segment
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
ct.cast(self._shape, ct.POINTER(cp.cpSegmentShape)).contents.b = b
def _get_b(self):
return ct.cast(self._shape, ct.POINTER(cp.cpSegmentShape)).contents.b
b = property(_get_b,
doc="""The second of the two endpoints for this segment""")
[docs] def unsafe_set_radius(self, r):
"""Set the radius of the segment
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
ct.cast(self._shape, ct.POINTER(cp.cpSegmentShape)).contents.r = r
def _get_radius(self):
return ct.cast(self._shape, ct.POINTER(cp.cpSegmentShape)).contents.r
radius = property(_get_radius,
doc="""The radius/thickness of the segment""")
[docs]class Poly(Shape):
"""A convex polygon shape
Slowest, but most flexible collision shape.
It is legal to send in None as body argument to indicate that this
shape is not attached to a body.
"""
[docs] def __init__(self, body, vertices, offset=(0, 0), radius=0):
"""Create a polygon
body : `Body`
The body to attach the poly to
vertices : [(x,y)] or [`Vec2d`]
Define a convex hull of the polygon with a counterclockwise
winding.
offset : (x,y) or `Vec2d`
The offset from the body's center of gravity in body local
coordinates.
radius : int
Set the radius of the poly shape.
"""
self._body = body
self.offset = offset
self._set_verts(vertices)
body_body = None if body is None else body._body
if body != None:
body._shapes.add(self)
self._shape = cp.cpPolyShapeNew2(body_body, len(vertices), self.verts, offset, radius)
self._shapecontents = self._shape.contents
[docs] def unsafe_set_radius(self, radius):
"""Unsafe set the radius of the poly.
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
cp.cpPolyShapeSetRadius(self._shape, radius)
def _get_radius(self):
return cp.cpPolyShapeGetRadius(self._shape)
radius = property(_get_radius,
doc="""The radius of the poly shape. Extends the poly in all
directions with the given radius""")
def _set_verts(self, vertices):
auto_order_vertices = True
self.verts = (Vec2d * len(vertices))
self.verts = self.verts(Vec2d(0, 0))
i_vs = enumerate(vertices)
if auto_order_vertices and not u.is_clockwise(vertices):
i_vs = zip(range(len(vertices)-1, -1, -1), vertices)
for (i, vertex) in i_vs:
self.verts[i].x = vertex[0]
self.verts[i].y = vertex[1]
@staticmethod
[docs] def create_box(body, size=(10,10), offset=(0,0), radius=0):
"""Convenience function to create a box centered around the body position.
The size is given as as (w,h) tuple.
"""
x,y = size[0]*.5,size[1]*.5
vs = [(-x,-y),(-x,y),(x,y),(x,-y)]
return Poly(body, vs, offset, radius)
[docs] def get_vertices(self):
"""Get the vertices in world coordinates for the polygon
:return: [`Vec2d`] in world coords
"""
#shape = ct.cast(self._shape, ct.POINTER(cp.cpPolyShape))
#num = shape.contents.numVerts
#verts = shape.contents.verts
points = []
rv = self._body.rotation_vector
bp = self._body.position
vs = self.verts
o = self.offset
for i in range(len(vs)):
p = (vs[i]+o).cpvrotate(rv)+bp
points.append(Vec2d(p))
return points
[docs] def unsafe_set_vertices(self, vertices, offset=(0, 0)):
"""Unsafe set the vertices of the poly.
.. note::
This change is only picked up as a change to the position
of the shape's surface, but not it's velocity. Changing it will
not result in realistic physical behavior. Only use if you know
what you are doing!
"""
self._set_verts(vertices)
cp.cpPolyShapeSetVerts(self._shape, len(vertices), self.verts, offset)
[docs]class SegmentQueryInfo(object):
"""Segment queries return more information than just a simple yes or no,
they also return where a shape was hit and it's surface normal at the hit
point. This object hold that information.
"""
[docs] def __init__(self, shape, start, end, t, n):
"""You shouldn't need to initialize SegmentQueryInfo objects on your
own.
"""
self._shape = shape
self._t = t
self._n = n
self._start = start
self._end = end
def __repr__(self):
return "SegmentQueryInfo(%s, %s, %s, %s, %s)" % (self.shape, self._start, self._end, self.t, self.n)
shape = property(lambda self: self._shape
, doc = """Shape that was hit""")
t = property(lambda self: self._t
, doc = """Distance along query segment, will always be in the range [0, 1]""")
n = property(lambda self: self._n
, doc = """Normal of hit surface""")
[docs] def get_hit_point(self):
"""Return the hit point in world coordinates where the segment first
intersected with the shape
"""
#todo: use ffi function
return Vec2d(self._start).interpolate_to(self._end, self.t)
[docs] def get_hit_distance(self):
"""Return the absolute distance where the segment first hit the shape
"""
#todo: use ffi function
return Vec2d(self._start).get_distance(self._end) * self.t
[docs]def moment_for_circle(mass, inner_radius, outer_radius, offset=(0, 0)):
"""Calculate the moment of inertia for a circle"""
return cp.cpMomentForCircle(mass, inner_radius, outer_radius, offset)
[docs]def moment_for_segment(mass, a, b):
"""Calculate the moment of inertia for a segment"""
return cp.cpMomentForSegment(mass, a, b)
[docs]def moment_for_poly(mass, vertices, offset=(0, 0)):
"""Calculate the moment of inertia for a polygon"""
verts = (Vec2d * len(vertices))
verts = verts(Vec2d(0, 0))
for (i, vertex) in enumerate(vertices):
verts[i].x = vertex[0]
verts[i].y = vertex[1]
return cp.cpMomentForPoly(mass, len(verts), verts, offset)
[docs]def moment_for_box(mass, width, height):
"""Calculate the momentn of inertia for a box"""
return cp.cpMomentForBox(mass, width, height)
[docs]def reset_shapeid_counter():
"""Reset the internal shape counter
pymunk keeps a counter so that every new shape is given a unique hash
value to be used in the spatial hash. Because this affects the order in
which the collisions are found and handled, you should reset the shape
counter every time you populate a space with new shapes. If you don't,
there might be (very) slight differences in the simulation.
"""
cp.cpResetShapeIdCounter()
[docs]class Arbiter(object):
"""Arbiters are collision pairs between shapes that are used with the
collision callbacks.
.. Warning::
Because arbiters are handled by the space you should never
hold onto a reference to an arbiter as you don't know when it will be
destroyed! Use them within the callback where they are given to you
and then forget about them or copy out the information you need from
them.
"""
[docs] def __init__(self, _arbiter, space):
"""Initialize an Arbiter object from the Chipmunk equivalent struct
and the Space.
.. note::
You should never need to create an instance of this class directly.
"""
self._arbiter = _arbiter
self._arbitercontents = self._arbiter.contents
self._space = space
self._contacts = None # keep a lazy loaded cache of converted contacts
def _get_contacts(self):
point_set = cp.cpArbiterGetContactPointSet(self._arbiter)
if self._contacts is None:
self._contacts = []
for i in range(point_set.count):
self.contacts.append(Contact(point_set.points[i]))
return self._contacts
contacts = property(_get_contacts,
doc="""Information on the contact points between the objects. Return [`Contact`]""")
def _get_shapes(self):
shapeA_p = ct.POINTER(cp.cpShape)()
shapeB_p = ct.POINTER(cp.cpShape)()
cpffi.cpArbiterGetShapes(self._arbiter, shapeA_p, shapeB_p)
a, b = self._space._get_shape(shapeA_p), self._space._get_shape(shapeB_p)
return a, b
shapes = property(_get_shapes,
doc="""Get the shapes in the order that they were defined in the
collision handler associated with this arbiter""")
def _get_elasticity(self):
return self._arbiter.contents.e
def _set_elasticity(self, elasticity):
self._arbiter.contents.e = elasticity
elasticity = property(_get_elasticity, _set_elasticity,
doc="""Elasticity""")
def _get_friction(self):
return self._arbiter.contents.u
def _set_friction(self, friction):
self._arbiter.contents.u = friction
friction = property(_get_friction, _set_friction, doc="""Friction""")
def _get_surface_velocity(self):
return self._arbiter.contents.surface_vr
surface_velocity = property(_get_surface_velocity,
doc="""Used for surface_v calculations, implementation may change""")
def _get_total_impulse(self):
return cp.cpArbiterTotalImpulse(self._arbiter)
total_impulse = property(_get_total_impulse,
doc="""Returns the impulse that was applied this step to resolve the
collision.
This property should only be called from a post-solve, post-step""")
def _get_total_impulse_with_friction(self):
return cp.cpArbiterTotalImpulseWithFriction(self._arbiter)
total_impulse_with_friction = property(_get_total_impulse_with_friction,
doc="""Returns the impulse with friction that was applied this step to
resolve the collision.
This property should only be called from a post-solve, post-step""")
def _get_total_ke(self):
return cp.cpArbiterTotalKE(self._arbiter)
total_ke = property(_get_total_ke,
doc="""The amount of energy lost in a collision including static, but
not dynamic friction.
This property should only be called from a post-solve, post-step""")
def _get_stamp(self):
return self._arbiter.contents.stamp
stamp = property(_get_stamp,
doc="""Time stamp of the arbiter. (from the space)""")
def _get_is_first_contact(self):
return bool(cpffi.cpArbiterIsFirstContact(self._arbiter))
is_first_contact = property(_get_is_first_contact,
doc="""Returns true if this is the first step that an arbiter existed.
You can use this from preSolve and postSolve to know if a collision
between two shapes is new without needing to flag a boolean in your
begin callback.""")
[docs]class BB(object):
"""Simple bounding box class. Stored as left, bottom, right, top values."""
[docs] def __init__(self, *args):
"""Create a new instance of a bounding box. Can be created with zero
size with bb = BB() or with four args defining left, bottom, right and
top: bb = BB(left, bottom, right, top)
"""
if len(args) == 0:
self._bb = cp.cpBB()
elif len(args) == 1:
self._bb = args[0]
else:
self._bb = cpffi.cpBBNew(args[0], args[1], args[2], args[3])
def __repr__(self):
return 'BB(%s, %s, %s, %s)' % (self.left, self.bottom, self.right, self.top)
def __eq__(self, other):
return self.left == other.left and self.bottom == other.bottom and \
self.right == other.right and self.top == other.top
def __ne__(self, other):
return not self.__eq__(other)
[docs] def intersects(self, other):
"""Returns true if the bounding boxes intersect"""
return bool(cpffi.cpBBIntersects(self._bb, other._bb))
[docs] def contains(self, other):
"""Returns true if bb completley contains the other bb"""
return bool(cpffi.cpBBContainsBB(self._bb, other._bb))
[docs] def contains_vect(self, v):
"""Returns true if this bb contains the vector v"""
return bool(cpffi.cpBBContainsVect(self._bb, v))
[docs] def merge(self, other):
"""Return the minimal bounding box that contains both this bb and the
other bb
"""
return BB(cpffi.cpBBMerge(self._bb, other._bb))
[docs] def expand(self, v):
"""Return the minimal bounding box that contans both this bounding box
and the vector v
"""
return BB(cpffi.cpBBExpand(self._bb, v))
left = property(lambda self: self._bb.l)
bottom = property(lambda self: self._bb.b)
right = property(lambda self: self._bb.r)
top = property(lambda self: self._bb.t)
[docs] def clamp_vect(self, v):
"""Returns a copy of the vector v clamped to the bounding box"""
return cpffi.cpBBClampVect(self._bb, v)
[docs] def wrap_vect(self, v):
"""Returns a copy of v wrapped to the bounding box.
That is, BB(0,0,10,10).wrap_vect((5,5)) == Vec2d(10,10)
"""
return cp.cpBBWrapVect(self._bb, v)
#del cp, ct, u


Reports confusing else branches. else branches are confusing
when the if statement is followed by other statements and the if branch
cannot complete normally, for example because it ends with a return statement. In these
cases the statements in the else can be moved after the if statement and
the else branch removed.
Use the checkbox below to also report else branches of if statements whose
if branch cannot complete normally and which are not followed by more statements,
similar to the Redundant Else intention.
Powered by InspectionGadgets


Greetings comrade, This is what I created my fourth week of Digital Engineering This is the box that I designed in CorelDRAW, I used the laser cutter to inscirbe my image onto the surface of the cardboard, I used a mixture of rastering and vectoring cuts to create my design and cut out the pieces. This is my final result for the box I created. Second, I made a press fit kit using CorelDRAW and the laser cutter, I made hairline cuts for the laser to cut out the pieces of cardboard.
Here is my final design for the press fit kit!!!! Next I made a cork coaster designed again in CorelDRAW and laser inscibed the image onto a circular cork coaster. Lastly, I designed a Skyrim themed lether bracelet that has all the Skyrim holds inscribed on it.


SUDOGEST - pseudoephedrine hydrochloride liquid
Major Pharmaceuticals, Inc
Disclaimer: Most OTC drugs are not reviewed and approved by FDA, however they may be marketed if they comply with applicable regulations and policies. FDA has not evaluated whether this product complies.
Drug Facts
Active ingredient (in each 5 mL) Purpose
Pseudoephedrine hydrochloride 15 mg .............. Nasal decongestant
Uses
-
temporarily relieves nasal congestion due to common cold, hay fever or other upper respiratory allergies
- temporarily relieves sinus congestion and pressure
- promotes nasal and/or sinus drainage
Warnings
-
Do not use if you are now taking a prescription monoamine oxidase inhibitor (MAOI) (certain drugs for depression, psychiatric or emotional conditions or Parkinson’s disease), or for 2 weeks after stopping the MAOI drug. If you do not know if your prescription drug contains an MAOI, ask a doctor or pharmacist before taking this product.
Ask a doctor before use if you have
- heart disease
- high blood pressure
- thyroid disease
- diabetes
- trouble urinating due to an enlarged prostate gland
- a sodium restricted diet
When using this product do not use more than directed
Stop use and ask a doctor if
- you get nervous, dizzy or sleepless
- symptoms do not improve within 7 days or occur with fever
If pregnant or breast-feeding, ask a health professional before use. Keep out of the reach of children. In case of overdose, get medical help or contact a poison control center right away.
Directions
- Take at every 6 hours, if needed
- Do not exceed 4 doses in 24 hours.
Adults and children 12 years of age and over
|
4 teaspoonfuls (tsp)
|
Children 6 to under 12 years of age
|
2 teaspoonfuls (tsp)
|
| Children under 6 years of age |
DO NOT USE
|
Other information store at room temperature
Inactive ingredients
citric acid, FD&C blue no. 1, FD&C red no. 40, glycerin, grape flavor, purified water, saccharin sodium, sodium benzoate, sodium citrate, sorbitol solution.
Questions? Serious Adverse Effects call:
800-616-2471
†Major SudoGest is not manufactured or distributed by Pfizer Consumer Healthcare, distributor of Children's Sudafed® Nasal Decongestant.
Distributed by:
Major Pharmaceuticals
31778 Enterprise Drive
Livonia, MI 48150 USA


Message from James Gustave Speth for the International Day for the
Eradication of Poverty
New York, 17 October 1995
International Day for the Eradication of Poverty
Mr. James Gustave Speth
Each day, 67,000 people are added to the ranks of the world's poor.
That means over the course of a year, nearly 25 million additional people
will be trapped in a life of substandard living conditions, hunger and
limited opportunities for a better life. Most of these people will be in
the developing world, and seven out of 10 will be female.
With the prospect of as many as 1.5 billion people living in poverty
by the year 2025, today should be marked as a day of alarm.
But it should also be marked as a day of optimism because the international
community has begun to work together to tackle this problem, which afflicts
all regions of the world.
At the Social Summit, which took place in Copenhagen last March, world
leaders came together to acknowledge the worsening problem of global poverty,
deplore its spread and commit themselves to actions to reverse the trend.
Never before have so many heads of state and government joined hands to
reach a consensus for building a poverty-free world.
The agreements reached in Copenhagen were revolutionary in their scope,
complexity and urgency. They recognized the key role to be played by people-centered
development in eradicating poverty and reminded all of us that escaping
poverty is about a lot more than higher incomes -- it is also about greater,
equity, opportunity and empowerment.
In Copenhagen, governments committed themselves to the goal of eradicating
poverty "as an ethical, social, political and economic imperative
of humankind," by ensuring that "people living in poverty have
access to productive resources, including credit, land, education and training,
technology, knowledge and information, and to public services."
One of the most important steps toward achieving these goals, according
to the Copenhagen agreements, is to formulate or strengthen national strategies
to reduce poverty and narrow the gap between the haves and the have-nots.
These strategies must have clear definitions of poverty and specific targets
for eradicating it.
The United Nations Development Programme is committed to assisting governments
in the preparation of these strategies. We will offer both financial and
technical assistance to get the job done and to help countries formulate
and implement national policies that are conducive to equitable social
and economic advancement. A strong "enabling environment" that
supports growth; gives priority to the poor and to jobs and sustainable
livelihoods; and encourages participation, tolerance and respect for human
diversity and the rule of law, is absolutely central to any actions aimed
at eradicating poverty.
This enabling environment must promote justice and fundamental fairness
among nations as well as within them. This means strong countries giving
access to their markets to weaker countries. It means sharing modern technology.
And it means financial support for development assistance and debt relief.
Debt continues to cripple too many economies and prevents them from making
crucial investments in human development.
Poverty eradication will only be achieved and be sustainable if we attack
the root causes of poverty.
Eliminating poverty is the most important objective pursued by UNDP
through its commitment to sustainable human development. The priority we
assign to poverty eradication was endorsed by our Executive Board in June.
The other three main dimensions of UNDP's work are advancing women's role
in development, protecting and regenerating the environment, and creating
employment.
UNDP aims to bring its commitments to women, the environment, and jobs
into a broad drive to eliminate poverty. To succeed, UNDP will continue
to be an agency which pursues sustainable human development in all sectors,
all issues and all policies that have a substantial impact on the prospects
for poverty eradication and increased equity.
UN-sponsored conferences like the Social Summit, last year's International
Conference on Population and Development, and last September's Fourth World
Conference on Women, have called for interdisciplinary and multisectoral
responses to monumental development challenges. I believe we are beginning
to pull everything together and are seeing some real progress. Building
new alliances among UN agencies has been crucial to this end. UN agencies
just this week took a major step forward in building such alliances.
Several multi-agency task forces have been established to enable UN
development agencies and programs to take the lead in following up to commitments
made at the Social Summit and other international conferences. These task
forces will focus the UN system's energies on expanding basic socialservices
in developing countries, increasing access to productive assets and income,
and building an enabling environment -- all of which are critical components
of our collective responsibility to combat poverty.
Our goal for today -- and for the International Year for the Eradication
of Poverty, which begins in December -- is to maintain the momentum gained
in Copenhagen and to constantly search for innovative ways to transform
the concepts presented at Social Summit into a reality that lifts people
out of poverty, builds equity and -- more than anything else -- makes a
difference in peoples lives.
|


COVID-19 UK Choropleth Map
UK latest COVID-19 cases breakdown
London latest COVID-19 cases breakdown


This theme is a skin for Bootstrap, which means that can be used with any site built with the Bootstrap framework 3. With easy installation and customization thanks to the LESS/SASS files included and the custom themes colors ready to use. This skin is based on a material design and also extends the styles directly applied to Bootstrap files. There’s no overwritten rules or bloating CSS, making a lightweight skin as Boostrap is itself.
If you like the project, please support it, you will donate to it and put like
IE9+, Opera, Safari, Yandex browser, Chrome, Firefox, Mobile Safari, Android
http://stas-melnikov.ru/material_bootstrap_theme/
http://stas-melnikov.ru e-mail<EMAIL_ADDRESS>linkedIn: https://www.linkedin.com/in/melnik909 github: https://github.com/melnik909 facebook: https://www.facebook.com/melnik909
MIT


Destiny C++ | Overview | Reference | Sorting
Class and Object Design
| rsl2D | R_D | Martin's
Questions
Foundation 2.5 prototype releases
Bold are relatively major releases - use the latest bold one. Red
releases are gone.
Alpha pre-releases
- 2.5a6.2a - Dec 4 R_D and NULL
- 2.5a6.2 - Dec 3 patches to 6.1
- 2.5a6.1 - Nov 23 pseudo-operator
->
- 2.5a6 - Nov 23 autodoc
- 2.5a5.9 - Nov 17
- 2.5a5.8 - Nov 13
- 2.5a5.5 - Nov 11 working
foundation
- 2.5a5 - Nov 10
- 2.5a4.9 - Nov 9
- 2.5a4.8 - Nov 4 - secondary
references
- 2.5a4.5 - Nov
2 - memory management!
- 2.5a4.02 - Oct 23
- 2.5a4.01 - Oct 23
- 2.5a3 - Oct 21 - final working rsl2D
- 2.5a2 - Oct 14
- 2.5a1 - Oct 13
everything above lives in /dest/applied/gf2.5/Releases/gf/
Pre-pre- alpha
2.5a6.2a Dec 4
- R_D is updated to handle NULL in the following way:
- if the return value of any message route to D is NULL, a new R_D is returned
which points to NULL, instead of previously where simply NULL was returned to RSL.
RSL has no concept of NULL.
- Foundation's C++ Resources support a method LogicalValue() which is called, for
example, when the object is evaluated in a boolean expression. R_D's c++ LogicalValue()
method returns the result of it's DRef's isValid() method, so the result of a method
call into D can be tested against NULL by an RSL if statement.
2.5a6.2 Dec 3
- No recompilation since 2.5a6 is necessary
- no rsl2D
- ECI_OStream now correctly translates for String objects the control characters
'\n', '\t', '\r', '\\' into their respective escape sequences.
- DO_Composite gets three standard RSL methods via
route()
only:
Bool contains(String objectName)
answers
the question: does this object contain an object named by objectName?
Bool doesNotContain(String objectname)
same as the above, only not
addPrivate(String objectName, Object x)
makes a secondary reference to x,
named by objectName.
- patch #1 (granitecore: rslEvents.cc): fix for
->
operator.
Symptom was that each line of code that used it, such as x
-> f (
args )
would work correctly once.
Problem was that this situation was invoking a never-before-seen condition in processing
the argument list args which recycled the objects that formed the program
code itself which defined the argument list args.
- patch #2 (granitecore: res_class.cc): superclass name determination
for D (native) classes has been corrected. Formerly, names of D classes from RSL's
perspective were "Composite".
- patch #3 (D: DECI_OStream.cc): check for valid Enumerator. caused a core
dump when streaming a DComposite object which had not initialized its KeyedCollection
implementation, where DO_KeyedCollection::elements()
returns DNULL.
2.5a6.1 Nov 23
- no recompilation since 2.5a6 necessary
- no rsl2D re-generation necessary
- rsl gets special message passing syntax via the
->
pseudo-operator.
A common problem in RSL is the desire to do the equivalent of in C++ or Java a.b.c.m()
,
where m is a method of c, and c is an instance variable of object
b, and b is an instance variable of object a. But in rsl, "."
is not an operator, ie, (
expression).m()
is illegal. Recently , the operator "/
"
was introduced to allow repeated instance variable access, following URI syntax,
eg a / b / c
, but this still does not
allow the sending of a message to the object this expression evaluates to.
This version introduces the special operator ->
in an expression
of the form
expr ->
messagename (
arglist )
wher expr is any expression. The object that expr evaluates to gets
the message messagename(arglist). This entire expression is valid wherever expressions
are valid in RSL - that is, anywhere execpt around a "."
For example,
a / b / c -> m( );
send the message m to c (inside b ( inside a) ).
In C++ syntax, this might look like a.b.c.m()
or a.b.c->m()
f() -> g();
the result of f() is sent the message g.
o.m(b/c -> f() );
send the message f to the result of (b/c), and send this result
as an argument of the message m to the object o. In C++ syntax,
this might look like o.m(b.c.f())
- Lastly, rsl2D is updated to use this prototype version,
and
- autodoc is introduced.
2.5a6 Nov 23
- requires recompilation
- does NOT require rsl2D regeneration.
- The function
DO_ClassGroup::addClass(const DR_Class&)
allows Class objects to be added to the group. This greatly simplifies the D package
library structure since a DLibrary subclass along with its ugly create() switch/case
thing is not necessary. However, Library objects may still be added with old method
so existing libraries will work. see this
example.
DRef DO_KeyedCollection::get(DR_String&)
is changed to get(const DR_String&)
- added
RWCString DR_String::const_val() const;
- Basic methods added to D.rsl, implemented by
DO_Object::route()
:
:=
and assign(Object)
toString()
toBoolean()
route(Message)
Class()
dtypeid()
2.5a5.9 Nov 17
- requires recompilation
- does NOT require rsl2D regeneration.
- RSL syntax object . variable available for member access to DComposites.
Note that since "." is not an operator in RSL, the slash is still preferable
since the object can override "/" to negotiate access, and multiple slashes
may be given as an expresion (ie a/b/c/d ...)
- new global comparative operators such as
int operator<(const DRef& left, const DRef&
right)
resolve to (left.compare(right) == c_less);
- RSL method
localVarNames(
) of class Object, which returns a List
of the names of "local" variables. Available to both RSL classes and D
classes from within RSL.
2.5a5.8 Nov 13
- Reduced error output
- Instances of pure RSL objects may be passed to D objects. They arrive simply
as instances of Composite, and may be accessed from D using get(), add(), etc.
- Full support for standard RSL plumbing for D objects, such as the ability to
use a D Bool object in RSL if statements, etc. This means that R_D supports
as pass-throughs the following C++ Resource methods
isEqual()
- using D::compare()
Assign()
- using D::assign()
LogicalValue()
- using D::toBoolean()
StrValue()
- using D::toString()
print()
- using ECI_OStream
rslprint()
- using D::toString()
- postOrder() and preOrder() methods added to BinaryTree, so a descending sort
can be done indirectly. a "sortDescending" interface will be added to List
in the next release.
2.5a5.5
- removed optimization (-fast).
- Sorting with comparators and binary tree through
List -- but not available directly in RSL.
- ECI_OStream streams objects correctly, with
the exception of strings that have embedded control characters.
- introduction of
- BinaryTree
- SortedBinaryTree
- OStream
2.5a5
2.5a4.9 - Nov 9
- Attempt to speed things up by:
- optimized compilation with -fast.
- removing an fflush() call at the end of every write to the logfile!
- removed
- test introduction of
2.5a4.8 - Nov 4
- Introduction of secondary references to eliminate
the reference count cycle problem.
- contains a bug: the location of librsl.so is hardcoded to a path outside the
release hierarchy. This is why it is deleted. (Russell has it on CD however)
2.5a4.5 - Nov 2
- First working version with full memory management in D!
- contains a bug: location of librsl.so is hardcoded to a path outside the release
hierarchy. This is why it is deleted. (Russell has it on CD however)
2.5a4.01
2.5a3 - Oct 21
- This is the first official rsl2D version
- rsl2D is near-finalized. Only operators remain.
- Composite working
2.5a2 - Oct 14
2.5a1 - Oct 13
- Moved to /dest/applied/gf2.5
- first release using new build structure
Oct 1
- DClass and class objects for List, String, and Dictionary. Each class that uses
it needs the following (using T for the class name):
- each class defines a class DOC_T : public DO_Class in the .cc file
and implements private D*spawn() and public DR_T::New().
- DO_T defines a static DR_Class data member which is defined in the .cc file to
point to a new DOC_T object. It is named DO_T::Tclass
- DO_T defines a method DRef DO_T::Class() overriding D::Class() to return the
object DO_T::Tclass
- DComposite shell (methods unimplemented)
alpha 0.9 - sept 30
- const_get() introduced to DRef, String and other classes to avoid the
side effects of safe_get(). This will probably be rolled into the rsl2D
templates.
- DClass and Drecycler introduced, but not used.
alpha 0.8 - Sept 29
- integration release, combined with R_D that does basic messaging for Strings.
In particular, in the foundation 2.5 beta, R_String is a DR_String !
- DLibrary
- DClassGroup
alpha 0.5 - Sept 25
- Message classes completed. arguments stored in dictionary.
alpha 0.4 - Sept 25
- Dictionary enumerator & multiple add(), get() methods of Dictionary
- unfinished work on Composite & Context
alpha 0.3 - Sept 25
- abstract KeyedCollection & its Dictionary subclass
alpha 0.2 - Sept 24
- Solidified collection enumerator policy: every collection implements a DO_Enumerator
subclass but only a DR_Enumerator subclass for each distinct collection category
(that is, for each abstract DR_Collection subclass). For example, there is a DO_ListEnumerator
but no DR_ListEnumerator because the DR_Enumerator interface is sufficient for DO_ListEnumerator
(and it is a DO_Enumerator). But DR_KeyedContext exists and is used for every subclass
of DO_KeyedCollection.
- message & route() introduced
alpha 0.1 - Sept 21
Try it! This release exists as compiled into libD.so in /dest/home/holtrf/dev/packages/Releases/D/D-0.1
To use it, you need both the headers and the shared lib. Try using it with one
of these two ways, (but whatever you do, don't just copy it):
A. Add the directory to your LD_LIBRARY_PATH for libD.so, and add -I/dest/home/holtrf/dev/packages/Releases/D/D-0.1
to the compile flags in your makefile. Also add a -L/dest/home/holtrf/...
to the link line.
OR
B. make sure "." is in your LD_LIBRARY_PATH, as it probably should be,
and ln -s /dest/home/holtrf/dev/packages/Releases/D/D-0.1/libD.so. Also
add the -I as described in A. above, but add -L. to the link line.
(that's a -L followed by dot, the same as -L$(PWD) ).
Note! For the gnu compiler, you must compile
and link whatever executables you use with -frtti. For regular C++
programs, follow the model set out in the makefile.
What's available
For basic examples, start at dtestmain.cc in the directory above. Also, look at
DString.h, DList.h. This is a real basic set of stuff, mostly infrastructure and
superclasses.
- the basis for reference and object interaction
- collections & collection enumeration
What's not available & when
- Composites -- by tomorrow
- message passing -- wednesday
- class objects -- wednesday (and by extension, recycling)
- R_D - wednesday or thursday
Destiny C++ | Overview
Class and Object Design |
rsl2D | R_D | Martin's Questions


{% if ci.specific_policies.count %}
| Scope | Data Use Permitted | Minimum Letter Grade Required | |
|---|---|---|---|
| {{ policy.scope }} | {{ policy.default_grant|yesno }} | {{ policy.minimum_grade }} | delete |
You don't have any data policies other than your main policy.
With Specific Policies, you can apply fine-grained control to specific types of data about you.
{% endif %}


Phone Buddy Notifier is an Apple Watch app that alerts you when you lose bluetooth connection with your iPhone. Phone Buddy keeps track of your Apple Watch and alerts you when needed. Phone Buddy Alerts can be configured to display when your iPhone connection is lost, when Apple Watch battery has completed charging, or when devices move apart!
The Phone Lost Alert configured on the Apple Watch is all you need to keep your iPhone safe. The Phone Lost Alert is shown on your Apple Watch when your watch loses connection with your iPhone. As such, this alert will ensure you don't forget your iPhone when leaving your home or other places. Phone Lost Alert is guaranteed to display on your Apple Watch.
To enable Phone Lost Alert:
In certain situations, you may want an additional layer of protection to get an early alert on your Apple Watch when you are leaving an area. Distance Going Away Alerts serve this purpose. However, due to signal interference Distance Alerts may produce false alerts or fail to alert in some cases.
 This alert will ensure you don't forget your Apple Watch.
To enable Watch Left Behind Alert:
Phone Lost Alert is an Apple Watch feature that displays an alert on your Apple Watch when your iPhone and Watch lose bluetooth connection. Phone Lost Alert is guaranteed to display on your Apple Watch.
By default, Phone Lost Alert has the features "Sure Alert" Mode and "Loud Alarm" enabled. Phone Lost Alert features can be configured by pressing "Customize Lost Alert". Please note there is no signal threshold option for Phone Lost Alert as threshold settings are covered with Distance Alerts.
You may enable both Lost Alert and Distance Alert concurrently.
Phone Lost Alert is a Time Sensitive Alert. Time Sensitive alerts can bypass Focus modes and Do Not Disturb settings so you never miss an important alert. To ensure Phone Lost Alert is displayed, please allow Time Senstive alerts or add Phone Buddy to Focus modes allowed notifications through iPhone Settings app.
You can test Phone Lost Alert by going to the iPhone Settings app > "Bluetooth" > Toggle "Bluetooth" OFF and a Phone Lost Alert should display on your watch in a few seconds.
Disabling Bluetooth through Control Center or Airplane mode will not trigger a Phone Lost Alert as the Apple Watch remains connected with these changes.
Phone Buddy needs to stay running in the background to continue delivering alerts (the app should be visible in the app switcher tray or dock). If you are only using Phone Lost Alert on Apple Watch, you may fully quit the iPhone app through a swipe up gesture. If you are using multiple alerts, leaving Phone Buddy running in the background of both devices is recommended.
If you have misplaced your iPhone, you can use the Signal Strength monitor on your Apple Watch to help located your iPhone.
Open Phone Buddy on Apple Watch and press the 'Signal:--' button to observe signal strength and move towards the direction where signal strength improves.
When nearby, Press 'Play Ring' to help locate your iPhone further.
Distance alerts use Bluetooth signal strength as a proxy for device distance and display an alert when your devices move apart beyond the set thresholds.
Using the Show Signal Strength toggle in the Distance Alerts tab you can observe signal changes to choose a signal threshold that fits your needs.
Choosing a signal threshold that is too low or requires many seconds to trigger may prevent Distance Alerts from being displayed on your Apple Watch because the connection could be fully lost before your threshold settings are triggered.
Sure Alert Mode is a Phone Lost Alert setting that delays Phone Lost Alert by a few seconds to make sure there wasn't a transient issue. It's common with Bluetooth for devices to lose connection for a second or two due to interference and then reconnect right back. Sure Alert Mode makes it so these connection events don't lead to alerts. You can configure the waiting time for a reconnection on your Apple Watch: Open Phone Buddy > "Phone Alerts" > "Customize Lost Alert" > "Sure Alert".
When Phone Lost Alert on Apple Watch is not enabled, Phone Buddy will display a reminder to enable Phone Lost Alert each day. You can disable this reminder alert by opening Phone Buddy on Apple Watch and going to "Phone Alerts" > "Customize Lost Alert" > "Alert Display Options" and disable "Daily Lost Alert Reminder".
Wifi Safe Zone pauses configured alerts when your devices are connected to a Wifi network. Since Wifi range is larger than Bluetooth range, the Phone Lost alert may need up to 100 meters distance from your Home Wifi to display.
Home Wifi Safe Zone pauses configured alerts when your iPhone is connected to a set Home Wifi network. Since Wifi range is larger than Bluetooth range, alerts may need up to 100 meters distance from your Home Wifi to display.
To set your home Wifi network enable the Home Wifi Safe Zone setting in the Watch Alerts tab when your iPhone is on your home Wifi network. To update this network, toggle this setting Off to On when your iPhone is on the desired Wifi network.
The primary reason that Phone Buddy would fail to notify you of a disconnection is because Active Mode on Apple Watch was not turned on. Please make sure Active mode is enabled to ensure notifications are prompt. If the Apple Watch shuts down Active Mode will turn off and you need to open Phone Buddy on Apple Watch to re-enable. In certain conditions pending software updates can impact phone to watch communication. If Phone Buddy continues to fail to notify of connection loss, please contact support.
iOS automatically forwards notifications to a device based on its state. Distance alerts are posted on Apple Watch when the iPhone is locked and within range. See this Apple article for more information:
https://support.apple.com/en-us/HT204791
Active mode notifications (Phone Lost Alert and Phone Found Alert) are guaranteed to post on the Apple Watch.
Most app issues arise from failed communication between your Watch and iPhone. These issues can be resolved by restarting the Apple Watch. To restart your Apple Watch:
1) Press and hold the side button until you see the Power Off slider.
2) Drag the Power Off slide.
3) After your watch turns off, press and hold the side button again until you see the Apple logo.
If you recieved a Bluetooth issue alert or there is a change in the accuracy of bluetooth alerts from Phone Buddy a Bluetooth power cycle may fix the issue.
To peform a Blueooth power cycle on your iPhone go to Settings > Bluetooth > and toggle to OFF. Wait 15 seconds then toggle back to ON. Same steps can be followed on Apple Watch if needed
If you ever have any questions about using Phone Buddy Notifier, you can reach us at feedback@fre-studios.com.


It Helps
CharMap allows you to view and use all characters and symbols available in all fonts (some examples of fonts are "Arial", "Times New Roman", "Webdings") installed on your computer. You can input all music note symbols using it.Read More
It's Stable
Character Palette allows you to view and use all characters and symbols, including music symbols, available in all fonts (some examples of fonts are "Arial", "Times New Roman", "Webdings") installed on your computer.Read More
It's Easy
Character Palette allows you to view and use all characters and symbols, including music symbols, available in all fonts (some examples of fonts are "Arial", "Times New Roman", "Webdings") installed on your computer.Read More
It's Quick
Character Palette allows you to view and use all characters and symbols, including music symbols, available in all fonts (some examples of fonts are "Arial", "Times New Roman", "Webdings") installed on your computer.Read More


Landing Page
Special Projects
This story is part of a series of specially designed stories that represents some of the best journalism The Post has to offer. Check out the rest of the special projects here.

Sexual misconduct in professional settings perpetrated by high-profile individuals isn’t a new phenomenon that has recently been discovered. There have been instances of this for a long time, whether they have been reported or not.
People usually associate the start of the #MeToo movement with the outpouring of social media reactions and stories to the hashtag, after media mogul Harvey Weinstein was accused by multiple women of inappropriate sexual behavior and abuse. Since then, #MeToo has brought down more than 200 powerful men who were accused of sexual assault and harassment.
For Ohio University, the rise of the sexual harassment allegations of celebrity alumni made a significant impact on its public image. It started with the resignation of a high-profile alumnus: the former chairman and CEO of Fox News, Roger Ailes. Soon, Ailes’ resignation was followed by the firing of former Today co-host Matt Lauer in the midst of the #MeToo era.
Robert Foehl
As far as famous alumni go, Ailes’ position as chairman and CEO of Fox News gave him prominence that no one could ignore before he resigned amid allegations of sexual harassment.
OU recognized that, and Ailes visited his alma mater in 2012 to give a talk on freedom of speech and media bias. He even gave a large donation to the school, which resulted in The Roger E. Ailes Newsroom being dedicated to him in 2007. That was a result of the $500,000 donation he made to the university, according to a previous report from The Post.
He agreed to pay in full within five years, but the donation and a $40,000 endowment were returned to him before his death at age 77 in 2017.
“I remember being really proud, and I remember seeing a video of them ripping down that sign off the wall of the Roger Ailes Newsroom,” Mallory Golski, a senior studying strategic communication, who spent a lot of time her freshman year in the WOUB newsroom, said.
Starting in 2014, Ailes was accused by more than 20 women of sexual harassment. In 2016, he resigned from Fox because of the accusations and became a media consultant to then-presidential candidate Donald Trump.
Katherine Jellison, a history professor, said it made sense to quickly remove his name from the newsroom and return Ailes’ donations in order to save face and prevent any lasting harm to the university’s reputation.
The scars that were left on the wall were eventually painted over, but students and faculty members wouldn’t forget the drama anytime soon. His ouster by one of the country’s top media companies affected much more than a name on a wall.

Katherine Jellison
Katherine Jellison
The world was dumbstruck when news initially broke in November 2017 that Matt Lauer was fired from NBC news after 20 years of being a co-host on Today. The news came a week after CBS fired “CBS This Morning” host Charlie Rose almost a month after the Weinstein news broke.
Known as the “Face of Today,” Lauer was given earned an undergraduate degree from OU in 1997 at the age of 39. Lauer was a previous student of the School of Media Arts and Studies in the Scripps College of Communication but dropped out in 1979 to become a producer for WOWK-TV in Huntington, West Virginia.
“Matt Lauer was the obvious example of someone who one might idolize if they were looking to go into broadcast, especially here at OU,” Golski said.
Golski said she recalls waking up to a push notification on the day the accusations came out and initially thinking it was an April Fool’s joke, despite it being November. It became a “flashbulb memory” for her that she won’t forget anytime soon.
Mallory Golski
Lauer, who publicly denied the allegations, was replaced by Hoda Kotb, who has anchored Today with Savannah Guthrie ever since.
The Scripps College of Communication and OU were quick to denounce Lauer’s actions and tweeted a statement expressing their disappointment in the alumnus. Alex Stuckey, a Pulitzer Prize-winning OU and Post alumna, called on the university in a tweet to deal with Lauer’s connection to OU and address the exclusive Today internship that the Scripps College collaborated with Lauer to create.
E.W. Scripps School of Journalism Director Robert Stewart was inspired by Stuckey’s tweet to create an internship task force with the help of student leaders to advise the journalism school on protecting students before, during and after their internships.
As the impact of the #MeToo movement spread across the country, conversations between the university and students continued to grow at OU. Since then, the university experienced a record number of reported sexual assaults on campus during the Fall Semester, and multiple professors have also been accused of sexual harassment since 2017.
Although OU has been making headlines for those reasons, many view that those situations show that OU is showing its ability to handle them correctly and establish conversations that are productive to changing the climate surrounding sexual harassment and assault.
“Reputation is absolutely everything,” Robert Foehl, a business law and ethics professor, said.
Foehl said he believes the university has done all it can to deal with all the situations, whether it is professors, notable alumni or campus crime.
Robert Foehl
“Nothing can happen in a day or two,” Foehl said. “From my vantage point, OU acted deliberately, acted swiftly and acted precisely.”
The Scripps College of Communication may have been hit the hardest compared to other parts of the university with the allegations against Ailes, Lauer and suspended journalism professor Yusuf Kalyango, leading more people to scrutinize the school.
“In neither case did we notice negative attention toward the college or its programs because the alleged behaviors of both individuals happened decades after leaving Ohio University,” Scott Titsworth, the dean of the Scripps College of Communication, said in an email.
Titsworth said he thinks the college will be recognized for the actions it took in response to the accusations rather than for what Lauer and Ailes did.
“We are at a place right now where a lot of universities have to come to terms and reckon with really famous alumni who are also experiencing these same things,” Student Senate President Maddie Sloat, a senior studying communication studies, said.
When prospective students Google “Ohio University Alumni,” Lauer and Ailes will be two of the top results that show up, but there are many other names that they can look to. While those two may be a deterrent for some, other people will see names like Turner Sports reporter Allie LaForce, former Ohio Gov. George Voinovich, Washington Post reporter and former Post Editor-in-Chief Wesley Lowery and Modern Family actor Ed O’Neill.
Golski said she believes students should look to the student movements that are trying to change the narrative at OU. Golski was a key organizer for the Sept. 27 “It's On Us, Bobcats” rally, which came as a response to the reports of sexual assault on campus during the Fall Semester.
Maddie Sloat
Golski — along with Cody Shanklin and Hannah Burke, who is a member of the Post Publishing Board — led the rally of 500 students who marched from College Green and down Court Street, East State Street and South College Street.
Mallory Golski
Golski believes that those situations are not the fault of what the university teaches in the classroom, but of the “boys club mentality” that has been pervasive in the media industry for a long time.
Jellison believes that this movement will be a moment in U.S. history that people won’t forget anytime soon. She said the downfall of high-profile politicians, journalists and entertainers may be what the country needed in order to change the way women are treated.
Katherine Jellison
“We have this even larger #MeToo movement that says we are tired of being the #MeToo person on the plane, on the street, in the crowd or wherever it may occur,” Jellison said. “Women are gaining a voice, presence and level of power to where they can maybe change the basic way we live life in this country and maybe the way women and girls are treated in this country.”
OU and the Scripps College are also finding new ways to move forward and find better proactive and reactive ways to deal with these things.
Titsworth said the Scripps College is exploring various ways in which the topic of sexual harassment can be implemented at multiple points in the curriculum so students have an understanding of legal, moral and ethical issues surrounding those behaviors.
“We want (our) students to be leaders in confronting all types of workplace discrimination and harassment,” Titsworth said in an email.
Robert Foehl
Sloat and Golski said they both believe that the process of changing the culture has already started at OU, but it needs to continue in order for there to be any permanent change.
Sloat said she wishes these things would have changed hundreds of years ago, but it is great to have the chance to be one of the people experiencing and making the change happen.
Maddie Sloat
“It’s taken this generational shift and culture change that's slow to happen, but is happening finally, to bring it to the forefront of this conversation,” Sloat said.
The accusations and backlash against Ailes and Lauer could have the potential to teach the university and its students a valuable lesson about how to discourage this behavior and handle it correctly if it occurs.
Mallory Golski
“While sexual assault and sexual violence still exists in the world, it's not being applauded and ignored here,” Golski said.
A previous version of this article incorrectly stated Katherine Jellison’s department. The article has been updated to reflect the most accurate information.
Landing Page
This story is part of a series of specially designed stories that represents some of the best journalism The Post has to offer. Check out the rest of the special projects here.


[§415A-1] Title. This chapter shall be known and may be cited as the "Hawaii Professional Corporation Act". [L 1985, c 259, pt of §1]


Sales Data
🌸Sales Table: The number of Sales cookies per day for each branch🌸
Add a new branch to table
Location Name:
Minimum customers per hours
Maximum customers per hours
Average cookies per sale
Click Here to add Branch