Module org.dyn4j

Class CategoryFilter

  • All Implemented Interfaces:

    public final class CategoryFilter
    extends Object
    implements Filter
    A Filter for categorized fixtures.

    Constructing a CategoryFilter requires supplying two integers: a category integer and a mask integer.

    The usage of this class can be explained as follows:

     CategoryFilter f1 = new CategoryFilter(1, 1);
     CategoryFilter f2 = new CategoryFilter(2, 2);
     CategoryFilter f3 = new CategoryFitler(3, 3);
     f1.isAllowed(f2); // returns false
     f2.isAllowed(f3); // returns true?!
    This is because the integers passed in are being used via their binary representation. If we examine the binary representation of these numbers:
     1 = 0...0001
     2 = 0...0010
     3 = 0...0011
    We see that 3 is actually a combination of 1 and 2. Because of this f3 will actually be part of category 1 and 2, not its own category.

    Because of this representation, there are a maximum of 64 categories that can be represented:

     category  1 =  1 = 2^0
     category  2 =  2 = 2^1
     category  3 =  4 = 2^2
     category  4 =  8 = 2^3
     category  5 = 16 = 2^4
     category 64 = Long.MAX_VALUE = 2^64
    In addition, the mask integer is handled in a similar way. f3 will be able to collide with both category 1 and 2 because of the binary representation of 3.

    In general, the mask or category can be generated by OR-ing the categories. For example:

     final long CATEGORY_0 = 1;
     final long CATEGORY_1 = 2;
     final long CATEGORY_2 = 4;
     final long MASK_ALL = Long.MAX_VALUE;
     // make f1 part of category 0, and allow collisions with category 0 and 1
     CategoryFilter f1 = new CategoryFilter(CATEGORY_0, CATEGORY_0 | CATEGORY_1);
     // make f2 part of category 1 and 2, and allow collisions with category 0 and 2
     CategoryFilter f2 = new CategoryFilter(CATEGORY_1 | CATEGORY_2, CATEGORY_0 | CATEGORY_2);
     // make f3 part of category 2, and allow collision with every category
     CategoryFilter f3 = new CategoryFilter(CATEGORY_2, MASK_ALL);
     f1.isAllowed(f2); // returns true since f1 can collide with 0 or 1 and f2 is part of 1
                       // and because f2 can collide with 0 or 2 and f1 is part of 0
     f1.isAllowed(f3); // returns false since f1 can collide with 0 or 1 but f3 is part of 2 only
                       // even though f3 is allowed to collide with all categories (both must work)
     f2.isAllowed(f3); // returns true since f2 can collide with 0 or 2 and f3 is part of 2
                       // and because f3 can collide with all categories
    As its apparent from the code above, both f1.isAllowed(f2) and f2.isAllowed(f1) must return true if the entire result is to be deemed true.

    By default the CategoryFilter will be set to category 1 and have a mask of all category bits.

    William Bittle
    • Constructor Detail

      • CategoryFilter

        public CategoryFilter()
        Default constructor.

        By default the category is 1 and the mask is all categories.

      • CategoryFilter

        public CategoryFilter​(long category,
                              long mask)
        Full constructor.
        category - the category bits
        mask - the mask bits
    • Method Detail

      • isAllowed

        public boolean isAllowed​(Filter filter)
        Returns true if the given Filter and this Filter allow the objects to interact.

        If the given Filter is not the same type as this Filter then a value of true is returned.

        If the given Filter is null, a value of true is returned.

        Specified by:
        isAllowed in interface Filter
        filter - the other Filter
      • hashCode

        public int hashCode()
        hashCode in class Object
      • getCategory

        public long getCategory()
        Returns the category bits.
        long the category bits
      • getMask

        public long getMask()
        Returns the mask bits.
        long the mask bits