Skip to content

Custom Selectors

bliepp edited this page Nov 25, 2020 · 5 revisions

Dimension of Selectors

Selectors work in every dimension as long as its Vector types match and they don't try to access custom components (like z). This also means that a SphereSelector is a CircleSelector and a BoxSelector is a RectangleSelector in 2D.

Base class

imd_cookie_cutter has an abstract boilerplate Selector class called ISelectorStrategy. Although you could write an own base class with a contains method yourself, it is highly recommended to use ISelectorSrategy to make your class work with functions like isinstance().

Creating your own class

Most Selector classes need at least one constructor parameter to even make sense. This parameter is its position. If you do not need any other parameters than the position you don't need to override the constructor (__init__()).

import imd_cookie_cutter as imdcc

class MySelector(imdcc.ISelectorStartegy):
    def __init__(self, position, param2, param3, ...):
        super().__init__(position)

        # whatever setup you need, e.g. radius
        self.__param2 = param2
        self.__param3 = param3
        ...

Since this is still an abstract class we need to override the contains method.

class MySelector(imdcc.ISelectorStartegy):
    def __init__(self, position, param2, param3, ...):
        super().__init__(position)

        # whatever setup you need, e.g. radius
        self.__param2 = param2
        self.__param3 = param3
        ...
    
    def contains(self, point, strict=False):
        is_inside = ... # check if point is inside of MySelector's volume
        return is_inside

While the contains method checks if the given point (of type imdcc.Vector<N>D) is inside the the custom volume (defined by self.position and other custom parameters) it should also get the boolean argument strict (defaults to False). This should be used to define whether atoms at the border of the condition should be counted as containing or not. On a spherical Selector for example this would define if it will check for < self.radius or <= self.radius. If you don't need it just keep it as an argument but never use it.

Using Vectors

The parameter point in the contains method usually is of type imdcc.Vector<N>D where <N> stands for a dimension (e.g. imdcc.Vector3D). Adding and subtracting Vectors should work fine. Multiplying two Vectors returns the dot product of both. Multiplying a Vector and a scalar (int, float or bool) works fine, too. Prebuild Vector classes are

  • Vector3D(x, y, z)
  • Vector2D(x, y)
  • Vector(*components) (abstract, don't instantiate directly)

Although instantiating from the class Vector for higher or lower dimensional Vectors is technically possible it is recommended to create a child class, such as:

class Vector4D(imdcc.Vector):
    def __init__(self, x, y, z, w):
        super().__init__(x, y, z, w)

This prevents multiplying two Vectors of different dimensions.

Properties

Vectors have the following properties:

  • components list of components as reference
  • dimension
  • length

Examples of useful selectors

Although you can obviously use custom Selectors too create your own geometrically shaped Selectors, there are some not so obvious ideas you could use Selectors for.

Everthing

An Everything Selector might come in handy if you need a True statement which is compatible with the selector.contains() pattern.

class EverythingSelector(imdcc.ISelectorStartegy):
    def contains(self, point):
        return True

Nothing

On the other hand a Nothing Selector might come in handy, too, if a not my_EverythingSelector is hard to realize.

class NothingSelector(imdcc.ISelectorStartegy):
    def contains(self, point):
        return False