Locations Locations represent ground positions or areas that satellites can access. Brahe provides two fundamental location types—points and polygons—with full GeoJSON interoperability and extensible metadata support.
All location types implement the AccessibleLocation trait, which provides a common interface for coordinate access, property management, and GeoJSON import/export. This design allows you to work with different location geometries through a unified API.
Coordinate Units
All coordinates are specified in geodetic longitude (λ), latitude (φ), and altitude (h) using the WGS84 reference frame. All units are in degrees (for λ and φ) and meters (for h) for consistency with the GeoJSON standard.
PointLocation A PointLocation represents a single geodetic point on Earth's surface. This is the most common location type, used for ground stations, cities, or specific observation points.
Initialization from Coordinates Create a point location from geodetic coordinates (longitude, latitude, altitude):
Python Rust
import brahe as bh
bh . initialize_eop ()
# Create location (longitude, latitude, altitude in meters)
# San Francisco, CA
sf = bh . PointLocation ( - 122.4194 , 37.7749 , 0.0 )
# Add an identifier for clarity
sf = sf . with_name ( "San Francisco" )
print ( f "Location: { sf . get_name () } " )
print ( f "Longitude: { sf . longitude ( bh . AngleFormat . DEGREES ) : .4f } deg" )
print ( f "Latitude: { sf . latitude ( bh . AngleFormat . DEGREES ) : .4f } deg" )
# Expected output:
# Location: San Francisco
# Longitude: -122.4194 deg
# Latitude: 37.7749 deg
use brahe as bh ;
use bh :: utils :: Identifiable ;
use bh :: AccessibleLocation ;
fn main () {
bh :: initialize_eop (). unwrap ();
// Create location (longitude, latitude, altitude in meters)
// San Francisco, CA
let sf = bh :: PointLocation :: new (
- 122.4194 , // longitude in degrees
37.7749 , // latitude in degrees
0.0 // altitude in meters
). with_name ( "San Francisco" );
let geodetic = sf . center_geodetic ();
println! ( "Location: {}" , sf . get_name (). unwrap_or_default ());
println! ( "Longitude: {:.4} deg" , geodetic [ 0 ]);
println! ( "Latitude: {:.4} deg" , geodetic [ 1 ]);
// Expected output:
// Location: San Francisco
// Longitude: -122.4194 deg
// Latitude: 37.7749 deg
}
Coordinate Units
Python uses degrees for input convenience. Rust uses radians (SI standard). Both use meters for altitude.
Initialization from GeoJSON Load locations from GeoJSON strings or files:
Python Rust
import brahe as bh
import json
bh . initialize_eop ()
# GeoJSON Point feature
geojson_str = """
{
"type": "Feature",
"properties": {"name": "Svalbard Station"},
"geometry": {
"type": "Point",
"coordinates": [15.4038, 78.2232, 458.0]
}
}
"""
location = bh . PointLocation . from_geojson ( json . loads ( geojson_str ))
print ( f "Loaded: { location . get_name () } " )
print ( f "Longitude: { location . longitude ( bh . AngleFormat . DEGREES ) : .4f } deg" )
print ( f "Latitude: { location . latitude ( bh . AngleFormat . DEGREES ) : .4f } deg" )
print ( f "Altitude: { location . altitude () : .1f } m" )
# Expected output:
# Loaded: Svalbard Station
# Longitude: 15.4038 deg
# Latitude: 78.2232 deg
# Altitude: 458.0 m
use brahe as bh ;
use bh :: utils :: Identifiable ;
use bh :: AccessibleLocation ;
fn main () {
bh :: initialize_eop (). unwrap ();
// GeoJSON Point feature
let geojson = r#"
{
"type": "Feature",
"properties": {"name": "Svalbard Station"},
"geometry": {
"type": "Point",
"coordinates": [15.4038, 78.2232, 458.0]
}
}
"# ;
// Parse JSON string first
let json : serde_json :: Value = serde_json :: from_str ( geojson ). unwrap ();
let location = bh :: PointLocation :: from_geojson ( & json ). unwrap ();
let geodetic = location . center_geodetic ();
println! ( "Loaded: {}" , location . get_name (). unwrap_or_default ());
println! ( "Longitude: {:.4} deg" , geodetic [ 0 ]);
println! ( "Latitude: {:.4} deg" , geodetic [ 1 ]);
println! ( "Altitude: {:.1} m" , geodetic [ 2 ]);
// Expected output:
// Loaded: Svalbard Station
// Longitude: 15.4038 deg
// Latitude: 78.2232 deg
// Altitude: 458.0 m
}
Accessing Coordinates Retrieve coordinates in different formats:
Python Rust
import brahe as bh
bh . initialize_eop ()
location = bh . PointLocation ( - 122.4194 , 37.7749 , 0.0 )
# Access in degrees
print ( f "Longitude: { location . longitude ( bh . AngleFormat . DEGREES ) } deg" )
print ( f "Latitude: { location . latitude ( bh . AngleFormat . DEGREES ) } deg" )
print ( f "Altitude: { location . altitude () } m" )
# Shorthand access (in degrees)
print ( f "Lon (deg): { location . lon : .6f } " )
print ( f "Lat (deg): { location . lat : .6f } " )
# Get geodetic array [lat, lon, alt] in radians and meters
geodetic = location . center_geodetic ()
print ( f "Geodetic: [ { geodetic [ 0 ] : .6f } , { geodetic [ 1 ] : .6f } , { geodetic [ 2 ] : .1f } ]" )
# Get ECEF Cartesian position [x, y, z] in meters
ecef = location . center_ecef ()
print ( f "ECEF: [ { ecef [ 0 ] : .1f } , { ecef [ 1 ] : .1f } , { ecef [ 2 ] : .1f } ] m" )
# Expected output:
# Longitude: -122.4194 deg
# Latitude: 37.7749 deg
# Altitude: 0.0 m
# Lon (deg): -122.419400
# Lat (deg): 37.774900
# Geodetic: [-122.419400, 37.774900, 0.0]
# ECEF: [-2706174.8, -4261059.5, 3885725.5] m
use brahe as bh ;
use bh :: AccessibleLocation ;
fn main () {
bh :: initialize_eop (). unwrap ();
let location = bh :: PointLocation :: new (
- 122.4194 ,
37.7749 ,
0.0
);
// Access geodetic coordinates (in degrees)
let geodetic = location . center_geodetic ();
println! ( "Longitude: {:.4} deg" , geodetic [ 0 ]);
println! ( "Latitude: {:.4} deg" , geodetic [ 1 ]);
println! ( "Altitude: {:.1} m" , geodetic [ 2 ]);
// Get ECEF Cartesian position [x, y, z] in meters
let ecef = location . center_ecef ();
println! ( "ECEF: [{:.1}, {:.1}, {:.1}] m" , ecef [ 0 ], ecef [ 1 ], ecef [ 2 ]);
// Expected output:
// Longitude: -122.4194 deg
// Latitude: 37.7749 deg
// Altitude: 0.0 m
// ECEF: [-2706174.8, -4261059.5, 3885725.5] m
}
PolygonLocation A PolygonLocation represents a closed polygon area on Earth's surface. This is useful for imaging regions, coverage zones, or geographic areas of interest.
Initialization from Vertices Create a polygon from a list of vertices:
Python Rust
import brahe as bh
bh . initialize_eop ()
# Define polygon vertices (longitude, latitude, altitude)
# Simple rectangular region
vertices = [
[ - 122.5 , 37.7 , 0.0 ],
[ - 122.35 , 37.7 , 0.0 ],
[ - 122.35 , 37.8 , 0.0 ],
[ - 122.5 , 37.8 , 0.0 ],
[ - 122.5 , 37.7 , 0.0 ], # Close the polygon
]
polygon = bh . PolygonLocation ( vertices ) . with_name ( "SF Region" )
print ( f "Name: { polygon . get_name () } " )
print ( f "Vertices: { polygon . num_vertices } " )
print (
f "Center: ( { polygon . longitude ( bh . AngleFormat . DEGREES ) : .4f } , { polygon . latitude ( bh . AngleFormat . DEGREES ) : .4f } )"
)
# Expected output:
# Name: SF Region
# Vertices: 4
# Center: (-122.4250, 37.7500)
use brahe as bh ;
use bh :: utils :: Identifiable ;
use bh :: AccessibleLocation ;
use nalgebra as na ;
fn main () {
bh :: initialize_eop (). unwrap ();
// Define polygon vertices (lon, lat, alt in degrees and meters)
let vertices = vec! [
na :: SVector :: < f64 , 3 > :: new ( - 122.5 , 37.7 , 0.0 ),
na :: SVector :: < f64 , 3 > :: new ( - 122.35 , 37.7 , 0.0 ),
na :: SVector :: < f64 , 3 > :: new ( - 122.35 , 37.8 , 0.0 ),
na :: SVector :: < f64 , 3 > :: new ( - 122.5 , 37.8 , 0.0 ),
na :: SVector :: < f64 , 3 > :: new ( - 122.5 , 37.7 , 0.0 ),
];
let polygon = bh :: PolygonLocation :: new ( vertices ). unwrap ()
. with_name ( "SF Region" );
let center = polygon . center_geodetic ();
println! ( "Name: {}" , polygon . get_name (). unwrap_or_default ());
println! ( "Vertices: {}" , polygon . num_vertices ());
println! ( "Center: ({:.4}, {:.4})" , center [ 0 ], center [ 1 ]);
// Expected output:
// Name: SF Region
// Vertices: 4
// Center: (-122.4250, 37.7500)
}
Initialization from GeoJSON Load polygon areas from GeoJSON:
Python Rust
import brahe as bh
import json
bh . initialize_eop ()
# GeoJSON Polygon feature
geojson_str = """
{
"type": "Feature",
"properties": {"name": "Target Area"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-122.5, 37.7, 0],
[-122.35, 37.7, 0],
[-122.35, 37.8, 0],
[-122.5, 37.8, 0],
[-122.5, 37.7, 0]
]]
}
}
"""
polygon = bh . PolygonLocation . from_geojson ( json . loads ( geojson_str ))
print ( f "Name: { polygon . get_name () } " )
print ( f "Vertices: { polygon . num_vertices } " )
print (
f "Center: ( { polygon . longitude ( bh . AngleFormat . DEGREES ) : .4f } , { polygon . latitude ( bh . AngleFormat . DEGREES ) : .4f } )"
)
# Expected output:
# Name: Target Area
# Vertices: 5
# Center: (-122.4250, 37.7500)
use brahe as bh ;
use bh :: utils :: Identifiable ;
use bh :: AccessibleLocation ;
fn main () {
bh :: initialize_eop (). unwrap ();
let geojson = r#"
{
"type": "Feature",
"properties": {"name": "Target Area"},
"geometry": {
"type": "Polygon",
"coordinates": [[
[-122.5, 37.7, 0],
[-122.35, 37.7, 0],
[-122.35, 37.8, 0],
[-122.5, 37.8, 0],
[-122.5, 37.7, 0]
]]
}
}
"# ;
// Parse JSON string first
let json : serde_json :: Value = serde_json :: from_str ( geojson ). unwrap ();
let polygon = bh :: PolygonLocation :: from_geojson ( & json ). unwrap ();
let center = polygon . center_geodetic ();
println! ( "Name: {}" , polygon . get_name (). unwrap_or_default ());
println! ( "Vertices: {}" , polygon . num_vertices ());
println! ( "Center: ({:.4}, {:.4})" , center [ 0 ], center [ 1 ]);
// Expected output:
// Name: Target Area
// Vertices: 4
// Center: (-122.4250, 37.7500)
}
Working with Properties Both location types support custom properties for storing metadata:
Python Rust
import brahe as bh
bh . initialize_eop ()
location = bh . PointLocation ( - 122.4194 , 37.7749 , 0.0 )
# Add scalar properties
location . add_property ( "antenna_gain_db" , 42.5 )
location . add_property ( "frequency_mhz" , 8450.0 )
# Add string properties
location . add_property ( "operator" , "NOAA" )
# Add boolean flags
location . add_property ( "uplink_enabled" , True )
# Retrieve properties
props = location . properties
gain = props . get ( "antenna_gain_db" )
operator = props . get ( "operator" )
uplink = props . get ( "uplink_enabled" )
print ( f "Antenna Gain: { gain } " )
print ( f "Operator: { operator } " )
print ( f "Uplink Enabled: { uplink } " )
# Expected output:
# Antenna Gain: 42.5
# Operator: NOAA
# Uplink Enabled: True
use brahe as bh ;
use bh :: AccessibleLocation ;
use serde_json :: json ;
fn main () {
bh :: initialize_eop (). unwrap ();
let location = bh :: PointLocation :: new ( - 122.4194 , 37.7749 , 0.0 )
. add_property ( "antenna_gain_db" , json ! ( 42.5 ))
. add_property ( "frequency_mhz" , json ! ( 8450.0 ))
. add_property ( "operator" , json ! ( "NOAA" ))
. add_property ( "uplink_enabled" , json ! ( true ));
// Access properties
let props = location . properties ();
if let Some ( gain ) = props . get ( "antenna_gain_db" ) {
println! ( "Antenna Gain: {}" , gain );
}
if let Some ( operator ) = props . get ( "operator" ) {
println! ( "Operator: {}" , operator );
}
if let Some ( uplink ) = props . get ( "uplink_enabled" ) {
println! ( "Uplink Enabled: {}" , uplink );
}
// Expected output:
// Antenna Gain: 42.5
// Operator: "NOAA"
// Uplink Enabled: true
}
Exporting to GeoJSON Convert locations back to GeoJSON format:
Python Rust
import brahe as bh
bh . initialize_eop ()
location = (
bh . PointLocation ( - 122.4194 , 37.7749 , 0.0 ) . with_name ( "San Francisco" ) . with_id ( 1 )
)
# Export to GeoJSON dict
geojson = location . to_geojson ()
print ( "Exported GeoJSON:" )
print ( geojson )
# The output includes all properties and identifiers
# Can be loaded back with from_geojson()
reloaded = bh . PointLocation . from_geojson ( geojson )
print ( f " \n Reloaded: { reloaded . get_name () } (ID: { reloaded . get_id () } )" )
# Expected output:
# Exported GeoJSON:
# {'geometry': {'coordinates': [-122.4194, 37.7749, 0.0], 'type': 'Point'}, 'properties': {'id': 1, 'name': 'San Francisco'}, 'type': 'Feature'}
#
# Reloaded: San Francisco (ID: 1)
use brahe as bh ;
use bh :: utils :: Identifiable ;
use bh :: AccessibleLocation ;
fn main () {
bh :: initialize_eop (). unwrap ();
let location = bh :: PointLocation :: new ( - 122.4194 , 37.7749 , 0.0 )
. with_name ( "San Francisco" )
. with_id ( 1 );
// Export to GeoJSON
let geojson = location . to_geojson ();
println! ( "Exported GeoJSON:" );
println! ( "{}" , geojson );
// The output includes all properties and identifiers
// Can be loaded back with from_geojson()
let reloaded = bh :: PointLocation :: from_geojson ( & geojson ). unwrap ();
println! ( " \n Reloaded: {} (ID: {})" ,
reloaded . get_name (). unwrap_or_default (),
reloaded . get_id (). unwrap_or ( 0 ));
// Expected output:
// Exported GeoJSON:
// {"geometry":{"coordinates":[-122.4194,37.7749,0.0],"type":"Point"},"properties":{"id":1,"name":"San Francisco"},"type":"Feature"}
//
// Reloaded: San Francisco (ID: 1)
}
See Also