CelestiaContent/src/celscript/lua/celx_position.cpp

342 lines
7.8 KiB
C++

// celx_position.cpp
//
// Copyright (C) 2003-2008, the Celestia Development Team
//
// Lua script extensions for Celestia: position object
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include "celx.h"
#include "celx_internal.h"
#include "celx_position.h"
#include <Eigen/Geometry>
using namespace Eigen;
// ==================== Position ====================
// a 128-bit per component universal coordinate
int position_new(lua_State* l, const UniversalCoord& uc)
{
CelxLua celx(l);
UniversalCoord* ud = reinterpret_cast<UniversalCoord*>(lua_newuserdata(l, sizeof(UniversalCoord)));
*ud = uc;
celx.setClass(Celx_Position);
return 1;
}
UniversalCoord* to_position(lua_State* l, int index)
{
CelxLua celx(l);
return static_cast<UniversalCoord*>(celx.checkUserData(index, Celx_Position));
}
static UniversalCoord* this_position(lua_State* l)
{
CelxLua celx(l);
UniversalCoord* uc = to_position(l, 1);
if (uc == nullptr)
{
celx.doError("Bad position object!");
}
return uc;
}
static int position_get(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(2, 2, "Invalid access of position-component");
UniversalCoord* uc = this_position(l);
string key = celx.safeGetString(2, AllErrors, "Invalid key in position-access");
double value = 0.0;
if (key == "x")
value = uc->x;
else if (key == "y")
value = uc->y;
else if (key == "z")
value = uc->z;
else
{
if (!lua_getmetatable(l, 1))
{
celx.doError("Internal error: couldn't get metatable");
return 0;
}
lua_pushvalue(l, 2);
lua_rawget(l, -2);
return 1;
}
lua_pushnumber(l, (lua_Number)value);
return 1;
}
static int position_set(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(3, 3, "Invalid access of position-component");
UniversalCoord* uc = this_position(l);
string key = celx.safeGetString(2, AllErrors, "Invalid key in position-access");
double value = celx.safeGetNumber(3, AllErrors, "Position components must be numbers");
if (key == "x")
uc->x = value;
else if (key == "y")
uc->y = value;
else if (key == "z")
uc->z = value;
else
{
celx.doError("Invalid key in position-access");
}
return 0;
}
static int position_getx(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(1, 1, "No arguments expected for position:getx()");
UniversalCoord* uc = this_position(l);
lua_Number x;
x = uc->x;
lua_pushnumber(l, x);
return 1;
}
static int position_gety(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(1, 1, "No arguments expected for position:gety()");
UniversalCoord* uc = this_position(l);
lua_Number y;
y = uc->y;
lua_pushnumber(l, y);
return 1;
}
static int position_getz(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(1, 1, "No arguments expected for position:getz()");
UniversalCoord* uc = this_position(l);
lua_Number z;
z = uc->z;
lua_pushnumber(l, z);
return 1;
}
static int position_vectorto(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(2, 2, "One argument expected to position:vectorto");
UniversalCoord* uc = this_position(l);
UniversalCoord* uc2 = to_position(l, 2);
if (uc2 == nullptr)
{
celx.doError("Argument to position:vectorto must be a position");
return 0;
}
celx.newVector(uc2->offsetFromUly(*uc));
return 1;
}
static int position_orientationto(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(3, 3, "Two arguments expected for position:orientationto");
UniversalCoord* src = this_position(l);
UniversalCoord* target = to_position(l, 2);
if (target == nullptr)
{
celx.doError("First argument to position:orientationto must be a position");
return 1;
}
auto upd = celx.toVector(3);
if (upd == nullptr)
{
celx.doError("Second argument to position:orientationto must be a vector");
return 1;
}
Vector3d src2target = target->offsetFromKm(*src).normalized();
Vector3d v = src2target.cross(*upd).normalized();
Vector3d u = v.cross(src2target);
Matrix3d m;
m.row(0) = v; m.row(1) = u; m.row(2) = src2target * (-1);
Quaterniond qd(m);
celx.newRotation(qd);
return 1;
}
static int position_tostring(lua_State* l)
{
// TODO: print out the coordinate as it would appear in a cel:// URL
lua_pushstring(l, "[Position]");
return 1;
}
static int position_distanceto(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(2, 2, "One argument expected to position:distanceto()");
UniversalCoord* uc = this_position(l);
UniversalCoord* uc2 = to_position(l, 2);
if (uc2 == nullptr)
{
celx.doError("Position expected as argument to position:distanceto");
return 0;
}
lua_pushnumber(l, uc2->offsetFromKm(*uc).norm());
return 1;
}
static int position_add(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(2, 2, "Need two operands for addition");
UniversalCoord* p1 = nullptr;
UniversalCoord* p2 = nullptr;
Vector3d* v2 = nullptr;
if (celx.isType(1, Celx_Position) && celx.isType(2, Celx_Position))
{
p1 = celx.toPosition(1);
p2 = celx.toPosition(2);
// this is not very intuitive, as p1-p2 is a vector
celx.newPosition(*p1 + *p2);
}
else
if (celx.isType(1, Celx_Position) && celx.isType(2, Celx_Vec3))
{
p1 = celx.toPosition(1);
v2 = celx.toVector(2);
celx.newPosition(p1->offsetUly(*v2));
}
else
{
celx.doError("Bad position addition!");
}
return 1;
}
static int position_sub(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(2, 2, "Need two operands for subtraction");
UniversalCoord* p1 = nullptr;
UniversalCoord* p2 = nullptr;
Vector3d* v2 = nullptr;
if (celx.isType(1, Celx_Position) && celx.isType(2, Celx_Position))
{
p1 = celx.toPosition(1);
p2 = celx.toPosition(2);
celx.newVector(p1->offsetFromUly(*p2));
}
else
if (celx.isType(1, Celx_Position) && celx.isType(2, Celx_Vec3))
{
p1 = celx.toPosition(1);
v2 = celx.toVector(2);
celx.newPosition(p1->offsetUly(*v2));
}
else
{
celx.doError("Bad position subtraction!");
}
return 1;
}
static int position_addvector(lua_State* l)
{
CelxLua celx(l);
celx.checkArgs(2, 2, "One argument expected to position:addvector()");
UniversalCoord* uc = this_position(l);
if (uc == nullptr)
return 0;
auto v3d = celx.toVector(2);
if (v3d == nullptr)
{
celx.doError("Vector expected as argument to position:addvector");
return 0;
}
UniversalCoord ucnew = uc->offsetUly(*v3d);
position_new(l, ucnew);
return 1;
}
void CreatePositionMetaTable(lua_State* l)
{
CelxLua celx(l);
celx.createClassMetatable(Celx_Position);
celx.registerMethod("__tostring", position_tostring);
celx.registerMethod("distanceto", position_distanceto);
celx.registerMethod("vectorto", position_vectorto);
celx.registerMethod("orientationto", position_orientationto);
celx.registerMethod("addvector", position_addvector);
celx.registerMethod("__add", position_add);
celx.registerMethod("__sub", position_sub);
celx.registerMethod("__index", position_get);
celx.registerMethod("__newindex", position_set);
celx.registerMethod("getx", position_getx);
celx.registerMethod("gety", position_gety);
celx.registerMethod("getz", position_getz);
lua_pop(l, 1); // remove metatable from stack
}