/*************************************************************************** qsaxes.h ------------------- version : 0.1 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. * * * ***************************************************************************/ #ifndef QSAXES_H #define QSAXES_H #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include"qsgraphicaldata.h" #include"qsdrv.h" #include"qscobject.h" #include"qsprojection.h" class QTimer; class QSPlot; class QSAxes; /** * \brief Simple QSCObject wrapper around QSAxes * * QSAxes doesn't inherit QCObject ( multimple inheritance from QObject is not allowed ), instead * a shadow QSCObject is providen, so use:axes->shadowObject() instead of casting. Notice that * this object inherits QSCGroup, so all objects added to this group will be bound with this axes - * it will allow them to to use this axes coordinate system, for example arrow could point at * some area of a graph. Constructor is a private memeber. You have to create an QSAxes2D or QSAxes3D * first and use QSAxes::shadowObject() to get a pointer to this object. */ class QSCAxesShadow : public QSCGroup { friend class QSAxes; Q_OBJECT public: /** * Destructor. */ virtual ~QSCAxesShadow(); virtual void setAutoUpdates( bool enabled ); /** * Can't change parent axes. This method does nothing. */ virtual void setParentAxes( QSAxes * ); virtual void setBox( const QSRectf& rect, QSDrv *drv ); virtual QSRectf box( QSDrv *drv ); virtual bool isHit( const QSPt2f &p, QSDrv* drv ); virtual bool isAxesShadow(); virtual int style(); virtual QString name(); virtual void draw( QSDrv *drv, bool blocking, bool transparent ); virtual void paintSkeleton( QPainter *p, double dpi = 72.0 ); virtual void paint( QPainter *p, double dpi = 72.0, bool blocking=true, bool transparent=true ); virtual bool busy() const; virtual void stop(); virtual void loadStateFromStream( QDataStream& stream, QSObjectFactory *factory ); virtual void saveStateToStream( QDataStream& stream, QSObjectFactory *factory ); public slots: virtual void forceUpdate(); protected: /** * Protected constructor. Use QSAxes::shadowObject() to create QSCAxesShadow object. */ QSCAxesShadow( QSAxes *parent ); private slots: virtual void slot_object_added( QSCObject *object ); virtual void slot_object_removed( QSCObject *object ); virtual void slot_draw_objects( QSDrv *drv, bool, bool ); virtual void slot_update(); void slot_draw_ends(); }; //----------------------------------------------------------------------------------------------------// /** * \brief Base graph object * * Base class for all axes.Generaly it holds a list of axes and datasets.There can be any number of axes in this * object. They are avaliable as a simple list without further interpretation. Axes also implements QSCObject ( canvas * object ) interface, so can be added to the canvas. Warning: It does not inherit QSCObject ( problem * with multiple inheritance ) directly, you must create such object with shadowObject() method. This object can repaint * itself using a given painter or driver. It takes much time to repaint a graph if it contains many datapoints, * so it can be repainted in the background see paint() ( 'blocking' argument ), state(), stop(). sigDrawEnds() * When it state changes and it needs redrawing it notify it using sigUpdate() . * @author Kamil Dobkowski */ class QSAxes : public QSGraphicalData { Q_OBJECT friend class QSPlot; Q_PROPERTY( double xPosMM READ xPosMM WRITE setXPosMM ) Q_PROPERTY( double yPosMM READ yPosMM WRITE setYPosMM ) Q_PROPERTY( double widthMM READ widthMM WRITE setWidthMM ) Q_PROPERTY( double heightMM READ heightMM WRITE setHeightMM ) Q_PROPERTY( bool drawInBackground READ drawInBackground WRITE setDrawInBackground ) Q_PROPERTY( bool axesOnly READ axesOnly WRITE setAxesOnly ) Q_PROPERTY( QString background READ background_property WRITE set_background_property ) public: /** * Current state. * @see #state */ enum InternalState { Waiting = 0, Busy }; /** * See mixedToCanvas() , canvasToMixed(). When data point is to be drawn its coordinates are first mapped to * world coordinate system using QSPlot::defaultAxis() and QSAxis::dataToWorld(). Notice that each dataset can * use a different set of axes. World coorinate system is a simple (1,1) square for QSAxes2D, and (1,1,1) cube * for QSAxes3D. Next if point is 'outside' axes ( has coordinates lower than 0.0 or greater than 1.0 ) is * trown out, see proj() and QSProjection::clipPoint2(). If it is visible its coordinates are mapped to canvas * ( screen ) coordinates using proj() and QSProjection::world2DToCanvas() and the point is drawn on the screen. * You can next map canvas coordinates to mm's ( it is a matter of a dpi scale factor ). There are also normCoordinates, * but they are rarely used. */ enum CoordinateSystem { mmCoord, normCoord, worldCoord, dataCoord }; /** * Element category ( used by QSDrvHitTest ). You can find out which element is currently drawn * using QSDrv::currentElement(), of course you will be able to call this function only if drawing * is done in the background. See state() . */ enum ElementCategory { GeneralCategory, AxisCategory, GridCategory, DatasetCategory, UnknownCategory }; /** * Constructor. */ QSAxes( QObject * parent, const QSProjection *proj, const char * name=0 ); /** * Destructor. */ virtual ~QSAxes(); /** * Returns the current state. * Drawing - means that work is in progress at the moment (. * using background handler callback ). * Waiting - work is finished. * You can stop drawing at any time by calling 'stop()'. */ InternalState state() const { return m_internal_state; } /** * Stops drawing immediately. */ virtual void stop(); /** * Returns true if a last plot drawing operation was complete * or false if was stopped before end. */ bool complete() const { return m_is_complete; } //----------------------------------------------------------------// /** * Set position on a page in mm. This is not used by this class. * It is only a useful hint. If you want to set the paint area * basing on this parameter you must call setCanvasRect instead: * QSCShadowObject uses this properties to find its size. * Example: setCanvasRect( calculateCanvasRect(dpi) ) */ void setPosMM( const QSPt2f& pos_mm ); /** * Sets x position */ void setXPosMM( double x_mm ); /** * Sets y position */ void setYPosMM( double y_mm ); /** * Sets size of the axes on a page in mm. This is not used by this class * It is only a useful hint.If you want to set the paint area you must * call setCanvasRect instead. Example: setCanvasRect( calculateCanvasRect(dpi) ) * QSCShadowObject uses this properties to calculate its size. */ void setSizeMM( const QSPt2f& size_mm ); /** * Sets width in mm. */ void setWidthMM( double w_mm ); /** * Sets height in mm */ void setHeightMM( double h_mm ); /** * Returns position of the axes on the page in mm. */ QSPt2f posMM() const { return m_pos_mm; } /** * Returns position of the axes on the page in mm. */ double xPosMM() const { return m_pos_mm.x; } /** * Returns position of the axes on the page in mm. */ double yPosMM() const { return m_pos_mm.y; } /** * Returns size of the axes in mm. */ QSPt2f sizeMM() const { return m_size_mm; } /** * Returns size of the axes in mm. */ double widthMM() const { return m_size_mm.x; } /** * Returns size of the axes in mm. */ double heightMM() const { return m_size_mm.y; } /** * Calculates canvas area from canvasPosMM() and canvasSizeMM() */ QSRectf calculateCanvasRect( double dpi = 72.0 ); /** * Sets the canvas rectangle to be painted. There is no 'paremetersChanged()' * or any other notification ! */ void setCanvasRect( const QSRectf& r ); /** * Returns canvas position. * Result valid only during drawing - see @ref #state . */ QSRectf canvasRect() const { return QSRectf( m_cpos.x, m_cpos.y, m_csize.x, m_csize.y ); } /** * Turn on a spectial mode of fitting to canvas rect. There is no 'paremetersChanged()' * or any other notification. */ void setFitToCanvasRect( bool enabled ); /** * */ bool fitToCanvasRect() const { return m_transformation_rect; } /** * This is only a hint. You must pass 'blocking' value each time * tou call paintPlot or drawPlot */ void setDrawInBackground( bool enabled ); /** * See 'setDrawInBackground()' */ bool drawInBackground() const { return m_draw_in_background; } //-------------------------------------------------------------// /** * Draws only axes ( not datasets ) -fast mode. */ void setAxesOnly( bool enabled ); /** * Return an axes only setting. */ bool axesOnly() const { return m_axes_only; } /** * Sets the background color. */ void setBackground( const QSGFill& fill ); /** * Returns the current background color. */ QSGFill background() const; //------------------------------------------------------------// /** * Remembered view contains such parameters as axis min ,axis max, axis scale, axis reversed. * Up to three different views can be remembered ( index must be in 0-2 ). */ virtual void rememberCurrentView( int index ); /** * Sets the view properties */ virtual void setRememberedView( int index ); //------------------------------------------------------------// /** * Triggers transformation update after you modified 'setCanvasRect', datasets, axes etc. * It is called also when redrawing, so there is no need to call it by hand. */ virtual void initMappings( QSDrv *drv ); /** * Canvas coordinates are on-screen pixels coordinates. See 'canvasPos()' and 'canvasSize()'. * Normalized coordinates maps canvas coordinates to <0,1> rectangle. * Example: canvasToNormalized(canvasPos()) returns ( 0.0, 0.0 ) point. * See also 'initMappings()' */ double canvasToNormalizedX( double value ) const ; /** * See canvasToNormalizedX() */ double canvasToNormalizedY( double value ) const ; /** * See canvasToNormalizedX() */ QSPt2f canvasToNormalized( const QSPt2f& pos ) const; /** * See canvasToNormalizedX() */ double normalizedXToCanvas( double value ) const ; /** * See canvasToNormalizedX() */ double normalizedYToCanvas( double value ) const ; /** * See canvasToNormalizedX() */ QSPt2f normalizedToCanvas( const QSPt2f& pos ) const; /** * From data to screen coordinates. * See also 'initMappings()' */ QSPt2f dataToCanvas( const QSPt3f& pos, QSAxis *xAxis, QSAxis *yAxis, QSAxis *zAxis ) const; /** * From data to screen coordinates. * See also 'initMappings()' */ QSPt2f dataToCanvas( const QSPt2f& pos, QSAxis *xAxis, QSAxis *yAxis ) const; /** * From mixed type coordinates to canvas. Not all combinations of CoordinateSystems are allowed in all cases. * In in_coords parameter you can describe which coordinate system is used for each point coordinate. See * CoordinateSystem . */ virtual QSPt3f mixedToCanvas( const QSPt3f& pos, CoordinateSystem in_coords[3], double dpi, QSAxis *xAxis, QSAxis *yAxis, QSAxis *zAxis ) const = 0; /** * From canvas to mixed coordinates. In out_coords parameter you can request which coordinate system * should be used for each output coordinate. Not all combinations of CoordinateSystems are allowed in all cases. * See CoordinateSystem . */ virtual QSPt3f canvasToMixed( const QSPt3f& pos, CoordinateSystem out_coords[3], double dpi, QSAxis *xAxis, QSAxis *yAxis, QSAxis *zAxis ) const = 0; //------------------------------------------------------------// /** * Controls if method 'updatePlot()' will be called automatically * after any parameter ( by set... method ) or data ( setMatrix... ) changes. */ void setAutoUpdates( bool enabled ); /** * Returns the auto-updates setting. */ bool autoUpdates() const { return m_auto_updates; } //----------------------------------------------------------------// /** * The same as axisCount()+plotCount(). */ virtual int childCount() const; /** * Returns a child object - it is a joined list of child axes and * child plots. */ virtual QSData *child( int index ) const; //----------------------------------------------------------------// /** * Returns a total number of child plots. */ int plotCount() const; /** * Adds a new plot to the list. Emits sigChildAdded(). * The newly constructed object should be immediately added * to the child list. */ void plotAdd( QSPlot *p ); /** * Adds a new plot to the list. Emits sigChildAdded(). * The newly constructed object should be immediately added * to the child list. */ void plotInsert( int beforePos, QSPlot *p ); /** * Removes a dataset from the dataset list but doesn't delete it. * Emits sigChildRemoved ( all child datasets are deleted in destructor however ). */ void plotRemove( QSPlot *p ); /** * Removes and deletes a dataset from the dataset list. Emits sigChildRemoved * It doesn't remove it nor deletes it if it is not found on the child list. */ void plotDelete( QSPlot *p ); /** * Returns a plot at the index 'index'. * Plots are numbered from 0 ( at the back ) to * plotCount()-1 ( at the front ). */ QSPlot *plot( int index ) const ; /** * Returns the current index of the given plot. */ int plotIndex( QSPlot *o ) const ; /** * Moves the given object to the front. Emits sigChildOrder. */ void plotToFront( QSPlot *o ); /** * Moves the given object to the back. Emits sigChildDOrder. */ void plotToBack( QSPlot *o ); /** * Raises the given object. Emits sigChildOrder. */ void plotRaise( QSPlot *o ); /** * Lowers the given object. Emits sigChildOrder. */ void plotLower( QSPlot * o ); /** * Reorderes the given object. Emits sigChildOrder. */ void plotReorder( int position, QSPlot * o ); //----------------------------------------------------------------// /** * Returns a total number of child axes. */ int axisCount() const; /** * Adds a new axis to the list. Emits sigChildAdded(). * The newly constructed axis object should be immediately added * to the child list. */ void axisAdd( QSAxis *axis ); /** * Adds a new axis to the list. Emits sigChildAdded(). * The newly constructed axis object should be immediately added * to the child list. */ void axisInsert( int position, QSAxis *axis ); /** * Removes an axis from the axis list but doesn't delete it * ( all child axes are deleted in destructor however ). * You can't remove an axis if it is the last axis of the * given type ( there always must be at least a one X,Y,V,Z axis present ). * Operation is silently ignored in the case, and function returns false;. * Emits sigChildRemoved */ bool axisRemove( QSAxis *axis ); /** * Removes and deletes an axis from the axis list * You can't remove an axis if it is the last axis of the * given type ( there always must be at least a one X,Y,V,Z axis present ). * Operation is silently ignored in the case, and function returns false;. * Emits sigChildRemoved */ bool axisDelete( QSAxis *axis ); /** * Returns axis of a given type. Returned axis is always first axis found * ( with the lowest index ). axisType has type of QSAxis::AxisType. */ QSAxis *axisOfType( int axisType ) const; /** * Returns an axis at the index 'index'. * Axes are numbered from 0 ( at the back ) to * axisCount()-1 ( at the front ). */ QSAxis *axis( int index ) const; /** * Returns the current index of the given axis. */ int axisIndex( QSAxis *axis ) const ; /** * Moves the given axis to the front. Emits sigChildOrder. */ void axisToFront( QSAxis *axis ); /** * Moves the given axis to the back. Emits sigChildDOrder. */ void axisToBack( QSAxis *axis ); /** * Raises the given axis. Emits sigChildOrder. */ void axisRaise( QSAxis *axis ); /** * Lowers the given axis. Emits sigChildOrder. */ void axisLower( QSAxis *axis ); /** * Reorderes the given axis. Emits sigChildOrder. */ void axisReorder( int position, QSAxis *axis ); //----------------------------------------------------------------// //----------------------------------------------------------------// /** * Returns a shadow object. It has the same position and size as axes. * When this position is changed by object->setBox a position and size * of this object is updated ( see 'posMM()' and 'sizeMM()' ). * Do not delete it. */ QSCAxesShadow *shadowObject(); //----------------------------------------------------------------// /** * Info about the given point */ virtual QString posInfo( QSPt2f& pos ); //--------------------------------------------------------------------------// /** * Paints the plot to the given painter, 'dpi' is used to calculate * a pixel-height of points and fonts. If blocking is true, this function * returns after drawing ends ( may take a while ). If blocking is false * driver is copied using QSDrv::copy(), this function returns immediately, * drawing is continued in a timer event */ virtual void paintPlot( QPainter *p, double dpi=72.0, bool blocking=true, bool transparent=true ) = 0; /** * Paints the plot with the given driver, 'drv->dpi' is used to calculate * a pixel-height of points and fonts. If blocking is true, this function * returns after drawing ends ( may take a while ). If blocking is false * driver is copied using QSDrv::copy(), this function returns immediately, * drawing is continued in a timer event */ virtual void drawPlot( QSDrv *drv, bool blocking=true, bool transparent=true ) = 0; /** * Paints (fast )simplified version of this object */ virtual void paintSkeleton( QPainter *p, double dpi=72.0, bool reallyFast=false ); /** * Emits sigUpdate */ void forceUpdate() { emit sigUpdate(); } /** * */ QSDrv *run_gDriver() const { return m_drv; } /** * */ double run_dpi() const { return m_curr_dpi; } /** * Returns a projection used by this axis object. */ const QSProjection *proj() const { return m_proj; } //----------------------------------------------------------------// void set_background_property( const QString& value ); QString background_property() const; /** * Restores all axes and datasets. */ virtual void loadStateFromStream( QDataStream& stream, QSObjectFactory *factory ); /** * Saves all axes and datasets. */ virtual void saveStateToStream( QDataStream& stream, QSObjectFactory *factory ); signals: /** * Emitted after any data change in child plots and an axes object itself. */ void sigDataChanged( QSGraphicalData *b, int channel ); /** * */ void sigUpdate(); /** * After all ranges and transforms are calculated */ void sigRangesValid(); /** * Emitted when draw ends but before graphics is closed. */ void sigUserDraw( QSDrv *drv, bool blocking, bool transparent ); /** * Emitted when draw ends, after graphics has been closed. */ void sigDrawEnds(); //----------------------------------------------------------------// protected: /** * Reimplemented. Calls stop(). */ virtual void dataChanging( QSData *object, int channel = -1 ); /** * Reimplemented. Emits sigDataChanged() and ( see setAutoUpdates() ) sigUpdate(). */ virtual void dataChanged( QSData *object, int channel = -1 ); /** * Reimplemented. Calls stop(). */ virtual void parametersChanging(); /** * Reimplemented. Emits ( see setAutoUpdates() ) sigUpdate(). */ virtual void parametersChanged(); /** * Starts redrawing process. */ virtual void start( QSDrv *drv, bool blocking, bool transparent ); /** * Called when all ranges are calculated. * Default implementation emits 'sigRangesValid' */ virtual void axisRangesCalculated() { emit sigRangesValid(); } /** * This function is called in 'start()' before drawing starts. * Default implementation does nothing. */ virtual void allocRuntimeData() {} /** * This function is called in 'stop()' after drawing stops. * Default implementation does nothing. */ virtual void freeRuntimeData() {} /** * Draws an axis. It is reimplemented in QSAxes2D and QSAxes3D */ virtual void drawAxis( QSAxis */*axis*/ ) {} /** * Draws an axis grid. It is reimplemented in QSAxes2D and QSAxes3D */ virtual void drawGrid( QSAxis */*axis*/, bool /*major*/ ) {} /** * Reimplemented from QObject */ virtual void childEvent ( QChildEvent * ); struct margins_t { int l; int r; int t; int b; } m_m; InternalState m_internal_state; QSGFill m_bckg_fill; QSPt2f m_csize; QSPt2f m_cpos; QSPt2f m_pos_mm; QSPt2f m_size_mm; double m_curr_dpi; QSDrv *m_drv; bool m_bkg_handler; bool m_axes_only; bool m_really_fast; bool m_blocking; bool m_transparent; QSCAxesShadow *m_shadow_object; bool m_transformation_rect; bool m_draw_in_background; const QSProjection *m_proj; int m_curr_dataset_nr; private: struct qsaxes_private_data; qsaxes_private_data *d; QTimer *m_timer; // change to fields bool m_runtime_data_allocated; bool m_current_started; bool m_is_complete; bool m_auto_updates; bool m_delete_driver; double m_almost_zero; void calculate_auto_ranges(); private slots: void work_proc(); }; //---------------------------------------------------------------------------------------------------// /** * \brief Object which have a parent axes. * * Axis or dataset * @author Kamil Dobkowski */ class QSAxesChild : public QSGraphicalData { Q_OBJECT public: /** * Constructor. The object should be added immediately to the * Axes child list. */ QSAxesChild( QSAxes *parentAxes, const char *name=0 ); /** * Destructor */ virtual ~QSAxesChild(); /** * Returns parent axes. */ QSAxes *parentAxes() const { return m_axes; } protected: QSAxes *m_axes; }; #endif