Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Trigonometric Functions

⚠️ Warning

HelixQL is deprecated in HelixDB v2. Queries are now written with the Rust DSL and dispatched as JSON — see the Querying guide. This section is kept as a reference for legacy HelixQL projects.

For the complete documentation index optimized for AI agents, see llms.txt.

Trigonometric Functions

HelixQL provides a comprehensive set of trigonometric functions for angular calculations, including standard trigonometric functions (sine, cosine, tangent) and their inverse counterparts, essential for geospatial calculations, physics simulations, and angular measurements.

Available Functions

SIN - Sine

SIN(x)  // Returns sin(x)

Returns the sine of an angle in radians.

COS - Cosine

COS(x)  // Returns cos(x)

Returns the cosine of an angle in radians.

TAN - Tangent

TAN(x)  // Returns tan(x)

Returns the tangent of an angle in radians.

ASIN - Arcsine

ASIN(x)  // Returns arcsin(x)

Returns the arcsine (inverse sine) of x in radians. Domain: [-1, 1].

ACOS - Arccosine

ACOS(x)  // Returns arccos(x)

Returns the arccosine (inverse cosine) of x in radians. Domain: [-1, 1].

ATAN - Arctangent

ATAN(x)  // Returns arctan(x)

Returns the arctangent (inverse tangent) of x in radians.

ATAN2 - Two-Argument Arctangent

ATAN2(y, x)  // Returns atan2(y, x)

Returns the angle in radians between the positive x-axis and the point (x, y). This function handles all quadrants correctly and is commonly used for angle calculations.

⚠️ Warning

When using the SDKs or curling the endpoint, the query name must match what is defined in the queries.hx file exactly.

Example 1: Geospatial bearing calculations

Calculate the bearing (direction) between geographic coordinates:

QUERY CalculateBearings() =>
    locations <- N::Location
        ::{
            name, latitude, longitude,
            radians_lat: MUL(_::{latitude}, DIV(PI(), 180.0)),
            radians_lon: MUL(_::{longitude}, DIV(PI(), 180.0)),
            sin_lat: SIN(MUL(_::{latitude}, DIV(PI(), 180.0))),
            cos_lat: COS(MUL(_::{latitude}, DIV(PI(), 180.0))),
            tan_lat: TAN(MUL(_::{latitude}, DIV(PI(), 180.0)))
        }
    RETURN locations

QUERY CreateLocation(name: String, latitude: F64, longitude: F64) =>
    location <- AddN<Location>({ name: name, latitude: latitude, longitude: longitude })
    RETURN location
N::Location {
    name: String,
    latitude: F64,
    longitude: F64
}

Here’s how to run the query using the SDKs or curl

from helix.client import Client

client = Client(local=True, port=6969)

# Create locations with geographic coordinates
locations = [
    {"name": "New York", "latitude": 40.7128, "longitude": -74.0060},
    {"name": "London", "latitude": 51.5074, "longitude": -0.1278},
    {"name": "Tokyo", "latitude": 35.6762, "longitude": 139.6503},
]

for location in locations:
    client.query("CreateLocation", location)

result = client.query("CalculateBearings", {})
print("Location bearings:", result)
use helix_rs::{HelixDB, HelixDBClient};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = HelixDB::new(Some("http://localhost"), Some(6969), None);

    let locations = vec![
        ("New York", 40.7128, -74.0060),
        ("London", 51.5074, -0.1278),
        ("Tokyo", 35.6762, 139.6503),
    ];

    for (name, latitude, longitude) in &locations {
        let _inserted: serde_json::Value = client.query("CreateLocation", &json!({
            "name": name,
            "latitude": latitude,
            "longitude": longitude,
        })).await?;
    }

    let result: serde_json::Value = client.query("CalculateBearings", &json!({})).await?;

    println!("Location bearings: {result:#?}");

    Ok(())
}
package main

import (
    "fmt"
    "log"

    "github.com/HelixDB/helix-go"
)

func main() {
    client := helix.NewClient("http://localhost:6969")

    locations := []map[string]any{
        {"name": "New York", "latitude": 40.7128, "longitude": -74.0060},
        {"name": "London", "latitude": 51.5074, "longitude": -0.1278},
        {"name": "Tokyo", "latitude": 35.6762, "longitude": 139.6503},
    }

    for _, location := range locations {
        var inserted map[string]any
        if err := client.Query("CreateLocation", helix.WithData(location)).Scan(&inserted); err != nil {
            log.Fatalf("CreateLocation failed: %s", err)
        }
    }

    var result map[string]any
    if err := client.Query("CalculateBearings", helix.WithData(map[string]any{})).Scan(&result); err != nil {
        log.Fatalf("CalculateBearings failed: %s", err)
    }

    fmt.Printf("Location bearings: %#v\n", result)
}
import HelixDB from "helix-ts";

async function main() {
    const client = new HelixDB("http://localhost:6969");

    const locations = [
        { name: "New York", latitude: 40.7128, longitude: -74.0060 },
        { name: "London", latitude: 51.5074, longitude: -0.1278 },
        { name: "Tokyo", latitude: 35.6762, longitude: 139.6503 },
    ];

    for (const location of locations) {
        await client.query("CreateLocation", location);
    }

    const result = await client.query("CalculateBearings", {});

    console.log("Location bearings:", result);
}

main().catch((err) => {
    console.error("CalculateBearings query failed:", err);
});
curl -X POST \
  http://localhost:6969/CreateLocation \
  -H 'Content-Type: application/json' \
  -d '{"name":"New York","latitude":40.7128,"longitude":-74.0060}'

curl -X POST \
  http://localhost:6969/CreateLocation \
  -H 'Content-Type: application/json' \
  -d '{"name":"London","latitude":51.5074,"longitude":-0.1278}'

curl -X POST \
  http://localhost:6969/CreateLocation \
  -H 'Content-Type: application/json' \
  -d '{"name":"Tokyo","latitude":35.6762,"longitude":139.6503}'

curl -X POST \
  http://localhost:6969/CalculateBearings \
  -H 'Content-Type: application/json' \
  -d '{}'

Example 2: Angle calculations with ATAN2

Use ATAN2 to calculate angles between vectors and points:

QUERY CalculateAngles() =>
    vectors <- N::Vector
        ::{
            x, y,
            angle_radians: ATAN2(_::{y}, _::{x}),
            angle_degrees: MUL(ATAN2(_::{y}, _::{x}), DIV(180.0, PI()))
        }
    RETURN vectors

QUERY CreateVector(x: F64, y: F64) =>
    vector <- AddN<Vector>({ x: x, y: y })
    RETURN vector
N::Vector {
    x: F64,
    y: F64
}

Here’s how to run the query using the SDKs or curl

from helix.client import Client

client = Client(local=True, port=6969)

# Create vectors in different quadrants
vectors = [
    {"x": 1.0, "y": 1.0},      # 45 degrees
    {"x": -1.0, "y": 1.0},     # 135 degrees
    {"x": -1.0, "y": -1.0},    # -135 degrees
    {"x": 1.0, "y": -1.0},     # -45 degrees
]

for vector in vectors:
    client.query("CreateVector", vector)

result = client.query("CalculateAngles", {})
print("Vector angles:", result)
use helix_rs::{HelixDB, HelixDBClient};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = HelixDB::new(Some("http://localhost"), Some(6969), None);

    let vectors = vec![
        (1.0, 1.0),      // 45 degrees
        (-1.0, 1.0),     // 135 degrees
        (-1.0, -1.0),    // -135 degrees
        (1.0, -1.0),     // -45 degrees
    ];

    for (x, y) in &vectors {
        let _inserted: serde_json::Value = client.query("CreateVector", &json!({
            "x": x,
            "y": y,
        })).await?;
    }

    let result: serde_json::Value = client.query("CalculateAngles", &json!({})).await?;

    println!("Vector angles: {result:#?}");

    Ok(())
}
package main

import (
    "fmt"
    "log"

    "github.com/HelixDB/helix-go"
)

func main() {
    client := helix.NewClient("http://localhost:6969")

    vectors := []map[string]any{
        {"x": 1.0, "y": 1.0},      // 45 degrees
        {"x": -1.0, "y": 1.0},     // 135 degrees
        {"x": -1.0, "y": -1.0},    // -135 degrees
        {"x": 1.0, "y": -1.0},     // -45 degrees
    }

    for _, vector := range vectors {
        var inserted map[string]any
        if err := client.Query("CreateVector", helix.WithData(vector)).Scan(&inserted); err != nil {
            log.Fatalf("CreateVector failed: %s", err)
        }
    }

    var result map[string]any
    if err := client.Query("CalculateAngles", helix.WithData(map[string]any{})).Scan(&result); err != nil {
        log.Fatalf("CalculateAngles failed: %s", err)
    }

    fmt.Printf("Vector angles: %#v\n", result)
}
import HelixDB from "helix-ts";

async function main() {
    const client = new HelixDB("http://localhost:6969");

    const vectors = [
        { x: 1.0, y: 1.0 },      // 45 degrees
        { x: -1.0, y: 1.0 },     // 135 degrees
        { x: -1.0, y: -1.0 },    // -135 degrees
        { x: 1.0, y: -1.0 },     // -45 degrees
    ];

    for (const vector of vectors) {
        await client.query("CreateVector", vector);
    }

    const result = await client.query("CalculateAngles", {});

    console.log("Vector angles:", result);
}

main().catch((err) => {
    console.error("CalculateAngles query failed:", err);
});
curl -X POST \
  http://localhost:6969/CreateVector \
  -H 'Content-Type: application/json' \
  -d '{"x":1.0,"y":1.0}'

curl -X POST \
  http://localhost:6969/CreateVector \
  -H 'Content-Type: application/json' \
  -d '{"x":-1.0,"y":1.0}'

curl -X POST \
  http://localhost:6969/CreateVector \
  -H 'Content-Type: application/json' \
  -d '{"x":-1.0,"y":-1.0}'

curl -X POST \
  http://localhost:6969/CreateVector \
  -H 'Content-Type: application/json' \
  -d '{"x":1.0,"y":-1.0}'

curl -X POST \
  http://localhost:6969/CalculateAngles \
  -H 'Content-Type: application/json' \
  -d '{}'

Example 3: Inverse trigonometric functions

Use inverse trigonometric functions to recover angles from ratios:

QUERY RecoverAngles() =>
    measurements <- N::Measurement
        ::{
            ratio,
            angle_from_sin: ASIN(_::{ratio}),
            angle_from_cos: ACOS(_::{ratio}),
            angle_from_tan: ATAN(_::{ratio})
        }
    RETURN measurements

QUERY CreateMeasurement(ratio: F64) =>
    measurement <- AddN<Measurement>({ ratio: ratio })
    RETURN measurement
N::Measurement {
    ratio: F64
}

Here’s how to run the query using the SDKs or curl

from helix.client import Client

client = Client(local=True, port=6969)

# Create measurements with various ratios
ratios = [0.0, 0.5, 0.707, 0.866, 1.0]

for ratio in ratios:
    client.query("CreateMeasurement", {"ratio": ratio})

result = client.query("RecoverAngles", {})
print("Recovered angles:", result)
use helix_rs::{HelixDB, HelixDBClient};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = HelixDB::new(Some("http://localhost"), Some(6969), None);

    let ratios = vec![0.0, 0.5, 0.707, 0.866, 1.0];

    for ratio in &ratios {
        let _inserted: serde_json::Value = client.query("CreateMeasurement", &json!({
            "ratio": ratio,
        })).await?;
    }

    let result: serde_json::Value = client.query("RecoverAngles", &json!({})).await?;

    println!("Recovered angles: {result:#?}");

    Ok(())
}
package main

import (
    "fmt"
    "log"

    "github.com/HelixDB/helix-go"
)

func main() {
    client := helix.NewClient("http://localhost:6969")

    ratios := []float64{0.0, 0.5, 0.707, 0.866, 1.0}

    for _, ratio := range ratios {
        var inserted map[string]any
        if err := client.Query("CreateMeasurement", helix.WithData(map[string]any{
            "ratio": ratio,
        })).Scan(&inserted); err != nil {
            log.Fatalf("CreateMeasurement failed: %s", err)
        }
    }

    var result map[string]any
    if err := client.Query("RecoverAngles", helix.WithData(map[string]any{})).Scan(&result); err != nil {
        log.Fatalf("RecoverAngles failed: %s", err)
    }

    fmt.Printf("Recovered angles: %#v\n", result)
}
import HelixDB from "helix-ts";

async function main() {
    const client = new HelixDB("http://localhost:6969");

    const ratios = [0.0, 0.5, 0.707, 0.866, 1.0];

    for (const ratio of ratios) {
        await client.query("CreateMeasurement", { ratio });
    }

    const result = await client.query("RecoverAngles", {});

    console.log("Recovered angles:", result);
}

main().catch((err) => {
    console.error("RecoverAngles query failed:", err);
});
curl -X POST \
  http://localhost:6969/CreateMeasurement \
  -H 'Content-Type: application/json' \
  -d '{"ratio":0.0}'

curl -X POST \
  http://localhost:6969/CreateMeasurement \
  -H 'Content-Type: application/json' \
  -d '{"ratio":0.5}'

curl -X POST \
  http://localhost:6969/CreateMeasurement \
  -H 'Content-Type: application/json' \
  -d '{"ratio":0.707}'

curl -X POST \
  http://localhost:6969/CreateMeasurement \
  -H 'Content-Type: application/json' \
  -d '{"ratio":0.866}'

curl -X POST \
  http://localhost:6969/CreateMeasurement \
  -H 'Content-Type: application/json' \
  -d '{"ratio":1.0}'

curl -X POST \
  http://localhost:6969/RecoverAngles \
  -H 'Content-Type: application/json' \
  -d '{}'

Radians vs Degrees

All trigonometric functions in HelixQL work with radians. To convert between degrees and radians:

// Degrees to radians
radians = MUL(degrees, DIV(PI(), 180.0))

// Radians to degrees
degrees = MUL(radians, DIV(180.0, PI()))

💡 Tip

Use the PI() constant function for accurate conversion between degrees and radians.

Domain Restrictions

ℹ️ Note

Inverse trigonometric functions have domain restrictions:

  • ASIN(x), ACOS(x): x must be in [-1, 1]
  • ATAN(x): accepts all real numbers
  • ATAN2(y, x): accepts all real numbers for both arguments

ATAN2 vs ATAN

ATAN2 is preferred over ATAN for angle calculations because:

  • It handles all four quadrants correctly
  • It avoids division by zero when x = 0
  • It returns values in the full range [-π, π]
// ATAN2 correctly handles all quadrants
ATAN2(1.0, 1.0)    // π/4 (first quadrant)
ATAN2(1.0, -1.0)   // 3π/4 (second quadrant)
ATAN2(-1.0, -1.0)  // -3π/4 (third quadrant)
ATAN2(-1.0, 1.0)   // -π/4 (fourth quadrant)

Use in Geospatial Calculations

Trigonometric functions are essential for geospatial calculations:

// Calculate great circle distance (Haversine formula)
QUERY CalculateDistance(lat1: F64, lon1: F64, lat2: F64, lon2: F64) =>
    dlat <- SUB(lat2, lat1)
    dlon <- SUB(lon2, lon1)
    a <- ADD(
        POW(SIN(DIV(dlat, 2.0)), 2.0),
        MUL(MUL(COS(lat1), COS(lat2)), POW(SIN(DIV(dlon, 2.0)), 2.0))
    )
    c <- MUL(2.0, ATAN2(SQRT(a), SQRT(SUB(1.0, a))))
    distance <- MUL(6371.0, c)  // Earth radius in km
    RETURN distance