Skip to content

Region

FluxRender.regions

CircularRegion

CircularRegion(center: Sequence[float], radius: float, world_fixed: bool = False, visible: bool = False, color_active: Sequence[float] = (1, 1, 1, 0.3), color_inactive: Sequence[float] = (0, 0.1, 0.2, 0.3))

Bases: SpatialRegion

A static, circular spatial boundary used for spatial queries and interactions.

The CircularRegion defines a precise area within the simulation. It is primarily utilized as a localized spawning zone for ParticleSystems (acting as an emitter) or as a targeted sampling area for DataProbes.

Its most powerful feature is its dual-coordinate nature: it can either be rigidly anchored to the UI screen space (pixels) or embedded directly into the mathematical world space, scaling and panning seamlessly with the camera.

Parameters:

Name Type Description Default
center Sequence[float]

The (x, y) coordinates of the region's center. Units depend strictly on the world_fixed flag.

required
radius float

The radius of the circle. Units depend strictly on the world_fixed flag.

required
world_fixed bool

The coordinate system toggle.

  • False (Default): center and radius are evaluated in screen pixels. The region stays fixed on the screen regardless of camera movement.
  • True: center and radius are evaluated in mathematical world units. The region acts as a physical area in the mathematical space.
False
visible bool

Whether to render region on screen (useful for debugging).

False
color_active Sequence[float]

RGBA color sequence when Region.active is True.

(1, 1, 1, 0.3)
color_inactive Sequence[float]

RGBA color sequence when Region.active is False.

(0, 0.1, 0.2, 0.3)
Notes
  • units: The world_fixed flag is crucial for determining how the center and radius parameters are interpreted. When world_fixed is False, they are in screen pixels; when True, they are in world units.
  • rendering: If visible is set to True, it is essential to add the CircularRegion instance to the scene using scene.add(your_region) for it to be rendered. However, even if visible is False, the CircularRegion can still function as an emitter or probe target without being added to the scene.
Example

Creating a screen-fixed UI Particle emitter:

import FluxRender as fr

# [Initialize scene and math engine here]

# A fixed 50px radius circle in the bottom-left corner of the screen UI
ui_emitter = fr.CircularRegion(center=(100.0, 100.0), radius=50.0, world_fixed=False)

particle_system = fr.ParticleSystem(
    vec_function = lambda x, y: (0.0, 1.0),  # Example vector function that emits particles upwards
    emitter=ui_emitter
)

scene.add(particle_system) # You don't need to add the CircularRegion itself to the scene for it to function as an emitter, but you do need to add it if you want it to be visible.

Creating a visible, world-fixed Particle emitter:

import FluxRender as fr

# [Initialize scene and math engine here]

# A visible circular region centered at (1, 1) with a radius of 0.25 world unit
world_emitter = fr.CircularRegion(center=(1.0, 1.0), radius=0.25, world_fixed=True, visible=True)

particle_system = fr.ParticleSystem(
    vec_function = lambda x, y: (y, -x),  # Example vector function that emits particles in a circular pattern
    emitter=world_emitter
)

scene.add(particle_system, world_emitter) # We want the CircularRegion to be visible, so we need to add it to the scene.

Source code in FluxRender/regions.py
def __init__(self,
             center: Sequence[float],
             radius: float,
             world_fixed: bool = False,
             visible: bool = False,
             color_active: Sequence[float] = (1, 1, 1, 0.3),
             color_inactive: Sequence[float] = (0, 0.1, 0.2, 0.3),
             ):
    """
    Args:
        center (Sequence[float]): The (x, y) coordinates of the region's center.
            Units depend strictly on the `world_fixed` flag.
        radius (float): The radius of the circle. Units depend strictly on the `world_fixed` flag.
        world_fixed (bool, optional): The coordinate system toggle.

            * **False** (Default): `center` and `radius` are evaluated in screen pixels. The region stays fixed on the screen regardless of camera movement.
            * **True**: `center` and `radius` are evaluated in mathematical world units. The region acts as a physical area in the mathematical space.
        visible (bool, optional): Whether to render region on screen (useful for debugging).
        color_active (Sequence[float], optional): RGBA color sequence when Region.active is True.
        color_inactive (Sequence[float], optional): RGBA color sequence when Region.active is False.

    Notes:
        * **units**: The `world_fixed` flag is crucial for determining how the `center` and `radius` parameters are interpreted. When `world_fixed` is False, they are in screen pixels; when True, they are in world units.
        * **rendering**: If `visible` is set to True, it is essential to add the CircularRegion instance to the scene using `scene.add(your_region)` for it to be rendered. However, even if `visible` is False, the CircularRegion can still function as an emitter or probe target without being added to the scene.

    Example:
        Creating a screen-fixed UI Particle emitter:
        ```python
        import FluxRender as fr

        # [Initialize scene and math engine here]

        # A fixed 50px radius circle in the bottom-left corner of the screen UI
        ui_emitter = fr.CircularRegion(center=(100.0, 100.0), radius=50.0, world_fixed=False)

        particle_system = fr.ParticleSystem(
            vec_function = lambda x, y: (0.0, 1.0),  # Example vector function that emits particles upwards
            emitter=ui_emitter
        )

        scene.add(particle_system) # You don't need to add the CircularRegion itself to the scene for it to function as an emitter, but you do need to add it if you want it to be visible.
        ```

        Creating a visible, world-fixed Particle emitter:
        ```python
        import FluxRender as fr

        # [Initialize scene and math engine here]

        # A visible circular region centered at (1, 1) with a radius of 0.25 world unit
        world_emitter = fr.CircularRegion(center=(1.0, 1.0), radius=0.25, world_fixed=True, visible=True)

        particle_system = fr.ParticleSystem(
            vec_function = lambda x, y: (y, -x),  # Example vector function that emits particles in a circular pattern
            emitter=world_emitter
        )

        scene.add(particle_system, world_emitter) # We want the CircularRegion to be visible, so we need to add it to the scene.
        ```
    """

    super().__init__()
    self.center = center
    self.radius = radius

    self.world_fixed = world_fixed
    self.visible = visible

    self.color_active = tuple(color_active)
    self.color_inactive = tuple(color_inactive)

contains

contains(point: tuple)

Checks whether a given spatial point falls within the circular region. The point should be in the same coordinate space as the region (screen or world) based on the world_fixed flag.

Parameters:

Name Type Description Default
point tuple

A tuple representing the (x, y) coordinates of the point to check. The coordinate space of the point must match the region's coordinate space as determined by the world_fixed flag.

required

Returns:

Name Type Description
contains bool

True if the point is within the circular region, False otherwise.

Source code in FluxRender/regions.py
def contains(self, point: tuple):
    """
    Checks whether a given spatial point falls within the circular region.
    The point should be in the same coordinate space as the region (screen or world) based on the `world_fixed` flag.

    Args:
        point (tuple): A tuple representing the (x, y) coordinates of the point to check. The coordinate space of the point must match the region's coordinate space as determined by the `world_fixed` flag.

    Returns:
        contains (bool): True if the point is within the circular region, False otherwise.
    """

    dx = point[0] - self.center[0]
    dy = point[1] - self.center[1]
    return dx * dx + dy * dy <= self.radius ** 2

get_center

get_center()

Returns the current center coordinates of the circular region in math coordinates, regardless of the world_fixed setting.

Returns:

Name Type Description
center Tuple[float, float]

The (x, y) coordinates of the region's center in math coordinates.

Source code in FluxRender/regions.py
def get_center(self):
    """
    Returns the current center coordinates of the circular region in math coordinates, regardless of the `world_fixed` setting.

    Returns:
        center (Tuple[float, float]): The (x, y) coordinates of the region's center in math coordinates.
    """

    if not self.world_fixed:
        return self.scene.coords.to_math(*self.center)

    return self.center

random_point_screen

random_point_screen()

Generates a single random point uniformly distributed within the circular region. The generated point is returned in screen coordinates, regardless of the region's world_fixed setting.

Returns:

Name Type Description
point Tuple[float, float]

The (x, y) coordinates of the generated point in screen coordinates.

Source code in FluxRender/regions.py
def random_point_screen(self):
    """
    Generates a single random point uniformly distributed within the circular region.
    The generated point is returned in screen coordinates, regardless of the region's `world_fixed` setting.

    Returns:
        point (Tuple[float, float]): The (x, y) coordinates of the generated point in screen coordinates.
    """

    radius = np.sqrt(np.random.uniform(0, self.radius ** 2))
    angle = np.random.uniform(0, 2 * np.pi)

    x = self.center[0] + radius * np.cos(angle)
    y = self.center[1] + radius * np.sin(angle)

    if self.world_fixed and self.scene is not None:
        # Convert from world to screen coordinates
        x, y = self.scene.coords.to_screen(x, y)

    return x, y

random_points_screen

random_points_screen(count: int)

Generates a specified number of random points uniformly distributed within the circular region. The generated points are returned in screen coordinates, regardless of the region's world_fixed setting. Args: count (int): The number of random points to generate.

Returns:

Name Type Description
points Tuple of two numpy arrays

(x_coordinates, y_coordinates) of the generated points in screen coordinates.

Source code in FluxRender/regions.py
def random_points_screen(self, count: int):
    """
    Generates a specified number of random points uniformly distributed within the circular region.
    The generated points are returned in screen coordinates, regardless of the region's `world_fixed` setting.
    Args:
        count (int): The number of random points to generate.

    Returns:
        points (Tuple of two numpy arrays): (x_coordinates, y_coordinates) of the generated points in screen coordinates.
    """


    points = np.zeros((count, 2), dtype=np.float32)

    random_radius = np.sqrt(np.random.uniform(0, self.radius ** 2, count))
    random_angle = np.random.uniform(0, 2 * np.pi, count)

    points[:, 0] = self.center[0] + random_radius * np.cos(random_angle)
    points[:, 1] = self.center[1] + random_radius * np.sin(random_angle)

    if self.world_fixed and self.scene is not None:
        # Convert from world to screen coordinates
        points[:, 0], points[:, 1] = self.scene.coords.to_screen(points[:, 0], points[:, 1])

    return points[:, 0], points[:, 1]

CursorRegion

CursorRegion(radius: float = 50.0, visible: bool = False, color_active=(1, 1, 1, 0.3), color_inactive=(0, 0.1, 0.2, 0.3), always_active: bool = False)

Bases: SpatialRegion

A dynamic spatial region permanently attached to the user's mouse cursor.

The CursorRegion serves as the primary interactive bridge between the user and the mathematical simulation. By translating raw screen-space mouse coordinates into actionable world-space queries in real-time, it allows users to directly "paint" particles onto the screen (as an emitter) or dynamically sample local vector properties simply by hovering over them (as a DataProbe carrier).

Parameters:

Name Type Description Default
radius float

The interaction radius around the cursor, defined in screen pixels.

50.0
visible bool

Whether to render a visual halo around the mouse cursor.

False
color_active Sequence[float]

RGBA color of the halo when the region is actively triggered (e.g., mouse button held down).

(1, 1, 1, 0.3)
color_inactive Sequence[float]

RGBA color of the halo when the cursor is merely hovering.

(0, 0.1, 0.2, 0.3)
always_active bool

Behavioral toggle.

  • False (Default): The region only emits/probes when the user clicks and holds the mouse button.
  • True: The region constantly emits/probes data on every frame, regardless of mouse clicks.
False
Notes
  • Scene Addition Required: Unlike CircularRegion, a CursorRegion instance always needs to be added to the scene using scene.add(your_region).
Example

Setting up an interactive, visible cursor emitter:

import FluxRender as fr

# [Initialize scene and coordinate system here]

# Creates a 30px visible halo around the mouse. Particles will only spawn when the user clicks and drags the mouse across the field.
interactive_cursor = fr.CursorRegion(
    radius=30.0,
    visible=True,
)

particle_system = fr.ParticleSystem(
    vec_function = lambda x, y: (y, -x),  # Example vector function that emits particles in a circular pattern
    emitter=interactive_cursor
)

scene.add(particle_system, interactive_cursor)

Setting up a constantly active cursor probe:

import FluxRender as fr

# [Initialize scene and coordinate system here]

math_engine = fr.VectorMathEngine(scene, primary_vector_function=lambda x, y: (y, -x))

# A CursorRegion that continuously probes the vector field under the mouse cursor, even without clicks.
probing_cursor = fr.CursorRegion(
    radius=20.0,
    visible=False,
    always_active=True
)

probe = fr.DataProbe(
    target_region=probing_cursor,
    math_engine=math_engine,
    measured_property=fr.Property.VELOCITY
)
probe.add_listener(lambda value: print(f"Current velocity at cursor: {value}", end="\r"))

scene.add(probe, probing_cursor)

Source code in FluxRender/regions.py
def __init__(self,
             radius: float = 50.0,
             visible: bool = False,
             color_active=(1, 1, 1, 0.3), color_inactive=(0, 0.1, 0.2, 0.3),
             always_active: bool = False
             ):
    """
    Args:
        radius (float, optional): The interaction radius around the cursor, defined in screen pixels.
        visible (bool, optional): Whether to render a visual halo around the mouse cursor.
        color_active (Sequence[float], optional): RGBA color of the halo when the region is actively triggered (e.g., mouse button held down).
        color_inactive (Sequence[float], optional): RGBA color of the halo when the cursor is merely hovering.
        always_active (bool, optional): Behavioral toggle.

            * **False** (Default): The region only emits/probes when the user clicks and holds the mouse button.
            * **True**: The region constantly emits/probes data on every frame, regardless of mouse clicks.

    Notes:
        * **Scene Addition Required**: Unlike CircularRegion, a CursorRegion instance always needs to be added to the scene using `scene.add(your_region)`.

    Example:
        Setting up an interactive, visible cursor emitter:
        ```python
        import FluxRender as fr

        # [Initialize scene and coordinate system here]

        # Creates a 30px visible halo around the mouse. Particles will only spawn when the user clicks and drags the mouse across the field.
        interactive_cursor = fr.CursorRegion(
            radius=30.0,
            visible=True,
        )

        particle_system = fr.ParticleSystem(
            vec_function = lambda x, y: (y, -x),  # Example vector function that emits particles in a circular pattern
            emitter=interactive_cursor
        )

        scene.add(particle_system, interactive_cursor)
        ```

        Setting up a constantly active cursor probe:
        ```python
        import FluxRender as fr

        # [Initialize scene and coordinate system here]

        math_engine = fr.VectorMathEngine(scene, primary_vector_function=lambda x, y: (y, -x))

        # A CursorRegion that continuously probes the vector field under the mouse cursor, even without clicks.
        probing_cursor = fr.CursorRegion(
            radius=20.0,
            visible=False,
            always_active=True
        )

        probe = fr.DataProbe(
            target_region=probing_cursor,
            math_engine=math_engine,
            measured_property=fr.Property.VELOCITY
        )
        probe.add_listener(lambda value: print(f"Current velocity at cursor: {value}", end="\\r"))

        scene.add(probe, probing_cursor)
        ```

    """

    super().__init__()
    self.scene = None
    self.radius = radius
    self.color_active = color_active
    self.color_inactive = color_inactive
    self.visible = visible
    self.always_active = always_active

contains

contains(point: tuple)

Checks whether a given spatial point falls within the cursor region. The point should be in the screen coordinate space (pixels).

Parameters:

Name Type Description Default
point tuple

A tuple representing the (x, y) coordinates of the point to check in screen space.

required

Returns:

Name Type Description
contains bool

True if the point is within the cursor region, False otherwise.

Source code in FluxRender/regions.py
def contains(self, point: tuple):
    """
    Checks whether a given spatial point falls within the cursor region.
    The point should be in the screen coordinate space (pixels).

    Args:
        point (tuple): A tuple representing the (x, y) coordinates of the point to check in screen space.

    Returns:
        contains (bool): True if the point is within the cursor region, False otherwise.
    """

    cursor_x, cursor_y = self.scene.mouse_pos
    dx = point[0] - cursor_x
    dy = point[1] - cursor_y
    return dx * dx + dy * dy <= self.radius ** 2

get_center

get_center()

Returns the current center coordinates of the cursor region in math coordinates.

Returns:

Name Type Description
center Tuple[float, float]

The (x, y) coordinates of the region's center in math coordinates.

Source code in FluxRender/regions.py
def get_center(self):
    """
    Returns the current center coordinates of the cursor region in math coordinates.

    Returns:
        center (Tuple[float, float]): The (x, y) coordinates of the region's center in math coordinates.
    """

    if self.scene is not None:
        return self.scene.coords.to_math(*self.scene.mouse_pos)
    else:
        return (0, 0)

random_point_screen

random_point_screen()

Generates a single random point uniformly distributed within the cursor region. The generated point is returned in screen coordinates.

Returns:

Name Type Description
point Tuple[float, float]

The (x, y) coordinates of the generated point in screen coordinates.

Source code in FluxRender/regions.py
def random_point_screen(self):
    """
    Generates a single random point uniformly distributed within the cursor region.
    The generated point is returned in screen coordinates.

    Returns:
        point (Tuple[float, float]): The (x, y) coordinates of the generated point in screen coordinates.
    """

    cursor_x, cursor_y = self.scene.mouse_pos

    radius = np.sqrt(np.random.uniform(0, self.radius ** 2))
    angle = np.random.uniform(0, 2 * np.pi)

    x = cursor_x + radius * np.cos(angle)
    y = cursor_y + radius * np.sin(angle)

    return x, y

random_points_screen

random_points_screen(count: int)

Generates a specified number of random points uniformly distributed within the cursor region. The generated points are returned in screen coordinates. Args: count (int): The number of random points to generate.

Returns:

Name Type Description
points Tuple of two numpy arrays

(x_coordinates, y_coordinates) of the generated points in screen coordinates.

Source code in FluxRender/regions.py
def random_points_screen(self, count: int):
    """
    Generates a specified number of random points uniformly distributed within the cursor region.
    The generated points are returned in screen coordinates.
    Args:
        count (int): The number of random points to generate.

    Returns:
        points (Tuple of two numpy arrays): (x_coordinates, y_coordinates) of the generated points in screen coordinates.
    """

    cursor_x, cursor_y = self.scene.mouse_pos

    random_radius = np.sqrt(np.random.uniform(0.0, self.radius ** 2, count))
    random_angle = np.random.uniform(0.0, 2.0 * np.pi, count)

    generated_points_x = cursor_x + random_radius * np.cos(random_angle)
    generated_points_y = cursor_y + random_radius * np.sin(random_angle)

    return generated_points_x, generated_points_y