diff --git a/modules/geom/doc/composite.rst b/modules/geom/doc/composite.rst new file mode 100644 index 0000000000000000000000000000000000000000..0271a206bc9d82d42a7661a58a3ab73deac27f2f --- /dev/null +++ b/modules/geom/doc/composite.rst @@ -0,0 +1,529 @@ +Geometric Objects +================================================================================ + +.. currentmodule:: ost.geom + +Geometrical Objects in Two Dimensions +-------------------------------------------------------------------------------- + +.. class:: Line2() + Line2(from, to) + + Parametric line in two dimensions as defined by an origin and a normalized + direction vector. The first constructor creates a line with origin (0,0) and + direction along the x axis. The second signature creates a line originating + from `from` and pointing towards `to`. + + .. method:: At(t) + + Returns the point on the line at (signed) distance t from origin. + + :param t: free parameter + :type t: float + :rtype: :class:`Vec2` + + + .. method:: GetOrigin() + + Returns the origin of the line: Also available as :attr:`origin`. + + :rtype: :class:`Vec2` + + .. method:: GetDirection() + + Returns the normalized direction vector. Also available as + :attr:`direction`. + + :rtype: :class:`Vec2` + + .. attribute:: direction + + .. attribute:: origin + + +.. class:: Rectangle2() + Rectangle2(top_left, bottom_right) + + Axis aligned rectangle. The first signature creates a rectangle with top-left + corner (-1, -1) and bottom-right corner (1, 1), wheras the second method + allows to set the top-left and bottom-right corners directly. + + :type top_left: :class:`Vec2` + :param top_left: The top-left corner + :param bottom_right: The bottom-right corner + :type bottom_right: :class:`Vec2` + + .. method:: GetWidth() + + Returns the width of the rectangle. Also available as :attr:`width`. + + .. method:: GetHeight() + + Returns the height of the rectangle. Also available as :attr:`height`. + + .. attribute:: width + + :type: float + + .. attribute:: height + + :type: float + + .. method:: GetStart() + + Get top-left corner + + :rtype: :class:`Vec2` + + .. method:: GetEnd() + + Get bottom-right corner + + :rtype: :class:`Vec2` + + .. method:: SetStart(top_left) + + Set top-left corner, leaving the bottom-right corner untouched. + + .. method:: SetEnd(bottom_right) + + Set the bottom-right corner, leaving the top-left corner untouched. + +.. class:: Circle2() + Circle2(circle) + Circle2(center, radius) + + The first signature creates a circle centered at (0, 0) and radius 1.0. The + second signature creates a circle with the same paramters as `circle`. The + third signature creates a new circle with given center and radius. + + .. method:: SetCenter(center) + + Set center of circle + + :type center: :class:`Vec2` + :param center: The new center + + .. method:: SetRadius(radius) + + Set radius of circle + + :type radius: float + :param center: The new radius + + .. method:: GetCenter() + + Returns the center of the circle + + .. method:: GetRadius() + + Returns the radius of the circle + + .. method:: GetArea() + + Returns the area of the circle + + .. method:: GetCircumference() + + Returns the circumference of the circle + + +.. class:: Ellipse2() + Ellipse2(center, a, b, gamma) + + An ellipse is defined by a center, two principal axis and gamma that + defines the angle between the first principal axis an the x-axis. + + .. method:: At(t) + + ? + + .. method:: AtAngle(angle) + + ? + + .. method:: GetBoundingBox() + + Returns the bounding rectangle (axis-aligned) of the ellipse + + :rtype: :class:`Rectangle2` + + + .. method:: GetA() + + Returns the first principal-axis + + .. method:: GetB() + + Returns the second principal-axis + + .. method:: GetGamma() + + Returns the angle of the first principal axis to the x-axis + + .. method:: GetArea() + + Returns the area of the ellipse + + .. method:: GetOrigin() + + Returns the center of the ellipse + + .. method:: SetA(a) + + Set the length of the first principal axis + + .. method:: SetB(b) + + Set the length of the second principal axis + + .. method:: SetGamma(gamma) + + Set the angle of the first principal axis to the x-axis + + .. method:: SetOrigin(ori) + + Set the center of the ellipse + +Geometrical Objects in Three Dimensions +------------------------------------------------------------------------------- + +.. class:: Line3() + Line3(from, to) + + Parametric line in three dimensions as defined by an origin and a normalized + direction vector. The first constructor creates a line with origin (0,0) and + direction along the x axis. The second signature creates a line originating + from `from` and pointing towards `to`. + + .. method:: At(t) + + Returns the point on the line at (signed) distance t from origin. + + :param t: free parameter + :type t: float + :rtype: :class:`Vec3` + + + .. method:: GetOrigin() + + Returns the origin of the line: Also available as :attr:`origin`. + + :rtype: :class:`Vec3` + + .. method:: GetDirection() + + Returns the normalized direction vector. Also available as + :attr:`direction`. + + :rtype: :class:`Vec3` + + .. attribute:: direction + + :type: :class:`Vec3` + + .. attribute:: origin + + :type: :class:`Vec3` + +.. class:: Plane() + Plane(p1, p2, p3) + Plane(x, y, z, p) + Plane(line, point) + Plane(point, normal) + + A plane in 3d-space. The plane can be constructed by either passing in 3 + points (p1, p2, p3), a normal and a point, the four parameters that define the + implicit plane equation (`x`, `y`, `z`, `p`) or a line and a point. + + .. method:: GetNormal() + + Returns the normal of the plane. Also available as :attr:`normal` + + :rtype: :class:`Vec3` + + .. method:: GetP() + + Returns the plane offset, i.e. the projection of any point on the plane onto + the normal. Also available as :attr:`p`. + + :rtype: float + + .. method:: GetOrigin() + + Get the origin of the plane. Also available as :attr:`origin`. + + :rtype: :class:`Vec3` + + .. attribute:: origin + + :type: :class:`Vec3` + .. attribute:: normal + + :type: :class:`Vec3` + + .. attribute:: p + + :type: float + + +.. class:: Sphere() + Sphere(center, radius) + + Represents a sphere in 3d space. The first constructor creates a sphere with + radius 1, centered at (0, 0, 0), the second allows you to set the radius and + center directly. + + :param center: The center + :type center: :class:`Vec3` + :param radius: The radius + :type radius: float + + .. attribute:: radius + + The radius of the sphere. Read-write. Also available as :meth:`GetRadius`, + :meth:`SetRadius`. + + :type: float + + .. attribute:: origin + + The center of the sphere. Read-write. Also available as :meth:`GetOrigin`, + :meth:`SetOrigin`. + + :type: :class:`Vec3` + + .. method:: GetOrigin() + + See :attr:`origin` + + .. method:: SetOrigin(origin) + + See :attr:`origin` + + .. method:: GetRadius() + + See :attr:`radius` + + .. method:: SetRadius(radius) + + See :attr:`radius` + +.. class:: AlignedCuboid(min, max) + + Axis aligned cuboid is a cuboid whose axes are aligned to the x-, y-, and z- + axes of the coordinate system. For arbitrarily oriented bounding cuboid + class, see :class:`Cuboid`. + + .. method:: GetMin() + + Get minimum coordinate, i.e. the lower bound of x-, y-, and z for + any point in the cuboid + + :rtype: :class:`Vec3` + + .. method:: GetMax() + + Get maximum coordinate, i.e. the upper bound of x-, y-, and z for + any point in the cuboid. + + :rtype: :class:`Vec3` + +.. class:: CuboidAxis() + CuboidAxis(dir, half_extent) + + A cuboid axis is defined by a half-extent, and a direction vector. This class + is used in together with the :class:`Cuboid` class. + + :param dir: Direction vector, will be normalized + :type dir: :class:`Vec3` + :param half_extent: The half extent + :type half_extent: float + + .. attribute:: vector + + The normalized direction vector of the cuboid axis. Also available as + :meth:`GetVector` + + :type: :class:`Vec3` + + .. attribute:: half_extent + + The half extent of the cuboid axis is the magnitude of the cuboid + axis measured from the center to the corner. Also available as + :meth:`GetHalfExtent` + + :type: float + + .. attribute:: extent + + The extent of the cuboid axis. This value is always twice the + :attr:`half_extent`. Read-only. Also available as + :meth:`GetExtent`. + + :type: float + + .. method:: GetHalfExtent() + + See :attr:`half_extent` + .. method:: GetExtent() + + See :attr:`extent` + + .. method:: GetVector() + + See :attr:`vector` + +.. class:: Cuboid(center, axis_a, axis_b, axis_c) + + An arbitrarily oriented cuboid defined by a center and 3 axis. The 3 cuboid + axis are stored in the order they are passed to the constructor. This means, + that there is no guarantee that the 3 axes form a right-handed coordinate + system. If a right-handed coordinate system is a requirement, you have to + ensure this on your own: + + .. code-block:: python + + center=... + axis_a=geom.CuboidAxis(...) + axis_b=geom.CuboidAxis(...) + axis_c=geom.CuboidAxis(geom.Cross(axis_a.vector, axis_b.vector), ...) + + cuboid=geom.Cuboid(center, axis_a, axis_b, axis_c) + + :param center: The center + :type center: :class:`Vec3` + :param axis_a: The first axis + :type axis_a: :class:`CuboidAxis` + :param axis_b: The second axis + :type axis_b: :class:`CuboidAxis` + :param axis_c: The third axis + :type axis_c: :class:`CuboidAxis` + + .. attribute:: center + + The center of the cuboid. + + :type: :class:`Vec3` + + .. attribute:: axis_a + + The first cuboid axis + + :type: :class:`CuboidAxis` + + .. attribute:: axis_b + + The second cuboid axis + + :type: :class:`CuboidAxis` + + .. attribute:: axis_c + + The third cuboid axis + + :type: :class:`CuboidAxis` + +Operations on Geometrical Objects +-------------------------------------------------------------------------------- + +.. function:: Angle(lhs, rhs) + + Calculate the angle (in radians) between `lhs` and `rhs`. + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :rtype: float + +.. function:: IntersectionPoint(lhs, rhs) + + Calculates and returns the intersection point between `lhs` and `rhs` + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :raises: :exc:`GeomException` when the two objects do not intersect + :rtype: :class:`Vec3` (:class:`Vec2` in case of :class:`Line2`) + +.. function:: IntersectionLine(plane2, plane2) + + Returns the intersection line between `plane1` and `plane2`. + + :param plane1: The first plane + :type plane1: :class:`Plane` + :param plane2: The second plane + :type plane2: :class:`Plane` + + :raises: :exc:GeomException if the two planes are parallel. + +.. function:: Distance(lhs, rhs) + + Returns the minimal distance between `lhs` and `rhs`. + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :rtype: float + +.. function:: IsOnLine(line, point, epsilon=geom.EPSILON) + + Check whether `point` lies on `line` and returns true if point i no further + away than `epsilon`. + + :rtype: bool + +.. function:: IsInPlane(plane, object, epsilon=geom.EPSILON) + + Check whether `object` lies in `plane` and returns true if the difference is + no bigger than `epsilon`. + + :param plane: The plane + :type plane: :class:`Plane` + :param object: The object + :type object: :class:`Vec3` or :class:`Line3` + + :rtype: bool + +.. function:: AreParallel(lhs, rhs, epsilon=geom.EPSILON) + + Check whether `lhs` and `rhs` are parallel and returns true, if the difference + is below the given treshold `epsilon`. + + :param lhs: First object + :type lhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :param rhs: Second object + :type rhs: :class:`Line2`, :class:`Line3`, :class:`Plane` + + :rtype: bool + +.. function:: AreIntersecting(line1, line2, epsilon=geom.EPSILON) + + Check whether `line1` and `line2` are intersecting and returns true, if they + intersect below the given threshold `epsilon`. + + :param lhs: First line + :type lhs: :class:`Line2`, :class:`Line3` + + :param rhs: Second line + :type rhs: :class:`Line2`, :class:`Line3` + + :rtype: bool + + + +.. function:: IsInSphere(sphere, point) + + Check whether the `sphere` contains `point`. + + :rtype: bool \ No newline at end of file diff --git a/modules/geom/doc/geom.rst b/modules/geom/doc/geom.rst index 27accb014bd6291c9c96b861ecc4e4fb232c48da..51ad8ce723d7604b49f81fb3138287053103958d 100644 --- a/modules/geom/doc/geom.rst +++ b/modules/geom/doc/geom.rst @@ -1,15 +1,16 @@ -:mod:`geom` -- vectors, matrices and geometrical objects +:mod:`ost.geom` -- vectors, matrices and geometrical objects ================================================================================ -.. module:: geom +.. module:: ost.geom :synopsis: Functions and classes for vectors, matrices and geometrical objects in 2, 3 and four dimensions -The geom modules contains functions and classes for vectors, matrices and other geometrical objects in 2, 3 and four dimensions. +The geom modules contains functions and classes for vectors, matrices and other +geometrical objects in 2, 3 and four dimensions. .. toctree:: vec - - \ No newline at end of file + mat + composite \ No newline at end of file diff --git a/modules/geom/doc/mat.rst b/modules/geom/doc/mat.rst new file mode 100644 index 0000000000000000000000000000000000000000..c8736733a7a18533cf18e6fcf40ddecf6b3a52c7 --- /dev/null +++ b/modules/geom/doc/mat.rst @@ -0,0 +1,167 @@ +Matrices +================================================================================ + +.. currentmodule:: ost.geom + +The :mod:`~ost.geom` module defines matrices in two, three and four dimensions. +All matrices store the values in row-major order, meaning that, the matrix ((1, +2), (3,4)) stores the values as (1, 2, 3, 4). This is illustrated in +the following code examples: + +.. code-block:: python + + m=geom.Mat2(1, 2, 3, 4) + print m # will print {{1,2},{3,4}} + print m[(0,0)], m[(0,1)], m[(1,0)], m[(1,1)] # will print 1, 2, 3, 4 + +Matrices support arithmetic via overloaded operators. The following operations are +supported: + + * adding and subtracting two matrices + * negation + * multiplication of matrices + * multiplying and dividing by scalar value + +The Matrix Classes +-------------------------------------------------------------------------------- + +.. class:: Mat2() + Mat2(d00, d01, d10, d11) + + 2x2 real-valued matrix. The first signature creates a new identity matrix. The + second signature initializes the matrix in row-major order. + + .. staticmethod:: Identity() + + Returns the 2x2 identity matrix + + +.. class:: Mat3() + Mat3(d00, d01, d02, d10, d11, d12, d20, d21, d22) + + 3x3 real-valued matrix. The first signature creates a new identity matrix. The + second signature initializes the matrix in row-major order. + + .. staticmethod:: Identity() + + Returns the 3x3 identity matrix + +.. class:: Mat4() + Mat4(d00, d01, d02, d03, d10, d11, d12, d13, d20, d21, d22, d23, d30, d31, d32, d33) + + 4x4 real-valued matrix. The first signature creates a new identity matrix. The + second signature initializes the matrix in row-major order. + + .. method:: ExtractRotation() + + Returns the 3x3 submatrix + + .. method:: PasteRotation(mat) + + Set the 3x3 submatrix of the top-left corner to `mat` + + .. method:: ExtractTranslation() + + Extract translation component from matrix. Only meaningful when matrix + is a combination of rotation and translation matrices, otherwise the result + is undefined. + + .. PasteTranslation(trans) + + Set the translation component of the matrix to `trans` + + :param trans: The translation + :type trans: :class:`Vec3` + + .. staticmethod:: Identity() + + Returns the 4x4 identity matrix + +Functions Operating on Matrices +-------------------------------------------------------------------------------- +.. function:: Equal(lhs, rhs, epsilon=geom.EPSILON) + + Compares the two matrices `lhs` and `rhs` and returns True, if all + of the element-wise differences are smaller than epsilon. `lhs` + and `rhs` must be matrices of the same dimension. + + :param lhs: First matrix + :type lhs: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + :param rhs: Second matrix + :type rhs: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + +.. function:: Transpose(mat) + + Returns the transpose of `mat` + + :param mat: The matrix to be transposed + :type lhs: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + +.. function:: Invert(mat) + + Returns the inverse of `mat` + + :param mat: The matrix to be inverted + :type mat: :class:`Mat2`, :class:`Mat3` or :class:`Mat4` + + What happens when determinant is 0? + +.. function:: CompMultiply(lhs, rhs) + + Returns the component-wise product of `lhs` and `rhs`. `lhs` and + `rhs` must be vectors of the same dimension. + + :param lhs: The lefthand-side vector + :type lhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + :param rhs: The righthand-side vector + :type rhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + +.. function:: CompDivide(lhs, rhs) + + Returns the component-wise quotient of `lhs` divided by `rhs`. `lhs` + and `rhs` must be vectors of the same dimension. + + :param lhs: The lefthand-side vector + :type lhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + :param rhs: The righthand-side vector + :type rhs: :class:`~Vec2`, :class:`~Vec3` or + :class:`~Vec4` + +.. function:: Det(mat) + + Returns the determinant of `mat` + :param mat: A matrix + :type mat: :class:`~Mat2`, :class:`~Mat3` or :class:`~Mat4` + +.. function:: Minor(mat, i, j) + + Returns the determinant of the 2x2 matrix generated from `mat` by + removing the ith row and jth column. + +.. function:: EulerTransformation(phi, theta, xi) + + Returns a rotation matrix for the 3 euler angles `phi`, `theta`, and + `xi`. The 3 angles are given in radians. + + +.. function:: AxisRotation(axis, angle) + + Returns a rotation matrix that represents a rotation of `angle` + around the `axis`. + + :param axis: The rotation axis. Will be normalized + :type axis: :class:`Vec3` + :param angle: Rotation angle (radians) in clockwise direction when + looking down the axis. + +.. function:: OrthogonalVector(vec) + + Get arbitrary vector orthogonal to `vec`. The returned vector is of length + 1, except when `vec` is a zero vector. In that case, the returned vector is + (0, 0, 0). + + :param vec: A vector of arbitrary length + :type vec: :class:`Vec3` \ No newline at end of file diff --git a/modules/geom/doc/vec.rst b/modules/geom/doc/vec.rst index b3da8088bc8748bdede06b340ecb3e0222db4555..d3876bcb1f9b46049869a3be84e51bdef9ff7e23 100644 --- a/modules/geom/doc/vec.rst +++ b/modules/geom/doc/vec.rst @@ -1,9 +1,11 @@ Vectors ================================================================================ -.. currentmodule:: geom +.. currentmodule:: ost.geom -The :class:`Vec2`, :class:`Vec3`, :class:`Vec4` classes implement vectors in 2, 3 and four dimensions. They support basic arithmetic via overloaded operators. Essentially, the following basic operations are available: +The :class:`Vec2`, :class:`Vec3`, :class:`Vec4` classes implement vectors in 2, +3 and four dimensions. They support basic arithmetic via overloaded operators. +Essentially, the following basic operations are available: * adding and subtracting two vectors * negation @@ -19,7 +21,8 @@ This is shown in the following example: print vec_a+vec_b print vec_a*3-vec_b -The standard vector operations are implemented as :ref:`free standing functions <vector-functions>`: +The standard vector operations are implemented as :ref:`free standing functions +<vector-functions>`: .. code-block:: python diff --git a/modules/geom/pymod/export_composite2.cc b/modules/geom/pymod/export_composite2.cc index f9e793ee10d7e05eddc608113e3d28c43146ec8e..96f42ab26ebfb5ed216aa285d2d3499ecb626bb7 100644 --- a/modules/geom/pymod/export_composite2.cc +++ b/modules/geom/pymod/export_composite2.cc @@ -42,6 +42,8 @@ void export_Composite2() .def("At",&Line2::At) .def("GetOrigin",&Line2::GetOrigin) .def("GetDirection",&Line2::GetDirection) + .add_property("direction", &Line2::GetDirection) + .add_property("origin", &Line2::GetOrigin) ; class_<Polygon2>("Polygon2",init<>()) diff --git a/modules/geom/pymod/export_composite3.cc b/modules/geom/pymod/export_composite3.cc index 8468578df28234c4b1d2ad11eafa6b57a4cde915..bf269d55258f21ba21a56c010654ae3a3ab9e47d 100644 --- a/modules/geom/pymod/export_composite3.cc +++ b/modules/geom/pymod/export_composite3.cc @@ -18,10 +18,9 @@ //------------------------------------------------------------------------------ #include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> -using namespace boost::python; - #include <ost/geom/geom.hh> +using namespace boost::python; void export_Composite3() { using namespace geom; @@ -32,6 +31,8 @@ void export_Composite3() .def("At",&Line3::At) .def("GetOrigin",&Line3::GetOrigin) .def("GetDirection",&Line3::GetDirection) + .add_property("origin", &Line3::GetOrigin) + .add_property("direction", &Line3::GetDirection) ; { // scope @@ -49,6 +50,7 @@ scope PlaneScope = .def("GetNormal",&Plane::GetNormal) .add_property("normal", &Plane::GetNormal) .add_property("origin", &Plane::GetOrigin) + .add_property("p", &Plane::GetP) .def("GetP",&Plane::GetP) ; @@ -105,6 +107,8 @@ scope PlaneScope = .def(init<const Vec3&,Real>()) .def("GetOrigin",&Sphere::GetOrigin) .def("GetRadius",&Sphere::GetRadius) + .add_property("origin", &Sphere::GetOrigin, &Sphere::SetOrigin) + .add_property("radius", &Sphere::GetRadius, &Sphere::SetRadius) ; class_<CuboidAxis>("CuboidAxis", init<>()) @@ -113,29 +117,50 @@ scope PlaneScope = .def("GetVector", &CuboidAxis::GetVector, return_value_policy<copy_const_reference>()) .def("GetExtent", &CuboidAxis::GetExtent) + + .add_property("vector", make_function(&CuboidAxis::GetVector, + return_value_policy<copy_const_reference>())) + .add_property("half_extent", &CuboidAxis::GetHalfExtent) + .add_property("extent", &CuboidAxis::GetExtent) ; class_<Cuboid>("Cuboid", init<>()) .def(init<const geom::Vec3&, const CuboidAxis&,const CuboidAxis&, const CuboidAxis&>()) .def("GetCenter",&Cuboid::GetCenter) + .add_property("center", &Cuboid::GetCenter) .def("GetVecA", &Cuboid::GetVecA, return_value_policy<copy_const_reference>()) + .add_property("vec_a", make_function(&Cuboid::GetVecA, + return_value_policy<copy_const_reference>())) .def("GetVecB", &Cuboid::GetVecB, return_value_policy<copy_const_reference>()) + .add_property("vec_b", make_function(&Cuboid::GetVecB, + return_value_policy<copy_const_reference>())) .def("GetVecC", &Cuboid::GetVecC, return_value_policy<copy_const_reference>()) + .add_property("vec_c", make_function(&Cuboid::GetVecC, + return_value_policy<copy_const_reference>())) .def("GetAxisA", &Cuboid::GetAxisA, return_value_policy<copy_const_reference>()) + .add_property("axis_a", make_function(&Cuboid::GetAxisA, + return_value_policy<copy_const_reference>())) .def("GetAxisB", &Cuboid::GetAxisB, return_value_policy<copy_const_reference>()) + .add_property("axis_b", make_function(&Cuboid::GetAxisB, + return_value_policy<copy_const_reference>())) .def("GetAxisC", &Cuboid::GetAxisC, - return_value_policy<copy_const_reference>()) + return_value_policy<copy_const_reference>()) + .add_property("axis_c", make_function(&Cuboid::GetAxisC, + return_value_policy<copy_const_reference>())) .def("GetHalfExtents", &Cuboid::GetHalfExtents) + .add_property("half_extents", &Cuboid::GetHalfExtents) ; class_<AlignedCuboid>("AlignedCuboid", init<geom::Vec3, geom::Vec3>()) - .def("GetMin", &AlignedCuboid::GetMin, return_value_policy<copy_const_reference>()) - .def("GetMax", &AlignedCuboid::GetMax, return_value_policy<copy_const_reference>()) + .def("GetMin", &AlignedCuboid::GetMin, + return_value_policy<copy_const_reference>()) + .def("GetMax", &AlignedCuboid::GetMax, + return_value_policy<copy_const_reference>()) ; } diff --git a/modules/geom/src/vecmat3_op.hh b/modules/geom/src/vecmat3_op.hh index 43961e798eebaea9a6943e0d59ed4ceb5531b9f6..44c835768d3355e5c01e7785df971d9886162494 100644 --- a/modules/geom/src/vecmat3_op.hh +++ b/modules/geom/src/vecmat3_op.hh @@ -36,10 +36,12 @@ Real DLLEXPORT_OST_GEOM Length(const Vec3& v); Real DLLEXPORT_OST_GEOM Length2(const Vec3& v); //! return true if components differ not more than ephilon -bool DLLEXPORT_OST_GEOM Equal(const Vec3& v1, const Vec3& v2, Real ephilon=EPSILON); +bool DLLEXPORT_OST_GEOM Equal(const Vec3& v1, const Vec3& v2, + Real ephilon=EPSILON); //! return true if components differ not more than ephilon -bool DLLEXPORT_OST_GEOM Equal(const Mat3& m1, const Mat3& m2, Real ephilon=EPSILON); +bool DLLEXPORT_OST_GEOM Equal(const Mat3& m1, const Mat3& m2, + Real ephilon=EPSILON); //! vector dot product Real DLLEXPORT_OST_GEOM Dot(const Vec3& v1, const Vec3& v2); diff --git a/modules/img/alg/doc/alg.rst b/modules/img/alg/doc/alg.rst new file mode 100644 index 0000000000000000000000000000000000000000..46d0e063df81071cfec50ac9077a6350ec538e6e --- /dev/null +++ b/modules/img/alg/doc/alg.rst @@ -0,0 +1,65 @@ +:mod:`img.alg` - Image Processing Algorithms +================================================================================ + + +Usage of Image Algorithms +-------------------------------------------------------------------------------- + +Image algorithms are objects. To execute them, the algorithms are applied to an +image by passing it to the :meth:`img.ImageHandle.Apply` or +:meth:`img.ImageHandle.ApplyIP` method: + +.. code-block:: python + + image=img.CreateImage(img.Size(200, 200)) + fft_image=image.Apply(img.alg.FFT()) + image.ApplyIP(img.alg.FFT()) + + +.. class:: FFT + + Fast Fourier Transforms the image. The FFT algorithms is aware of the + image's domain. The following rules apply: + + * SPATIAL -> HALF_FREQUENCY + * HALF_FREQUENCY -> SPATIAL + * FREQUENCY -> COMPLEX_SPATIAL + * COMPLEX_SPATIAL -> FREQUENCY + +.. class:: GaussianFilter(sigma=1.0) + + Applies a gaussian filter to the supplied image. Sigma is given in pixels. + + Implemented after I.T.Young, L.J. van Vliet,"Recursive implementation of the + Gaussian filter", Signal Processing, 44(1995), 139-151 + +Filters in Fourier Space +-------------------------------------------------------------------------------- + +The following filters operate in Fourier Space. If the image they are applied on is in spatial domain, they will first be converted to frequency domain and then converted back after the filter has been applied. + +.. class:: LowpassFilter(freq_limit) + + Filters an image by masking out frequencies higher than + `freg_limit`. + + .. method:: GetLimit() + + Returns the frequency limit + + .. method:: SetLimit(freq) + + Set the frequency limit + +.. class:: HighpassFilter + + Filters an image by masking out frequences lower than `freq_limit` + + .. method:: GetLimit() + + Returns the frequency limit + + .. method:: SetLimit(freq) + + Set the frequency limit + \ No newline at end of file diff --git a/modules/img/base/doc/img.rst b/modules/img/base/doc/img.rst new file mode 100644 index 0000000000000000000000000000000000000000..e09e24d647935adb1eca5f8df01ec00a912aa583 --- /dev/null +++ b/modules/img/base/doc/img.rst @@ -0,0 +1,186 @@ +:mod:`img` Images and Density Maps +================================================================================ + +.. module:: mol + :synopsis: Images and Density Maps + +Introduction : The ImageHandle +-------------------------------------------------------------------------------- + +OpenStructure offers extensive processing capabilities for planar 2d images and +3d maps using the img module. Images are manipulated through the use of +dox[ost::img::ImageHandle|ImageHandles]. + +ImageHandles provide a clean and efficient interface to interact with images and +maps. An :class:`ImageHandle` can store an image in either real ('SPATIAL') or +Fourier ('FREQUENCY') space and always keep track of the currently active +domain. This means,for example that one can apply a Fourier Transformation to an +ImageHandle containing a 'SPATIAL' image and the ImageHandle will correctly +identify the new active domain as 'FREQUENCY'. The ImageHandle also understands, +for example, that applying a Fourier Transform to a centrosymmetric 'FREQUENCY' +image results in a real 'SPATIAL' image, but applying it to a +non-centrosymmetric one results in a complex 'SPATIAL' image. + +Furthermore, the ImageHandle will make sure that real and Fourier space +information about the image are always in sync. If, for example, the pixel +sampling is changed while the current active domain is real space, the pixel +sampling in Fourier space will be adjusted accordingly, and vice versa. + +Moreover, the ImageHandle allows the extraction of both complex and real numeric +values from images in any active domain. If the domain is complex in nature, but +a real numeric value is requested, the amplitude of the complex number will be +returned. If the numerical nature of the domain is real and a complex number is +requested, the complex part will be set to 0. + +Creating and visualizing ImageHandles +-------------------------------------------------------------------------------- +As a first step, enter the following lines in the OpenStructure python console: + + .. code-block:: python + + im=img.CreateImage(img.Size(200,200)) + +This will create an empty, 2D image, with a height and width of 200 pixels, whose +origin (ie the pixel with the coordinates <0,0>) is in the top-left corner. + + .. code-block:: python + + v=gui.CreateDataViewer(im) + +A viewer window will pop up (see below), showing a white frame on a black background. +The inner area of the white frame is the image, which is empty. + +Reading and writing into an image +------------------------------------------------------------------------------- + +Data can be read and written from and into an image using the following commands: + + .. code-block:: python + + # writes the real value 23.4 into pixel 10,10 + im.SetReal(img.Point(10,10),23.4) + # reads the value in pixel 10,10 + val=im.GetReal(img.Point(10,10)) + +The complex equivalents are also available + + .. code-block:: python + + # writes the complex value value 2+3j into pixel 10,10 + im.SetComplex(img.Point(10,10),2+3j) + # reads the value in pixel 10,10 + val=im.GetComplex(img.Point(10,10)) + +The image knows in which domain it is, and will adjust the type of data being written +accordingly. For example, if one writes a complex value in a 'SPATIAL' image, the value +will be automatically converted to a real one by taking the amplitude of the complex number +On the other hand, if one writes a real value in a 'FREQUENCY' image, the value is automatically +converted to complex by setting the imaginary part to 0. + +## Applying algorithms + +Let us fill the image with random values. + + .. code-block:: python + + rand_alg = img.alg.Randomize() # create algorithm object + im.ApplyIP( rand_alg ) # apply algorithm object in-place + +As you can see, applying an algorithm is conceptually a two-step process. First, +an instance of an algorithm class is created, yielding an algorithm object (in +this case 'rand\_alg'). In a second step, the algorithm object is applied to an +image, either in-place, modifying the image, or out-of-place, leaving the +original image untouched, and returning the result as a new image. Note that the +in-place/out-of-place logic is decoupled from the algorithm object. + +Now that we have some (noisy) data present, let us run another algorithm, this +time a Gaussian filter with a sigma of 4 pixel. + + .. code-block:: python + + im.ApplyIP( img.alg.GaussianFilter(4.0) ) # apply temporary algorithm object in-place + +As you can see, it is not always necessary to create an independent algorithm +instance first, in many cases a temporary object will suffice (this applies to +the randomization algorithm as well, 'im.ApplyIP(alg.Randomize())' would have +been fine). However, when used this way, the algorithm class will cease to exist +as soon as the algorithm is applied. This can be important if the algorithm +stores some values that need to be recovered later. For example: + + .. code-block:: python + + stat=img.alg.Stat() + im.ApplyIP(stat) + mean=stat.GetMean() + +Algorithms are stateful objects and can store values. The 'Stat' algorithm +computes basic statistics about the image it is applied on (maximum and minimum +values, standard deviations, etc). The data are stored within the algorithm +instance and can be recovered using the algorithm's methods. It would obviously +make very little sense not to create an instance of the 'Stat' algorithm. When +the algorithms ceases to exist, all information would be lost. + +Applying a Fourier Transform +-------------------------------------------------------------------------------- + +An image is Fourier-transformed using the 'img.alg.FFT()' algorithm object: + + .. code-block:: python + + im=io.LoadImage("imagename.tif") # load the image + # create an instance of the fft algorithm object + fft=img.alg.FFT() + # do the actual Fourier transformation + im_ft=im.Apply(fft) + # back-transform + im2 = im_ft.Apply(fft) + # if this is run from within the dng graphical frontend, open viewers to + # look at the images + gui.CreateDataViewer(im) + gui.CreateDataViewer(im_ft) + gui.CreateDataViewer(im2) + +It is not really necessary to use the 'fft' variable to store the 'im.alg.FFT()' +instance, a temporary object can be used, since the 'FFT' algorithm object is stateless. In addition, the algorithm can be applied in-place to avoid the +creation of a second image: + + .. code-block:: python + + im=io.LoadImage("imagename.tif") # load the image + # do the actual Fourier transformation, in-place using temporary object + im.ApplyIP(alg.FFT()) + # repeating this command will do the back-transform + im.ApplyIP(alg.FFT()) + +As said before, the 'alg.FFT()' algorithm does not require a direction to be given, this is implicitly +determined by the active domain of the underlying image state: a 'SPATIAL' image will always be +transformed to the 'FREQUENCY' domain, and vice-versa. + +Extracting and Pasting Images +-------------------------------------------------------------------------------- + +An image can be extracted and pasted into another image using the 'Extract()' +and 'Paste()' member functions: + + .. code-block:: python + + # load the image + im=io.LoadImage("imagename.tif") + # generate a subimage from the region going from (10,10) to (30,30) + im2=im.Extract(img.Extent(img.Point(10,10),img.Point(30,30))) + # generate an empty image with the same size as the original image + im3=img.CreateImage(im.GetExtent()) + # paste the subimage into the empty image + im3.Paste(im2) + +Note that the extent is fully honored for the paste operation, i.e. only the +region where the pasted-to and the pasted-in image overlap will be affected. + + + + .. + | | | | + |:-------------------------------------------------:|:-------------------------------------------------------------------:|:------------------------------------------------------------------------:| + |![Empty Image] (docs/tut/dv1.jpg "Empty Image") | ![After Randomization] (docs/tut/dv2.jpg "After Randomization") | ![After Gaussian Filtering] (docs/tut/dv3.jpg "After Randomization") | + |Empty Image | After Randomization | After Gaussian Filtering | + \ No newline at end of file diff --git a/modules/index.rst b/modules/index.rst index 13f18a11826fc23b6781058e13700c025cbfa018..09dc2d92040d082437f85ac38f8cb2b62c3e4b69 100644 --- a/modules/index.rst +++ b/modules/index.rst @@ -26,6 +26,7 @@ Modules conop/conop mol/base/mol seq/base/seq + base/base Extending OpenStructure --------------------------------------------------------------------------------