# Spatial Index

## Overview

Joule provides implementation of a spatial Index based on the Quad Tree data structure and algorithm. The search area is divided in to rectangle and thus the world is flattened from a sphere in to a rectangle spatial index.

This feature is provided as a service which can be embedded within custom processors and has its own DSL.

## Example & DSL attributes

The below example creates a search tree of the world as flattened rectangle.

```yaml
spatial index:
  top left coordinates: [-180f,-90f]
  width: 360
  area: 64800
  max levels: 24
  preferred max elements: 50
```

### Attributes schema

<table><thead><tr><th width="214">Attribute</th><th width="217">Description</th><th width="219">Data Type</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>top left coordinates</td><td>North west coordinate to create the spatial index </td><td>Float<br>Default: [-180f, -90f]</td><td>true</td></tr><tr><td>width</td><td>Width of the search area in terms of degrees</td><td><p>Integer</p><p>Default: 360</p></td><td>false</td></tr><tr><td>area</td><td>Search area</td><td><p>Integer</p><p>Default: 64800</p></td><td>false</td></tr><tr><td>max levels</td><td>Maximun number of sub spatial indexes.  Range must be within 0 to 24.</td><td><p>Integer</p><p>Default: 16</p></td><td>false</td></tr><tr><td>preferred max elements</td><td>Maximun number of elements within a bounded area.</td><td><p>Integer</p><p>Default: 500</p></td><td>false</td></tr></tbody></table>

### API Example

This example demonstrates how to query initialise the spatial index and query it thereafter within a custom processor.

{% hint style="info" %}
For further information how to use this service please [contact fractalworks](https://www.fractalworks.io/contact)
{% endhint %}

```java
private QuadTree<GeoFence> geoFenceSearchTree;

@Override
public void initialize(Properties prop) throws ProcessorException {
    super.initialize(prop);
    geoFenceSearchTree.initialise();
    
    // Other custom initialization
}

/**
* Query the geoFenceSearchTree with passed location information 
*
* @param event
* @param entityLatitude
* @param entityLongitude
*/
private GeoTrackingInfo queryGeospace(final StreamEvent event, final double entityLatitude, final double entityLongitude){
    // Perform geofence search
    Collection<GeoFence> foundGeoFences = geoFenceSearchTree.query(new Tuple<>(entityLatitude, entityLongitude));
    Object trackingKey = event.getValue(trackingEventKey);
    
    // Update stateful tracking
    GeoTrackingInfo info = state.get(trackingKey);
    
    info.setCurrentLatLng(entityLatitude, entityLongitude, event.getEventTime());
    info.setCurrentGeofenceIds(foundGeoFences);
    
    return info;        
}

/**
* Set QuadTree for processor
*
* @param geoFenceSearchTree
*/
@JsonProperty(value = "spatial index")
public void setGeoFenceSearchTree(QuadTree<GeoFence> geoFenceSearchTree) {
   this.geoFenceSearchTree = geoFenceSearchTree;
}
```
