core.bones.spatial

spatial contains - The SpatialBone to handle coordinates - and haversine to calculate the distance between two points on earth using their latitude and longitude.

Module Contents

Classes

SpatialBone

The "SpatialBone" is a specific type of data structure designed to handle spatial data, such as geographical

Functions

haversine(lat1, lng1, lat2, lng2)

Calculate the distance between two points on Earth's surface in meters.

core.bones.spatial.haversine(lat1, lng1, lat2, lng2)

Calculate the distance between two points on Earth’s surface in meters.

This function uses the haversine formula to compute the great-circle distance between two points on Earth’s surface, specified by their latitude and longitude coordinates. The haversine formula is particularly useful for small distances on the Earth’s surface, as it provides accurate results with good performance.

For more details on the haversine formula, see Haversine formula.

Parameters:
  • lat1 (float) – Latitude of the first point in decimal degrees.

  • lng1 (float) – Longitude of the first point in decimal degrees.

  • lat2 (float) – Latitude of the second point in decimal degrees.

  • lng2 (float) – Longitude of the second point in decimal degrees.

Returns:

Distance between the two points in meters.

Return type:

float

class core.bones.spatial.SpatialBone(*, boundsLat, boundsLng, gridDimensions, **kwargs)

Bases: viur.core.bones.base.BaseBone

The “SpatialBone” is a specific type of data structure designed to handle spatial data, such as geographical coordinates or geometries. This bone would typically be used for representing and storing location-based data, like the coordinates of a point of interest on a map or the boundaries of a geographic region. This feature allows querying elements near a specific location. Before using, designate the map region for which the index should be constructed. To ensure the best accuracy, minimize the region size; using the entire world is not feasible since boundary wraps are not executed. GridDimensions indicates the number of sub-regions the map will be partitioned into. Results beyond the size of these sub-regions will not be considered during searches by this algorithm.

Note

Example: When using this feature to find the nearest pubs, the algorithm could be set to consider results within 100km but not those 500km away. Setting the sub-region size to roughly 100km in width and height allows the algorithm to exclude results further than 200km away at the database-query-level, significantly enhancing performance and reducing query costs.

Example region: Germany: `boundsLat=(46.988, 55.022), boundsLng=(4.997, 15.148)`

Parameters:
  • boundsLat (tuple[float, float]) – The outer bounds (Latitude) of the region we will search in

  • boundsLng (tuple[float, float]) – The outer bounds (Longitude) of the region we will search in

  • gridDimensions (tuple[int, int]) – (Tuple[int, int]) The number of sub-regions the map will be divided in

  • boundsLat

  • boundsLng

Initializes a new SpatialBone.

Parameters:
  • boundsLat (tuple[float, float]) – Outer bounds (Latitude) of the region we will search in.

  • boundsLng (tuple[float, float]) – Outer bounds (Longitude) of the region we will search in.

  • gridDimensions (tuple[int, int]) – Number of sub-regions the map will be divided in

type = 'spatial'
getGridSize()

Calculate and return the size of the sub-regions in terms of fractions of latitude and longitude.

Returns:

A tuple containing the size of the sub-regions as (fractions-of-latitude, fractions-of-longitude)

Return type:

(float, float)

isInvalid(value)

Validate if the given point (latitude, longitude) falls within the specified boundaries. Rejects all values outside the defined region.

Parameters:

value (tuple[float, float]) – A tuple containing the location of the entry as (latitude, longitude)

Returns:

An error description if the value is invalid or False if the value is valid

Return type:

str | bool

singleValueSerialize(value, skel, name, parentIndexed)

Serialize a single value (latitude, longitude) for storage. If the bone is indexed, calculate and add tile information for efficient querying.

Parameters:
  • value – A tuple containing the location of the entry as (latitude, longitude)

  • skel (SkeletonInstance) – The instance of the Skeleton this bone is attached to

  • name (str) – The name of this bone

  • parentIndexed (bool) – A boolean indicating if the parent bone is indexed

Returns:

A dictionary containing the serialized data, including coordinates and tile information (if indexed)

Return type:

dict | None

singleValueUnserialize(val)

Deserialize a single value (latitude, longitude) from the stored data.

Parameters:

val – A dictionary containing the serialized data, including coordinates

Returns:

A tuple containing the location of the entry as (latitude, longitude)

Return type:

Tuple[float, float] | None

parseSubfieldsFromClient()

Determines if subfields (latitude and longitude) should be parsed from the client.

Returns:

Always returns True, as latitude and longitude are required

Return type:

bool

isEmpty(value)

Check if the given raw value is considered empty (either not present or equal to the empty value).

Parameters:

value (Any) – The raw value to be checked

Returns:

True if the raw value is considered empty, False otherwise

Return type:

bool

getEmptyValue()

Returns an empty value for the bone, which represents an invalid position. Use 91.0, 181.0 as a special marker for empty, as they are both out of range for Latitude (-90, +90) and Longitude (-180, 180), but will be accepted by Vi and Admin.

Returns:

A tuple representing an empty value for this bone (91.0, 181.0)

Return type:

Tuple[float, float]

singleValueFromClient(value, skel, bone_name, client_data)

Load a single value from a client

Parameters:
  • value – The single value which should be loaded.

  • skel – The SkeletonInstance where the value should be loaded into.

  • bone_name – The bone name of this bone in the SkeletonInstance.

  • client_data – The data taken from the client, a dictionary with usually bone names as key

Returns:

A tuple. If the value is valid, the first element is the parsed value and the second is None. If the value is invalid or not parseable, the first element is a empty value and the second a list of ReadFromClientError.

buildDBFilter(name, skel, dbFilter, rawFilter, prefix=None)

Parses the client’s search filter specified in their request and converts it into a format understood by the datastore.

  • Ignore filters that do not target this bone.

  • Safely handle malformed data in rawFilter (this parameter is directly controlled by the client).

For detailed information on how this geo-spatial search works, see the ViUR documentation.

Parameters:
  • name (str) – The property name this bone has in its Skeleton (not the description!)

  • skel (SkeletonInstance) – The skeleton this bone is part of

  • dbFilter (db.Query) – The current viur.core.db.Query instance to which the filters should be applied

  • rawFilter (dict) – The dictionary of filters the client wants to have applied

  • prefix (Optional[str]) – Optional string, specifying a prefix for the bone’s name (default is None)

Returns:

The modified viur.core.db.Query instance

Return type:

db.Query

calculateInternalMultiQueryLimit(dbQuery, targetAmount)

Provides guidance to viur.core.db.Query on the number of entries that should be fetched in each subquery.

Parameters:
  • dbQuery (viur.core.db.Query) – The viur.core.db.Query instance

  • targetAmount (int) – The desired number of entries to be returned from the db.Query

Returns:

The number of elements db.Query should fetch for each subquery

Return type:

int

customMultiQueryMerge(name, lat, lng, dbFilter, result, targetAmount)

Randomly returns ‘targetAmount’ elements from ‘result’.

Parameters:
  • name (str) – The property-name this bone has in its Skeleton (not the description!)

  • lat – Latitude of the reference point

  • lng – Longitude of the reference point

  • dbFilter (viur.core.db.Query) – The db.Query instance calling this function

  • result (list[viur.core.db.Entity]) – The list of results for each subquery that was executed

  • targetAmount (int) – The desired number of results to be returned from db.Query

Returns:

List of elements to be returned from db.Query

Return type:

List[db.Entity]

setBoneValue(skel, boneName, value, append, language=None)

Sets the value of the bone to the provided ‘value’. Sanity checks are performed; if the value is invalid, the bone value will revert to its original (default) value and the function will return False.

Parameters:
  • skel (SkeletonInstance) – Dictionary with the current values from the skeleton the bone belongs to

  • boneName (str) – The name of the bone that should be modified

  • value (Any) – The value that should be assigned. Its type depends on the type of the bone

  • append (bool) – If True, the given value will be appended to the existing bone values instead of replacing them. Only supported on bones with multiple=True

  • language (None | str) – Optional, the language of the value if the bone is language-aware

Returns:

A boolean indicating whether the operation succeeded or not

Return type:

bool

structure()

Describes the bone and its settings as an JSON-serializable dict. This function has to be implemented for subsequent, specialized bone types.

Return type:

dict