Boost logo

Boost :

From: Andy Little (andy_at_[hidden])
Date: 2006-10-02 05:42:08


"Larry Evans" <cppljevans_at_[hidden]> wrote in message

> My motivation was to avoid the need for the "external" typedef
> like the rank*_type's in:
>
> http://archives.free.net.ph/message/20060917.155443.96aa800a.en.html
>
> I was hoping this intializer syntax would allow something like:
>
> rcmatrix<2,2,rank2_type> mat
> {{ 0, 1}
> ,{ 2, 3}
> };

FWIW I'm still proceeding with the single tuple approach for the matrix
elements.
Its interesting to see it done the other way anyhow.

Anyway I have just got my version of a Fusion matrix working in a simple GUI
application.

The App doesnt have much functionality yet, but does provide horizontal and
vertical scrolling and clipping to an arbitrary box in the display.
Next is to allow model elements (lines, polygons etc) to be active and respond
to being grabbed by the mouse...

Anyway Here is the annotated use of Fusion. The matrix is used to transform
points in the model (2D) to the actual graphics device.
Hopefully the device can soon be a printer as well, though currently only screen
output is implemented:

#include "display_to_device.hpp"

// model to device transform ctor
// set up the transform matrix in the ctor
quanta::model_to_device::model_to_device(
    quanta::model_display const & display
){
    // A matrix representing translation from
    // the (2D) model origin to the display origin.
    // The display is represented as an element in the
    // model in model units (mm) and at some position
    // relative to the model origin.

    // Scrolling is represented by
    // moving the display around in the model.

    // The ones'and zero's are 'static' values
    // in numeric and reciprocal_length units.
    // In many cases involving calcs with them
    // the compiler can optimise them away completely
    // See my inner_product example
    // in the Generic programming section
    // of the Boost Vault for more info.

    // All the matrix calcs follow the laws of
    // dimensional analysis :-)

    translation_matrix translation(
        translation_elements(
            one(), zero(), zero_per_mm(),
            zero(), one(), zero_per_mm(),
            -display.m_position.x, -display.m_position.y, one()
        )
    );

    //--------
    // (a rotation matrix could be added here
    // to allow the display to be rotated in the model
    // for example for printing)
    //----------

    // The display is in model units of mm.
    // the device is in double units representing pixels.
    // (Its actually converted to ints in the device in Windows)
    // The display origin coincides with the device origin
    // so all that is needed now is scaling
    scaling_matrix scaling(
        scaling_elements(
            display.m_device_size.x/display.m_size.x,zero_per_mm(),zero_per_mm(),
            zero_per_mm(),display.m_device_size.y/display.m_size.y,zero_per_mm(),
            zero(),zero(),one()
        )
    );
    // concat the two matrices to the resulting transform matrix
    // ready for transforming points:

    this->transform_matrix = translation * scaling ;
}

// transform operator
// transform a coordinate in model units (mm)
// to a coordinate in device units (double)
 quan::two_d::vect<double>
 quanta::model_to_device::operator()(
    quan::two_d::vect<quan::length::mm> const & in
 )const
{
    // make a 1 row, 3 column matrix
    // to represent a homogeneous coordinate

    // Here constructing the fusion vector
    // representing the elements
    typedef boost::fusion::vector3<
        quan::length::mm,quan::length::mm,one
> coordinate_elements;

    // here the row vector, a 1 row by 3 column matrix
    typedef quan::rc_matrix<
        1,3,coordinate_elements
> coordinate_matrix_type;

    // initialise the homogeneous coordinate from
    // the input coordinate
    // still in quan::length::mm units
    coordinate_matrix_type coordinate(
        coordinate_matrix_type::elements(
            in.x,in.y,one()
        )
    );

    // Deduce the type of the result coordinate.
    typedef quan::meta::binary_operation<
        coordinate_matrix_type,
        quan::meta::times,
        transform_matrix_type
>::type result_coordinate_type;

    // If the transform is dimensionally correct,
    // then the result coordinate
    // is actually in double units
    // There is no need for casting!

    typedef result_coordinate_type::type_at<0,0>::type x_type;
    BOOST_MPL_ASSERT((boost::is_same<x_type,double>));

    typedef result_coordinate_type::type_at<0,1>::type y_type;
    BOOST_MPL_ASSERT((boost::is_same<y_type,double>));

    // The h part of the resulting homogeneous coordinate
    // should be a 'static' value.
    typedef result_coordinate_type::type_at<0,2>::type h_type;
    BOOST_MPL_ASSERT((quan::fusion::is_static_value<h_type>));

    // and its runtime type should be a numeric
    // rather than a quantity
    // for dimensional analysis to succeed.
    // else the calc is incorrect.
    // Actually it is a double
    typedef h_type::runtime_type runtime_type;
    BOOST_MPL_ASSERT((boost::is_same<runtime_type,double>));

    // h's value should be 1.
    // If not then we would need to scale when converting
    // to a non-homogeneous coordinate.
    typedef h_type::static_value_type static_value_type;
    typedef boost::mpl::equal_to<
        static_value_type,
        quan::meta::one_type_of<static_value_type>::type
>::type h_equals_one;
    BOOST_MPL_ASSERT((h_equals_one));

    // OK Apply the transform...

    result_coordinate_type result_coordinate
    = coordinate * this->transform_matrix;

    // Now convert back to a non-homogeneous coordinate.
    // we know h is 1 so no need to scale.
    // The types of the result are double
    // so no implicit conversions

    return quan::two_d::vect<double>(
        result_coordinate.at<0,0>(),result_coordinate.at<0,1>()
    );

}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk