# Celx Scripting: Position

## position

A "position" object contains the exact coordinates of a point in space. A "position" object is relative to a coordinate system (i.e. a frame of reference, see Celx Scripting: Frame) and may need to be converted to or from universal coordinates before further use.

Within a CELX script, the position methods need to be prefixed with the obtained "position" object, separated with a colon.

The following methods can be used to obtain a "position" object:

Notes:

1. Position components (X,Y,Z) in Celestia are stored in millionths of a light year. So when you have your own positions defined in km or miles, you have to convert these positions. Therefore, you can use a constant, which must be initialized first within your script:
• From km to millionths of a light year, use a constant uly_to_km = 9460730.4725808.
• From miles to millionths of a light year, use a constant uly_to_mls = 5912956.5453630.
2. Next you can convert km or miles to millionths of a light year as follows:
• millionths_of_a_light_year = number:km / uly_to_km
• millionths_of_a_light_year = number:miles / uly_to_mls
3. Internally "position" objects use 128 bit per component and therefore have higher precision than available directly in Lua (which typically uses 64-bit IEEE754 double precision floating point numbers). The calculations that you can perform however on a "position" object are limited, so you'll often want to convert "position" objects to normal Lua numbers.
In order to avoid precision problems, the usual practice is to convert a "position" object to a "vector" object, relative to the origin (such as the Sun or Solar System Barycenter). You can do this by subtracting the origin's position from the object- or observer position to get a "vector" object like this:
```-- Get a vector giving the heliocentric position of the Earth
function earthpos(jd)
local sun = celestia:find("Sol")
local earth = celestia:find("Sol/Earth")
return earth:getposition(jd) - sun:getposition(jd)
end
```

## Operators

"Position" objects can be added and subtracted from each other.
It is also possible to add a "position" object with a "vector" object, or subtract a "vector" object from a "position" object.

• position + vector → position
• position + position → position
• position - position → vector
• position - vector → position

Note:Subtracting two "position" objects produces a "vector" object and NOT a "position" object.

## Members

You can access and assign the x, y, and z components of a "position" object directly, e.g.

```earth = celestia:find("Sol/Earth")
earthpos = earth:getposition()
ep_x = earthpos.x
ep_y = earthpos.y
ep_z = earthpos.z
```
```obs = celestia:getobserver()
obspos = obs:getposition()
obspos.x = 1
obspos.y = 0
obspos.x = 0
obs = celestia:setpostion(obspos)
```

Note: Accessing components this way returns normal Lua numbers, which have less precision than the 128-bit values stored in a "position" object.

## Methods

This chapter contains a list of all available position methods, which can be used on "position" objects.

Add a vector to the position and return the result as a "position" object.

Arguments:

vec
The vector to be added to the position. Must be a "vector" object.

Notes:

1. You can also use position = position + vector instead of this position:addvector() method. Both have the same result.
2. Like position components, the vector components (X,Y,Z) in Celestia are also stored in millionths of a light year.
3. A CELX "position" object contains the exact coordinates of a point in space. A position is relative to a coordinate system and may need to be converted to or from universal coordinates before further use.
4. The position methods can be used on a CELX "position" object. "Position" objects can also be used in other methods, requiring a "position" object as an argument.

Example:
Goto a position in space just beside the path where Earth will be over 1 day. Look from that position at Earth and see how Earth comes towards you and just misses you (time is sped up 3600x).

```-- Find and select Earth
earth = celestia:find("Sol/Earth")
celestia:select(earth)
obs = celestia:getobserver()
-- Set frame of reference to "universal".
obs:setframe(celestia:newframe("universal"))
-- Determine the actual position of Earth
now = celestia:gettime()
posearth = earth:getposition(now)
-- Determine and goto new observer position, to just miss Earth within 1 day
newpos = earth:getposition(now+1)
vec = celestia:newvector(0, 0, 0.002)
obs:goto(newpos,1.0)
wait(0.0)
-- Look at Earth and see how it comes towards you
upvec = celestia:newvector(0,1,0)
obs:lookat(newpos, posearth, upvec)
celestia:settimescale(3600)
obs:track(earth)
```

### vectorto

vector position:vectorto(position:target)

Return the "vector" object, pointing from this position to the target position.

Arguments:

target
The target position the vector should be pointing to. Must be a "position" object.

Notes:

1. You can also use vector = position target - position source instead of this position:vectorto() method. Both have the same result.
2. The precision of a vector (IEEE754 double precision floating point) may be insufficient to express this distance exactly.
3. A CELX "vector" object is a geometric object that has both a length and direction [X, Y, Z] in a 3 dimensional coordinate system.
4. The vector methods can be used on a CELX "vector" object. "Vector" objects can also be used in other methods, requiring a "vector" object as an argument.

Example:
Get a vector, giving the heliocentric position of the Earth

```now = celestia:gettime()
sunpos = celestia:find("Sol"):getposition(now)
earthpos = celestia:find("Sol/Earth"):getposition(now)
heliovector = sunpos:vectorto(earthpos)
```

### distanceto

number position:distanceto(position:target)

Return the distance in kilometers from this position to the target position, as a number.

Arguments:

target
The target position the distance must be calculated to. Must be a "position" object.

Example:
Determine and display the actual distance from the obserber to Neptune.

```now = celestia:gettime()
neptunepos = celestia:find("Sol/Neptune"):getposition(now)
obs = celestia:getobserver()
obspos = obs:getposition()
distance = obspos:distanceto(neptunepos)
celestia:print("The center of Neptune is " .. distance .. " km away", 10.0, -1, -1, 2, 4)
wait(10.0)
```

### orientationto

rotation position:orientationto(position:target, vector:up)

Return a "rotation" object which can be used to orient a viewer to point from this position toward the target position.

Arguments:

target
The target position at which the viewer should focus on. Must be a "position" object.
up
The up vector, defining which axis should be pointing up. Must be a "vector" object.
Must not be parallel to the target direction, otherwise the rotation is undefined.

Notes:

1. A CELX "rotation" object is internally a Quaternion, which is one possibility to mathematically describe a rotation in 3 dimensions (i.e. it can be converted to a rotation matrix). A rotation can also be used to describe the orientation of objects or the observer (i.e. where the observer is looking to, and where "up" is).
2. The rotation methods can be used on a CELX "rotation" object. "Rotation" objects can also be used in other methods, requiring a "rotation" object as an argument.

Example:
Goto a position just beside Mars and orient the observer towards the planet.

```obs = celestia:getobserver()
-- Set frame of reference to "universal".
obs:setframe(celestia:newframe( "universal"))
-- Find the actual position of Mars.
mars = celestia:find("Sol/Mars")
marspos = mars:getposition()
-- Calculate new position just far away from Mars.
newpos = marspos + celestia:newvector(0, 0, 0.002)
obs:goto(newpos, 0.0)
wait(0.0)
-- view towards Mars and follow the planet
rotation = newpos:orientationto(marspos, celestia:newvector(0, 1, 0))
obs:setorientation(rotation)
obs:follow(mars)
```

### getx

number position:getx()

Return the X coordinate of the position as a number.

Notes:

1. The precision is returned as a double-precision floating point value and may not have sufficient precision to express the exact position.

Example:
Get the actual position of Earth and display the X-, Y- and Z-components of that position in the lower left corner of the screen.

```now = celestia:gettime()
earthpos = celestia:find("Sol/Earth"):getposition(now)
earthpos_x = earthpos:getx()
earthpos_y = earthpos:gety()
earthpos_z = earthpos:getz()
celestia:print("Universal position of Earth:\nX = " .. earthpos_x ..
"\nY = " .. earthpos_y .. "\nZ = " .. earthpos_z, 10.0, -1, -1, 2, 7)
wait(10.0)
```

### gety

number position:gety()

Return the Y coordinate of the position as a number.

Notes:

1. The precision is returned as a double-precision floating point value and may not have sufficient precision to express the exact position.

Example:
Get the actual position of Earth and display the X-, Y- and Z-components of that position in the lower left corner of the screen.

```now = celestia:gettime()
earthpos = celestia:find("Sol/Earth"):getposition(now)
earthpos_x = earthpos:getx()
earthpos_y = earthpos:gety()
earthpos_z = earthpos:getz()
celestia:print("Universal position of Earth:\nX = " .. earthpos_x ..
"\nY = " .. earthpos_y .. "\nZ = " .. earthpos_z, 10.0, -1, -1, 2, 7)
wait(10.0)
```

### getz

number position:getz()

Return the Z coordinate of the position as a number.

Notes:

1. The precision is returned as a double-precision floating point value and may not have sufficient precision to express the exact position.

Example:
Get the actual position of Earth and display the X-, Y- and Z-components of that position in the lower left corner of the screen.

```now = celestia:gettime()
earthpos = celestia:find("Sol/Earth"):getposition(now)
earthpos_x = earthpos:getx()
earthpos_y = earthpos:gety()
earthpos_z = earthpos:getz()
celestia:print("Universal position of Earth:\nX = " .. earthpos_x ..
"\nY = " .. earthpos_y .. "\nZ = " .. earthpos_z, 10.0, -1, -1, 2, 7)
wait(10.0)
```