From 6d86cbdcdeb60cdaa5146d186a33e844a09aaf86 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 18 May 2011 22:20:17 -0600 Subject: Implement Vectors in python. --- libdimension-python/Makefile.am | 3 +- libdimension-python/Scene.c | 74 +++++++ libdimension-python/Vector.c | 355 ++++++++++++++++++++++++++++++++++ libdimension-python/dimension.c | 45 ++++- libdimension-python/scene.c | 106 ---------- libdimension-python/tests/Makefile.am | 3 +- libdimension-python/tests/geometry.py | 52 +++++ 7 files changed, 523 insertions(+), 115 deletions(-) create mode 100644 libdimension-python/Scene.c create mode 100644 libdimension-python/Vector.c delete mode 100644 libdimension-python/scene.c create mode 100755 libdimension-python/tests/geometry.py diff --git a/libdimension-python/Makefile.am b/libdimension-python/Makefile.am index adb792b..239f051 100644 --- a/libdimension-python/Makefile.am +++ b/libdimension-python/Makefile.am @@ -30,4 +30,5 @@ dimension_la_SOURCES = dimension.c dimension_la_LDFLAGS = -avoid-version -module dimension_la_LIBADD = $(top_builddir)/libdimension/libdimension.la -EXTRA_DIST = scene.c +EXTRA_DIST = Scene.c \ + Vector.c diff --git a/libdimension-python/Scene.c b/libdimension-python/Scene.c new file mode 100644 index 0000000..48a41cb --- /dev/null +++ b/libdimension-python/Scene.c @@ -0,0 +1,74 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +typedef struct dmnsn_py_Scene { + PyObject_HEAD + dmnsn_scene *scene; +} dmnsn_py_Scene; + +static PyObject * +dmnsn_py_Scene_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + dmnsn_py_Scene *self; + self = (dmnsn_py_Scene *)type->tp_alloc(type, 0); + self->scene = dmnsn_new_scene(); + return (PyObject *)self; +} + +static int +dmnsn_py_Scene_init(dmnsn_py_Scene *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static void +dmnsn_py_Scene_dealloc(dmnsn_py_Scene *self) +{ + dmnsn_delete_scene(self->scene); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyMethodDef dmnsn_py_Scene_methods[] = { + { NULL } +}; + +static PyGetSetDef dmnsn_py_Scene_getsetters[] = { + { NULL } +}; + +static PyTypeObject dmnsn_py_SceneType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "dimension.Scene", + .tp_basicsize = sizeof(dmnsn_py_Scene), + .tp_dealloc = (destructor)dmnsn_py_Scene_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = "Dimension scene", + .tp_methods = dmnsn_py_Scene_methods, + .tp_getset = dmnsn_py_Scene_getsetters, + .tp_init = (initproc)dmnsn_py_Scene_init, + .tp_new = dmnsn_py_Scene_new, +}; + +static bool +dmnsn_py_init_SceneType(void) +{ + Py_INCREF(&dmnsn_py_SceneType); + return PyType_Ready(&dmnsn_py_SceneType) >= 0; +} diff --git a/libdimension-python/Vector.c b/libdimension-python/Vector.c new file mode 100644 index 0000000..ca7d4e1 --- /dev/null +++ b/libdimension-python/Vector.c @@ -0,0 +1,355 @@ +/************************************************************************* + * Copyright (C) 2009-2011 Tavian Barnes * + * * + * This file is part of The Dimension Python Module. * + * * + * The Dimension Python Module is free software; you can redistribute it * + * and/ or modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either version * + * 3 of the License, or (at your option) any later version. * + * * + * The Dimension Python Module is distributed in the hope that it will * + * be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * + * the GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +typedef struct dmnsn_py_Vector { + PyObject_HEAD + dmnsn_vector v; +} dmnsn_py_Vector; + +static PyTypeObject dmnsn_py_VectorType; + +static int +dmnsn_py_Vector_init(dmnsn_py_Vector *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = { "x", "y", "z", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ddd", kwlist, + &self->v.x, &self->v.y, &self->v.z)) + return -1; + + return 0; +} + +static PyObject * +dmnsn_py_Vector_repr(dmnsn_py_Vector *self) +{ + PyObject *x = PyFloat_FromDouble(self->v.x); + PyObject *y = PyFloat_FromDouble(self->v.y); + PyObject *z = PyFloat_FromDouble(self->v.z); + + if (!x || !y || !x) { + Py_XDECREF(z); + Py_XDECREF(y); + Py_XDECREF(x); + return NULL; + } + + PyObject *repr = PyUnicode_FromFormat("dimension.Vector(%R, %R, %R)", + x, y, z); + Py_DECREF(z); + Py_DECREF(y); + Py_DECREF(x); + return repr; +} + +static PyObject * +dmnsn_py_Vector_str(dmnsn_py_Vector *self) +{ + PyObject *x = PyFloat_FromDouble(self->v.x); + PyObject *y = PyFloat_FromDouble(self->v.y); + PyObject *z = PyFloat_FromDouble(self->v.z); + + if (!x || !y || !x) { + Py_XDECREF(z); + Py_XDECREF(y); + Py_XDECREF(x); + return NULL; + } + + PyObject *repr = PyUnicode_FromFormat("<%S, %S, %S>", x, y, z); + Py_DECREF(z); + Py_DECREF(y); + Py_DECREF(x); + return repr; +} + +static PyObject * +dmnsn_py_Vector_richcompare(PyObject *lhs, PyObject *rhs, int op) +{ + if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType)) { + PyErr_SetString(PyExc_TypeError, + "Vectors can only be compared with Vectors"); + return NULL; + } + if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType)) { + PyErr_SetString(PyExc_TypeError, + "Vectors can only be compared with Vectors"); + return NULL; + } + + dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; + dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; + + bool equal = + dmnsn_vector_norm(dmnsn_vector_sub(vlhs->v, vrhs->v)) < dmnsn_epsilon; + + PyObject *result; + switch (op) { + case Py_EQ: + result = equal ? Py_True : Py_False; + break; + case Py_NE: + result = !equal ? Py_True : Py_False; + break; + default: + result = Py_NotImplemented; + break; + } + + Py_INCREF(result); + return result; +} + +static PyObject * +dmnsn_py_Vector_add(PyObject *lhs, PyObject *rhs) +{ + if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType) + || !PyObject_TypeCheck(rhs, &dmnsn_py_VectorType)) + { + PyErr_SetString(PyExc_TypeError, + "Vectors can only be added to Vectors"); + return NULL; + } + + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; + dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; + ret->v = dmnsn_vector_add(vlhs->v, vrhs->v); + } + return (PyObject *)ret; +} + +static PyObject * +dmnsn_py_Vector_sub(PyObject *lhs, PyObject *rhs) +{ + if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType) + || !PyObject_TypeCheck(rhs, &dmnsn_py_VectorType)) + { + PyErr_SetString(PyExc_TypeError, + "Vectors can only be subtracted from Vectors"); + return NULL; + } + + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; + dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; + ret->v = dmnsn_vector_sub(vlhs->v, vrhs->v); + } + return (PyObject *)ret; +} + +static PyObject * +dmnsn_py_Vector_mul(PyObject *lhs, PyObject *rhs) +{ + dmnsn_py_Vector *vec; + double dbl; + + if (PyObject_TypeCheck(lhs, &dmnsn_py_VectorType)) { + vec = (dmnsn_py_Vector *)lhs; + dbl = PyFloat_AsDouble(rhs); + if (PyErr_Occurred()) + return NULL; + } else { + vec = (dmnsn_py_Vector *)rhs; + dbl = PyFloat_AsDouble(lhs); + if (PyErr_Occurred()) + return NULL; + } + + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + ret->v = dmnsn_vector_mul(dbl, vec->v); + } + return (PyObject *)ret; +} + +static PyObject * +dmnsn_py_Vector_div(PyObject *lhs, PyObject *rhs) +{ + if (!PyObject_TypeCheck(lhs, &dmnsn_py_VectorType)) { + PyErr_SetString(PyExc_TypeError, + "Vectors can only be divided by scalars"); + return NULL; + } + + double drhs = PyFloat_AsDouble(rhs); + if (PyErr_Occurred()) + return NULL; + + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + dmnsn_py_Vector *vlhs = (dmnsn_py_Vector *)lhs; + ret->v = dmnsn_vector_div(vlhs->v, drhs); + } + return (PyObject *)ret; +} + +static int +dmnsn_py_Vector_bool(PyObject *obj) +{ + dmnsn_py_Vector *vec = (dmnsn_py_Vector *)obj; + return dmnsn_vector_norm(vec->v) >= dmnsn_epsilon; +} + +static PyObject * +dmnsn_py_Vector_positive(PyObject *rhs) +{ + Py_INCREF(rhs); + return rhs; +} + +static PyObject * +dmnsn_py_Vector_negative(PyObject *rhs) +{ + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + dmnsn_py_Vector *vrhs = (dmnsn_py_Vector *)rhs; + ret->v = dmnsn_vector_negate(vrhs->v); + } + return (PyObject *)ret; +} + +static PyObject * +dmnsn_py_Vector_cross(PyObject *self, PyObject *args) +{ + dmnsn_py_Vector *lhs, *rhs; + if (!PyArg_ParseTuple(args, "O!O!", + &dmnsn_py_VectorType, &lhs, + &dmnsn_py_VectorType, &rhs)) + return NULL; + + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + ret->v = dmnsn_vector_cross(lhs->v, rhs->v); + } + return (PyObject *)ret; +} + +static PyObject * +dmnsn_py_Vector_dot(PyObject *self, PyObject *args) +{ + dmnsn_py_Vector *lhs, *rhs; + if (!PyArg_ParseTuple(args, "O!O!", + &dmnsn_py_VectorType, &lhs, + &dmnsn_py_VectorType, &rhs)) + return NULL; + + return PyFloat_FromDouble(dmnsn_vector_dot(lhs->v, rhs->v)); +} + +static PyObject * +dmnsn_py_Vector_proj(PyObject *self, PyObject *args) +{ + dmnsn_py_Vector *u, *d; + if (!PyArg_ParseTuple(args, "O!O!", + &dmnsn_py_VectorType, &u, + &dmnsn_py_VectorType, &d)) + return NULL; + + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + ret->v = dmnsn_vector_proj(u->v, d->v); + } + return (PyObject *)ret; +} + +static PyNumberMethods dmnsn_py_Vector_as_number = { + .nb_add = dmnsn_py_Vector_add, + .nb_subtract = dmnsn_py_Vector_sub, + .nb_multiply = dmnsn_py_Vector_mul, + .nb_true_divide = dmnsn_py_Vector_div, + .nb_bool = dmnsn_py_Vector_bool, + .nb_positive = dmnsn_py_Vector_positive, + .nb_negative = dmnsn_py_Vector_negative, +}; + +static PyObject * +dmnsn_py_Vector_norm(dmnsn_py_Vector *self) +{ + return PyFloat_FromDouble(dmnsn_vector_norm(self->v)); +} + +static PyObject * +dmnsn_py_Vector_normalized(dmnsn_py_Vector *self) +{ + dmnsn_py_Vector *ret = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (ret) { + ret->v = dmnsn_vector_normalized(self->v); + } + return (PyObject *)ret; +} + +static PyMethodDef dmnsn_py_Vector_methods[] = { + { "norm", (PyCFunction)dmnsn_py_Vector_norm, METH_NOARGS, + "Return the magnitude of the vector" }, + { "normalized", (PyCFunction)dmnsn_py_Vector_normalized, METH_NOARGS, + "Return the magnitude of the vector" }, + { NULL } +}; + +static PyObject * +dmnsn_py_Vector_getx(dmnsn_py_Vector *self, void *closure) +{ + return PyFloat_FromDouble(self->v.x); +} + +static PyObject * +dmnsn_py_Vector_gety(dmnsn_py_Vector *self, void *closure) +{ + return PyFloat_FromDouble(self->v.y); +} + +static PyObject * +dmnsn_py_Vector_getz(dmnsn_py_Vector *self, void *closure) +{ + return PyFloat_FromDouble(self->v.z); +} + +static PyGetSetDef dmnsn_py_Vector_getsetters[] = { + { "x", (getter)dmnsn_py_Vector_getx, NULL, "x coordinate", NULL }, + { "y", (getter)dmnsn_py_Vector_gety, NULL, "y coordinate", NULL }, + { "z", (getter)dmnsn_py_Vector_getz, NULL, "z coordinate", NULL }, + { NULL } +}; + +static PyTypeObject dmnsn_py_VectorType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "dimension.Vector", + .tp_basicsize = sizeof(dmnsn_py_Vector), + .tp_repr = (reprfunc)dmnsn_py_Vector_repr, + .tp_str = (reprfunc)dmnsn_py_Vector_str, + .tp_as_number = &dmnsn_py_Vector_as_number, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = "Dimension vector", + .tp_richcompare = dmnsn_py_Vector_richcompare, + .tp_methods = dmnsn_py_Vector_methods, + .tp_getset = dmnsn_py_Vector_getsetters, + .tp_init = (initproc)dmnsn_py_Vector_init, +}; + +static bool +dmnsn_py_init_VectorType(void) +{ + dmnsn_py_VectorType.tp_new = PyType_GenericNew; + Py_INCREF(&dmnsn_py_VectorType); + return PyType_Ready(&dmnsn_py_VectorType) >= 0; +} diff --git a/libdimension-python/dimension.c b/libdimension-python/dimension.c index ca19844..511f197 100644 --- a/libdimension-python/dimension.c +++ b/libdimension-python/dimension.c @@ -23,13 +23,13 @@ #include #include "dimension.h" -#include "scene.c" +#include "Vector.c" +#include "Scene.c" static PyObject * dmnsn_py_dieOnWarnings(PyObject *self, PyObject *args) { int die; - if (!PyArg_ParseTuple(args, "i", &die)) return NULL; @@ -42,6 +42,11 @@ dmnsn_py_dieOnWarnings(PyObject *self, PyObject *args) static PyMethodDef DimensionMethods[] = { { "dieOnWarnings", dmnsn_py_dieOnWarnings, METH_VARARGS, "Turn Dimension warnings into fatal errors." }, + + { "cross", dmnsn_py_Vector_cross, METH_VARARGS, "Cross product." }, + { "dot", dmnsn_py_Vector_dot, METH_VARARGS, "Dot product." }, + { "proj", dmnsn_py_Vector_proj, METH_VARARGS, "Vector projection." }, + { NULL, NULL, 0, NULL } }; @@ -56,13 +61,39 @@ static struct PyModuleDef dimensionmodule = { PyMODINIT_FUNC PyInit_dimension(void) { - if (!dmnsn_py_init_SceneType()) + if (!dmnsn_py_init_VectorType() + || !dmnsn_py_init_SceneType()) return NULL; - PyObject *m = PyModule_Create(&dimensionmodule); - if (!m) + PyObject *module = PyModule_Create(&dimensionmodule); + if (!module) return NULL; - PyModule_AddObject(m, "Scene", (PyObject *)&dmnsn_py_SceneType); - return m; + PyModule_AddObject(module, "Vector", (PyObject *)&dmnsn_py_VectorType); + + /* Vector constants */ + dmnsn_py_Vector *zero = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + dmnsn_py_Vector *x = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + dmnsn_py_Vector *y = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + dmnsn_py_Vector *z = PyObject_New(dmnsn_py_Vector, &dmnsn_py_VectorType); + if (!zero || !x || !y || !z) { + Py_XDECREF(zero); + Py_XDECREF(x); + Py_XDECREF(y); + Py_XDECREF(z); + Py_DECREF(module); + return NULL; + } + zero->v = dmnsn_zero; + x->v = dmnsn_x; + y->v = dmnsn_y; + z->v = dmnsn_z; + PyModule_AddObject(module, "Zero", (PyObject *)zero); + PyModule_AddObject(module, "X", (PyObject *)x); + PyModule_AddObject(module, "Y", (PyObject *)y); + PyModule_AddObject(module, "Z", (PyObject *)z); + + PyModule_AddObject(module, "Scene", (PyObject *)&dmnsn_py_SceneType); + + return module; } diff --git a/libdimension-python/scene.c b/libdimension-python/scene.c deleted file mode 100644 index 5b6066c..0000000 --- a/libdimension-python/scene.c +++ /dev/null @@ -1,106 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes * - * * - * This file is part of The Dimension Python Module. * - * * - * The Dimension Python Module is free software; you can redistribute it * - * and/ or modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either version * - * 3 of the License, or (at your option) any later version. * - * * - * The Dimension Python Module is distributed in the hope that it will * - * be useful, but WITHOUT ANY WARRANTY; without even the implied * - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * - * the GNU Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -typedef struct { - PyObject_HEAD - dmnsn_scene *scene; -} dmnsn_py_SceneObject; - -static PyObject * -dmnsn_py_SceneNew(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - dmnsn_py_SceneObject *self; - self = (dmnsn_py_SceneObject *)type->tp_alloc(type, 0); - self->scene = dmnsn_new_scene(); - return (PyObject *)self; -} - -static int -dmnsn_py_SceneInit(dmnsn_py_SceneObject *self, PyObject *args, PyObject *kwds) -{ - return 0; -} - -static void -dmnsn_py_SceneDealloc(dmnsn_py_SceneObject *self) -{ - dmnsn_delete_scene(self->scene); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static PyMemberDef dmnsn_py_SceneMembers[] = { - { NULL } -}; - -static PyMethodDef dmnsn_py_SceneMethods[] = { - { NULL } -}; - -static PyGetSetDef dmnsn_py_SceneGetSetters[] = { - { NULL } -}; - -static PyTypeObject dmnsn_py_SceneType = { - PyVarObject_HEAD_INIT(NULL, 0) - "dimension.Scene", /* tp_name */ - sizeof(dmnsn_py_SceneObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)dmnsn_py_SceneDealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "Dimension scene", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - dmnsn_py_SceneMethods, /* tp_methods */ - dmnsn_py_SceneMembers, /* tp_members */ - dmnsn_py_SceneGetSetters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)dmnsn_py_SceneInit, /* tp_init */ - 0, /* tp_alloc */ - dmnsn_py_SceneNew, /* tp_new */ -}; - -static bool -dmnsn_py_init_SceneType(void) -{ - Py_INCREF(&dmnsn_py_SceneType); - return PyType_Ready(&dmnsn_py_SceneType) >= 0; -} diff --git a/libdimension-python/tests/Makefile.am b/libdimension-python/tests/Makefile.am index 4bebfda..17589ba 100644 --- a/libdimension-python/tests/Makefile.am +++ b/libdimension-python/tests/Makefile.am @@ -17,7 +17,8 @@ ## along with this program. If not, see . ## ########################################################################### -TESTS = demo.py +TESTS = geometry.py \ + demo.py TESTS_ENVIRONMENT = PYTHONPATH=$(top_builddir)/libdimension-python/.libs .py: diff --git a/libdimension-python/tests/geometry.py b/libdimension-python/tests/geometry.py new file mode 100755 index 0000000..b398a1b --- /dev/null +++ b/libdimension-python/tests/geometry.py @@ -0,0 +1,52 @@ +#!/usr/bin/python3 + +######################################################################### +# Copyright (C) 2010-2011 Tavian Barnes # +# # +# This file is part of The Dimension Test Suite. # +# # +# The Dimension Test Suite 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 3 of the # +# License, or (at your option) any later version. # +# # +# The Dimension Test Suite is distributed in the hope that it will be # +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty # +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +######################################################################### + +from dimension import * + +# Treat warnings as errors for tests +dieOnWarnings(True) + +assert Zero == Vector(0, 0, 0), Zero +assert X == Vector(1, 0, 0), X +assert Y == Vector(0, 1, 0), Y +assert Z == Vector(0, 0, 1), Z + +v = Vector(1.5, 2.5, 3.5) + +assert v.x == 1.5, v.x +assert v.y == 2.5, v.y +assert v.z == 3.5, v.z +assert repr(v) == 'dimension.Vector(1.5, 2.5, 3.5)', repr(v) +assert str(v) == '<1.5, 2.5, 3.5>', str(v) + +v = Vector(x = 2, y = 3, z = 6) + +assert v.norm() == 7, v.norm() +assert v.normalized() == v/7, v.normalized() +assert v + v == 2*v == v*2 == Vector(4, 6, 12), v + v +assert v/2 == v - v/2 == Vector(1, 1.5, 3), v/2 +assert +v == v, +v +assert v + -v == Zero, v + -v +assert cross(v, v) == Zero, cross(v, v) +assert dot(v, v) == v.norm()**2, dot(v, v) +assert v, bool(v) +assert not Zero, not Zero +assert proj(v, X) == 2*X, proj(v, X) -- cgit v1.2.3