MIRA
|
This document acts as a user manual. For further details on design requirements see Geometry (Requirements). These requirements lead to design decisions made within the geometry module.
The geometry module is a loose collection of geometry primitives like points (see mira::Point), lines (mira::Line), triangles (mira::createTriangle), and polygons (mira::Polygon3f). These primitives are all realized as template classes where you can define the required dimension and also the data type like int, float or double. The most common 2D and 3D data types are already defined.
These abstract data types can be used to perform intersections, unions, distance tests and etc.
Within the geometry module, also rasterization of geometric 2D primitives is supported (details see Rasterization). The rasterization concept is not only used to draw these primitives (this is better done with openCV), but can be used to implement other operations, like integration, min-max-search , blending operations, collision test etc.
Note that the geometry module only provides multidimensional primitives, it does not support the definition of complex 3D meshes like cylinder, torus, chamfer boxes or any other objects known from 3D modelling tools.
Basic operations like geometric intersections, unions, distances are provided by the boost::geometry library. For a detailed description of possibilities:
MIRA's collection of geometric primitives ensures not only compatibility towards the boost component but also most data types can be converted to the Eigen Math framework, which is extensivly used within MIRA. Also compatibility towards the OpenCV library is ensured on the point class. Therefore, it should be no problem to draw lines and points with the openCV. All other primitives have to use the rasterization algorithms provided here to work with openCV or have to be converted point-wise to openCV primitives.
The <geometry/geometry.h> header provides all the functionalites of the MIRA geometry module.
Points are derived from Eigen::Matrix, consisting of one column and N rows. To learn more about the capabilities of the Eigen::Matrix, see
The Point base class takes a member type and a dimension (number of elements) as template parameters:
Some frequently used Point types are pre-defined (2D and 3D, integer, float and double members):
Point members can be accessed either using the ()- or [] operator:
For the 2D and 3D variants, the special members x(), y() and z() are defined, referring to the first, second and third element, respectively (A.x() is equivalent to A[0] etc.).
The Line class does not represent one straight line, but a sequence of two or more points defining a sequence of line segments. Internally, it is realized as a vector of points, a so-called line string. This line string can be accessed like std::vector.
Like points, special line types can be defined with a base type and a dimension.
As for points, there are a predefined line types for lines in 2D and 3D, integer, float and double spaces.
For a line with one segment only (two points), boost::geometry::segment<PointType> can be used as alternative.
If only a line with 2 points is needed, a line segment will be used. There are also predefined segment types for 2D and 3D data, but also own types can be defined. The benefit of line segment is also the easy access.
The Rect class and its specializations can be used to represent rectangular boxes in arbitrary dimension (rectangle, cuboid, hyper-cuboid). All these structures have in common that they can be defined by two corner points.
Again, there are predefined data types for 2D and 3D cases.
Access is easy, since only the min-corner and max-corner can be accessed.
You can get also get the size of a rect / box by calling:
The size is a simple container, defining a (multidimensional) rectangular region or bounding box around a geometric primitive. In the 2D case you can access the width and height using mira::Size<T,2>::width() and mira::Size<T,2>::height(). The 3D case also supports mira::Size<T,3>::depth(). In any other case you can access the size along one dimension by using the dimension index.
Polygons are well known constructs in computer graphics. In principal they are almost like line strings, but closed, so the first and last point are the same. So in 2D this construct has an area and also can have holes. This is defined in the boost::geometry::polygon class, here each polygon has an outer ring (a closed linestring) and can have many inner rings. Refer to
to get more details on polygons and their usage.
Note that high dimensional geometric primitives cannot be processed by boost::geometry intersection or union operands, since each union, intersection is specialized to one dimension and today only traits for 2D are existing. You will get an error if you try.
Points can be converted to boost::geometry::point using
Since they are naturally Eigen matrices, no conversion to Eigen is needed. 2D and 3D Points have special conversion operators, allowing to convert also to OpenCV Point types.
You can use all functionalities provided by Eigen, like arithmetic operations, element wise operations and also casting operations to cast from one data type to another. Off course dimensionality is not cast-able. It is not possible to cast a 2D point into a 3D point since members will be left uninitialized.
Lines are only supported by boost::geometry. That's why no conversions to other libs are needed. If you want to use cv::polylines(), you have to create your own structs anyway.
Ellipsoids can only be converted into line strings in the 2D case.
Polygons are only supported by boost::geometry. That's why no conversions to other libs are needed. If you want to use cv::fillPoly(), you have to create your own structs anyway.
The idea of rasterization is based on the visitor principle. The goal of all rasterization tasks is to project a geometric object into a grid where the rasterizer tells the visitor which cells of the grid are covered by the geometrical object. Currently, only 2D Objects can be rasterized. 3D Voxel rasterization is planned for future work.
In order to keep the rasterizer as universal as possible, we do not assume certain types of raster targets like OpenCV images, QT images or own 2D arrays. Only the visitor knows on which data structure it operates. The rasterization entity only tells the visitor which pixels it has to visit to cover the area of the geometric object.
That way, the visitor implements all functionality processing the actual pixels. The designer can implement visitors to integrate the values of all pixels, find the maximum or minimum pixel or simply draw a color to the pixels.
In the following examples, we always try to find the maximum pixel inside an image for our geometric primitives.
Here we create a line string and parse it segment by segment.
For rastering a triangle, a very similar visitor has to be created.
To raster a rect is a simple task. We can again use the visitor from line rasterization.
A theoretical overview about geometric operations is given in:
A more precise list of functionality supported by the boost::geometry framework is presented in:
Here, the main operations of intersection, union, area, length, centroid, combine, envelope(bounding box), disjoint and distance are described.