2019-05-30 04:40:02 +08:00
/*
2022-07-19 19:40:43 +08:00
Copyright ( c ) 2008 - 2022 Jan W . Krieger ( < jan @ jkrieger . de > )
2019-05-30 04:40:02 +08:00
This software is free software : you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation , either version 2.1 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# ifndef JKQTPDRAWINGTOOLS_H_INCLUDED
# define JKQTPDRAWINGTOOLS_H_INCLUDED
2019-06-22 20:21:32 +08:00
# include "jkqtcommon/jkqtcommon_imexport.h"
2019-05-30 04:40:02 +08:00
# include <QPaintDevice>
# include <QPainter>
# include <QPolygonF>
# include <QPolygon>
# include <QRectF>
# include <QRect>
# include <QLineF>
# include <QLine>
2022-09-02 18:27:12 +08:00
# include <array>
2019-05-30 04:40:02 +08:00
# include <QPainterPath>
# include <QColor>
# include <QVector>
# include <vector>
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
# include <forward_list>
2019-05-30 04:40:02 +08:00
# include <cmath>
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
# include <utility>
2020-08-22 00:31:58 +08:00
# include <QDebug>
2022-09-06 18:39:23 +08:00
# include <QVector>
2022-09-02 20:19:47 +08:00
# include <QGuiApplication>
2022-09-08 03:50:58 +08:00
# include <QDataStream>
# include <ostream>
2019-05-30 04:40:02 +08:00
# include "jkqtcommon/jkqtpmathtools.h"
2023-06-25 23:55:05 +08:00
# include "jkqtcommon/jkqtpconcurrencytools.h"
2019-05-30 04:40:02 +08:00
# include "jkqtcommon/jkqtpcodestructuring.h"
class JKQTPEnhancedPainter ; // forward
2022-09-06 18:39:23 +08:00
/** \brief functor used to draw a custom JKQTPGraphSymbols
* \ ingroup jkqtptools_drawing
*
* Draw the symbol with these properties :
* - center at ( 0 , 0 )
* - width 1 , i . e . x = - 0.5 . . .0 .5
* - height 1 , i . e . y = - 0.5 . . .0 .5
* - you can assume that a proper pen and brush is set with the correct properties
* - scaling to the final size is donw by JKQTPPlotSymbol ( )
* - drawing is protected by surronding \ c p . save ( ) ; and \ c p . restore ( ) ; in JKQTPPlotSymbol ( )
* .
*
* As an example , the following code - snippet :
* \ code
* [ ] ( QPainter & p ) {
* p . drawEllipse ( QPointF ( - 0.2 , - 0.2 ) , 0.3 , 0.3 ) ;
* p . setBrush ( Qt : : NoBrush ) ;
* p . drawEllipse ( QPointF ( 0.2 , - 0.2 ) , 0.3 , 0.3 ) ;
* p . drawEllipse ( QPointF ( 0 , 0.2 ) , 0.3 , 0.3 ) ;
* } ;
* \ endcode
* generates this symbol : \ image html symbols / symbol_custom . png
*/
typedef std : : function < void ( QPainter & p ) > JKQTPCustomGraphSymbolFunctor ;
2019-05-30 04:40:02 +08:00
/*! \brief tool class with static values used by JKQTPlotter/JKQTBasePlotter
\ ingroup jkqtptools_drawing
*/
2019-06-22 20:21:32 +08:00
struct JKQTPlotterDrawingTools {
2024-01-23 04:31:09 +08:00
/** \brief a special placeholder that can be used to indicate that a color should be replaced by the "current color" in a certain context
*
2024-01-23 20:09:37 +08:00
* \ see JKQTPReplaceCurrentColor ( ) , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
static JKQTCOMMON_LIB_EXPORT const QColor CurrentColorPlaceholder ;
/** \brief a special placeholder that can be used to indicate that a color should be replaced by the "current color", but with 10% transparency in a certain context
*
2024-01-23 20:09:37 +08:00
* \ see JKQTPReplaceCurrentColor ( ) , JKQTPlotterDrawingTools : : CurrentColorPlaceholder_Trans10 , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
static JKQTCOMMON_LIB_EXPORT const QColor CurrentColorPlaceholder_Trans10 ;
/** \brief a special placeholder that can be used to indicate that a color should be replaced by the "current color", but with 25% transparency in a certain context
*
2024-01-23 20:09:37 +08:00
* \ see JKQTPReplaceCurrentColor ( ) , JKQTPlotterDrawingTools : : CurrentColorPlaceholder , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
static JKQTCOMMON_LIB_EXPORT const QColor CurrentColorPlaceholder_Trans25 ;
/** \brief a special placeholder that can be used to indicate that a color should be replaced by the "current color", but with 50% transparency in a certain context
*
2024-01-23 20:09:37 +08:00
* \ see JKQTPReplaceCurrentColor ( ) , JKQTPlotterDrawingTools : : CurrentColorPlaceholder , JKQTPlotterDrawingTools : : CurrentColorPlaceholder_Trans10 , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
static JKQTCOMMON_LIB_EXPORT const QColor CurrentColorPlaceholder_Trans50 ;
/** \brief a special placeholder that can be used to indicate that a color should be replaced by the "current color", but with 75% transparency in a certain context
*
2024-01-23 20:09:37 +08:00
* \ see JKQTPReplaceCurrentColor ( ) , JKQTPlotterDrawingTools : : CurrentColorPlaceholder , JKQTPlotterDrawingTools : : CurrentColorPlaceholder_Trans10 , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
static JKQTCOMMON_LIB_EXPORT const QColor CurrentColorPlaceholder_Trans75 ;
/** \brief a special placeholder that can be used to indicate that a color should be replaced by the "current color", but with 90% transparency in a certain context
*
2024-01-23 20:09:37 +08:00
* \ see JKQTPReplaceCurrentColor ( ) , JKQTPlotterDrawingTools : : CurrentColorPlaceholder , JKQTPlotterDrawingTools : : CurrentColorPlaceholder_Trans10 , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
static JKQTCOMMON_LIB_EXPORT const QColor CurrentColorPlaceholder_Trans90 ;
2019-05-30 04:40:02 +08:00
/** \brief smallest linewidth any line in JKQTPlotter/JKQTBasePlotter may have
*/
2019-06-22 20:21:32 +08:00
static JKQTCOMMON_LIB_EXPORT const double ABS_MIN_LINEWIDTH ;
2022-09-06 18:39:23 +08:00
/** \brief stores all custom JKQTPGraphSymbols registered using JKQTPRegisterCustomGraphSymbol
* \ ingroup jkqtptools_drawing
* \ internal
*/
2023-06-25 23:55:05 +08:00
static JKQTCOMMON_LIB_EXPORT JKQTPSynchronized < QVector < JKQTPCustomGraphSymbolFunctor > > JKQTPCustomGraphSymbolStore ;
2024-01-06 06:26:47 +08:00
typedef JKQTPSynchronized < QVector < JKQTPCustomGraphSymbolFunctor > > : : ReadLocker SymbolsReadLocker ;
typedef JKQTPSynchronized < QVector < JKQTPCustomGraphSymbolFunctor > > : : WriteLocker SymbolsWriteLocker ;
2019-05-30 04:40:02 +08:00
} ;
2024-01-23 04:31:09 +08:00
/*! \brief check whether \a col equals JKQTPlotterDrawingTools::CurrentColorPlaceholder (or one of its variants) and then replace it by \a currentColor
\ ingroup jkqtptools_drawing
2024-01-23 20:09:37 +08:00
\ see JKQTPlotterDrawingTools : : CurrentColorPlaceholder , JKQTPlotterDrawingTools : : CurrentColorPlaceholder_Trans10 , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
JKQTCOMMON_LIB_EXPORT void JKQTPReplaceCurrentColor ( QColor & col , const QColor & currentColor ) ;
/*! \brief check whether any color in \a grad equals JKQTPlotterDrawingTools::CurrentColorPlaceholder (or one of its variants) and then replace it by \a currentColor
\ ingroup jkqtptools_drawing
2024-01-23 20:09:37 +08:00
\ see JKQTPlotterDrawingTools : : CurrentColorPlaceholder , JKQTPlotterDrawingTools : : CurrentColorPlaceholder_Trans10 , . . . , JKQTFillStyleSummmary
2024-01-23 04:31:09 +08:00
*/
JKQTCOMMON_LIB_EXPORT void JKQTPReplaceCurrentColor ( QGradient & grad , const QColor & currentColor ) ;
2019-05-30 04:40:02 +08:00
/** \brief symbols that can be used to plot a datapoint for a graph
* \ ingroup jkqtptools_drawing
*/
2022-09-02 20:19:47 +08:00
enum JKQTPGraphSymbols : uint64_t {
2019-05-30 04:40:02 +08:00
JKQTPNoSymbol = 0 , /*!< \brief plots no symbol at all (usefull together with error bars) */
JKQTPDot , /*!< \brief a small dot \image html symbols/symbol_dot.png */
JKQTPCross , /*!< \brief a X cross \image html symbols/symbol_cross.png */
JKQTPPlus , /*!< \brief a + cross \image html symbols/symbol_plus.png */
JKQTPCircle , /*!< \brief an unfilled circle \image html symbols/symbol_circle.png */
JKQTPFilledCircle , /*!< \brief a filled circle \image html symbols/symbol_filled_circle.png */
JKQTPRect , /*!< \brief an unfilled rectangle \image html symbols/symbol_rect.png */
JKQTPFilledRect , /*!< \brief a filled rectangle \image html symbols/symbol_filled_rect.png */
JKQTPTriangle , /*!< \brief an unfilled triangle (tip at top) \image html symbols/symbol_triangle.png */
JKQTPFilledTriangle , /*!< \brief a filled triangle (tip at top) \image html symbols/symbol_filled_triangle.png */
JKQTPDiamond , /*!< \brief an unfilled diamond \image html symbols/symbol_diamond.png */
JKQTPFilledDiamond , /*!< \brief a filled diamond \image html symbols/symbol_filled_diamond.png */
JKQTPstar , /*!< \brief an unfilled diamond \image html symbols/symbol_star.png */
JKQTPFilledStar , /*!< \brief a filled diamond \image html symbols/symbol_filled_star.png */
JKQTPPentagon , /*!< \brief an unfilled pentagon \image html symbols/symbol_pentagon.png */
JKQTPFilledPentagon , /*!< \brief a filled pentagon \image html symbols/symbol_filled_pentagon.png */
JKQTPAsterisc , /*!< \brief an asterisc star with 5 arms \image html symbols/symbol_asterisc.png */
JKQTPHourglass , /*!< \brief an hour glass symbol \image html symbols/symbol_hourglass.png */
JKQTPFilledHourglass , /*!< \brief a filled hour glass symbol \image html symbols/symbol_filled_hourglass.png */
JKQTPCurvedTriangle , /*!< \brief a curved triangle\image html symbols/symbol_curved_triangle.png */
JKQTPFilledCurvedTriangle , /*!< \brief a filled curved triangle\image html symbols/symbol_filled_curved_triangle.png */
JKQTPHexagon , /*!< \brief an unfilled hexagon \image html symbols/symbol_hexagon.png */
JKQTPFilledHexagon , /*!< \brief a filled hexagon \image html symbols/symbol_filled_hexagon.png */
JKQTPRectCross , /*!< \brief a square symbol with a cross inside \image html symbols/symbol_rect_cross.png */
JKQTPRectPlus , /*!< \brief a square symbol with a plus inside \image html symbols/symbol_rect_plus.png */
JKQTPRectTriangle , /*!< \brief a square symbol with a triangle inside \image html symbols/symbol_rect_triangle.png */
JKQTPRectDownTriangle , /*!< \brief a square symbol with a triangle (tip to the bottom) inside \image html symbols/symbol_rect_downtriangle.png */
JKQTPRectLeftTriangle , /*!< \brief a square symbol with a triangle (tip to the left) inside \image html symbols/symbol_rect_lefttriangle.png */
JKQTPRectRightTriangle , /*!< \brief a square symbol with a triangle (tip to the right) inside \image html symbols/symbol_rect_righttriangle.png */
JKQTPCircleCross , /*!< \brief a circle symbol with a cross inside \image html symbols/symbol_circle_cross.png */
JKQTPCirclePlus , /*!< \brief a circle symbol with a plus inside \image html symbols/symbol_circle_plus.png */
JKQTPCirclePeace , /*!< \brief a circled peace symbol \image html symbols/symbol_circle_peace.png */
JKQTPDiamondPlus , /*!< \brief a diamond symbol with a plus inside \image html symbols/symbol_diamond_plus.png */
JKQTPDiamondCross , /*!< \brief a diamond symbol with a cross inside \image html symbols/symbol_diamond_cross.png */
JKQTPTripod , /*!< \brief a tripod symbol \image html symbols/symbol_tripod.png */
JKQTPDownTripod , /*!< \brief a tripod symbol, pointing down \image html symbols/symbol_down_tripod.png */
JKQTPLeftTripod , /*!< \brief a tripod symbol, pointing to the left \image html symbols/symbol_left_tripod.png */
JKQTPRightTripod , /*!< \brief a tripod symbol, pointing to the right \image html symbols/symbol_right_tripod.png */
JKQTPAsterisc6 , /*!< \brief an asterisc star with 6 arms \image html symbols/symbol_asterisc6.png */
JKQTPAsterisc8 , /*!< \brief an asterisc star with 8 arms \image html symbols/symbol_asterisc8.png */
JKQTPPeace , /*!< \brief a peace symbol \image html symbols/symbol_peace.png */
JKQTPTarget , /*!< \brief a target symbol (circle with cross) \image html symbols/symbol_target.png */
JKQTPDownTriangle , /*!< \brief an unfilled triangle (tip at bottom) \image html symbols/symbol_down_triangle.png */
JKQTPFilledDownTriangle , /*!< \brief a filled triangle (tip at bottom) \image html symbols/symbol_filled_down_triangle.png */
JKQTPLeftTriangle , /*!< \brief an unfilled triangle (tip to the left) \image html symbols/symbol_left_triangle.png */
JKQTPFilledLeftTriangle , /*!< \brief a filled triangle (tip to the left) \image html symbols/symbol_filled_left_triangle.png */
JKQTPRightTriangle , /*!< \brief an unfilled triangle (tip to the right) \image html symbols/symbol_right_triangle.png */
JKQTPFilledRightTriangle , /*!< \brief a filled triangle (tip to the right) \image html symbols/symbol_filled_right_triangle.png */
JKQTPDownCurvedTriangle , /*!< \brief a curved triangle, pointing down \image html symbols/symbol_down_curved_triangle.png */
JKQTPFilledDownCurvedTriangle , /*!< \brief a filled curved triangle, pointing down \image html symbols/symbol_filled_down_curved_triangle.png */
JKQTPLeftCurvedTriangle , /*!< \brief a curved triangle, pointing to the left \image html symbols/symbol_left_curved_triangle.png */
JKQTPFilledLeftCurvedTriangle , /*!< \brief a filled curved triangle, pointing to the left \image html symbols/symbol_filled_left_curved_triangle.png */
JKQTPRightCurvedTriangle , /*!< \brief a curved triangle, pointing to the right \image html symbols/symbol_right_curved_triangle.png */
JKQTPFilledRightCurvedTriangle , /*!< \brief a filled curved triangle, pointing to the right \image html symbols/symbol_filled_right_curved_triangle.png */
JKQTPOctagon , /*!< \brief an unfilled octagon \image html symbols/symbol_octagon.png */
JKQTPFilledOctagon , /*!< \brief a filled octagon \image html symbols/symbol_filled_octagon.png */
JKQTPUpDownTriangle , /*!< \brief a overlay of an up and a down triangle symbol \image html symbols/symbol_updowntriangle.png */
JKQTPFilledUpDownTriangle , /*!< \brief a filled version of the overlay of an up and a down triangle \image html symbols/symbol_filled_updowntriangle.png */
JKQTPHorizontalHourglass , /*!< \brief a horizontal hour glass symbol \image html symbols/symbol_horizontal_hourglass.png */
JKQTPFilledHorizontalHourglass , /*!< \brief a filled horizontal hour glass symbol \image html symbols/symbol_filled_horizontal_hourglass.png */
JKQTPSantaClauseHouse , /*!< \brief a small house symbol ("Das is das haus vom Nicolaus") \image html symbols/symbol_santaclause.png */
JKQTPFilledSantaClauseHouse , /*!< \brief a filled small house symbol ("Das is das haus vom Nicolaus") \image html symbols/symbol_filled_santaclause.png */
JKQTPMale , /*!< \brief a male symbol \image html symbols/symbol_male.png */
JKQTPFemale , /*!< \brief a female symbol \image html symbols/symbol_female.png */
JKQTPSymbolCount , /*!< \brief can be used to iterate over all symbols using: <code>for (int i=0; i<static_cast<int>(JKQTPSymbolCount); i++) { JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i); ... }</code> */
JKQTPMaxSymbolID = JKQTPSymbolCount - 1 , /*!< \brief points to the last available symbol, can be used to iterate over all symbols: <code>for (int i=0; i<=static_cast<int>(JKQTPMaxSymbolID); i++) { JKQTPGraphSymbols s=static_cast<JKQTPGraphSymbols>(i); ... }</code> */
JKQTPDefaultSymbol = JKQTPCross , /*!< \brief a default symbol used for plotting */
2022-09-02 20:19:47 +08:00
2022-09-06 17:57:58 +08:00
JKQTPCharacterSymbol = 0x100 , /*!< \brief draw a font-character as symbol with defined fill-brush (taken from symbol-color), you can use any character from a QFont by supplying \c JKQTPCharacterSymbol+QChar('').unicode() as JKQTPGraphSymbols
\ image html symbols / symbol_char_at . png " generated by JKQTPCharacterSymbol+QChar('@').unicode() "
\ image html symbols / symbol_char_club . png " generated by JKQTPCharacterSymbol+QChar(0x2663).unicode() " */
JKQTPFilledCharacterSymbol = JKQTPCharacterSymbol + 0xFFFF + 0xF , /*!< \brief draw a font-character as symbol with defined outline-pen and fill-brush, you can use any character from a QFont by supplying \c JKQTPFilledCharacterSymbol+QChar('').unicode() as JKQTPGraphSymbols
2022-09-06 18:39:23 +08:00
\ image html symbols / symbol_filled_char_at . png " generated by JKQTPFilledCharacterSymbol+QChar('@').unicode() "
\ image html symbols / symbol_filled_char_club . png " generated by JKQTPFilledCharacterSymbol+QChar(0x2663).unicode() "
*/
JKQTPFirstCustomSymbol = JKQTPFilledCharacterSymbol + 0xFFFF + 0xF , /*!< \brief draw a completely custom symbol, defined by supplying a functor to JKQTPRegisterCustomGraphSymbol()
\ image html symbols / symbol_custom . png " generated by <code>[](QPainter& p) { p.drawEllipse(QPointF(-0.2, -0.2), 0.3, 0.3); p.setBrush(Qt::NoBrush); p.drawEllipse(QPointF(0.2, -0.2), 0.3, 0.3); p.drawEllipse(QPointF(0, 0.2), 0.3, 0.3); };</code> " */
2019-05-30 04:40:02 +08:00
} ;
2022-09-02 20:19:47 +08:00
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , uint8_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , uint16_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , uint32_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , uint64_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , int8_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , int16_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , int32_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , int64_t b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + b ) ;
}
2022-09-08 04:00:09 +08:00
inline JKQTPGraphSymbols operator + ( JKQTPGraphSymbols a , const QChar & b ) {
return static_cast < JKQTPGraphSymbols > ( static_cast < uint64_t > ( a ) + static_cast < uint64_t > ( b . unicode ( ) ) ) ;
}
2022-09-08 03:50:58 +08:00
2023-06-25 23:55:05 +08:00
/** \brief register a JKQTPCustomGraphSymbolFunctor that draws a custom symbol.Returns an ID that allows to access the symbol!, <b>thread-safe</b>
2022-09-06 18:39:23 +08:00
* \ ingroup jkqtptools_drawing
*
* The functor is stored in the global / static store JKQTPlotterDrawingTools : : JKQTPCustomGraphSymbolStore , i . e . these are available throughout the runtime of the program
*
* \ see JKQTPCustomGraphSymbolFunctor for an example
*/
JKQTCOMMON_LIB_EXPORT JKQTPGraphSymbols JKQTPRegisterCustomGraphSymbol ( JKQTPCustomGraphSymbolFunctor & & ) ;
2023-06-25 23:55:05 +08:00
/** \brief register a JKQTPCustomGraphSymbolFunctor that draws a custom symbol.Returns an ID that allows to access the symbol!, <b>thread-safe</b>
2022-09-06 18:39:23 +08:00
* \ ingroup jkqtptools_drawing
*
* The functor is stored in the global / static store JKQTPlotterDrawingTools : : JKQTPCustomGraphSymbolStore , i . e . these are available throughout the runtime of the program
*
* \ see JKQTPCustomGraphSymbolFunctor for an example
*/
JKQTCOMMON_LIB_EXPORT JKQTPGraphSymbols JKQTPRegisterCustomGraphSymbol ( const JKQTPCustomGraphSymbolFunctor & ) ;
2019-05-30 04:40:02 +08:00
/** \brief converts a JKQTPGraphSymbols variable into a identifier string
* \ ingroup jkqtptools_drawing
*/
2019-06-22 20:21:32 +08:00
JKQTCOMMON_LIB_EXPORT QString JKQTPGraphSymbols2String ( JKQTPGraphSymbols pos ) ;
2019-05-30 04:40:02 +08:00
/** \brief converts a JKQTPGraphSymbols variable into a human-readable string
* \ ingroup jkqtptools_drawing
*/
2019-06-22 20:21:32 +08:00
JKQTCOMMON_LIB_EXPORT QString JKQTPGraphSymbols2NameString ( JKQTPGraphSymbols pos ) ;
2019-05-30 04:40:02 +08:00
/** \brief converts a String into a JKQTPGraphSymbols
* \ ingroup jkqtptools_drawing
*/
2019-06-22 20:21:32 +08:00
JKQTCOMMON_LIB_EXPORT JKQTPGraphSymbols String2JKQTPGraphSymbols ( const QString & pos ) ;
2019-05-30 04:40:02 +08:00
2022-09-08 03:50:58 +08:00
inline QDataStream & operator < < ( QDataStream & str , JKQTPGraphSymbols s ) {
2022-09-08 04:00:09 +08:00
str < < static_cast < quint64 > ( s ) ;
2022-09-08 03:50:58 +08:00
return str ;
}
inline QDataStream & operator > > ( QDataStream & str , JKQTPGraphSymbols & s ) {
2022-09-08 04:00:09 +08:00
str < < reinterpret_cast < quint64 & > ( s ) ;
2022-09-08 03:50:58 +08:00
return str ;
}
2023-06-25 23:55:05 +08:00
/*! \brief plot the specified symbol at pixel position x,y, <b>thread-safe</b>
2022-09-06 18:39:23 +08:00
\ ingroup jkqtptools_drawing
\ tparam TPainter Type of \ a painter : A class like JKQTPEnhancedPainter or < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a >
\ param painter the < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a > to draw to
\ param x x - coordinate of the symbol center
\ param y y - coordinate of the symbol center
\ param symbol type of the symbol to plot , see JKQTPGraphSymbols
\ param size size ( width / height ) of the symbol around ( \ a x , \ a y )
\ param symbolLineWidth width of the lines used to draw the symbol
\ param color color of the symbol lines
\ param fillColor color of the symbol filling
\ param symbolFont font used to draw symbols like \ c JKQTPCharacterSymbol + QChar ( ' @ ' ) . unicode ( )
*/
template < class TPainter >
inline void JKQTPPlotSymbol ( TPainter & painter , double x , double y , JKQTPGraphSymbols symbol , double size , double symbolLineWidth , QColor color , QColor fillColor , QFont symbolFont ) ;
2023-06-25 23:55:05 +08:00
/*! \brief plot the specified symbol at pixel position x,y, <b>thread-safe</b>
2022-09-06 18:39:23 +08:00
\ ingroup jkqtptools_drawing
\ param paintDevice the paint device to draw on
\ param x x - coordinate of the symbol center
\ param y y - coordinate of the symbol center
\ param symbol type of the symbol to plot , see JKQTPGraphSymbols
\ param size size ( width / height ) of the symbol around ( \ a x , \ a y )
\ param symbolLineWidth width of the lines used to draw the symbol
\ param color color of the symbol lines
\ param fillColor color of the symbol filling
\ param symbolFont font used to draw symbols like \ c JKQTPCharacterSymbol + QChar ( ' @ ' ) . unicode ( )
*/
JKQTCOMMON_LIB_EXPORT void JKQTPPlotSymbol ( QPaintDevice & paintDevice , double x , double y , JKQTPGraphSymbols symbol , double size , double symbolLineWidth , QColor color , QColor fillColor , const QFont & symbolFont ) ;
2019-05-30 04:40:02 +08:00
2020-08-22 00:31:58 +08:00
/** \brief symbols that can be used to plot a datapoint for a graph
* \ ingroup jkqtptools_drawing
2020-08-23 19:13:53 +08:00
*
* \ image html geo_arrow_tips . png
*
* Note that all arrows end at the designated line - end ( here indicated by dashed grey lines ) , even circles and rectangle :
*
* \ image html geo_arrow_tipsatlineend . png
*
2022-09-24 02:43:53 +08:00
*
* \ see JKQTPPlotLineDecorator ( ) , JKQTPPlotDecoratedLine ( ) , JKQTPLineDecoratorStyle , JKQTPLineDecoratorStyleCalcDecoratorSize ( )
*
* \ see \ ref JKQTPlotterGeometricArrows and \ ref JKQTPlotterGeometricGraphs for usage examples .
2020-08-22 00:31:58 +08:00
*/
enum JKQTPLineDecoratorStyle {
2022-09-06 17:07:52 +08:00
JKQTPNoDecorator = 0 , /*!< \brief no decorator, i.e. a simple line-end \image html linedecorators/none.png */
JKQTPArrow , /*!< \brief a simple arrow tip, unfilled \image html linedecorators/arrow.png */
JKQTPFilledArrow , /*!< \brief a nice filled arrow tip \image html linedecorators/filled_arrow.png */
JKQTPTriangleDecorator , /*!< \brief a triangular arrow tip \image html linedecorators/triangle.png */
JKQTPFilledTriangleDecorator , /*!< \brief a triangular filled arrow tip \image html linedecorators/filled_triangle.png */
JKQTPTriangleDecoratorAndBar , /*!< \brief a triangular arrow tip, with vertical bar \image html linedecorators/triangle_bar.png */
JKQTPFilledTriangleDecoratorAndBar , /*!< \brief a triangular filled arrow tip, with vertical bar \image html linedecorators/filled_triangle_bar.png */
JKQTPDoubleArrow , /*!< \brief a nice double-arrow tip \image html linedecorators/double_arrow.png*/
JKQTPFilledDoubleArrow , /*!< \brief a nice filled double-arrow tip \image html linedecorators/filled_double_arrow.png */
JKQTPCircleDecorator , /*!< \brief an open circle tip \image html linedecorators/circle.png */
JKQTPFilledCircleDecorator , /*!< \brief a filled circle tip \image html linedecorators/filled_circle.png */
JKQTPRectangleDecorator , /*!< \brief an open rectangle tip \image html linedecorators/rectangle.png */
JKQTPFilledRectangleDecorator , /*!< \brief a filled rectangle tip \image html linedecorators/filled_rectangle.png */
JKQTPArrowAndBar , /*!< \brief a simple arrow tip, unfilled, with vertical bar \image html linedecorators/arrow_bar.png */
JKQTPDoubleArrowAndBar , /*!< \brief a simple double-arrow tip, unfilled, with vertical bar \image html linedecorators/double_arrow_bar.png */
JKQTPBarDecorator , /*!< \brief a full vertical bar \image html linedecorators/bar.png */
JKQTPBracketDecorator , /*!< \brief a vertical bracket decorator \image html linedecorators/bracket.png */
JKQTPDiamondDecorator , /*!< \brief an open diamond tip \image html linedecorators/diamond.png */
JKQTPDiamondDecoratorAndBar , /*!< \brief an open diamond tip \image html linedecorators/diamond_bar.png */
JKQTPFilledDiamondDecorator , /*!< \brief a filled diamond tip \image html linedecorators/filled_diamond.png */
2022-09-20 03:53:53 +08:00
JKQTPFilledDiamondDecoratorAndBar , /*!< \brief a filled diamond tip \image html linedecorators/filled_diamond_bar.png */
2022-09-06 17:07:52 +08:00
JKQTPHalfBarDecorator , /*!< \brief a half vertical bar \image html linedecorators/half_bar.png */
JKQTPHarpoonDecorator , /*!< \brief an harpoon arrow \image html linedecorators/harpoon.png */
JKQTPHarpoonDecoratorAndBar , /*!< \brief an harpoon arrow, with vertical bar \image html linedecorators/harpoon_bar.png */
JKQTPSkewedBarDecorator , /*!< \brief a skewed vertical bar \image html linedecorators/skewed_bar.png */
2020-08-23 19:13:53 +08:00
JKQTPLineDecoratorCount , /*!< \brief can be used to iterate over all symbols using: <code>for (int i=0; i<static_cast<int>(JKQTPLineDecoratorCount); i++) { JKQTPLineDecoratorStyle s=static_cast<JKQTPLineDecoratorStyle>(i); ... }</code> */
JKQTPMaxLineDecoratorID = JKQTPLineDecoratorCount - 1 , /*!< \brief points to the last available symbol, can be used to iterate over all symbols: <code>for (int i=0; i<=static_cast<int>(JKQTPMaxLineDecoratorID); i++) { JKQTPLineDecoratorStyle s=static_cast<JKQTPLineDecoratorStyle>(i); ... }</code> */
2020-08-22 00:31:58 +08:00
JKQTPDefaultLineDecorator = JKQTPFilledArrow /*!< \brief a default symbol used for plotting */
} ;
/** \brief converts a JKQTPLineDecoratorStyle variable into a identifier string
* \ ingroup jkqtptools_drawing
*/
JKQTCOMMON_LIB_EXPORT QString JKQTPLineDecoratorStyle2String ( JKQTPLineDecoratorStyle pos ) ;
/** \brief converts a JKQTPLineDecoratorStyle variable into a human-readable string
* \ ingroup jkqtptools_drawing
*/
JKQTCOMMON_LIB_EXPORT QString JKQTPLineDecoratorStyle2NameString ( JKQTPLineDecoratorStyle pos ) ;
/** \brief converts a String into a JKQTPLineDecoratorStyle
* \ ingroup jkqtptools_drawing
*/
JKQTCOMMON_LIB_EXPORT JKQTPLineDecoratorStyle String2JKQTPLineDecoratorStyle ( const QString & pos ) ;
/*! \brief plot the specified symbol at pixel position x,y. Note that this function only draws the decorator, NOT the line pointing to it!
\ ingroup jkqtptools_drawing
\ tparam TPainter Type of \ a painter : A class like JKQTPEnhancedPainter or < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a >
\ param painter the < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a > to draw to
\ param x x - coordinate of the decorator tip
\ param y y - coordinate of the decorator tip
\ param angle_rad angle of the line pointing to ( x , y ) , given in radians , 0 rad points to the right , > 0 rad is a counter - clockwise rotation , as calculated by atan2 ( ) from dx , dy of a line !
\ param style type of the decorator to plot , see JKQTPLineDecoratorStyle
2022-09-24 02:43:53 +08:00
\ param size size of the decorator in pixels , the decorator fills at most the space \ c x . . . x + size and \ c y - size / 2. . . y - size / 2 , but may be smaller ( e . g . arrows are typically less high than the full \ a size pixels ) .
2020-08-22 00:31:58 +08:00
\ param [ out ] line_start optional output parameter : when drawing the line let it end here , not necessarily at ( x , y )
2022-09-24 02:43:53 +08:00
\ see JKQTPPlotLineDecorator ( ) , JKQTPPlotDecoratedLine ( ) , JKQTPLineDecoratorStyle , JKQTPLineDecoratorStyleCalcDecoratorSize ( )
2020-08-22 00:31:58 +08:00
*/
template < class TPainter >
inline void JKQTPPlotLineDecorator ( TPainter & painter , double x , double y , double angle_rad , JKQTPLineDecoratorStyle style , double size , QPointF * line_start = nullptr ) ;
2022-09-06 17:07:52 +08:00
/*! \brief plot a line with the given decorators \a style1 and a style2 at the start- and end-point repsectively, using the painter's current pen
\ ingroup jkqtptools_drawing
\ tparam TPainter Type of \ a painter : A class like JKQTPEnhancedPainter or < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a >
\ param painter the < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a > to draw to
\ param l line to draw
\ param style1 type of the first decorator to plot , see JKQTPLineDecoratorStyle
\ param size1 size of the first decorator
\ param style2 type of the second decorator to plot , see JKQTPLineDecoratorStyle
\ param size2 size of the second decorator
2022-09-24 02:43:53 +08:00
\ note a decorator fills at most the space \ c x . . . x + size and \ c y - size / 2. . . y - size / 2 ( where \ c size is \ a size1 or \ a size2 ) , but may be smaller ( e . g . arrows are typically less high than the full \ c size pixels ) .
\ see JKQTPPlotLineDecorator ( ) , JKQTPPlotDecoratedLine ( ) , JKQTPLineDecoratorStyle , JKQTPLineDecoratorStyleCalcDecoratorSize ( )
2022-09-06 17:07:52 +08:00
*/
template < class TPainter >
inline void JKQTPPlotDecoratedLine ( TPainter & painter , const QLineF & l , JKQTPLineDecoratorStyle style1 , double size1 , JKQTPLineDecoratorStyle style2 , double size2 ) ;
2022-09-24 02:43:53 +08:00
/*! \brief calculates the tail decorator size from the line width \a line_width, using decoratorSizeFactor and a non-linear scaling function that levels off towards small \a line_width and increases sub-linearly for large ones, so the arrow heads to not grow too much
\ ingroup jkqtptools_drawing
\ see JKQTPPlotLineDecorator ( ) , JKQTPPlotDecoratedLine ( ) , JKQTPLineDecoratorStyle , JKQTPLineDecoratorStyleCalcDecoratorSize ( )
*/
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
JKQTCOMMON_LIB_EXPORT double JKQTPLineDecoratorStyleCalcDecoratorSize ( double line_width , double decoratorSizeFactor ) ;
2019-05-30 04:40:02 +08:00
2022-08-25 21:17:50 +08:00
/*! \brief clips the given line (\a x1 , \a y1 ) -- (\a x2 , \a y2 ) to the given rectangle \a xmin .. \a xmax and \a ymin ... \a ymax
\ ingroup jkqtptools_drawing
\ return the clipped line in \ a x1 , \ a y1 , \ a x2 , \ a y2 and \ c true if the line is still to be drawn or \ c false else
This function implements the algorithm descripbed in https : //www.researchgate.net/publication/335018076_Another_Simple_but_Faster_Method_for_2D_Line_Clipping
i . e . in Pseudocode
\ verbatim
// x1 , y1 , x2 , y2 , xmin , ymax , xmax , ymin //
if not ( x1 < xmin and x2 < xmin ) and not ( x1 > xmax and x2 > xmax ) then
if not ( y1 < ymin and y2 < ymin ) and not ( y1 > ymax and y2 > ymax ) then
x [ 1 ] = x1
y [ 1 ] = y1
x [ 2 ] = x2
y [ 2 ] = y2
i = 1
repeat
if x [ i ] < xmin then
x [ i ] = xmin
y [ i ] = ( ( y2 - y1 ) / ( x2 - x1 ) ) * ( xmin - x1 ) + y1
elseif x [ i ] > xmax then
x [ i ] = xmax
y [ i ] = ( ( y2 - y1 ) / ( x2 - x1 ) ) * ( xmax - x1 ) + y1
endif
if y [ i ] < ymin then
y [ i ] = ymin
x [ i ] = ( ( x2 - x1 ) / ( y2 - y1 ) ) * ( ymin - y1 ) + x1
elseif y [ i ] > ymax then
y [ i ] = ymax
x [ i ] = ( ( x2 - x1 ) / ( y2 - y1 ) ) * ( ymax - y1 ) + x1
endif
i = i + 1
until i > 2
if not ( x [ 1 ] < xmin and x [ 2 ] < xmin ) and not ( x [ 1 ] > xmax and x [ 2 ] > xmax ) then
drawLine ( x [ 1 ] , y [ 1 ] , x [ 2 ] , y [ 2 ] )
endif
endif
endif
\ endverbatim
*/
inline bool JKQTPClipLine ( double & x1 , double & y1 , double & x2 , double & y2 , double xmin , double xmax , double ymin , double ymax ) {
if ( ! ( x1 < xmin & & x2 < xmin ) & & ! ( x1 > xmax & & x2 > xmax ) ) {
if ( ! ( y1 < ymin & & y2 < ymin ) & & ! ( y1 > ymax & & y2 > ymax ) ) {
double x [ 2 ] = { x1 , x2 } ;
double y [ 2 ] = { y1 , y2 } ;
for ( int i = 0 ; i < 2 ; i + + ) {
if ( x [ i ] < xmin ) {
x [ i ] = xmin ;
y [ i ] = ( ( y2 - y1 ) / ( x2 - x1 ) ) * ( xmin - x1 ) + y1 ;
} else if ( x [ i ] > xmax ) {
x [ i ] = xmax ;
y [ i ] = ( ( y2 - y1 ) / ( x2 - x1 ) ) * ( xmax - x1 ) + y1 ;
}
if ( y [ i ] < ymin ) {
y [ i ] = ymin ;
x [ i ] = ( ( x2 - x1 ) / ( y2 - y1 ) ) * ( ymin - y1 ) + x1 ;
} else if ( y [ i ] > ymax ) {
y [ i ] = ymax ;
x [ i ] = ( ( x2 - x1 ) / ( y2 - y1 ) ) * ( ymax - y1 ) + x1 ;
}
}
if ( ! ( x [ 0 ] < xmin & & x [ 1 ] < xmin ) & & ! ( x [ 0 ] > xmax & & x [ 1 ] > xmax ) ) {
x1 = x [ 0 ] ;
y1 = y [ 0 ] ;
x2 = x [ 1 ] ;
y2 = y [ 1 ] ;
return true ;
}
}
}
return false ;
}
/*! \brief clips the given line \a line to the given rectangle rectangle \a xmin .. \a xmax and \a ymin ... \a ymax
\ ingroup jkqtptools_drawing
\ return the clipped line or a line with 0 - length , i . e . QLineF ( )
This function implements the algorithm descripbed in https : //www.researchgate.net/publication/335018076_Another_Simple_but_Faster_Method_for_2D_Line_Clipping
*/
inline QLineF JKQTPClipLine ( const QLineF & line , double xmin , double xmax , double ymin , double ymax ) {
double x1 = line . x1 ( ) ;
double y1 = line . y1 ( ) ;
double x2 = line . x2 ( ) ;
double y2 = line . y2 ( ) ;
if ( JKQTPClipLine ( x1 , y1 , x2 , y2 , xmin , xmax , ymin , ymax ) ) {
return QLineF ( x1 , y1 , x2 , y2 ) ;
} else {
return QLineF ( ) ;
}
}
/*! \brief clips the given line \a line to the given rectangle \a clipRect
\ ingroup jkqtptools_drawing
\ param line line to be clipped
\ param clipRect rectangle to clip to
\ return the clipped line or a line with 0 - length , i . e . QLineF ( )
This function implements the algorithm descripbed in https : //www.researchgate.net/publication/335018076_Another_Simple_but_Faster_Method_for_2D_Line_Clipping
*/
inline QLineF JKQTPClipLine ( const QLineF & line , const QRectF & clipRect ) {
const double xmin = qMin ( clipRect . left ( ) , clipRect . right ( ) ) ;
const double xmax = qMax ( clipRect . left ( ) , clipRect . right ( ) ) ;
const double ymin = qMin ( clipRect . top ( ) , clipRect . bottom ( ) ) ;
const double ymax = qMax ( clipRect . top ( ) , clipRect . bottom ( ) ) ;
double x1 = line . x1 ( ) ;
double y1 = line . y1 ( ) ;
double x2 = line . x2 ( ) ;
double y2 = line . y2 ( ) ;
if ( JKQTPClipLine ( x1 , y1 , x2 , y2 , xmin , xmax , ymin , ymax ) ) {
return QLineF ( x1 , y1 , x2 , y2 ) ;
} else {
return QLineF ( ) ;
}
}
/*! \brief clips the given list of poly-lines \a polylines_in to the given rectangle \a clipRect
\ ingroup jkqtptools_drawing
\ param polylines_in list of poly - lines to be clipped
\ param clipRect rectangle to clip to
\ return a list of poly - lines representing the clipped lines . Note that some lines may be split further so the number of poly - lines in the output may actually be larger than the number of polylines in the input !
*/
2022-08-25 23:46:57 +08:00
JKQTCOMMON_LIB_EXPORT QList < QPolygonF > JKQTPClipPolyLines ( const QList < QPolygonF > & polylines_in , const QRectF & clipRect ) ;
2022-08-25 21:17:50 +08:00
/*! \brief clips the given poly-line \a polyline_in to the given rectangle \a clipRect
\ ingroup jkqtptools_drawing
\ param polyline_in poly - line to be clipped
\ param clipRect rectangle to clip to
\ return a list of poly - lines representing the clipped line .
*/
2022-08-25 23:46:57 +08:00
JKQTCOMMON_LIB_EXPORT QList < QPolygonF > JKQTPClipPolyLine ( const QPolygonF & polyline_in , const QRectF & clipRect ) ;
2022-08-25 21:17:50 +08:00
2022-08-26 04:32:34 +08:00
/*! \brief tries to reduce the complexity of the given list of poly-lines \a lines_in, but keeping the appearance as if all lines were drawn
\ ingroup jkqtptools_drawing
\ param lines_in list of poly - lines to be simplified
\ param maxDeltaXY a group has to be either less wide or less high than this , typically equals the linewidth of the poly - line
\ return a simplified version of lines_in
*/
JKQTCOMMON_LIB_EXPORT QList < QPolygonF > JKQTPSimplifyPolyLines ( const QList < QPolygonF > & lines_in , double maxDeltaXY = 1.0 ) ;
2022-08-25 21:17:50 +08:00
/*! \brief tries to reduce the complexity of the given poly-line \a lines_in, but keeping the appearance as if all lines were drawn
\ ingroup jkqtptools_drawing
\ param lines_in poly - line to be simplified
\ param maxDeltaXY a group has to be either less wide or less high than this , typically equals the linewidth of the poly - line
\ return a simplified version of lines_in
*/
2022-08-25 23:46:57 +08:00
JKQTCOMMON_LIB_EXPORT QPolygonF JKQTPSimplifyPolyLines ( const QPolygonF & lines_in , double maxDeltaXY = 1.0 ) ;
2022-08-25 21:17:50 +08:00
2019-05-30 04:40:02 +08:00
/*! \brief draw a tooltip, using the current brush and pen of the provided painter
\ ingroup jkqtptools_drawing
\ tparam TPainter Type of \ a painter : A class like JKQTPEnhancedPainter or < a href = " http://doc.qt.io/qt-5/qpainter.html " > QPainter < / a >
\ param painter QPainter - like object to use for painting
\ param x x - coordinate of position the tooltip points to
\ param y y - coordinate of position the tooltip points to
\ param rect rectangle of the main tooltip area
2020-08-23 19:30:20 +08:00
\ image html tooltiptool_example . png
2019-05-30 04:40:02 +08:00
*/
template < class TPainter >
inline void JKQTPDrawTooltip ( TPainter & painter , double x , double y , const QRectF & rect ) ;
2023-06-25 23:55:05 +08:00
/*! \brief return the consecutive ccordinates of the tips of a N-tipped star on a circle of radius 1.
Inner tips are on a irle of radius \ a inner_radius .
\ ingroup jkqtptools_drawing
*/
template < int N >
inline std : : array < QPointF , N * 2 > JKQTPGetStarCoordinates ( double inner_radius = 0.5 ) {
std : : array < QPointF , N * 2 > star_coords ;
const double angle = 360.0 / double ( N ) / 180.0 * JKQTPSTATISTICS_PI ;
for ( int i = 0 ; i < N ; i + + ) {
const double a = ( static_cast < double > ( i ) + 0.5 ) * angle ;
star_coords [ i * 2 ] = QPointF ( sin ( a ) , cos ( a ) ) ;
star_coords [ i * 2 + 1 ] = QPointF ( inner_radius * sin ( a + angle / 2.0 ) , inner_radius * cos ( a + angle / 2.0 ) ) ;
}
return star_coords ;
}
2019-05-30 04:40:02 +08:00
2023-06-25 23:55:05 +08:00
/** \brief internal datastructure used in JKQTPPlotSymbol() to precalculate certain data only once per runtime
* \ ingroup jkqtptools_drawing
* \ internal
*/
struct JKQTPSymbolPathsInternnal {
inline JKQTPSymbolPathsInternnal ( ) : pathsrotation ( 0 ) { } ;
QPainterPath paths ;
QPainterPath filledpaths ;
QVector < QLineF > lines ;
QPolygonF polygons ;
QPolygonF filledpolygons ;
qreal pathsrotation ;
} ;
2019-05-30 04:40:02 +08:00
template < class TPainter >
2022-09-02 20:19:47 +08:00
inline void JKQTPPlotSymbol ( TPainter & painter , double x , double y , JKQTPGraphSymbols symbol , double symbolSize , double symbolLineWidth , QColor color , QColor fillColor , QFont symbolFont ) {
2022-08-25 21:17:50 +08:00
if ( symbol = = JKQTPNoSymbol ) return ;
2019-05-30 04:40:02 +08:00
painter . save ( ) ; auto __finalpaint = JKQTPFinally ( [ & painter ] ( ) { painter . restore ( ) ; } ) ;
QPen p = painter . pen ( ) ;
p . setColor ( color ) ;
p . setWidthF ( qMax ( JKQTPlotterDrawingTools : : ABS_MIN_LINEWIDTH , symbolLineWidth ) ) ;
p . setStyle ( Qt : : SolidLine ) ;
p . setCapStyle ( Qt : : FlatCap ) ;
2022-09-02 18:27:12 +08:00
QPen pDescaled = p ;
pDescaled . setWidthF ( pDescaled . widthF ( ) / symbolSize ) ;
2022-09-06 17:57:58 +08:00
QFont fDescaled = symbolFont ;
fDescaled . setPointSizeF ( fDescaled . pointSizeF ( ) / symbolSize ) ;
2022-09-02 18:27:12 +08:00
const QBrush b = QBrush ( fillColor , Qt : : SolidPattern ) ;
2023-06-25 23:55:05 +08:00
static std : : vector < JKQTPSymbolPathsInternnal > all_paths = [ ] ( ) {
// this functor is called the the static variable symbolData is initialized, but only once per runtimme (guaranteed by C++)
std : : vector < JKQTPSymbolPathsInternnal > all_paths ;
all_paths . resize ( JKQTPSymbolCount ) ;
2022-09-02 18:27:12 +08:00
2023-06-25 23:55:05 +08:00
// calculate star cordinates as static values
const double s45 = fabs ( cos ( 45.0 / 180.0 * JKQTPSTATISTICS_PI ) ) ;
const auto star5cords = JKQTPGetStarCoordinates < 5 > ( 0.5 ) ;
const auto star6cords = JKQTPGetStarCoordinates < 6 > ( 0.5 ) ;
const auto star8cords = JKQTPGetStarCoordinates < 8 > ( 0.5 ) ;
all_paths [ JKQTPCross ] . paths . moveTo ( - 0.5 , - 0.5 ) ;
all_paths [ JKQTPCross ] . paths . lineTo ( 0.5 , 0.5 ) ;
all_paths [ JKQTPCross ] . paths . moveTo ( - 0.5 , + 0.5 ) ;
all_paths [ JKQTPCross ] . paths . lineTo ( + 0.5 , - 0.5 ) ;
all_paths [ JKQTPPlus ] . paths . moveTo ( - 0.5 , 0 ) ;
all_paths [ JKQTPPlus ] . paths . lineTo ( 0.5 , 0 ) ;
all_paths [ JKQTPPlus ] . paths . moveTo ( 0 , + 0.5 ) ;
all_paths [ JKQTPPlus ] . paths . lineTo ( 0 , - 0.5 ) ;
all_paths [ JKQTPCircle ] . paths . addEllipse ( QPointF ( 0 , 0 ) , 0.5 , 0.5 ) ;
all_paths [ JKQTPFilledCircle ] . filledpaths = all_paths [ JKQTPCircle ] . paths ;
all_paths [ JKQTPCircleCross ] . paths . addEllipse ( QPointF ( 0 , 0 ) , 0.5 , 0.5 ) ;
all_paths [ JKQTPCircleCross ] . paths . moveTo ( - 0.5 * s45 , - 0.5 * s45 ) ;
all_paths [ JKQTPCircleCross ] . paths . lineTo ( 0.5 * s45 , 0.5 * s45 ) ;
all_paths [ JKQTPCircleCross ] . paths . moveTo ( - 0.5 * s45 , + 0.5 * s45 ) ;
all_paths [ JKQTPCircleCross ] . paths . lineTo ( + 0.5 * s45 , - 0.5 * s45 ) ;
all_paths [ JKQTPCirclePlus ] . paths . addEllipse ( QPointF ( 0 , 0 ) , 0.5 , 0.5 ) ;
all_paths [ JKQTPCirclePlus ] . paths . moveTo ( - 0.5 , 0 ) ;
all_paths [ JKQTPCirclePlus ] . paths . lineTo ( 0.5 , 0 ) ;
all_paths [ JKQTPCirclePlus ] . paths . moveTo ( 0 , + 0.5 ) ;
all_paths [ JKQTPCirclePlus ] . paths . lineTo ( 0 , - 0.5 ) ;
all_paths [ JKQTPCirclePeace ] . paths . addEllipse ( QPointF ( 0 , 0 ) , 0.5 , 0.5 ) ;
all_paths [ JKQTPCirclePeace ] . paths . moveTo ( 0 , - 0.5 ) ;
all_paths [ JKQTPCirclePeace ] . paths . lineTo ( 0 , 0.5 ) ;
all_paths [ JKQTPCirclePeace ] . paths . moveTo ( 0 , 0 ) ;
all_paths [ JKQTPCirclePeace ] . paths . lineTo ( 0.5 * s45 , 0.5 * s45 ) ;
all_paths [ JKQTPCirclePeace ] . paths . moveTo ( 0 , 0 ) ;
all_paths [ JKQTPCirclePeace ] . paths . lineTo ( - 0.5 * s45 , 0.5 * s45 ) ;
all_paths [ JKQTPPeace ] . paths . moveTo ( 0 , - 0.5 ) ;
all_paths [ JKQTPPeace ] . paths . lineTo ( 0 , 0.5 ) ;
all_paths [ JKQTPPeace ] . paths . moveTo ( 0 , 0 ) ;
all_paths [ JKQTPPeace ] . paths . lineTo ( 0.5 * s45 , 0.5 * s45 ) ;
all_paths [ JKQTPPeace ] . paths . moveTo ( 0 , 0 ) ;
all_paths [ JKQTPPeace ] . paths . lineTo ( - 0.5 * s45 , 0.5 * s45 ) ;
all_paths [ JKQTPTarget ] . paths . addEllipse ( QPointF ( 0 , 0 ) , 0.33333 , 0.33333 ) ;
all_paths [ JKQTPTarget ] . paths . moveTo ( QPointF ( 0 , - 0.5 ) ) ;
all_paths [ JKQTPTarget ] . paths . lineTo ( QPointF ( 0 , 0.5 ) ) ;
all_paths [ JKQTPTarget ] . paths . moveTo ( QPointF ( - 0.5 , 0 ) ) ;
all_paths [ JKQTPTarget ] . paths . lineTo ( QPointF ( 0.5 , 0 ) ) ;
all_paths [ JKQTPFemale ] . paths . addEllipse ( - 0.25 , - 0.5 , 0.5 , 0.5 ) ;
all_paths [ JKQTPFemale ] . paths . moveTo ( 0 , 0 ) ;
all_paths [ JKQTPFemale ] . paths . lineTo ( 0 , 0.5 ) ;
all_paths [ JKQTPFemale ] . paths . moveTo ( - 0.5 / 3.0 , 0.5 / 2.0 ) ;
all_paths [ JKQTPFemale ] . paths . lineTo ( 0.5 / 3.0 , 0.5 / 2.0 ) ;
all_paths [ JKQTPMale ] . paths . addEllipse ( QRectF ( - 0.5 / 2.0 , - 0.5 / 2.0 , 0.5 , 0.5 ) ) ;
all_paths [ JKQTPMale ] . paths . moveTo ( QPointF ( + 0.5 / 2.0 * cos ( 45.0 / 180.0 * JKQTPSTATISTICS_PI ) , - 0.5 / 2.0 * cos ( 45.0 / 180.0 * JKQTPSTATISTICS_PI ) ) ) ;
all_paths [ JKQTPMale ] . paths . lineTo ( QPointF ( + 0.5 , - 0.5 ) ) ;
all_paths [ JKQTPMale ] . paths . moveTo ( QPointF ( + 0.5 - 0.5 / 2.0 , - 0.5 ) ) ;
all_paths [ JKQTPMale ] . paths . lineTo ( QPointF ( + 0.5 , - 0.5 ) ) ;
all_paths [ JKQTPMale ] . paths . lineTo ( QPointF ( + 0.5 , - 0.5 + 0.5 / 2.0 ) ) ;
all_paths [ JKQTPRect ] . paths . addRect ( - 0.5 , - 0.5 , 1 , 1 ) ;
all_paths [ JKQTPFilledRect ] . filledpaths = all_paths [ JKQTPRect ] . paths ;
all_paths [ JKQTPRectCross ] . paths . addRect ( - 0.5 , - 0.5 , 1 , 1 ) ;
all_paths [ JKQTPRectCross ] . paths . moveTo ( - 0.5 , - 0.5 ) ;
all_paths [ JKQTPRectCross ] . paths . lineTo ( 0.5 , 0.5 ) ;
all_paths [ JKQTPRectCross ] . paths . moveTo ( - 0.5 , + 0.5 ) ;
all_paths [ JKQTPRectCross ] . paths . lineTo ( + 0.5 , - 0.5 ) ;
all_paths [ JKQTPRectPlus ] . paths . addRect ( - 0.5 , - 0.5 , 1 , 1 ) ;
all_paths [ JKQTPRectPlus ] . paths . moveTo ( - 0.5 , 0 ) ;
all_paths [ JKQTPRectPlus ] . paths . lineTo ( 0.5 , 0 ) ;
all_paths [ JKQTPRectPlus ] . paths . moveTo ( 0 , + 0.5 ) ;
all_paths [ JKQTPRectPlus ] . paths . lineTo ( 0 , - 0.5 ) ;
all_paths [ JKQTPCurvedTriangle ] . paths . moveTo ( 0 , 0 - 0.5 ) ;
all_paths [ JKQTPCurvedTriangle ] . paths . quadTo ( 0 - 1.0 / 10.0 , 0 + 1.0 / 4.0 , 0 - 0.5 , 0 + 0.5 ) ;
all_paths [ JKQTPCurvedTriangle ] . paths . quadTo ( 0 , 0 + 1.0 / 4.0 , 0 + 0.5 , 0 + 0.5 ) ;
all_paths [ JKQTPCurvedTriangle ] . paths . quadTo ( 0 + 1.0 / 10.0 , 0 + 1.0 / 4.0 , 0 , 0 - 0.5 ) ;
all_paths [ JKQTPFilledCurvedTriangle ] . filledpaths = all_paths [ JKQTPCurvedTriangle ] . paths ;
all_paths [ JKQTPDownCurvedTriangle ] . paths = all_paths [ JKQTPCurvedTriangle ] . paths ;
all_paths [ JKQTPDownCurvedTriangle ] . pathsrotation = 180.0 ;
all_paths [ JKQTPFilledDownCurvedTriangle ] . filledpaths = all_paths [ JKQTPDownCurvedTriangle ] . paths ;
all_paths [ JKQTPFilledDownCurvedTriangle ] . pathsrotation = 180.0 ;
all_paths [ JKQTPLeftCurvedTriangle ] . paths = all_paths [ JKQTPCurvedTriangle ] . paths ;
all_paths [ JKQTPLeftCurvedTriangle ] . pathsrotation = - 90.0 ;
all_paths [ JKQTPFilledLeftCurvedTriangle ] . filledpaths = all_paths [ JKQTPLeftCurvedTriangle ] . paths ;
all_paths [ JKQTPFilledLeftCurvedTriangle ] . pathsrotation = - 90.0 ;
all_paths [ JKQTPRightCurvedTriangle ] . paths = all_paths [ JKQTPCurvedTriangle ] . paths ;
all_paths [ JKQTPRightCurvedTriangle ] . pathsrotation = 90.0 ;
all_paths [ JKQTPFilledRightCurvedTriangle ] . filledpaths = all_paths [ JKQTPRightCurvedTriangle ] . paths ;
all_paths [ JKQTPFilledRightCurvedTriangle ] . pathsrotation = 90.0 ;
2022-09-02 18:27:12 +08:00
{
QPolygonF poly ;
poly < < QPointF ( 0.0 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 ) ;
poly < < poly [ 0 ] ;
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPDiamondPlus ] . paths . addPolygon ( poly ) ;
all_paths [ JKQTPDiamondPlus ] . paths . moveTo ( poly [ 0 ] ) ;
all_paths [ JKQTPDiamondPlus ] . paths . lineTo ( poly [ 2 ] ) ;
all_paths [ JKQTPDiamondPlus ] . paths . moveTo ( poly [ 1 ] ) ;
all_paths [ JKQTPDiamondPlus ] . paths . lineTo ( poly [ 3 ] ) ;
2022-09-02 18:27:12 +08:00
}
{
QPolygonF poly ;
poly < < QPointF ( 0.0 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 ) ;
poly < < poly [ 0 ] ;
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPDiamondCross ] . paths . addPolygon ( poly ) ;
all_paths [ JKQTPDiamondCross ] . paths . moveTo ( ( poly [ 0 ] + poly [ 1 ] ) / 2.0 ) ;
all_paths [ JKQTPDiamondCross ] . paths . lineTo ( ( poly [ 2 ] + poly [ 3 ] ) / 2.0 ) ;
all_paths [ JKQTPDiamondCross ] . paths . moveTo ( ( poly [ 1 ] + poly [ 2 ] ) / 2.0 ) ;
all_paths [ JKQTPDiamondCross ] . paths . lineTo ( ( poly [ 3 ] + poly [ 0 ] ) / 2.0 ) ;
2022-09-02 18:27:12 +08:00
}
2023-06-29 14:44:20 +08:00
for ( size_t i = 0 ; i < star8cords . size ( ) ; i + = 2 ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPAsterisc8 ] . paths . moveTo ( star8cords [ i ] . x ( ) * 0.5 , star8cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPAsterisc8 ] . paths . lineTo ( 0 , 0 ) ;
2022-09-02 18:27:12 +08:00
}
2023-06-29 14:44:20 +08:00
for ( size_t i = 0 ; i < star6cords . size ( ) ; i + = 2 ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPAsterisc6 ] . paths . moveTo ( star6cords [ i ] . x ( ) * 0.5 , star6cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPAsterisc6 ] . paths . lineTo ( 0 , 0 ) ;
2022-09-02 18:27:12 +08:00
}
2023-06-29 14:44:20 +08:00
for ( size_t i = 0 ; i < star5cords . size ( ) ; i + = 2 ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPAsterisc ] . paths . moveTo ( star5cords [ i ] . x ( ) * 0.5 , star5cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPAsterisc ] . paths . lineTo ( 0 , 0 ) ;
2022-09-02 18:27:12 +08:00
}
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPRectTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) ;
all_paths [ JKQTPRectDownTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) ;
all_paths [ JKQTPRectLeftTriangle ] . polygons < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) ;
all_paths [ JKQTPRectRightTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) ;
all_paths [ JKQTPTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 , 0.0 - 0.5 ) ;
all_paths [ JKQTPFilledTriangle ] . filledpolygons = all_paths [ JKQTPTriangle ] . polygons ;
all_paths [ JKQTPDownTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) ;
all_paths [ JKQTPFilledDownTriangle ] . filledpolygons = all_paths [ JKQTPDownTriangle ] . polygons ;
all_paths [ JKQTPLeftTriangle ] . polygons < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) ;
all_paths [ JKQTPFilledLeftTriangle ] . filledpolygons = all_paths [ JKQTPLeftTriangle ] . polygons ;
all_paths [ JKQTPRightTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) ;
all_paths [ JKQTPFilledRightTriangle ] . filledpolygons = all_paths [ JKQTPRightTriangle ] . polygons ;
2023-06-29 14:44:20 +08:00
for ( size_t i = 0 ; i < star5cords . size ( ) ; i + + ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPstar ] . polygons < < QPointF ( 0.0 + star5cords [ i ] . x ( ) * 0.5 , 0.0 + star5cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPFilledStar ] . filledpolygons < < QPointF ( 0.0 + star5cords [ i ] . x ( ) * 0.5 , 0.0 + star5cords [ i ] . y ( ) * 0.5 ) ;
2022-09-02 18:27:12 +08:00
if ( i % 2 = = 0 ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPPentagon ] . polygons < < QPointF ( 0.0 + star5cords [ i ] . x ( ) * 0.5 , 0.0 + star5cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPFilledPentagon ] . filledpolygons < < QPointF ( 0.0 + star5cords [ i ] . x ( ) * 0.5 , 0.0 + star5cords [ i ] . y ( ) * 0.5 ) ;
2022-09-02 18:27:12 +08:00
}
}
2023-06-29 14:44:20 +08:00
for ( size_t i = 0 ; i < star6cords . size ( ) ; i + = 2 ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPHexagon ] . polygons < < QPointF ( 0.0 + star6cords [ i ] . x ( ) * 0.5 , 0.0 + star6cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPFilledHexagon ] . filledpolygons < < QPointF ( 0.0 + star6cords [ i ] . x ( ) * 0.5 , 0.0 + star6cords [ i ] . y ( ) * 0.5 ) ;
2019-05-30 04:40:02 +08:00
}
2023-06-29 14:44:20 +08:00
for ( size_t i = 0 ; i < star8cords . size ( ) ; i + = 2 ) {
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPOctagon ] . polygons < < QPointF ( 0.0 + star8cords [ i ] . x ( ) * 0.5 , 0.0 + star8cords [ i ] . y ( ) * 0.5 ) ;
all_paths [ JKQTPFilledOctagon ] . filledpolygons < < QPointF ( 0.0 + star8cords [ i ] . x ( ) * 0.5 , 0.0 + star8cords [ i ] . y ( ) * 0.5 ) ;
2022-09-02 18:27:12 +08:00
}
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPDiamond ] . polygons < < QPointF ( 0.0 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 ) ;
all_paths [ JKQTPFilledDiamond ] . filledpolygons = all_paths [ JKQTPDiamond ] . polygons ;
all_paths [ JKQTPHourglass ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) ;
all_paths [ JKQTPFilledHourglass ] . filledpolygons = all_paths [ JKQTPHourglass ] . polygons ;
all_paths [ JKQTPHorizontalHourglass ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) ;
all_paths [ JKQTPFilledHorizontalHourglass ] . filledpolygons = all_paths [ JKQTPHorizontalHourglass ] . polygons ;
all_paths [ JKQTPSantaClauseHouse ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 1.0 / 6.0 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 1.0 / 6.0 ) < < QPointF ( 0.0 , 0.0 - 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 1.0 / 6.0 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 1.0 / 6.0 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) ;
all_paths [ JKQTPFilledSantaClauseHouse ] . filledpolygons = all_paths [ JKQTPSantaClauseHouse ] . polygons ;
all_paths [ JKQTPUpDownTriangle ] . polygons < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 - 0.5 ) < < QPointF ( 0.0 , 0.0 + 0.5 ) < < QPointF ( 0.0 + 0.5 , 0.0 + 0.5 ) < < QPointF ( 0.0 , 0.0 - 0.5 ) < < QPointF ( 0.0 - 0.5 , 0.0 + 0.5 ) ;
all_paths [ JKQTPFilledUpDownTriangle ] . filledpolygons = all_paths [ JKQTPUpDownTriangle ] . polygons ;
all_paths [ JKQTPTripod ] . lines < < QLineF ( 0.0 , 0.0 - 0.5 , 0.0 , 0.0 )
2022-09-02 18:27:12 +08:00
< < QLineF ( 0.0 , 0.0 , 0.0 - s45 , 0.0 + s45 )
< < QLineF ( 0.0 , 0.0 , 0.0 + s45 , 0.0 + s45 ) ;
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPDownTripod ] . lines < < QLineF ( 0.0 , 0.0 + 0.5 , 0.0 , 0.0 )
2022-09-02 18:27:12 +08:00
< < QLineF ( 0.0 , 0.0 , 0.0 - s45 , 0.0 - s45 )
< < QLineF ( 0.0 , 0.0 , 0.0 + s45 , 0.0 - s45 ) ;
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPLeftTripod ] . lines < < QLineF ( 0.0 - 0.5 , 0.0 , 0.0 , 0.0 )
2022-09-02 18:27:12 +08:00
< < QLineF ( 0.0 , 0.0 , 0.0 + s45 , 0.0 - s45 )
< < QLineF ( 0.0 , 0.0 , 0.0 + s45 , 0.0 + s45 ) ;
2023-06-25 23:55:05 +08:00
all_paths [ JKQTPRightTripod ] . lines < < QLineF ( 0.0 + 0.5 , 0.0 , 0.0 , 0.0 )
2022-09-02 18:27:12 +08:00
< < QLineF ( 0.0 , 0.0 , 0.0 - s45 , 0.0 - s45 )
< < QLineF ( 0.0 , 0.0 , 0.0 - s45 , 0.0 + s45 ) ;
2023-06-25 23:55:05 +08:00
return all_paths ;
} ( ) ;
2019-05-30 04:40:02 +08:00
2022-08-30 15:44:40 +08:00
painter . setBrush ( QColor ( Qt : : transparent ) ) ;
painter . setPen ( p ) ;
2019-05-30 04:40:02 +08:00
switch ( symbol ) {
case JKQTPDot :
painter . drawPoint ( QPointF ( x , y ) ) ;
break ;
2022-09-02 18:27:12 +08:00
case JKQTPCross :
case JKQTPPlus :
case JKQTPCircle :
case JKQTPCircleCross :
case JKQTPCirclePlus :
case JKQTPCirclePeace :
case JKQTPPeace :
case JKQTPFemale :
case JKQTPMale :
case JKQTPTarget :
case JKQTPRect :
case JKQTPRectCross :
case JKQTPRectPlus :
case JKQTPDownCurvedTriangle :
case JKQTPCurvedTriangle :
case JKQTPLeftCurvedTriangle :
case JKQTPRightCurvedTriangle :
case JKQTPAsterisc :
case JKQTPAsterisc6 :
case JKQTPAsterisc8 :
case JKQTPDiamondPlus :
case JKQTPDiamondCross :
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( symbolSize , symbolSize ) ;
painter . setBrush ( QColor ( Qt : : transparent ) ) ;
painter . setPen ( pDescaled ) ;
2023-06-25 23:55:05 +08:00
if ( all_paths [ symbol ] . pathsrotation ! = 0.0 ) painter . rotate ( all_paths [ symbol ] . pathsrotation ) ;
painter . drawPath ( all_paths [ symbol ] . paths ) ;
2019-05-30 04:40:02 +08:00
break ;
2022-09-02 18:27:12 +08:00
case JKQTPFilledCircle :
case JKQTPFilledRect :
case JKQTPFilledDownCurvedTriangle :
case JKQTPFilledCurvedTriangle :
case JKQTPFilledLeftCurvedTriangle :
case JKQTPFilledRightCurvedTriangle :
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( symbolSize , symbolSize ) ;
2019-05-30 04:40:02 +08:00
painter . setBrush ( b ) ;
2022-09-02 18:27:12 +08:00
painter . setPen ( pDescaled ) ;
2023-06-25 23:55:05 +08:00
if ( all_paths [ symbol ] . pathsrotation ! = 0.0 ) painter . rotate ( all_paths [ symbol ] . pathsrotation ) ;
painter . drawPath ( all_paths [ symbol ] . filledpaths ) ;
2022-09-02 18:27:12 +08:00
2019-05-30 04:40:02 +08:00
break ;
2022-09-02 18:27:12 +08:00
case JKQTPRectTriangle :
case JKQTPRectDownTriangle :
case JKQTPRectLeftTriangle :
case JKQTPRectRightTriangle :
case JKQTPTriangle :
case JKQTPDownTriangle :
case JKQTPLeftTriangle :
case JKQTPRightTriangle :
case JKQTPstar :
case JKQTPPentagon :
case JKQTPHexagon :
case JKQTPOctagon :
case JKQTPUpDownTriangle :
case JKQTPSantaClauseHouse :
case JKQTPHourglass :
case JKQTPHorizontalHourglass :
case JKQTPDiamond :
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( symbolSize , symbolSize ) ;
painter . setBrush ( QColor ( Qt : : transparent ) ) ;
painter . setPen ( pDescaled ) ;
2023-06-25 23:55:05 +08:00
if ( all_paths [ symbol ] . pathsrotation ! = 0.0 ) painter . rotate ( all_paths [ symbol ] . pathsrotation ) ;
painter . drawConvexPolygon ( all_paths [ symbol ] . polygons ) ;
2019-05-30 04:40:02 +08:00
break ;
2022-09-02 18:27:12 +08:00
case JKQTPFilledTriangle :
case JKQTPFilledDownTriangle :
case JKQTPFilledLeftTriangle :
case JKQTPFilledRightTriangle :
case JKQTPFilledStar :
case JKQTPFilledPentagon :
case JKQTPFilledHexagon :
case JKQTPFilledOctagon :
case JKQTPFilledSantaClauseHouse :
case JKQTPFilledUpDownTriangle :
case JKQTPFilledHourglass :
case JKQTPFilledHorizontalHourglass :
case JKQTPFilledDiamond :
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( symbolSize , symbolSize ) ;
2019-05-30 04:40:02 +08:00
painter . setBrush ( b ) ;
2022-09-02 18:27:12 +08:00
painter . setPen ( pDescaled ) ;
2023-06-25 23:55:05 +08:00
if ( all_paths [ symbol ] . pathsrotation ! = 0.0 ) painter . rotate ( all_paths [ symbol ] . pathsrotation ) ;
painter . drawConvexPolygon ( all_paths [ symbol ] . filledpolygons ) ;
2019-05-30 04:40:02 +08:00
break ;
2022-09-02 18:27:12 +08:00
case JKQTPTripod :
case JKQTPDownTripod :
case JKQTPLeftTripod :
case JKQTPRightTripod :
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( symbolSize , symbolSize ) ;
painter . setBrush ( QColor ( Qt : : transparent ) ) ;
painter . setPen ( pDescaled ) ;
2023-06-25 23:55:05 +08:00
if ( all_paths [ symbol ] . pathsrotation ! = 0.0 ) painter . rotate ( all_paths [ symbol ] . pathsrotation ) ;
painter . drawLines ( all_paths [ symbol ] . lines ) ;
2022-09-02 18:27:12 +08:00
break ;
case JKQTPNoSymbol :
case JKQTPSymbolCount :
2022-09-02 20:19:47 +08:00
case JKQTPCharacterSymbol :
2022-09-06 17:57:58 +08:00
case JKQTPFilledCharacterSymbol :
2022-09-06 18:39:23 +08:00
case JKQTPFirstCustomSymbol :
2019-05-30 04:40:02 +08:00
break ;
}
2022-09-02 20:19:47 +08:00
if ( symbol > = JKQTPCharacterSymbol & & symbol < = JKQTPCharacterSymbol + 0xFFFF ) {
symbolFont . setStyleStrategy ( QFont : : PreferDefault ) ;
const QChar ch ( static_cast < uint16_t > ( symbol - JKQTPCharacterSymbol ) ) ;
const QFontMetricsF fm ( symbolFont ) ;
const QRectF tbr = fm . tightBoundingRect ( ch ) ;
const double scale = symbolSize / qMax ( tbr . width ( ) , tbr . height ( ) ) ;
painter . translate ( QPointF ( x , y ) ) ;
//painter.setPen(QColor("yellow"));
//painter.drawEllipse(QPointF(0,0),symbolSize/2.0,symbolSize/2.0);
painter . scale ( scale , scale ) ;
//painter.setPen(QColor("green"));
//painter.drawRect(tbr);
//painter.drawEllipse(QPointF(0,0),2,2);
painter . translate ( - tbr . center ( ) ) ; //QPointF(-tbr.width()/2.0,-tbr.height()/2.0)+QPointF(tbr.x(),tbr.y()));
//painter.setPen(QColor("red"));
//painter.drawRect(tbr);
//painter.drawEllipse(QPointF(0,0),2,2);
2022-09-06 17:57:58 +08:00
painter . setBrush ( color ) ;
painter . setPen ( Qt : : NoPen ) ;
QPainterPath path ;
path . addText ( 0 , 0 , symbolFont , ch ) ,
painter . drawPath ( path ) ;
}
if ( symbol > = JKQTPFilledCharacterSymbol & & symbol < = JKQTPFilledCharacterSymbol + 0xFFFF ) {
symbolFont . setStyleStrategy ( QFont : : PreferDefault ) ;
const QChar ch ( static_cast < uint16_t > ( symbol - JKQTPFilledCharacterSymbol ) ) ;
const QFontMetricsF fm ( symbolFont ) ;
const QRectF tbr = fm . tightBoundingRect ( ch ) ;
const double scale = symbolSize / qMax ( tbr . width ( ) , tbr . height ( ) ) ;
painter . setPen ( p ) ;
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( scale , scale ) ;
painter . translate ( - tbr . center ( ) ) ; //QPointF(-tbr.width()/2.0,-tbr.height()/2.0)+QPointF(tbr.x(),tbr.y()));
painter . setBrush ( b ) ;
QPainterPath path ;
path . addText ( 0 , 0 , symbolFont , ch ) ,
painter . drawPath ( path ) ;
2022-09-02 20:19:47 +08:00
}
2022-09-06 18:39:23 +08:00
if ( symbol > = JKQTPFirstCustomSymbol ) {
2024-01-06 06:26:47 +08:00
JKQTPlotterDrawingTools : : SymbolsReadLocker lock ( JKQTPlotterDrawingTools : : JKQTPCustomGraphSymbolStore ) ;
2022-09-06 18:39:23 +08:00
const int idx ( static_cast < int > ( symbol - JKQTPFirstCustomSymbol ) ) ;
2023-06-25 23:55:05 +08:00
if ( idx > = 0 & & idx < JKQTPlotterDrawingTools : : JKQTPCustomGraphSymbolStore - > size ( ) ) {
2022-09-06 18:39:23 +08:00
painter . setPen ( p ) ;
painter . translate ( QPointF ( x , y ) ) ;
painter . scale ( symbolSize , symbolSize ) ;
painter . setBrush ( b ) ;
painter . setPen ( pDescaled ) ;
2023-06-25 23:55:05 +08:00
const auto functor = JKQTPlotterDrawingTools : : JKQTPCustomGraphSymbolStore - > at ( idx ) ;
functor ( painter ) ;
2022-09-06 18:39:23 +08:00
}
}
2019-05-30 04:40:02 +08:00
}
template < class TPainter >
inline void JKQTPDrawTooltip ( TPainter & painter , double x , double y , const QRectF & rect )
{
QPolygonF poly ;
if ( y < rect . top ( ) ) {
poly < < rect . topLeft ( ) < < QPointF ( rect . left ( ) + rect . width ( ) / 3 , rect . top ( ) ) < < QPointF ( x , y ) < < QPointF ( rect . right ( ) - rect . width ( ) / 3 , rect . top ( ) ) < < rect . topRight ( ) < < rect . bottomRight ( ) < < rect . bottomLeft ( ) < < rect . topLeft ( ) ;
painter . drawPolygon ( poly ) ;
} else if ( y > rect . bottom ( ) ) {
poly < < rect . topLeft ( ) < < rect . topRight ( ) < < rect . bottomRight ( ) < < QPointF ( rect . right ( ) - rect . width ( ) / 3 , rect . bottom ( ) ) < < QPointF ( x , y ) < < QPointF ( rect . left ( ) + rect . width ( ) / 3 , rect . bottom ( ) ) < < rect . bottomLeft ( ) < < rect . topLeft ( ) ;
painter . drawPolygon ( poly ) ;
} else if ( x < rect . left ( ) ) {
poly < < QPointF ( x , y ) < < rect . topLeft ( ) < < rect . topRight ( ) < < rect . bottomRight ( ) < < rect . bottomLeft ( ) < < QPointF ( rect . left ( ) , rect . top ( ) + rect . height ( ) / 2 ) < < QPointF ( x , y ) ;
painter . drawPolygon ( poly ) ;
} else if ( x > rect . left ( ) ) {
poly < < rect . topLeft ( ) < < rect . topRight ( ) < < QPointF ( x , y ) < < QPointF ( rect . right ( ) , rect . top ( ) + rect . height ( ) / 2 ) < < rect . bottomRight ( ) < < rect . bottomLeft ( ) < < rect . topLeft ( ) ;
painter . drawPolygon ( poly ) ;
} else {
painter . drawRect ( rect ) ;
}
}
2020-08-22 00:31:58 +08:00
2022-09-06 17:07:52 +08:00
template < class TPainter >
inline void JKQTPPlotDecoratedLine ( TPainter & painter , const QLineF & l , JKQTPLineDecoratorStyle style1 , double size1 , JKQTPLineDecoratorStyle style2 , double size2 ) {
const double angle1 = atan2 ( l . p2 ( ) . y ( ) - l . p1 ( ) . y ( ) , l . p2 ( ) . x ( ) - l . p1 ( ) . x ( ) ) ;
const double angle2 = atan2 ( l . p1 ( ) . y ( ) - l . p2 ( ) . y ( ) , l . p1 ( ) . x ( ) - l . p2 ( ) . x ( ) ) ;
QPointF lx1 = l . p1 ( ) , lx2 = l . p2 ( ) ;
JKQTPPlotLineDecorator ( painter , l . p1 ( ) . x ( ) , l . p1 ( ) . y ( ) , angle1 , style1 , size1 , & lx1 ) ;
JKQTPPlotLineDecorator ( painter , l . p2 ( ) . x ( ) , l . p2 ( ) . y ( ) , angle2 , style2 , size2 , & lx2 ) ;
// draw corrected line
painter . drawLine ( QLineF ( lx1 , lx2 ) ) ;
}
2020-08-22 00:31:58 +08:00
template < class TPainter >
inline void JKQTPPlotLineDecorator ( TPainter & painter , double x , double y , double angle_rad , JKQTPLineDecoratorStyle style , double size , QPointF * line_start ) {
if ( line_start ) * line_start = QPointF ( x , y ) ;
static double default_theta_open_tip = 60.0 / 2.0 / 180.0 * JKQTPSTATISTICS_PI ;
static double tan__default_theta_open_tip = tan ( default_theta_open_tip ) ;
static double default_theta_closed_tip = 50.0 / 2.0 / 180.0 * JKQTPSTATISTICS_PI ;
static double tan__default_theta_closed_tip = tan ( default_theta_closed_tip ) ;
2020-08-23 19:13:53 +08:00
QPen pinit = painter . pen ( ) ;
pinit . setCapStyle ( Qt : : FlatCap ) ;
pinit . setJoinStyle ( Qt : : RoundJoin ) ;
2020-08-22 00:31:58 +08:00
QPen p0 = pinit ;
p0 . setWidthF ( 0 ) ;
{
painter . save ( ) ; auto __finalpaint = JKQTPFinally ( [ & painter ] ( ) { painter . restore ( ) ; } ) ;
painter . translate ( x , y ) ;
painter . rotate ( angle_rad / JKQTPSTATISTICS_PI * 180.0 ) ;
painter . setPen ( p0 ) ;
switch ( style ) {
case JKQTPArrow :
2020-08-23 19:13:53 +08:00
case JKQTPArrowAndBar : {
2020-08-22 00:31:58 +08:00
const QPointF poly [ 3 ] = {
QPointF ( size , - tan__default_theta_open_tip * size ) ,
QPointF ( 0 , 0 ) ,
QPointF ( size , tan__default_theta_open_tip * size )
} ;
painter . setPen ( pinit ) ;
2020-08-23 19:13:53 +08:00
if ( style = = JKQTPArrowAndBar ) painter . drawLine ( QPointF ( 0 , - tan__default_theta_open_tip * size ) , QPointF ( 0 , tan__default_theta_open_tip * size ) ) ;
2020-08-22 00:31:58 +08:00
painter . drawPolyline ( poly , 3 ) ;
} break ;
2020-08-23 19:13:53 +08:00
case JKQTPHarpoonDecorator :
case JKQTPHarpoonDecoratorAndBar : {
painter . setPen ( pinit ) ;
if ( style = = JKQTPHarpoonDecoratorAndBar ) painter . drawLine ( QPointF ( 0 , - tan__default_theta_open_tip * size ) , QPointF ( 0 , tan__default_theta_open_tip * size ) ) ;
painter . drawLine ( QPointF ( 0 , 0 ) , QPointF ( size , tan__default_theta_open_tip * size ) ) ;
} break ;
2020-08-22 00:31:58 +08:00
case JKQTPDoubleArrow :
2020-08-23 19:13:53 +08:00
case JKQTPDoubleArrowAndBar : {
2020-08-22 00:31:58 +08:00
const QPointF poly [ 3 ] = {
QPointF ( size , - tan__default_theta_open_tip * size ) ,
QPointF ( 0 , 0 ) ,
QPointF ( size , tan__default_theta_open_tip * size )
} ;
painter . setPen ( pinit ) ;
2020-08-23 19:13:53 +08:00
if ( style = = JKQTPDoubleArrowAndBar ) painter . drawLine ( QPointF ( 0 , - tan__default_theta_open_tip * size ) , QPointF ( 0 , tan__default_theta_open_tip * size ) ) ;
2020-08-22 00:31:58 +08:00
painter . drawPolyline ( poly , 3 ) ;
painter . translate ( 4.0 * pinit . widthF ( ) , 0 ) ;
painter . drawPolyline ( poly , 3 ) ;
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( 4.0 * pinit . widthF ( ) * cos ( angle_rad ) , 4.0 * pinit . widthF ( ) * sin ( angle_rad ) ) ;
} break ;
case JKQTPFilledArrow :
case JKQTPFilledDoubleArrow : {
const QPointF poly [ 4 ] = {
QPointF ( 0 , 0 ) ,
QPointF ( size , tan__default_theta_closed_tip * size ) ,
QPointF ( 0.75 * size , 0 ) ,
QPointF ( size , - tan__default_theta_closed_tip * size )
} ;
painter . drawPolygon ( poly , 4 ) ;
if ( style = = JKQTPFilledDoubleArrow ) {
2020-08-23 19:13:53 +08:00
painter . translate ( 0.5 * size , 0 ) ;
2020-08-22 00:31:58 +08:00
painter . drawPolygon ( poly , 4 ) ;
2020-08-23 19:13:53 +08:00
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( 1.25 * size * cos ( angle_rad ) , 1.25 * size * sin ( angle_rad ) ) ;
2020-08-22 00:31:58 +08:00
} else {
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( 0.75 * size * cos ( angle_rad ) , 0.75 * size * sin ( angle_rad ) ) ;
}
} break ;
case JKQTPTriangleDecorator :
2020-08-23 19:13:53 +08:00
case JKQTPTriangleDecoratorAndBar : {
2020-08-22 00:31:58 +08:00
const QPointF poly [ 3 ] = {
QPointF ( size , - tan__default_theta_closed_tip * size ) ,
QPointF ( 0 , 0 ) ,
QPointF ( size , tan__default_theta_closed_tip * size )
} ;
painter . setBrush ( Qt : : NoBrush ) ;
painter . setPen ( pinit ) ;
painter . drawConvexPolygon ( poly , 3 ) ;
2020-08-23 19:13:53 +08:00
if ( style = = JKQTPTriangleDecoratorAndBar ) painter . drawLine ( QPointF ( 0 , - tan__default_theta_closed_tip * size ) , QPointF ( 0 , tan__default_theta_closed_tip * size ) ) ;
2020-08-22 00:31:58 +08:00
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( size * cos ( angle_rad ) , size * sin ( angle_rad ) ) ;
} break ;
case JKQTPFilledTriangleDecorator :
2020-08-23 19:13:53 +08:00
case JKQTPFilledTriangleDecoratorAndBar : {
2020-08-22 00:31:58 +08:00
const QPointF poly [ 3 ] = {
QPointF ( size , - tan__default_theta_closed_tip * size ) ,
QPointF ( 0 , 0 ) ,
QPointF ( size , tan__default_theta_closed_tip * size )
} ;
painter . setPen ( p0 ) ;
painter . drawConvexPolygon ( poly , 3 ) ;
2020-08-23 19:13:53 +08:00
if ( style = = JKQTPFilledTriangleDecoratorAndBar ) {
2020-08-22 00:31:58 +08:00
painter . setPen ( pinit ) ;
painter . drawLine ( QPointF ( 0 , - tan__default_theta_closed_tip * size ) , QPointF ( 0 , tan__default_theta_closed_tip * size ) ) ;
}
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( size * cos ( angle_rad ) , size * sin ( angle_rad ) ) ;
} break ;
2020-08-23 19:13:53 +08:00
case JKQTPDiamondDecorator :
case JKQTPDiamondDecoratorAndBar : {
const QPointF poly [ 4 ] = {
QPointF ( 0 , 0 ) ,
QPointF ( size / 2.0 , - tan__default_theta_closed_tip * size ) ,
QPointF ( size , 0 ) ,
QPointF ( size / 2.0 , tan__default_theta_closed_tip * size )
} ;
painter . setBrush ( Qt : : NoBrush ) ;
painter . setPen ( pinit ) ;
painter . drawConvexPolygon ( poly , 4 ) ;
if ( style = = JKQTPDiamondDecoratorAndBar ) painter . drawLine ( QPointF ( 0 , - tan__default_theta_closed_tip * size ) , QPointF ( 0 , tan__default_theta_closed_tip * size ) ) ;
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( size * cos ( angle_rad ) , size * sin ( angle_rad ) ) ;
} break ;
2020-08-22 00:31:58 +08:00
2020-08-23 19:13:53 +08:00
case JKQTPFilledDiamondDecorator :
case JKQTPFilledDiamondDecoratorAndBar : {
const QPointF poly [ 4 ] = {
QPointF ( 0 , 0 ) ,
QPointF ( size / 2.0 , - tan__default_theta_closed_tip * size ) ,
QPointF ( size , 0 ) ,
QPointF ( size / 2.0 , tan__default_theta_closed_tip * size )
} ;
painter . setPen ( p0 ) ;
painter . drawConvexPolygon ( poly , 4 ) ;
if ( style = = JKQTPFilledDiamondDecoratorAndBar ) {
painter . setPen ( pinit ) ;
painter . drawLine ( QPointF ( 0 , - tan__default_theta_closed_tip * size ) , QPointF ( 0 , tan__default_theta_closed_tip * size ) ) ;
}
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( size * cos ( angle_rad ) , size * sin ( angle_rad ) ) ;
} break ;
2020-08-22 00:31:58 +08:00
case JKQTPCircleDecorator :
case JKQTPFilledCircleDecorator : {
if ( style = = JKQTPCircleDecorator ) {
painter . setBrush ( Qt : : NoBrush ) ;
painter . setPen ( pinit ) ;
} else {
painter . setPen ( p0 ) ;
}
2020-08-23 19:13:53 +08:00
painter . drawEllipse ( QRectF ( 0 , - size / 2.0 , size , size ) ) ;
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( size * cos ( angle_rad ) , size * sin ( angle_rad ) ) ;
2020-08-22 00:31:58 +08:00
} break ;
case JKQTPRectangleDecorator :
case JKQTPFilledRectangleDecorator : {
if ( style = = JKQTPRectangleDecorator ) {
painter . setBrush ( Qt : : NoBrush ) ;
painter . setPen ( pinit ) ;
} else {
painter . setPen ( p0 ) ;
}
2020-08-23 19:13:53 +08:00
painter . drawRect ( QRectF ( 0 , - size / 2.0 , size , size ) ) ;
if ( line_start ) * line_start = QPointF ( x , y ) + QPointF ( size * cos ( angle_rad ) , size * sin ( angle_rad ) ) ;
2020-08-22 00:31:58 +08:00
} break ;
2020-08-23 19:13:53 +08:00
case JKQTPBarDecorator : {
2020-08-22 00:31:58 +08:00
painter . setPen ( pinit ) ;
painter . drawLine ( QPointF ( 0 , - tan__default_theta_open_tip * size ) , QPointF ( 0 , tan__default_theta_open_tip * size ) ) ;
} break ;
2020-08-23 19:13:53 +08:00
case JKQTPHalfBarDecorator : {
painter . setPen ( pinit ) ;
painter . drawLine ( QPointF ( 0 , 0 ) , QPointF ( 0 , tan__default_theta_open_tip * size ) ) ;
} break ;
case JKQTPSkewedBarDecorator : {
painter . setPen ( pinit ) ;
painter . drawLine ( QPointF ( 0.25 * size , - tan__default_theta_open_tip * size ) , QPointF ( - 0.25 * size , tan__default_theta_open_tip * size ) ) ;
} break ;
2020-08-22 00:31:58 +08:00
case JKQTPBracketDecorator : {
const QPointF poly [ 4 ] = {
QPointF ( - size * 0.2 , - tan__default_theta_open_tip * size ) ,
QPointF ( 0 , - tan__default_theta_open_tip * size ) ,
QPointF ( 0 , tan__default_theta_open_tip * size ) ,
QPointF ( - size * 0.2 , tan__default_theta_open_tip * size )
} ;
painter . setPen ( pinit ) ;
painter . drawPolyline ( poly , 4 ) ;
} break ;
2020-08-22 00:40:30 +08:00
case JKQTPLineDecoratorCount :
case JKQTPNoDecorator :
break ;
2020-08-22 00:31:58 +08:00
}
}
}
2019-05-30 04:40:02 +08:00
# endif // JKQTPDRAWINGTOOLS_H_INCLUDED