[OpendTect_Developers] How to use the uiAxisHandler
Bruno Chaintreuil
bruno.chaintreuil at dgbes.com
Wed Feb 23 15:35:30 CET 2011
Dear All,
In OpendTect 4.2. the uiAxisHandler class has been slightly reworked to
fit the needs of our constantly improving 2D graphics displays. Since
the uiAxisHandler is quite a powerful object when it comes to
positioning data on a scene, I think this class really deserves a small
post here. Although there are some facilities for function drawing in
OpendTect that use internally the uiAxisHandler, you might want to draw
some specific data and/or have full control on its position on the
scene. Therefore you will have to use yourself the uiAxisHandler. Here
is a brief reminder on how this class works and what are its benefits.
The uiAxisHandler (uiTools/uiaxishandler.h and uiaxishandler.cc) is an
object that generates an axis to guide the positioning of a drawing
(graphics, function, pattern... ) on the scene canvas. It is
instantiated by giving a uiGraphicsScene (the equivalent of a
QGraphicsScene) and a Setup where you can specify its properties. It is
composed of an axis line, some grid lines and some annotations that can
be drawn on the scene with a specific LineStyle (width and color). Each
component can be turned on or off according to the setup wishes. The
setup requires a rectangle side (left, top, right or bottom) to
determine the placement in the scene and the axis orientation (vertical
for left and right, horizontal for top and bottom ). The other settings
are optional and will be set to default if not specified (see the Setup
class of the uiaxishandler.h for details). On the inner side of the
axis, the drawing will be positioned and drawn on the scene. Grid lines
perpendicular to the axis will optionally overlay this drawing. On the
outer side, annotations will be drawn. This annotations are the tick
(regular value marker orthogonal to the axis), axis values, and name. At
last a uiBorder will add an extra border between the axis and the scene
border. See attached picture number 1 for a schematic view of the
uiAxisHandler.
Once created, you can easily position your drawing relatively to the
axis by giving the uiAxisHandler a value range and using the getPix
function. For each value of your range, getPix will give you the
corresponding pixel on the scene. Every time the scene is resized (most
of the time by a user interaction), you will have to resize the
uiAxisHandler accordingly. This is done by calling the updateDevSize
function.
Let us now depict this with a very simple example : the drawing of
stratigraphic rectangle unit along a vertical Z axis. Let us suppose we
only want to display one single stratigraphic unit, say "Jurassic", in a
period ranging from 145 to 200 million years. We first create a class
myClass that holds a uiGraphicsScene scene_ and a uiAxisHandler* zaxis_.
Then the implementation of this drawing could be composed of two
functions initAxis and drawJurassicUnit. In initAxis we declare the
zaxis_ that will position the Jurassic unit on the scene. We give it a
Setup that will put the axis on the left side of the scene, with a
border of 20. Then we give the axis a name and a total Z range from 100
to 250 my.
void myClass::initAxis()
{
uiAxisHandler::Setup su( uiRect::Left );
uiBorder border( 20 );
su.border( border ).nogridline( true );
zaxis_ = new uiAxisHandler( &scene_, su );
zaxis_->setName( "Age (my)" );
zaxis_->setRange( 250, 100 ) );
}
The drawJurassicUnit will create and place the stratigraphic unit
rectangle on the scene using the zaxis_. To build the unit rectangle we
need a polygon of 4 points : x1, y1, x2, and y2. The vertical point y1
and y2 are the pixels of the range limits of the unit (145 and 200),
computed using the getPix function of the zaxis_. The x1 pixel is
nothing else than the axis line itself, given by the function pixToEdge.
The x2 position is the width of the scene (the unit will cover the whole
scene area towards the right). Now we can use the function addPolygon to
build the polygon on the scene given the 4 rectangle points. At last we
give the unit a title (translated on the scene by a uiTextItem) that we
place in the center of the unit display. Please see attached picture
number 2 to view the resulting display.
void myClass::drawJurassicUnit()
{
BufferString unitname( "Jurassic" );
Interval<float> unitzrange( 145, 200 );
int x1 = zaxis_->pixToEdge();
int x2 = (int)scene_.width();
int y1 = zaxis_->getPix( unitzrange.start );
int y2 = zaxis_->getPix( unitzrange.stop );
TypeSet<uiPoint> rectpts;
rectpts += uiPoint( x1, y1 );
rectpts += uiPoint( x2, y1 );
rectpts += uiPoint( x2, y2 );
rectpts += uiPoint( x1, y2 );
uiPolygonItem* pli = scene_.addPolygon( rectpts, true );
pli->setFillColor( Color::stdDrawColor(1) );
uiTextItem* ti = scene_.addItem( new uiTextItem( unitname ) );
ti->setPos( x1 + abs(x2-x1)/2, y1 + abs(y2-y1)/2 );
zaxis_->plotAxis();
}
This was a simple unidirectional case with only one axis. Of course you
might want to position the data along a X axis as well. Therefore you
need to declare another uiAxisHandler. The graphic will then be
positioned the same way with the getPix function in both the X and Z
direction. But you have to make sure the two axis will share a common
origin. This can be done by using the setBegin and setEnd functions of
the uiAxisHandler. Both require as input the adjacent uiAxisHandler that
will either share its end or its beginning, depending on the orientation
of the axis. In our example of the stratigraphic function, the initAxis
will just be added a xaxis_ and the zaxis_ and xaxis_ will be tied
together.
void myClass::initAxis()
{
...
uiAxisHandler::Setup xsu( uiRect::Top );
xsu.border( border );
xaxis_ = new uiAxisHandler( &scene_, xsu );
xaxis_->setRange( Interval<float>( 0, 3 ) );
xaxis_->setName( "Column number" );
xaxis_->setBegin( zaxis_ );
zaxis_->setEnd( xaxis_ );
}
In the drawJurassicUnit, only the computation of x1 and x2 will change.
Result is given in picture 3.
void myClass::drawJurassicUnit()
{
Interval<float> unitxrange( 1, 2 );
...
int x1 = xaxis_->getPix( unitxrange.start );
int x2 = xaxis_->getPix( unitxrange.stop );
...
xaxis_->plotAxis();
}
In OpendTect 4.2, you have now an option to put your annotation inside
the axis. This will report the ticks and values on the inner part of the
drawing. This is useful when you want to display for instance juxtaposed
views of different data in the same window without space separating the
views but still with some annotations. Therefore you just have to turn
on the annotinside_ boolean in the Setup before constructing the axis.
Attached in picture 4 is an example of the stratigraphic unit with the
the annotations inside.
I think you know all about the uiAxisHandler by now !
Happy coding and best Regards,
Bruno
--
Bruno Chaintreuil, MSc.
Software Engineer
dGB Earth Sciences B.V.
Nijverheidstraat 11-2, 7511 JM Enschede, The Netherlands
bruno.chaintreuil at dgbes.com
Tel: +31 534315155 , Fax: +31 534315104
http://www.dgbes.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.opendtect.org/pipermail/developers/attachments/20110223/60596bc1/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Axis_schematic.png
Type: image/png
Size: 22115 bytes
Desc: not available
URL: <http://lists.opendtect.org/pipermail/developers/attachments/20110223/60596bc1/attachment.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Jurassic_1Axis.png
Type: image/png
Size: 8636 bytes
Desc: not available
URL: <http://lists.opendtect.org/pipermail/developers/attachments/20110223/60596bc1/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Jurassic_2Axis.png
Type: image/png
Size: 9933 bytes
Desc: not available
URL: <http://lists.opendtect.org/pipermail/developers/attachments/20110223/60596bc1/attachment-0002.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Jurassic_2Axis_annotinside.png
Type: image/png
Size: 8904 bytes
Desc: not available
URL: <http://lists.opendtect.org/pipermail/developers/attachments/20110223/60596bc1/attachment-0003.png>
More information about the Developers
mailing list