<commit_before>""" BulletBase interfaces with Panda3d's Bullet module."""
# Standard
from collections import Iterable
from contextlib import contextmanager
from functools import wraps
from itertools import combinations, izip
from math import isnan, sqrt
# External
from libpanda import BitMask32, Point3, Quat, Vec3
import numpy as np
from panda3d.bullet import (BulletConstraint, BulletDebugNode,
                            BulletGenericConstraint, BulletGhostNode,
                            BulletWorld)
from panda3d.core import PythonCallbackObject, TransformState
from pandac.PandaModules import NodePath
# Project
#
from pdb import set_trace as BP


nan = float("nan")


class BulletBaseError(Exception):
    pass


class CollisionMonitor(object):
    """ Monitors collisions and records them."""

    def __init__(self, world):
        self.world = world
        self.reset()
        self.use_callback = False
        # self.use_callback = hasattr(self.world, "setContactAddedCallback")
        # # This method does not currently appear to work, so we use the
        # # older method instead.

    def push_notifiers(self, bodies):
        """ Stores initial notification state of bodies, and sets up
        the collisions notification callback."""
        if self.use_callback:
            # Store whether each bodies initially notifies of collisions.
            self.notifies = {body: body.notifiesCollisions()
                             for body in bodies}
            # Set all bodies to notify.
            for body in bodies:
                body.notifyCollisions(True)
            # Add the collision callback.
            self.world.setContactAddedCallback(PythonCallbackObject(self))
        else:
            # This is for Panda3d 1.8, because it doesn't have the
            # contact callback methods.
            # Store the bodies.
            self.bodies = bodies
        # Reset collision count.
        self.reset()

    def pop_notifiers(self):
        """ Restores initial notification state of bodies, and removes
        collisions notification callback."""
        if self.use_callback:
            # Remove the collision callback.
            self.world.clearContactAddedCallback()
            for body, notify in self.notifies.iteritems():
                # Restores initial notification state of bodies.
                body.notifyCollisions(notify)
        else:
            # This is for Panda3d 1.8, because it doesn't have the
            # contact callback methods.
            pass

    def reset(self):
        self._N = 0

    def __nonzero__(self):
        return self._N > 0

    def __iadd__(self, x):
        self._N += x

    def __gt__(self, x):
        return self._N > x

    def __ge__(self, x):
        return self._N >= x

    def __lt__(self, x):
        return self._N < x

    def __le__(self, x):
        return self._N <= x

    def __call__(self, data):
        """ Callback."""
        self.__iadd__(1)

    def detect18(self):
        """ This is for Panda3d 1.8, because it doesn't have the
        contact callback methods."""
        if not self.use_callback:
            detect = lambda a, b: self.world.contactTestPair(
                a, b).getNumContacts()
            n = sum(detect(a, b) for a, b in combinations(self.bodies, 2))
            self.__iadd__(n / 2)


class JointManager(dict):
    """ Subclass of dict for managing Bullet constraints."""

    def __init__(self, *args, **kwargs):<commit_msg>Adding contact detection classes and functionality. Other minor tweaks.<commit_after>""" BulletBase interfaces with Panda3d's Bullet module."""
# Standard
from collections import Iterable, defaultdict
from contextlib import contextmanager
from functools import update_wrapper
from itertools import combinations, izip
from math import isnan, sqrt
# External
from libpanda import BitMask32, Point3, Quat, Vec3
import numpy as np
from panda3d.bullet import (BulletConstraint, BulletDebugNode,
                            BulletGenericConstraint, BulletGhostNode,
                            BulletWorld)
from panda3d.core import PythonCallbackObject, TransformState
from pandac.PandaModules import NodePath
# Project
#
from pdb import set_trace as BP


nan = float("nan")


class BulletBaseError(Exception):
    pass


class Contact(object):

    def __init__(self, contact_result):
        self._contact_result = contact_result
        self._N = None
        self._points = None

    @property
    def N(self):
        if self._N is None:
            self._N = self._contact_result.getNumContacts()
        return self._N

    @property
    def points(self):
        if self._points is None:
            self._points = []
            for contact in self._contact_result.getContacts():
                mpoint = contact.getManifoldPoint()
                pa = mpoint.getPositionWorldOnA()
                pb = mpoint.getPositionWorldOnB()
                self._points.append((pa + pb) / 2.)
        return self._points


class ContactMonitor(object):
    """ Monitors contacts between bodies."""

    def __init__(self, world, bodies):
        self.world = world
        self.bodies = bodies
        self.n_bodies = len(bodies)
        self.reset()

    def reset(self):
        self._pairs = None
        self._contacts = None
        self._points = None
        self._mtx = None
        self._N = None

    def _detect(self, a, b):
        return Contact(self.world.contactTestPair(a.node(), b.node()))

    @property
    def pairs(self):
        """ Detects contacts between `self.bodies`."""
        if self._pairs is None:
            pairs = combinations(enumerate(self.bodies), 2)
            self._pairs = defaultdict()
            for (i, a), (j, b) in pairs:
                contact = self._detect(a, b)
                self._pairs[i, j] = contact
                self._pairs[j, i] = contact
        return self._pairs

    @property
    def contacts(self):
        if self._contacts is None:
            self._contacts = sorted(((i, j), c)
                                    for (i, j), c in self.pairs.iteritems()
                                    if c.N > 0 and i < j)
        return self._contacts

    @property
    def points(self):
        if self._points is None:
            self._points = [((i, j), c.points) for (i, j), c in self.contacts]
        return self._points

    @property
    def matrix(self):
        if self._mtx is None:
            self._mtx = np.zeros([self.n_bodies] * 2, dtype="i")
            for (i, j), contact in self.contacts:
                self._mtx[i, j] = contact.N
        return self._mtx

    @property
    def N(self):
        if self._N is None:
            self._N = len(self.contacts)
        return self._N


class CollisionMonitor(object):
    """ Monitors collisions and records them."""

    def __init__(self, world):
        self.world = world
        self.reset()
        self.use_callback = False
        # self.use_callback = hasattr(self.world, "setContactAddedCallback")
        # # This method does not currently appear to work, so we use the
        # # older method instead.

    def push_notifiers(self, bodies):
        """ Stores initial notification state of bodies, and sets up
        the collisions notification callback."""
        if self.use_callback:
            # Store whether each bodies initially notifies of collisions.
            self.notifies = {body: body.notifiesCollisions()
                             for body in bodies}
            # Set all bodies to notify.
            for body in bodies:
                body.notifyCollisions(True)
            # Add the collision callback.
            self.world.setContactAddedCallback(PythonCallbackObject(self))
        else:
            # This is for Panda3d 1.8, because it doesn't have the
            # contact callback methods.
            # Store the bodies.
            self.bodies = bodies
        # Reset collision count.
        self.reset()

    def pop_notifiers(self):
        """ Restores initial notification state of bodies, and removes
        collisions notification callback."""
        if self.use_callback:
            # Remove the collision callback.
            self.world.clearContactAddedCallback()
            for body, notify in self.notifies.iteritems():
                # Restores initial notification state of bodies.
                body.notifyCollisions(notify)
        else:
            # This is for Panda3d 1.8, because it doesn't have the
            # contact callback methods.
            pass

    def reset(self):
        self._N = 0

    def __nonzero__(self):
        return self._N > 0

    def __iadd__(self, x):
        self._N += x

    def __gt__(self, x):
        return self._N > x

    def __ge__(self, x):
        return self._N >= x

    def __lt__(self, x):
        return self._N < x

    def __le__(self, x):
        return self._N <= x

    def __call__(self, data):
        """ Callback."""
        self.__iadd__(1)

    def detect18(self):
        """ This is for Panda3d 1.8, because it doesn't have the
        contact callback methods."""
        if not self.use_callback:
            def detect(a, b):
                return self.world.contactTestPair(a, b).getNumContacts() > 0
            n = sum(detect(a, b) for a, b in combinations(self.bodies, 2))
            self += n


class JointManager(dict):
    """ Subclass of dict for managing Bullet constraints."""

    def __init__(self, *args, **kwargs):
{'fraction_non_alphanumeric': 0.08762125685364824, 'fraction_numerical': 0.005272037115141291, 'mean_word_length': 2.0158982511923687, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7125294', 'n_tokens_mistral': 2642, 'n_tokens_neox': 2504, 'n_words': 828}