You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1093 lines
30 KiB
1093 lines
30 KiB
/***************************************************************************
|
|
qsaxes.cpp
|
|
-------------------
|
|
begin : 01-January-2000
|
|
|
|
copyright : (C) 2000 by Kamil Dobkowski
|
|
email : kamildobk@poczta.onet.pl
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program 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 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include"qsaxes.h"
|
|
#include"qsaxis.h"
|
|
#include"qsplot.h"
|
|
#include"qschildlist.h"
|
|
#include<assert.h>
|
|
#include<math.h>
|
|
#include<algo.h>
|
|
#include<qregexp.h>
|
|
#include<qtimer.h>
|
|
#include<qpainter.h>
|
|
|
|
|
|
|
|
struct QSAxes::qsaxes_private_data {
|
|
QSChildList<QSPlot> m_plots;
|
|
QSChildList<QSAxis> m_axes;
|
|
};
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSCAxesShadow::QSCAxesShadow( QSAxes *parent )
|
|
: QSCGroup(parent) {
|
|
m_parent_axes = parent;
|
|
connect( parent, SIGNAL(sigUpdate()), this, SLOT(slot_update()) );
|
|
connect( objects(), SIGNAL(sigAdded(QSCObject*)), this, SLOT(slot_object_added(QSCObject*)) );
|
|
connect( objects(), SIGNAL(sigRemoved(QSCObject*)), this, SLOT(slot_object_removed(QSCObject*)) );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSCAxesShadow::~QSCAxesShadow() {
|
|
// parent axes object deletes itself after QSAxesShadow has been deleted.
|
|
// see QSAxes::childEvent
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::setAutoUpdates( bool enabled ) {
|
|
QSCObject::setAutoUpdates( enabled );
|
|
m_parent_axes->setAutoUpdates( enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::forceUpdate() {
|
|
m_parent_axes->forceUpdate();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::slot_update() {
|
|
QSCGroup::forceUpdate();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::setParentAxes( QSAxes * ) {
|
|
// can't change parent axes
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::setBox( const QSRectf& rect, QSDrv *drv ) {
|
|
QSRectf r = rect.normalize();
|
|
m_parent_axes->setPosMM( QSPt2f( QSCoord::pixelsToMM(r.pos.x,drv->dpi),
|
|
QSCoord::pixelsToMM(r.pos.y,drv->dpi)) );
|
|
m_parent_axes->setSizeMM( QSPt2f( QSCoord::pixelsToMM(r.size.x,drv->dpi),
|
|
QSCoord::pixelsToMM(r.size.y,drv->dpi)) );
|
|
m_parent_axes->setCanvasRect(m_parent_axes->calculateCanvasRect(drv->dpi));
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSRectf QSCAxesShadow::box( QSDrv *drv ) {
|
|
return QSRectf( QSCoord::mmToPixels(m_parent_axes->posMM().x,drv->dpi),
|
|
QSCoord::mmToPixels(m_parent_axes->posMM().y,drv->dpi),
|
|
QSCoord::mmToPixels(m_parent_axes->sizeMM().x,drv->dpi),
|
|
QSCoord::mmToPixels(m_parent_axes->sizeMM().y,drv->dpi) );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSCAxesShadow::isHit( const QSPt2f &p, QSDrv* drv )
|
|
{
|
|
return box(drv).contains(p) || m_objects->objectAt(p,drv,true);
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSCAxesShadow::isAxesShadow() {
|
|
return true;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
int QSCAxesShadow::style() {
|
|
return Resizeable | Moveable;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QString QSCAxesShadow::name() {
|
|
return QString(tr("Axes: "))+m_parent_axes->title();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::draw( QSDrv *drv, bool blocking, bool transparent ) {
|
|
connect( m_parent_axes, SIGNAL(sigDrawEnds()), this, SLOT(slot_draw_ends()) );
|
|
connect( m_parent_axes, SIGNAL(sigUserDraw(QSDrv*,bool,bool)), this, SLOT(slot_draw_objects(QSDrv*,bool,bool)) );
|
|
bool blocking_drawing = !m_parent_axes->drawInBackground() || blocking;
|
|
m_parent_axes->setCanvasRect(m_parent_axes->calculateCanvasRect(drv->dpi));
|
|
m_parent_axes->drawPlot( drv, blocking_drawing, transparent );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::paint( QPainter *p, double dpi, bool blocking, bool transparent ) {
|
|
connect( m_parent_axes, SIGNAL(sigDrawEnds()), this, SLOT(slot_draw_ends()) );
|
|
connect( m_parent_axes, SIGNAL(sigUserDraw(QSDrv*,bool,bool)), this, SLOT(slot_draw_objects(QSDrv*,bool,bool)) );
|
|
bool blocking_drawing = !m_parent_axes->drawInBackground() || blocking;
|
|
m_parent_axes->setCanvasRect(m_parent_axes->calculateCanvasRect(dpi));
|
|
m_parent_axes->paintPlot( p, dpi, blocking_drawing, transparent );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::slot_draw_objects( QSDrv *drv, bool blocking, bool transparent ) {
|
|
disconnect( m_parent_axes, SIGNAL(sigUserDraw(QSDrv*,bool,bool)), this, SLOT(slot_draw_objects(QSDrv*,bool,bool)) );
|
|
m_objects->draw( drv, blocking, transparent );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::paintSkeleton( QPainter *p, double dpi ) {
|
|
m_parent_axes->setCanvasRect(m_parent_axes->calculateCanvasRect(dpi));
|
|
m_parent_axes->paintSkeleton(p,dpi,true);
|
|
m_objects->paintSkeleton(p,dpi);
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::slot_draw_ends() {
|
|
disconnect( m_parent_axes, SIGNAL(sigDrawEnds()), this, SLOT(slot_draw_ends()) );
|
|
emit sigDrawEnds( this );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSCAxesShadow::busy() const {
|
|
return ( m_parent_axes->state() == QSAxes::Busy );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::stop() {
|
|
m_parent_axes->stop();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory ) {
|
|
QSCGroup::loadStateFromStream( stream, factory );
|
|
parentAxes()->loadStateFromStream( stream, factory );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::saveStateToStream( QDataStream& stream, QSObjectFactory *factory ) {
|
|
QSCGroup::saveStateToStream( stream, factory );
|
|
parentAxes()->saveStateToStream( stream, factory );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::slot_object_added( QSCObject *object )
|
|
// we hope that this signal is received by this object before any other object which also connects
|
|
// to QSCObjectCollection::sigAdded will get this signal. So this other object will see a newly added object
|
|
// which has already parentAxes() property set.
|
|
{
|
|
object->setParentAxes( m_parent_axes );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSCAxesShadow::slot_object_removed( QSCObject *object )
|
|
{
|
|
object->setParentAxes( NULL );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSCAxesShadow *QSAxes::shadowObject()
|
|
{
|
|
if ( !m_shadow_object ) m_shadow_object = new QSCAxesShadow( this );
|
|
return m_shadow_object;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::childEvent ( QChildEvent *e )
|
|
{
|
|
if ( e->removed() && e->child() == shadowObject() ) delete this;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
|
|
QSAxes::QSAxes(QObject* parent, const QSProjection *proj, const char* name )
|
|
:QSGraphicalData(parent, NULL, name )
|
|
{
|
|
m_internal_state = Waiting;
|
|
m_bkg_handler = true;
|
|
m_auto_updates = true;
|
|
m_is_complete = false;
|
|
m_axes_only = false;
|
|
m_really_fast = false;
|
|
m_delete_driver = false;
|
|
m_runtime_data_allocated = false;
|
|
m_shadow_object = NULL;
|
|
m_bckg_fill = QSGFill::transparentFill;
|
|
m_transformation_rect = false;
|
|
m_draw_in_background = true;
|
|
m_proj = proj;
|
|
|
|
m_curr_dpi = 72.0;
|
|
m_cpos.set( 0.0, 0.0 );
|
|
m_csize.set( 100.0, 100.0 );
|
|
m_pos_mm.set( 20.0, 20.0 );
|
|
m_size_mm.set( 100.0, 100.0 );
|
|
|
|
m_m.l = 0;
|
|
m_m.r = 0;
|
|
m_m.t = 0;
|
|
m_m.b = 0;
|
|
|
|
d = new qsaxes_private_data();
|
|
|
|
m_timer = new QTimer( this );
|
|
connect( m_timer, SIGNAL(timeout()), this, SLOT(work_proc()) );
|
|
|
|
// default axes
|
|
axisAdd( new QSAxis( QSAxis::XAxisType, this ) );
|
|
axisAdd( new QSAxis( QSAxis::YAxisType, this ) );
|
|
axisAdd( new QSAxis( QSAxis::ZAxisType, this ) );
|
|
axisAdd( new QSAxis( QSAxis::VAxisType, this ) );
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxes::~QSAxes()
|
|
{
|
|
stop();
|
|
delete d;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
// Graphics attributes
|
|
|
|
void QSAxes::setPosMM( const QSPt2f& new_pos_mm )
|
|
{
|
|
SET_PROPERTY( m_pos_mm, new_pos_mm );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setXPosMM( double x_mm )
|
|
{
|
|
SET_PROPERTY( m_pos_mm.x, x_mm );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setYPosMM( double y_mm )
|
|
{
|
|
SET_PROPERTY( m_pos_mm.y, y_mm );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setSizeMM( const QSPt2f& new_size_mm )
|
|
{
|
|
SET_PROPERTY( m_size_mm, new_size_mm );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setWidthMM( double w_mm )
|
|
{
|
|
SET_PROPERTY( m_size_mm.x, w_mm );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setHeightMM( double h_mm )
|
|
{
|
|
SET_PROPERTY( m_size_mm.y, h_mm );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setDrawInBackground( bool enabled )
|
|
{
|
|
SET_PROPERTY( m_draw_in_background, enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setAxesOnly( bool enabled )
|
|
{
|
|
SET_PROPERTY( m_axes_only, enabled );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setBackground( const QSGFill& fill )
|
|
{
|
|
SET_PROPERTY( m_bckg_fill, fill );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSGFill QSAxes::background() const
|
|
{
|
|
return m_transparent ? m_bckg_fill : QSGFill();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::set_background_property( const QString& value )
|
|
{
|
|
setBackground( toQSGFill(value) );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QString QSAxes::background_property() const
|
|
{
|
|
return toQString(background());
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setAutoUpdates( bool enabled )
|
|
{
|
|
m_auto_updates = enabled;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
double QSAxes::canvasToNormalizedX( double value ) const
|
|
{
|
|
return m_csize.x>0.0 ? ((value-m_cpos.x)/m_csize.x) : 0.0;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
double QSAxes::canvasToNormalizedY( double value ) const
|
|
{
|
|
return m_csize.y>0.0 ? ((value-m_cpos.y)/m_csize.y) : 0.0;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt2f QSAxes::canvasToNormalized( const QSPt2f& pos ) const
|
|
{
|
|
return QSPt2f( m_csize.x>0.0 ? ((pos.x-m_cpos.x)/m_csize.x) : 0.0,
|
|
m_csize.y>0.0 ? ((pos.y-m_cpos.y)/m_csize.y) : 0.0 );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
double QSAxes::normalizedXToCanvas( double x ) const
|
|
{
|
|
return m_cpos.x + x * m_csize.x;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
double QSAxes::normalizedYToCanvas( double y ) const
|
|
{
|
|
return m_cpos.y + y * m_csize.y;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt2f QSAxes::normalizedToCanvas( const QSPt2f& pos ) const
|
|
{
|
|
return QSPt2f( m_cpos.x + pos.x * m_csize.x,
|
|
m_cpos.y + pos.y * m_csize.y );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt2f QSAxes::dataToCanvas( const QSPt3f& pos, QSAxis *xAxis, QSAxis *yAxis, QSAxis *zAxis ) const
|
|
{
|
|
return m_proj->world3DToCanvas( QSPt3f( xAxis->dataToWorld( pos.x ),
|
|
yAxis->dataToWorld( pos.y ),
|
|
zAxis->dataToWorld( pos.z ) ) );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPt2f QSAxes::dataToCanvas( const QSPt2f& pos, QSAxis *xAxis, QSAxis *yAxis ) const
|
|
{
|
|
return m_proj->world2DToCanvas( QSPt2f( xAxis->dataToWorld( pos.x ),
|
|
yAxis->dataToWorld( pos.y ) ) );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
// d->m_plots
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
int QSAxes::plotCount() const
|
|
{
|
|
return d->m_plots.count();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotAdd( QSPlot *p )
|
|
{
|
|
if ( p ) {
|
|
parametersChanging();
|
|
d->m_plots.add( p );
|
|
emit sigChildAdded( p );
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotInsert( int beforePos, QSPlot *p )
|
|
{
|
|
if ( p ) {
|
|
parametersChanging();
|
|
d->m_plots.insert( beforePos, p );
|
|
emit sigChildAdded( p );
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotRemove( QSPlot *p )
|
|
// not deleted
|
|
// signal emmited after removal !!!!!!
|
|
{
|
|
if ( p ) {
|
|
parametersChanging();
|
|
if ( d->m_plots.remove(d->m_plots.find(p)) ) {
|
|
emit sigChildRemoved( p );
|
|
emit sigChildListChanged();
|
|
}
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotDelete( QSPlot *p )
|
|
{
|
|
if ( p ) {
|
|
parametersChanging();
|
|
if ( d->m_plots.remove(d->m_plots.find(p)) ) {
|
|
emit sigChildRemoved( p );
|
|
emit sigChildListChanged();
|
|
delete p;
|
|
}
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSPlot *QSAxes::plot( int index ) const
|
|
{
|
|
return d->m_plots[index];
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
int QSAxes::plotIndex( QSPlot *o ) const
|
|
{
|
|
return d->m_plots.find(o);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotToFront( QSPlot *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_plots.toFront( d->m_plots.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotToBack( QSPlot *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_plots.toBack( d->m_plots.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotLower( QSPlot *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_plots.lower( d->m_plots.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotRaise( QSPlot *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_plots.raise( d->m_plots.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::plotReorder( int position, QSPlot *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_plots.reorder( position, d->m_plots.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
int QSAxes::axisCount() const
|
|
{
|
|
return d->m_axes.count();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisAdd( QSAxis *p )
|
|
{
|
|
if ( p ) {
|
|
parametersChanging();
|
|
d->m_axes.add( p );
|
|
emit sigChildAdded( p );
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisInsert( int beforePos, QSAxis *p )
|
|
{
|
|
if ( p ) {
|
|
parametersChanging();
|
|
d->m_axes.insert( beforePos, p );
|
|
emit sigChildAdded( p );
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSAxes::axisRemove( QSAxis *a )
|
|
// not deleted
|
|
// signal emitted after removal !!!!!
|
|
{
|
|
if ( a ) {
|
|
// can't remove the last axis of the given type
|
|
int axes_count = 0;
|
|
for( int i=0; i<axisCount(); i++ ) if ( axis(i)->type() == a->type() ) axes_count++;
|
|
if ( axes_count < 2 && a->type() != QSAxis::UnknownAxisType ) return false;
|
|
|
|
parametersChanging();
|
|
if ( d->m_axes.remove(d->m_axes.find(a)) ) {
|
|
emit sigChildRemoved( a );
|
|
emit sigChildListChanged();
|
|
}
|
|
parametersChanged();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
bool QSAxes::axisDelete( QSAxis *a )
|
|
{
|
|
if ( a ) {
|
|
// can't remove the last axis of the given type
|
|
int axes_count = 0;
|
|
for( int i=0; i<axisCount(); i++ ) if ( axis(i)->type() == a->type() ) axes_count++;
|
|
if ( axes_count < 2 ) return false;
|
|
|
|
parametersChanging();
|
|
if ( d->m_axes.remove(d->m_axes.find(a)) ) {
|
|
emit sigChildRemoved( a );
|
|
emit sigChildListChanged();
|
|
delete a;
|
|
}
|
|
parametersChanged();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxis *QSAxes::axis( int index ) const
|
|
{
|
|
return d->m_axes[index];
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
int QSAxes::axisIndex( QSAxis *o ) const
|
|
{
|
|
return d->m_axes.find(o);
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxis *QSAxes::axisOfType( int type ) const
|
|
{
|
|
for ( int axis_nr=0; axis_nr<axisCount(); axis_nr++ )
|
|
if ( axis(axis_nr)->type() == type ) return axis(axis_nr);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisToFront( QSAxis *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_axes.toFront( d->m_axes.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisToBack( QSAxis *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_axes.toBack( d->m_axes.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisLower( QSAxis *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_axes.lower( d->m_axes.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisRaise( QSAxis *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_axes.raise( d->m_axes.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::axisReorder( int position, QSAxis *o )
|
|
{
|
|
parametersChanging();
|
|
d->m_axes.reorder( position, d->m_axes.find(o) );
|
|
emit sigChildOrder();
|
|
emit sigChildListChanged();
|
|
parametersChanged();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
int QSAxes::childCount() const
|
|
{
|
|
return axisCount()+plotCount();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSData *QSAxes::child( int index ) const
|
|
{
|
|
return ( index < axisCount() ? (QSData *)axis(index) : (QSData *)plot(index-axisCount()) );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
// Parameters/Data changing
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::parametersChanging()
|
|
{
|
|
stop();
|
|
QSGraphicalData::parametersChanging();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::parametersChanged()
|
|
{
|
|
stop();
|
|
if ( m_auto_updates ) emit sigUpdate();
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::dataChanging( QSData *object, int channel )
|
|
{
|
|
stop();
|
|
QSGraphicalData::dataChanging( object, channel );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::dataChanged( QSData *object, int channel )
|
|
{
|
|
stop();
|
|
QSGraphicalData::dataChanged(object,channel);
|
|
if ( m_auto_updates ) emit sigUpdate();
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
// Redrawing
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::start( QSDrv *init_drv, bool blocking, bool transparent )
|
|
{
|
|
if ( m_internal_state == Busy ) stop();
|
|
m_bkg_handler = !blocking && !m_axes_only;
|
|
if ( m_bkg_handler ) {
|
|
m_drv = init_drv->copy();
|
|
m_delete_driver = true;
|
|
} else {
|
|
m_drv = init_drv;
|
|
m_delete_driver = false;
|
|
}
|
|
|
|
m_curr_dpi = m_drv->dpi;
|
|
m_is_complete = false;
|
|
m_blocking = blocking;
|
|
m_transparent = transparent;
|
|
d->m_plots.setPos( 0 );
|
|
|
|
m_drv->setCurrentElement( GeneralCategory, 0 );
|
|
m_internal_state = Busy;
|
|
allocRuntimeData();
|
|
m_runtime_data_allocated = true;
|
|
calculate_auto_ranges();
|
|
axisRangesCalculated();
|
|
|
|
// draw minor grid
|
|
if ( !m_really_fast )
|
|
for( int axis=0; axis < d->m_axes.count(); axis++ ) {
|
|
m_drv->setCurrentElement( GridCategory, axis );
|
|
drawGrid( d->m_axes[axis], false );
|
|
}
|
|
|
|
// draw major grid
|
|
if ( !m_really_fast )
|
|
for( int axis=0; axis < d->m_axes.count(); axis++ ) {
|
|
m_drv->setCurrentElement( GridCategory, axis );
|
|
drawGrid( d->m_axes[axis], true );
|
|
}
|
|
|
|
// draw axes
|
|
for( int axis=0; axis < d->m_axes.count(); axis++ ) {
|
|
m_drv->setCurrentElement( AxisCategory, axis );
|
|
drawAxis( d->m_axes[axis] );
|
|
}
|
|
|
|
// start drawing datasets - see work_proc() for the rest.
|
|
m_curr_dataset_nr = 0;
|
|
m_drv->setClipping( true );
|
|
if ( d->m_plots.isValidPos() && !m_axes_only ) {
|
|
m_drv->setCurrentElement( DatasetCategory, m_curr_dataset_nr++ );
|
|
m_current_started = d->m_plots.current()->start();
|
|
if ( m_bkg_handler ) m_timer->start( 0, FALSE );
|
|
else while( d->m_plots.isValidPos() ) work_proc();
|
|
} else {
|
|
d->m_plots.setPos( d->m_plots.count() ); // immediately move to the end
|
|
stop();
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::work_proc()
|
|
// drawing datasets
|
|
{
|
|
if ( !m_current_started || !d->m_plots.current()->step() ) {
|
|
d->m_plots.current()->end();
|
|
d->m_plots.setPos( d->m_plots.pos() + 1 );
|
|
if ( d->m_plots.isValidPos() ) {
|
|
m_drv->setCurrentElement( DatasetCategory, m_curr_dataset_nr++ );
|
|
m_current_started = d->m_plots.current()->start();
|
|
} else {
|
|
stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::stop()
|
|
// stop drawing now.
|
|
// Make sure that next drawing will start from beginnig.
|
|
{
|
|
if ( m_internal_state == Busy ) {
|
|
// not completed !
|
|
if ( d->m_plots.isValidPos() ) { d->m_plots.current()->end(); }
|
|
emit sigUserDraw( m_drv, m_blocking, m_transparent );
|
|
m_timer->stop();
|
|
}
|
|
|
|
d->m_plots.setPos( d->m_plots.count() );
|
|
if ( m_runtime_data_allocated ) freeRuntimeData();
|
|
m_runtime_data_allocated = false;
|
|
if ( m_delete_driver ) delete m_drv;
|
|
m_delete_driver = false;
|
|
m_drv = NULL;
|
|
|
|
if ( m_internal_state == Busy ) {
|
|
m_internal_state = Waiting;
|
|
emit sigDrawEnds();
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::calculate_auto_ranges()
|
|
{
|
|
// initialize axes
|
|
for ( int axis=0; axis<d->m_axes.count(); axis++ ) {
|
|
bool first_time = true;
|
|
bool is_data = false;
|
|
double data_min = 1.0;
|
|
double data_max = 1.0;
|
|
for ( int i=0; i<d->m_plots.count(); i++ ) {
|
|
double min = 0.0;
|
|
double max = 0.0;
|
|
if ( d->m_plots[i]->getAxisRange(d->m_axes[axis],min,max) ) {
|
|
is_data = true;
|
|
if ( first_time ) {
|
|
first_time = false;
|
|
data_min = min;
|
|
data_max = max;
|
|
} else {
|
|
data_min = QMIN( data_min, min );
|
|
data_max = QMAX( data_max, max );
|
|
}
|
|
}
|
|
}
|
|
|
|
d->m_axes[axis]->initAxis( data_min, data_max, is_data );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QString QSAxes::posInfo( QSPt2f& pos )
|
|
{
|
|
QString result = QString::null;
|
|
for( int i=plotCount()-1; i>=0; i-- )
|
|
if ( (result=plot(i)->posInfo(pos)) != QString::null ) {
|
|
result = tr(" You clicked at:\n\n Plot ") + QString::number(i) + QString(" : ") + plot(i)->title() + "\n\n" + result;
|
|
return result;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSRectf QSAxes::calculateCanvasRect( double dpi )
|
|
{
|
|
return QSRectf( QSCoord::mmToPixels(posMM().x,dpi),
|
|
QSCoord::mmToPixels(posMM().y,dpi),
|
|
QSCoord::mmToPixels(sizeMM().x,dpi),
|
|
QSCoord::mmToPixels(sizeMM().y,dpi) );
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::paintSkeleton( QPainter *p, double dpi, bool reallyFast )
|
|
{
|
|
m_really_fast = reallyFast;
|
|
bool m_prev_axes_only = m_axes_only;
|
|
m_axes_only = true;
|
|
paintPlot(p,dpi,true,true);
|
|
m_axes_only = m_prev_axes_only;
|
|
m_really_fast = false;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::initMappings( QSDrv *init_drv )
|
|
{
|
|
if ( !state() ) {
|
|
calculate_auto_ranges();
|
|
m_drv = init_drv;
|
|
m_curr_dpi = m_drv->dpi;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setCanvasRect( const QSRectf& r )
|
|
{
|
|
m_cpos.x = r.pos.x;
|
|
m_cpos.y = r.pos.y;
|
|
m_csize.x = r.size.x;
|
|
m_csize.y = r.size.y;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setFitToCanvasRect( bool enabled )
|
|
{
|
|
m_transformation_rect = enabled;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::rememberCurrentView( int index )
|
|
{
|
|
if ( index >=0 && index < 3 )
|
|
for( int i=0; i<axisCount(); i++ ) axis(i)->rememberCurrentView( index );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::setRememberedView( int index )
|
|
{
|
|
if ( index >=0 && index < 3 )
|
|
for( int i=0; i<axisCount(); i++ ) axis(i)->setRememberedView( index );
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::loadStateFromStream( QDataStream& stream, QSObjectFactory *factory )
|
|
{
|
|
QSGraphicalData::loadStateFromStream( stream, factory );
|
|
|
|
// load all axes
|
|
int axes_to_delete = axisCount();
|
|
int axis_count; stream >> axis_count;
|
|
for( int i=0; i<axis_count; i++ ) {
|
|
QSAxis *new_axis = dynamic_cast<QSAxis*>(factory->loadObjectFromStream(stream,this));
|
|
assert( new_axis ); axisAdd( new_axis );
|
|
}
|
|
for( int i=0; i<axes_to_delete; i++ ) {
|
|
axisDelete( axis(0) );
|
|
}
|
|
|
|
// load datasets
|
|
for( int i=0; i<plotCount(); i++ ) {
|
|
plotDelete( plot(i) );
|
|
}
|
|
int plot_count; stream >> plot_count;
|
|
for( int i=0; i<plot_count; i++ ) {
|
|
QSPlot *new_plot = dynamic_cast<QSPlot*>(factory->loadObjectFromStream(stream,this));
|
|
assert( new_plot ); plotAdd( new_plot );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
void QSAxes::saveStateToStream( QDataStream& stream, QSObjectFactory *factory )
|
|
{
|
|
QSGraphicalData::saveStateToStream( stream, factory );
|
|
// save all axes
|
|
stream << (int)axisCount();
|
|
for( int i=0; i<axisCount(); i++ ) {
|
|
factory->saveObjectToStream( axis(i), stream );
|
|
}
|
|
// save all datasets
|
|
stream << (int)plotCount();
|
|
for( int i=0; i<plotCount(); i++ ) {
|
|
factory->saveObjectToStream( plot(i), stream );
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxesChild::QSAxesChild( QSAxes *parentAxes, const char *name )
|
|
:QSGraphicalData(NULL,parentAxes,name)
|
|
{
|
|
assert(parentAxes);
|
|
m_axes = parentAxes;
|
|
}
|
|
|
|
//-------------------------------------------------------------//
|
|
|
|
QSAxesChild::~QSAxesChild()
|
|
{
|
|
}
|
|
|