From 4347d27c04ba728949c0b738667a493c0d4a6f34 Mon Sep 17 00:00:00 2001 From: jkriege2 Date: Sun, 28 Jul 2019 14:59:09 +0200 Subject: [PATCH] * reworked color-palette-system: 1. added several new (JKQTPMathImageBone, JKQTPMathImageCool, JKQTPMathImageCopper, JKQTPMathImageAutumn, JKQTPMathImageSeismic, JKQTPMathImageTerrain, JKQTPMathImageViridis, JKQTPMathImageMagma, JKQTPMathImageInferno, JKQTPMathImagePlasma) 2. reworked LUT-types (now a QVector, instead of a C-array, suing malloc) 3. reworked available functions to build LUTs (cleanup, more options, clearer names) 4. added functions to load palettes from files 5. Improved documentation * added example for user-controlled color palettes --- doc/dox/examples_and_tutorials.dox | 6 + doc/dox/jkqtplotter.dox | 3 + ...ildColorPaletteLUTLinInterpolateSorted.cdr | Bin 0 -> 36637 bytes ...ildColorPaletteLUTLinInterpolateSorted.png | Bin 0 -> 26735 bytes .../JKQTPBuildColorPaletteLUTSorted.cdr | Bin 0 -> 29183 bytes .../JKQTPBuildColorPaletteLUTSorted.png | Bin 0 -> 22587 bytes doc/images/palettes/palette_AFMhot.png | Bin 199 -> 175 bytes doc/images/palettes/palette_BBlRdYe.png | Bin 394 -> 362 bytes doc/images/palettes/palette_BWprint.png | Bin 229 -> 204 bytes doc/images/palettes/palette_BlMaYe.png | Bin 228 -> 204 bytes doc/images/palettes/palette_BlYe.png | Bin 385 -> 353 bytes doc/images/palettes/palette_BrBG.png | Bin 364 -> 307 bytes doc/images/palettes/palette_GnRdVi.png | Bin 261 -> 235 bytes doc/images/palettes/palette_HSV.png | Bin 219 -> 194 bytes doc/images/palettes/palette_Matlab.png | Bin 203 -> 179 bytes doc/images/palettes/palette_PuOr.png | Bin 377 -> 356 bytes doc/images/palettes/palette_RYGB.png | Bin 304 -> 275 bytes doc/images/palettes/palette_YeBl.png | Bin 378 -> 346 bytes doc/images/palettes/palette_YeGnBu.png | Bin 367 -> 343 bytes doc/images/palettes/palette_YeMaBl.png | Bin 240 -> 214 bytes doc/images/palettes/palette_autumn.png | Bin 0 -> 154 bytes doc/images/palettes/palette_blue.png | Bin 180 -> 156 bytes doc/images/palettes/palette_bluegreen.png | Bin 341 -> 331 bytes doc/images/palettes/palette_bluegreenred.png | Bin 187 -> 163 bytes doc/images/palettes/palette_bluered.png | Bin 181 -> 159 bytes doc/images/palettes/palette_bluewhitered.png | Bin 386 -> 349 bytes doc/images/palettes/palette_bone.png | Bin 0 -> 282 bytes doc/images/palettes/palette_cool.png | Bin 0 -> 154 bytes doc/images/palettes/palette_copper.png | Bin 0 -> 260 bytes doc/images/palettes/palette_cyan.png | Bin 183 -> 159 bytes doc/images/palettes/palette_cyanwhite.png | Bin 188 -> 164 bytes doc/images/palettes/palette_gray.png | Bin 182 -> 158 bytes doc/images/palettes/palette_green.png | Bin 180 -> 156 bytes doc/images/palettes/palette_greenblue.png | Bin 341 -> 325 bytes doc/images/palettes/palette_inferno.png | Bin 0 -> 383 bytes doc/images/palettes/palette_invAFMhot.png | Bin 195 -> 171 bytes doc/images/palettes/palette_invBWprint.png | Bin 241 -> 215 bytes doc/images/palettes/palette_invHSV.png | Bin 220 -> 195 bytes doc/images/palettes/palette_invMatlab.png | Bin 208 -> 183 bytes doc/images/palettes/palette_invRYGB.png | Bin 309 -> 280 bytes doc/images/palettes/palette_invblue.png | Bin 178 -> 154 bytes doc/images/palettes/palette_invcyan.png | Bin 181 -> 157 bytes doc/images/palettes/palette_invgray.png | Bin 177 -> 153 bytes doc/images/palettes/palette_invgreen.png | Bin 178 -> 154 bytes doc/images/palettes/palette_invmagenta.png | Bin 187 -> 163 bytes doc/images/palettes/palette_invocean.png | Bin 202 -> 176 bytes doc/images/palettes/palette_invrainbow.png | Bin 347 -> 316 bytes doc/images/palettes/palette_invred.png | Bin 178 -> 154 bytes .../palettes/palette_invtrafficlight.png | Bin 587 -> 220 bytes doc/images/palettes/palette_invyellow.png | Bin 189 -> 165 bytes doc/images/palettes/palette_magenta.png | Bin 186 -> 162 bytes doc/images/palettes/palette_magentawhite.png | Bin 187 -> 163 bytes doc/images/palettes/palette_magentayellow.png | Bin 181 -> 158 bytes doc/images/palettes/palette_magma.png | Bin 0 -> 359 bytes doc/images/palettes/palette_ocean.png | Bin 203 -> 178 bytes doc/images/palettes/palette_plasma.png | Bin 0 -> 348 bytes doc/images/palettes/palette_rainbow.png | Bin 346 -> 316 bytes doc/images/palettes/palette_red.png | Bin 181 -> 157 bytes doc/images/palettes/palette_redblue.png | Bin 181 -> 157 bytes doc/images/palettes/palette_redgreenblue.png | Bin 190 -> 161 bytes doc/images/palettes/palette_redwhiteblue.png | Bin 364 -> 343 bytes doc/images/palettes/palette_seismic.png | Bin 0 -> 189 bytes doc/images/palettes/palette_stepsBlGn.png | Bin 221 -> 198 bytes doc/images/palettes/palette_stepsBrBG.png | Bin 241 -> 216 bytes doc/images/palettes/palette_stepsGnBl.png | Bin 224 -> 199 bytes doc/images/palettes/palette_stepsPuOr.png | Bin 235 -> 210 bytes doc/images/palettes/palette_stepsYeGnBu.png | Bin 228 -> 203 bytes doc/images/palettes/palette_terrain.png | Bin 0 -> 256 bytes doc/images/palettes/palette_trafficlight.png | Bin 247 -> 221 bytes doc/images/palettes/palette_viridis.png | Bin 0 -> 342 bytes doc/images/palettes/palette_whitecyan.png | Bin 189 -> 165 bytes doc/images/palettes/palette_whitemagenta.png | Bin 189 -> 165 bytes doc/images/palettes/palette_whiteyellow.png | Bin 188 -> 164 bytes doc/images/palettes/palette_yellow.png | Bin 187 -> 163 bytes doc/images/palettes/palette_yellowmagenta.png | Bin 181 -> 157 bytes doc/images/palettes/palette_yellowwhite.png | Bin 187 -> 163 bytes doc/template_verbatimgraph.txt | 19 + examples/CMakeLists.txt | 1 + examples/README.md | 1 + examples/imageplot_userpal/CMakeLists.txt | 28 + examples/imageplot_userpal/README.md | 210 + .../imageplot_userpal/imageplot_userpal.cpp | 173 + .../imageplot_userpal/imageplot_userpal.pro | 27 + .../imageplot_userpal/imageplot_userpal.qrc | 9 + .../imageplot_userpal_and_lib.pro | 8 + .../palettes/All_idl_cmaps.xml | 10581 +++++++++++++ .../palettes/All_mpl_cmaps.xml | 12903 ++++++++++++++++ .../palettes/CoolWarmUChar257.csv | 258 + .../palettes/CoolWarmUChar33.csv | 34 + .../palettes/NSW_Discrete_Z_ColorMap.xml | 47 + lib/jkqtcommon/CMakeLists.txt | 4 +- lib/jkqtcommon/jkqtpbasicimagetools.cpp | 4661 +++--- lib/jkqtcommon/jkqtpbasicimagetools.h | 835 +- lib/jkqtplotter/graphs/jkqtpimage.cpp | 28 +- lib/jkqtplotter/graphs/jkqtpimage.h | 4 +- lib/jkqtplotter/graphs/jkqtpimagergb.cpp | 26 +- lib/jkqtplotter/graphs/jkqtpscatter.cpp | 4 +- lib/jkqtplotter/gui/jkqtpcomboboxes.cpp | 4 +- lib/jkqtplotter/jkqtpbaseplotterstyle.cpp | 4 +- lib/jkqtplotter/jkqtpdatastorage.cpp | 14 + lib/jkqtplotter/jkqtpdatastorage.h | 15 + lib/jkqtplotter/jkqtpimagetools.cpp | 12 +- screenshots/imageplot_userpal.png | Bin 0 -> 176 bytes screenshots/imageplot_userpal_1_linear.png | Bin 0 -> 198 bytes screenshots/imageplot_userpal_2_linear.png | Bin 0 -> 224 bytes screenshots/imageplot_userpal_palsimple.png | Bin 0 -> 176 bytes screenshots/imageplot_userpal_palsteps2.png | Bin 0 -> 176 bytes screenshots/imageplot_userpal_program.png | Bin 0 -> 18844 bytes .../imageplot_userpal_program_small.png | Bin 0 -> 15264 bytes 109 files changed, 27750 insertions(+), 2169 deletions(-) create mode 100644 doc/images/JKQTPBuildColorPaletteLUTLinInterpolateSorted.cdr create mode 100644 doc/images/JKQTPBuildColorPaletteLUTLinInterpolateSorted.png create mode 100644 doc/images/JKQTPBuildColorPaletteLUTSorted.cdr create mode 100644 doc/images/JKQTPBuildColorPaletteLUTSorted.png create mode 100644 doc/images/palettes/palette_autumn.png create mode 100644 doc/images/palettes/palette_bone.png create mode 100644 doc/images/palettes/palette_cool.png create mode 100644 doc/images/palettes/palette_copper.png create mode 100644 doc/images/palettes/palette_inferno.png create mode 100644 doc/images/palettes/palette_magma.png create mode 100644 doc/images/palettes/palette_plasma.png create mode 100644 doc/images/palettes/palette_seismic.png create mode 100644 doc/images/palettes/palette_terrain.png create mode 100644 doc/images/palettes/palette_viridis.png create mode 100644 doc/template_verbatimgraph.txt create mode 100644 examples/imageplot_userpal/CMakeLists.txt create mode 100644 examples/imageplot_userpal/README.md create mode 100644 examples/imageplot_userpal/imageplot_userpal.cpp create mode 100644 examples/imageplot_userpal/imageplot_userpal.pro create mode 100644 examples/imageplot_userpal/imageplot_userpal.qrc create mode 100644 examples/imageplot_userpal/imageplot_userpal_and_lib.pro create mode 100644 examples/imageplot_userpal/palettes/All_idl_cmaps.xml create mode 100644 examples/imageplot_userpal/palettes/All_mpl_cmaps.xml create mode 100644 examples/imageplot_userpal/palettes/CoolWarmUChar257.csv create mode 100644 examples/imageplot_userpal/palettes/CoolWarmUChar33.csv create mode 100644 examples/imageplot_userpal/palettes/NSW_Discrete_Z_ColorMap.xml create mode 100644 screenshots/imageplot_userpal.png create mode 100644 screenshots/imageplot_userpal_1_linear.png create mode 100644 screenshots/imageplot_userpal_2_linear.png create mode 100644 screenshots/imageplot_userpal_palsimple.png create mode 100644 screenshots/imageplot_userpal_palsteps2.png create mode 100644 screenshots/imageplot_userpal_program.png create mode 100644 screenshots/imageplot_userpal_program_small.png diff --git a/doc/dox/examples_and_tutorials.dox b/doc/dox/examples_and_tutorials.dox index 7e469bf978..9833f556cc 100644 --- a/doc/dox/examples_and_tutorials.dox +++ b/doc/dox/examples_and_tutorials.dox @@ -101,6 +101,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int \image html imageplot_small.png \subpage JKQTPlotterImagePlot `JKQTPColumnMathImage`
image data copied from C-style row-major array into a single column of the internal datastore
Describes several options of the image plotting classes (different ways of color coding, what to do with data above/below the limits etc.) + \image html imageplot_userpal_program_small.png + \subpage JKQTPlotterImagePlotUserPalette + `JKQTPColumnMathImage`
user-defines palettes
palettes from files \image html imageplot_modifier_small.png \subpage JKQTPlotterImagePlotModifier `JKQTPColumnMathImage`
image data copied from C-style row-major array into a single column of the internal datastore
Image is modified by a second image to display two data dimensions at the same time @@ -146,6 +149,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int \image html test_styling_small.png \subpage JKQTPlotterStyling Modifying different Aspects of the Styling of JKQTPlotter + \image html imageplot_userpal_small.png + \subpage JKQTPlotterImagePlotUserPalette + `JKQTPColumnMathImage`
user-defines palettes
palettes from files diff --git a/doc/dox/jkqtplotter.dox b/doc/dox/jkqtplotter.dox index 13bd5e12b3..7e6da375e1 100644 --- a/doc/dox/jkqtplotter.dox +++ b/doc/dox/jkqtplotter.dox @@ -509,6 +509,9 @@ Examples: \defgroup jkqtplotter_imagelots_tools Tool Functions & Classes for Image Drawing \ingroup jkqtplotter_imagelots +\defgroup jkqtplotter_imagelots_tools_LUTS Tool Functions to Build Lookup-Tables for Palettes +\ingroup jkqtplotter_imagelots_tools + \defgroup jkqtplotter_imagelots_contour Contour Graphs (based on Image Data) \ingroup jkqtplotter_imagelots diff --git a/doc/images/JKQTPBuildColorPaletteLUTLinInterpolateSorted.cdr b/doc/images/JKQTPBuildColorPaletteLUTLinInterpolateSorted.cdr new file mode 100644 index 0000000000000000000000000000000000000000..9140d9b51ba279a1f7d1f61aa109ef810a18d081 GIT binary patch literal 36637 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%0D+MFoD7uH$gsBPzC1rLN ztX{DKxHNE=!=;vT?aARf^KTe}f`W%=UC)i1$Imuo$dCxtc~ z^C2E{Kx1dgnfavN=fc)Kr!IA-5)K4eX5YSEDF52rY_R>#x^mru7BpMY*5;ch?vI3w zJV|nSem*ib_6S^X1BhG!e|~&&@(`@{V!;B=mU?4rOB-~OpH6FYF!KrESBi*;*nNla z*v+!FM}SdD`cpA*TnIW8{7%+UUj=(C0O17~MoR|1LchrUNg!I`Jgonos~aS1Jx}T zsZMN8&NAps6B6do*F+L^>|Y*9?kju0fC~r+l({0_M*$Vh*5%8HL*;ZXv%#b%r5xc_ z(?F~Chl}+#03cxA(4h***q5uZn3y^V_->j^d88339qP%uugRq_#N5`VqN z8Hnxe?FBx)+YqN=^YKiDrly9*sgStIecMgp8b??IA}78oY0w zt+9%z7&fmM+(_PO^%&nSg=c4H=jYQhF)_WkJ3KrDE5U)Q;Gvgr*s{pyX6dCKc}pXt zuqV%_-ta6XwhMT$u!*YZ$?(|6s6L#igoC|epvG|<8t+-;mw=Dr==?hM^pSjn%Xgz) zSC=AbUzVT^$`@W%SYbI_4i_)^;S|4AQ!xb|7Ps~BwkA!JdnSnxqe^U(1SyG9C+6f` zW0IvM-66qc&-;9%Nj#{I4y}SC!+Mw2UNA*l!cB>OZWHBK(Ven_#ZQizQZgisKsiZHZ!(`?I25MOJMSUTLJRn7oJ|x71S4vZI?ON$d?j-# z(_4@2=F)W0RCdv9n zu3splL9{2Tvtjni5AGm+wD_fMtgleb9n)T2WQ6j3ydL=tQK-4rob_YK@o)%IQ>KY4 zkNY88g7b1K-lNj30mFVs{z>gGocvI=1TWND@sRi(^2TRcxWRa%^rLd{0qkaV^u391 zhgdnukM(-jGlaXlSAVnN!GjQw*TXME&&c6!u=Xj{QdK@jN}_k^nv-}3IEM|2E2J+Kg2-tz4h!`>O&*O@g8|L`ucA1{`MGl8zPr) zr6jMMQn>l6M^Y%NkM{$O$?<5|$Wol3;C-mT@F?}~P+Iw3sZ5HB3a(f0Br3OtdrmfP z{GP&3@^*Jux1I<&g<~9#L+IWw`APg3iM$Cf;DXyxb>qkGwRc%XK(~c(`o9~0kBykD zNMJQr9}T3IF+oj+KQO?MM z`b=W^{e%-N52A$k0eQ{mbgZ*aE{1?E&05VeI2O_3R^Ytm+4aF%ec~xYb-Kq(_M4drC^2+m8M^aRyVj^uLND<>P!AWrru_+Jy^y5UTrJIkM0l7KB1yS5LC`k-veydx=sg_t{)* zCOkI<2~L?AnkgQxx)P*!^(w#UM`fyn zqe`Ykwu_NoUkyAV5iyyuqRV68NpF&HkTE;-b3=E0E+@3BFMFEcB7P~vV6;H^{()DJ z91;VmxBgop7pV$1ed{8*7*ofnPq4whSR_vbCraX?AAS-hwG{3}N6i$?G7@2lWsPe0 z^tx;DktgS)b0`8IVmBeSNot(ADuA?(>w=X5^@1DQ$EPzi2n> z6WUH)wL;DV5nJBHOrZ~dhxE(N>k>sz85Oyi)nvHGcKSV}@n=XNu4L0~FHknG3A{Ki zaJ9uYnte68I?L|z!jV$MG*bWQ$}c@WH=miQ$^D-GfQf2&1toxw^4})(AlfNp3)bmLuH2p}J z5Qage$_ogmNrdfp6zuLgvt#{Pg&%2a zt{&wtVgk9a0#HGKriuLC?G81tfJE6u(CPREaz<$|(~}B{$%{S7uzDk+7P>WP6TlBD zl6^cK{Ms43ZR!9aBc6jj&lX-{PIhOjn*o#LU+H4uE1?PgHF5Vy{%|Nqq)fc`bR#~M zqt0Ev4aWP~va>T}Me{S;X6IoOv!z5IQM%Mh+efuaX8H7ri(MLp@ELBdh|YIg`Ahgh zbVhN(!69T#*Zaswr!?MuV=*tm@&Sl2=+}_49Tr3ECzG~f0#A1Ey?ihNUT^f# zwITz+4q52uq$& zZ{QR^Z^gZy@GKKefjm5omHg-f`0Aw;$o2F_DP^|{g+1?GnBM9U=gy`yg?HB4HZLAw zF9fkRkz%6rs>?zM!b*Ps6g<=*Xg8=kdJ~%JkOKCTBVmdpJAX=$EHf z9wv3FG+vCEkOCUUn7~MFiMg7Ps)@SCy?uKDA>Zp3aDHDOErxukcn{-H1CYDMJmB;) zyS*t-4Q%Cr9ylZsB(mrUK~3^>{T0lz0V#YaWD)TNh0TZ@hi2@`*Cs&#r*Cqui%#o~ z1eRJbpwD6r-Ttx=Q4?tY7>1*fGqi+bL`5y8&9}FhiTO{tNsS^@tec$qP zb-?h?{cOJz80N%_BRM37!h!>5%*B+09)84D8H`1$3RH{b`i+&dE24qEw-iKi&MgU7(+R6?xU6_!nAm(R>Zd3*%>u%wwIMT7M#F839B>;l7N}fGhd5E$O}))LS43-xizT*D|M7<)&Ox1(oa4A zy!LU#?x%B>4)oG#ZJ_%d(tbXI!8--%cj|h$6#O;Z>Hazuov(=VH<*Euy-fE)IzxB! z=rIb(C6J*n65SjWQrngyIgC>1Lq@SbO+#GopB>?3A2Vzv@3Mwn2gM_D8Zw0M<}sma zM0{22rcclcc7L|DjqcMY@&2LP45WPa&F@Kz3{IA$n?uECoAVA~v85atkJ4e@uq^m9 z57a@g?F!;C76JrB0+miKg0q<}o_XuId~%o0=NulaIOroT-_1({<8H4CjM|z6s}F=- zn=t&*(Yy20Xt%T;g>nJz7meb;IaAc{=-~G2&6&zgry7Mad?15&uiou8@cj%&8?rym zzGR2<13?c3)buP^BMOB-k7!YD)#}jYewv*qujZHYF7t5Lhn6tds=y)Q_jQVCv(|;v zg|42XQjQ~$5jl9~<0{Z)MC@O}4u0_Nd{;Vt(A=UR#G}yVPw$&83}0tl9&APw6)TBbiUUL{>LZZb#@k-GaXd zS{9$OKVgUAimUk`X6FA0?ZfpCgaqLphJJp&^$noFWcCf1?vvDMW>=2gh4OvXcO2BH znsDDsW;%HmdA zuMX_=J@fN-Ax|;y?od=*>dlY$Yi|PaRhAGQFazH?>ow-*r>5cOGGoMqdnUZ|*4)gW z3E%vJk8Y0_csiZApkt)Kl9LPEUUxV4FYNTi-gOPQp^a&UMY}&ge&|Q{t<|#Cl=a>Y zTfm2^W*_R`;Qebv-4p$iyzyOEHxcDMI(il7>2g=sM}aAlhPy>c5$ItNBIUzG0wQ4= z<-$J@Xx>-N4%M)bG6yw3%Hx8BWh!P`C@uy;SkUKs$rDl-DBjGHy#Hdk-6mFChO+!`XO@HYK3O`WS8Kq%e*79Eo?*tp8TwAaAa!=oMKwQI zmmi4*eTgZ+>flu|An)P1+Jl=~R8i6kJ&z};ey!TAU9JAS#W8*+J1p7utWECA1BI8) zsao*NZdoO%L1fw!(pT>2&gC##^Q*Kr zIbo_Prfvp(;gb9r@dV52H0eK8@(d4cNbG)XRkC~iYqkhb+=%W^Kztf^7N@?88@J!z zejAm>{oF0^%#ukTKVUU&?h9#Xg4CZoCiyBgtsEE=9Rj^T6>OBlom@tIIswlSnW#)% zea3HFY?!gqU>Iswv#K~(m{Z`!6D1sDZ1~sXMS5y7r6y(E85WF;+Vok6eT&HVq|W^h zQ0tc`V^V-mZyBeZ{&aj*&tymG=@40VsAL1eJl$VpyY7UAf{}8uCDdxG)Rwa)may#tANHsB2)k#TIf_zm42}2`uRtK${=(y$uzz7_%vcZQ%;oveg<_%=z%! zef?h5mp!$94!=DL(Q}_Cc#&6w^}-5PESV|jRpk*&ekMCe`lm`V5gwwE$TA9f27UIK zq?)hjY0omOqrER0P~SUmc<6@*yY7klm>Hr{_x7_O#&fg4V?lfA;O@Vgk1}EyP}F=l zG>?X<>WJ=(yr&C7^LMLWs@gozqXRA`X7j}9KF)IEIN3O1&w1@5`xd&4WZt@u3jU7rQ^Fx;!RmOEB$QM8nI(3YhL6XhrT}sO@+V_+Nm5>|D(2 zh;M+P$^b({BcuaGk_pGRUyg9MLZVVn0)+@=F{-n&ll zED!26l)IX`Ng~7sw!UUu8PxIK|5HW^Yd73O1zjgm*LHBS*!JV?&W2~vq>Nl8M=(-@EFh47>Du6 zQTJFhw!Gw6bwzDhDq8w8qqtL5CwH#?LTN=-$$Zc|Q;|H2=lH4+ezBjbIdk(hvwz_W zBeDZEfV_dzAvLK|r*Ocf@~0XzuFbC9tSS+bzlw7|Pem{T`b79UhT^Q}ZZpDHFZJO-ud#r)ufR2^yzZW!PRNvRC>%ThFc6Y9!2(!3 zr8?(aI`_~P1{t6A)VqkuhPq+N7J6qC=6lXitMjkFt=SwRLME+B>2=2i>=+aDBXN$8 zAE(R1)z!H%A3bQT_yyOnYxD z_Xu65nqCfr8u9h(W_N{vdt6ek*=b&x547EdD$$MlA&=+DvTZ8bzO{b$W6>=yCUht8 zjP7WxHxK_p^Bu3Rj^$+`DFgqM&PciWXiOP(xRK7>EEI)iQC6dB^9Csl|c0L9$l-l@-byA|;A zI-cV+o20`Z&jDJY+Ppd6BP(HHme2`qtPR!cPYfxWhbAiJEDr>RCQ#kc>lT zZ@b#wEWhQGY^SZFBQJc)@X{JuUV%v1Px>e3D{gEoy9cse-15E}8SoS7l+uI)BzCFJ z?D^Ot%hO+Y@R?`Vm$y#1lu2Hauk88@e2vA4MG7vs! zirh6}Q>KQ`VQ^`{b*n(0Ak?jc)m6NTk2W*saF9unfEXR;?xiO8eGKY!*9qwgoQ8x1 zr1<03x<&`$xttu8eUJcTzON4r0&?J_Kytz5(qXZ3DOV-{m|A7M`OYeIUshHoXgz_@ z1c;41Wseiy|6D7o5DwyTKnz|q12Q3X!k~69;2^cc26ePa*x5-2>|4n0iWdm%<2`!x z%E@V580mTiMDu?9_^~DnGA_-;SwcxLO9MCXUGB!gCi7c7dz?dS=|!u*f2$6+24m=a z!YmwwGWc*U{{FS+-8SHZnsI1~LD)oi;l0iOyy1U$)?hQOb_e#RM^!eJ;pW}vPNIeT zpu^39G%8AI9HR#arGfQ;-=&_sh&OC|!_Is4o#gMkES?Db$@QO7aornmD8u`D&YfDg z?kND7y!91aNE!Yf6I9>dZ_;XwzAR?#I|NV&d}s3@wR=!2qqGzy0d z>-2{Q+88fOvZ5E$ziRD9tmBmKSGubtM(tLzhO-`;w-zcs9&*Q>wz6uiP3Lo4uXK3& z{E$WJkhP{W%WuTD!55>H&NN0 zRlQT7UOVd((`fZ2jgrOmLSj!X7JSW=^%~Y?&63;1p>v7UBs!Q9E_e7-P$2x$tmyvA zbLrIF2$pGHWkI5G?OoK;{phsHbBt+zD^MwO={2kx+Pm1LYBHIuB^IrP18OD8%8#Sj zw1)sDJPd!L#=JS#Rkn>MMW?WarNIz8UrNySvKNNx;-wfZ&iE}!;RL<7S8P2+UhyYg z$%aCPu7*H#N(}8*&w%fo!ndm8DPj#h$x1^8?Qz2GPsLC&jSapE?~rCn`bHRIO{9EI zXz`)=`Xy6EQ`QVThi_hi{E#;Gb7G%?d~$5@uFraX93T8`gRY7`T9VFFh5fDKgR9N^ zlHz6a({8CLn8B0_^)6qe*BE2Y>m&}7 zJ~FN(EJ|5%Xqca9IuujzIwWh0wr)>CkMWfv*6nx&% zibW=hKUe5d9SC}Ci3j^AxtSb4a2#y8iNI3|A)AYTcl5m7CwbgA@vYck3hv+xb#D{J zP36;@R?Lha8P~o^!Z`!&IF^#WACHkgHdEcK+-}|qSbE!itR#MDuQ1y{3*l$l&rG~f z87yVARI>Qkf&XJN;kP?e;0#mSej;Rf0M@!`>fkz%N?9Qj*OHLTKe$W2sm$*>n_*b4 z$f5H%?P>DU)Pe69n^51)SKb8banfl|>aFDcSX|o}6x`{q6cdWq8Ga;+awz5sCy-n+ ze2XhyNaCYNQcvH+`+7e9|HGF_!UagDx(kN(fsCR?SHO~i6rO(~UcvwvPG(a5Kf=L1 zY}fxvNX}O2V;&43;2ZD_j`IR}!|k11Isf{};pJd&6~~S9l?zM8lVL0gQ`eXW0a?}p)TVSEnCm8Vm@n??InVueR8fUtT+uN0!`1%&ElP? zjy@*#7rzyrpmD)<4z7)bpgjC0nG~q(<)^e5xEXuMj)zQrCFr(0#62rJ@*IqTnxA~X9=F2Od+(~{Vy`;J*^zkS6@B@{; zH%AS220|w`5=r0ZVNjpBmbwqBKi{@>EcDsD6aJY0JjuwRUjSo=z$BP0lWI|46 z;eDwZt8};K-To=YRbpd>9+QE_g4S1l_P}0rAw-%m^?{qnP4w7quSLHQ=6lo+q-Kje%8?;m3@jXP$Opwx~?eZDdo_S%G(a%OSZ z#%V&aDP=awYwlhCfCt6_^EuitRUMk17uI7BUdWvu@EN$5x5z7WGIV1vO*)S&6QksCrzu-uj zyD4rKHw_sqiUTMl=Sz6d*2^3-o=E1pd`7lonZ@UPht@LwI#~CMBzH*eYPOd-Q_=1n zbQCJU<}0s654F)RlPD>OYadh~65To>;H{nO+G%;wShA)N<|VJk*0DSs>#RwGNaC}M z_)d#CR*c?EsK8~&nQv$4R#*Vc${}QQh%8t5|_30D6 zEo*HKv)Wm8&Asu`+<2eu>pT0I-S7^pZMGdx5o;lG_pi>vy=y!V@FE@)eRioly#^V< zMC;N%qIpY*%zr}CWR9f@j&ovIwR3X+c@P~d-mo(;uA5t+eucoE>Ha&VR|uaXv3p{6 zmfYimkd8kqW5-I!UHFs7#Gkc1HhB%x5=5i}j-ePv4z{`H?_^uJ{Lavfyq9pX9VU)c zcCHu;zN&4Z8hB_sCQch~oDd|P3kg1T^$#+m7R$D(iXZ-rMxRL-% z(@}UBncw0uxor1p45bXlGgBmV#Hsg8Zeax21^E;sjQ9#xw2I%j^rZ=R6A9eEAWz87 zZ`C>mSTP4H21(+7BCN}Fe84m)WYyjbd#X>bN-p?=-&^3H3SZv z8w@JA4rQp$@0=Gk#zhl0BU^Pb2eGPte)%>0@+;+r^r1hFw=i9_DY^_g$D5NRavhdf zP0FM&XK&AkQ(9VXk$Opz4|gmcLYUE-7Jqq|oV@pa{e|&lakW&~Oks8;DIxQH8mDGC ziIons71gCQa-tE3^x7j*ssL#ND{=(EOV^%`M{*bepS_q_3qCtjvrj0Yq;!Yo%}o3% z)XmVROc3?w?yuU*-bzPv*lmXtM9{vycYHXBX>R>Zt@V9&LPhgJzGrhp7W+o;id#kL z{;>!nwf4su^`tdelxC;MYULh&;HS(_?2-|WWqC~d>VIz17kTbJbAq}(r(?8B|FT`U z(1Jp(rPbpu<9|6Ern&XA>(>%KM7rJ!J(Xv@4z2u9Tk@y1eZtTPm1nnSqD%Cny|2V( zJ8RK=rk#8Q8I8FkySH{ymfr#opZQKoh-E%Ul_Su8P4e+ZV(&l#`u*k$}$aNv97Kg)Sr#sSo^VDbGg6a ze%zP?UWn$B=y$(~LSZ3Y2aYW%`_VLYo$CyrkG|MV$^VnQ;e_U5hkW4oU&O$R2z<7vuJJ3c_Xe2)JY8 zXvhXiB2&oIj$Gsf7HG-8Zfw0RnKoaCVXZrjIx_YA+;X1Z&5L%TU)T=sDKwCCXF56T zA7}IpeHq~qzn*OnGBO*|>&?*hf-^*`ZFPYOIcA3<-+SrO5QVtBLBJy<@L(+Plb5*Ol9)i@8aKoRS?(>5R># zp3gRBD54`pVg1wrMq{xQ?-*f0vyM5$WbzSO2%O6cJ#0hB&flA0Ds>Qvy#hKPH|=u*sRoh1hU24BXfX9w9J z^g7&gXSdyEeFgOk;*XSujptaxLj}d0g8r|#vqk%JX}p&rWL)BwOj3IN|L~Dck4{&FP&EU`aADr=k}}|M#%Du zWGlT4PP+=;XzqRy%(iWTPD2H`U`Y7sH?b-qCRE_}2;Js7a`-D*uZPex&)gQn^&PyU%U6 zvZa=n1d%xSHqGcQmRPCRxZ;FI9gI0Yj9 zchLkeLS9&a$B<9xKSgtM_qMlk;{;{%aIkW8=diGJb2~6_a9R|=gXNl-U4O#Xt$lwr zszSk#9*U*XYEBgqlEfTSr(D6X%;0}}K!5Q{J;jnUMo{p5ELy|iRW%<6V)9A=NgBrP@$A(uTQ7+NhgeZlX`=U@HRv(nB9VNwg77LeJkCvY|U`_kl zYrdyNqub=SUNogi%ARgzgDtTZzRM@xT(eH{MtP!wM2a#oj2c_q*x5wCAl-rV4kB`(y!$B)Jh&T#xw2^}3*Uk4uou^-Hb3=FhpZ1Fi3$4K;1AvVs_DkUGCRLnv(-jbMkTonH@ zhDEJs=>_#i>L@yKa?juT?Y-F173`^v5wAxw-YKsI!y3k9xJ=!o)_n^ue5y}IY7F|U z?R7Pm`OqlmAsm&#?ZO0OjV%y@VJz@&%ZzvCZ(sY(!29J#@Qt7mTrk;t@8m5p{61u zyPdr+*$Wey8RLswS^QbMPRi3*pPQ+&z!GEq9g~VHE62cSD9>D4OE$}sadedGDl&`h z;WwUyG6_bOegdv{)N3X4rzN9WfSKMv=-kzsYmoMclgBWPLA*(wT6t!W}<7mNCurX~L@hxf5|Tu>IqRAY|#mc^w( zYlcmR%(Qbup^Zv*p$&!3WcGs3r2F;GaMptKr{T}9$gM>9lbT}nY}7xwf4b~-UU`If zjHS&U6B}fXRMZnu*%JkC!UiOXn&;?pl}c2(unm>j7s7s;M?;J+dJgzF-(IC`Bbi~N@G(5q*OYvffp z`!qu$*N)L$=1PrFI>{|2LG96Ms3>>M!K9ytD!Kn2F1d%$1 z>#3okncsrpz*}%Q6w|P9=sA35GAYFj>6##|J05qRRkK~7#MaHm=FJ1r+7S*K2d%Nd zVeHehWd`dJT2j^Q3=x5jAC{uX5rS`&-2_5^&Y-+e8|@WZEFv>TSl5Us{Ay~!!_0=CuNix#bLEEjO>SFh=x^TZf{g@69DaB_49LqF$Vrwd8hxI36RyZt#`3aRlm`}N<268NuE%>QX@4*Orm{`XAt{~J61eeBym?ce|f z_CG7{pNGKx(~_jv^j{_V_v^n)^xx;e{nOIxe^~mTQ{nz;LBsMt7XJPEZwvo@eAPcK z5Ip{WM#N=S$X3oRyax6ZI*o26>W+0}D<}D4w-Ua89oagrvp2!kq0{Krp^k|mTQ|QF z6k8}GWXKlO-Ma<00G&p+0CgA(*#h4xB>x}}Y9U)QU*|U18gv@n8r04SvNiV_kgP%O zsvujlJ{V#RI*o1(YMUC_n!YAjaG|!ak!|_(9%2hRjcyBS^A_2b%w`4#Y>i!VY(Xur nk!|_cfmC`U8?Bsr2OJydbbvQ2aHJC0)d0fPz;<~|Cx{0CZ#svi literal 0 HcmV?d00001 diff --git a/doc/images/JKQTPBuildColorPaletteLUTLinInterpolateSorted.png b/doc/images/JKQTPBuildColorPaletteLUTLinInterpolateSorted.png new file mode 100644 index 0000000000000000000000000000000000000000..bc2f789764b3b8cf732ba659d9b025732fcb361b GIT binary patch literal 26735 zcmd3tWl&t!z z#ZVM*X3puiPoI9CU%xSGDza$E#K=%kP-yaUQW{WDACe(2V?=1kZ)iU5m_R`x^VvyC zs(EP0N>Ip4O9D9sfIwC*Hclug-~571A1%#w{HVD;zCN{7%-HmK2U`tjIkY~x6gDPK zBus^YWGE`2l$NWMdP*fC7sGBynPf^cRcyou_2zR}BB^CJS6q@zdCLZ(A7A~hXYziK z{|a&_>YLlPxei?Ifl7W0gBw)RMG8SJ(Z$_69*ItfvoS^ZfO-Q3;|R6u+S)3C|11NY z10Apy@0f%0OwiYZPVw@aY3XA;80v3Pdbb`GCzM)t{PErMx*-w41iy$*K5eJ!M0N*{ z@+^nKER`OJOFPZuj>RD0DaQ&!;GQd7m}tslcHipeaEtyRK>)iyKE;%X;280_o2#GB zBFs}hQf$=au$d@81qj8Ey2W7`zLC~lpQLz zrQZuZ(2cAoz*u8=pT&l`Zfna>@k5aVBm2qqYY}>|q)EV>M*sHpPcz^9H2zdiPDx`v zXY0?EQp4l3`>rpjM@3Q3C#eDl}Z#!ne7JSIMHx95|LuhMY+!y zL+|D5-I*~P&sg)By3iGr#9~2YPz+316iEJ-%=6cQD5J74FEeoqIoSoj=Rog)I$cWd z!USMmg{ux_?PBR7e+;d{ z3c(&dd0?uR6M%!qqM3(3?drSIyXv^&bP;{U-od<%#~8W4nYy)lmI=TJLj0ImM9F{? zkMt#6PJ+pdwIp?3hF`Hu(N~-X`!QN&*tImID^gcpSV~wGK-*8NE@w>xWDKRDbfUbZ zFQD3{>Z3@Tkg>#Y7uHkSk#MFfqWnSsO}&^&mkE~P23MPTnZc9EP~EpOT8BsLLCdf{ zyHU5qSISN9wg%gHLN2CZSY5wDtISjDG;*(jc7fR=!yU#olE9o$b@T$YjOeaSub zSccyWHVhV8;kBw(n%&D@%Q9zrXZ&cA+?8@&&&hSw4=-6H@0p{~p7gz6=CKqcL z1(5KmU3_dS&@T^M~}c?^P3C5S|hq4!!}t6YVyVWe9i3DDqEaV?um_c|4HN zi%5h^n;V^Dmd}~D-$4TC#;0e!XzD(LYca{C%)RaOc^wtl%BRR#$4SB!HA6ZLchox* z#X66#f-eyVA4j5uy_A+S*P}4ylope7HN)S zt7*GrabMSv!}`5r^l8KJ&hSTf-LdyvptFthSm&mN&r+d1x%oG6|M&N>u(Gi6k{Pqb zg#pfm=G9yHxKU&aC+h+q2_Zj$25-Tmht+kk-bKLL3jsl;Vy>L2yaEo@75(rRk>2pchf_R^BNT&e<>2NV(G*z}G@4ta`0l zt>{-lQQjUC3&DG9*&lS}=-5T3kK9!$!X$Yi6#^$w>T#sw% z9pPD@TMikPYBA=@J;>BdyQkw5{3TcDUdZ8M+P!|KJVk#Oc>m2fR3B`#U{Gw()M4sb zaXk6@X}-3i?z7H$Bb&ZR|ESAMXnT0OokK7~8ygFIKsTGUk!p(eLT+jEW6-%l9A2#S z2p_P^v3fIlgJF%o%kHYOR+(JUmzF@WL6KSEhs%+3|8vHSPKHU~MrxZ?({zdBoc6T# z-s<`0RwpTg4%-|%`6gLQp9g}4>_lRgP}ap)H8UOc&bTJU7Das`!*wGowf6S2Kre+y zxda_${|4*J%8l>6e!Yzsw`)tpdrUeA2~_Bsn+78x6u9Vqad3@F3*6g>0V z(=A_C({?%(v=?+58VwUTlQ=WOn#*d{;96Jib!R#Vp8DY%ytF;)Sm#pJnMDR2MH599 zocDbBI3ynBpVXAt7HIQq(R*rLKxFfKVu}FKFcupot?Az8kR#A1}KXv_!d`U#x z!|EV(^pW^51{1_3B2KKKmH;(h`_s0Qq1*g9*KKkuE zzBQxF5+oX18eQ}py4H9M1Qj13{3aKKCxsV^0z~z&3mIJz74ik_$NtV((&=j~?8SGz zTpWK(**jPN?y@7-McFse`*NcF+HlDfOTKl{GPucqZxjeKPOYxsNm zaNXyd?;95fo)GW5;ltZfW1dO%x3#~ES60`aYY%^Ph#IYpv%abad+f5FJN@m=_QB!q zzHYu|{+Jzf@IGYtHMn6ifA)}QxZX8hZ%`~A3e!_0T=NGiY2{^_ z%rz48>plw?T?XhM-MugO4csUi-ag)$zy0r$y{;~1*9&rf6?z=+cqpZ%rWOnI_*@&) zQRTwKehb%XqeuRaoh*w)8lpl=^W`4I$`OdLOZQ=PQH~}j^*3f`p z)E}T1R$CfdlPQ`twCBo$PQZd5MNQIW>c$UPAApM++8c*w(*>Z*0$suTuKX>bDELuB zDQJdG{D4HqUC_v$t0m0;e}~M2O!f4L^p3bRzVej*B?6xWv!~)3q~SJZY^LEV%TIon z;n4o7qV->28W(BREh6%lq7w!hYxF64_cNj~GE4@rMHpU1MWcb1P63m@-)zEC1W9gY zL?8CsPaRqT0`5OMq*9yr14#aUFAkV7Cj9F|`u6wy@Y}OD`3U}==-E!)>x{YV&PPQStKA%XRPAD50IPh8E;x{rt>M)GS66ab|)AW#PN> zJ?*x-ZU;hPDuCf-4vA#S#5{6wMRSr8|4&PELkf;fOceFKG41uf^t3>W8rmx#^nrC4 z3`hF#;e*Z>Lq@}{CTCR0D(9!mDK{mO3U!!|#10P+n+-)qgomF@)1gNVsVl~U@JL8D zzXb|>Y-&~vY*c83tJb-Ey%^Q-9E(jYgAi&(FSK@8ICS&f7h_P8(YE zk^hdxNuB zj)}u(U2ORT`D0n63oJ7y=K`c6($Udn@Ua;6ERT#-cwcVl1LGl|9UeffTc_P1=zbV| z*IrR!RiTiflFwiAX0ueO{OfWPA)@;6`bUwu3^zA7>E`5~YYYEhcHJa0k=H-Jex&^s za9FJ`lTD&S$xKR8y+4{M`WURz*l64*=y5cCx>R+(ri~tzHu4e-CgyiF_4I7J^V;t5 zib5rl0A+0DvYYfZrqamHu;m)7WG8+tPw_BIoUTGVUXC%a)3YI?vGTfm!eP>X$-tM_SM3^&pG#G$YURa{ z^^0$4Xz-pnbma$N*F!E7uc*ahXg4l^1nVe5st1!Ni^` zf4E&DK)`ygaJ$>%7?LoH=REyR&o_I1cZa77WeCzK`t3>7vZBYo0XD?+?RWr~!;jta zjaioF=8ILTMYwq`J5o7Zn9A|HmT*rNe|Nh5=f;X$;yNnS6zo0tdk$7v8^|T@-_;9s z8cki2K0h|OQP0JC0zBkO<<69>T@l)R% zkHe#MGqADoyN2`?3U?1;e6(#gO^Af6bCHsIr&oRdJ$AWSZA8-F@9MR3q0aw0DsAWq zT5{ULcT^Pv32jkhb)%oVQ)bb0xV25b+`GCC{Q3R&&;7R0Qg${iC#T%KukY)8wP}N{ z`rn;CmyUq!GhDye@j|1tvHcUYykcNnN5Ffl>I8OjbgU zknNwf!^2ttVZ!t84nL!b@#>-B_LY40EX>2V7yJg_&JZ$C?NJOZp>W#l*0t@&< zb9u3F!%c!$4zUClZ(&vQ_X42lhm}W>Mq}t=Knd43Uqm)k!MLivca*Gp_jj};ZLhyf zc$Eb_=#J(-2HYL~)E8`v9BU#wo@jM?^X;@4E0#OEL7OWo)8n2lOyIO=EA0c2x?>{r z7EgHy6Y%{3nJ9E;F)db(ugVyF+l{l=q{5bOn%&!icN|aH>fy>PlV{L%cOMKxu+L@E z9xj(Zww@I(?<;c%(w8($1YGPDck-<#hKIXsj3)v364C5lUcieQ2T?~SAv82ILtkUE zpYcl9$X!FiKE7>}b+7+uBVV=6#>poW^R;ssd(yAQOT4*bXv9eqAhtM=K_w1nH(BNp z5FGqLPQX^}umsr1sZv2-zW&x~hi25v^-En$4)KejS*dmjNIP+MftdWJ1miWFQfbQ) z8i(Dtdq_lJt1c!NE1E*~0ty|`yFc-~T#ux=8Ai}{+cuFdI%#aJS+_+>IjxzqQh8`N zrUx;4HAVW8ci`cvGCUV)(90#u?*H;DO=b9(^IZ3*L<5;HVmLAR-o z0{K1RoBRmA7{9RMhU`@~y)dI354;I($@j0mp|b^Uaz@oQRuMCK3o<%M8f{;(n|$4# zSY;E3Yd;NEp4dK-#1jq4v_FHS`sfkGon3!NC+$~mRQI86#)|);Hr3329f%4{nlTR1$IgKR=; z5!CtK^YJ5qndTsoUbhwPcWS)*U$Si5DhR6?4okg!wc1uDw}m&KN5El@qeC4|yY1+Y zNeoh6GRI~7OwKJK5$pj*DXUhfpVWDwvC0kq?vjfyv2L|Q^?iI}Je;l{0idN!7H7mD zRjNisMZv26_9Be?)Hs{ZsH5}NxH0ng{tzjz=;uM0*^s9V#<4#Dj789uY#oy~S**k$ zQAZJoB7IN&*ZHC_exj8#Z(n?c4jEXmckuxO8C!XPIZtl-{@8Kg=*Em!+3%i;0*ck( zY>N)Ahg5hn3nTb_V%TpKl_p52nS%{|D5`bO&%{Jm_hgwV5m5sN`9V%}dDh4_>4~I? z(xOa-MuwZS72f_q#swTrNa~4iT>#F3f=zC-n)g(x6bQ^6kw_x1v#T}CLDT>9);jC- zN-ju#2?UNV*EF?Se90_*o#k`fiC4^8i$_2TPGwQ$Dg9mY1L%mum$IcavK*70JyCOp z`vx!^c!EkfG!o`@nj^y}i;M&j94*kz-EP6L zMHO39wF*q@m`b}mtk!-Yo!`S%5g6DL{DP8;z8k{oD2b(y!`p5znQ1jc{M4nm%faC0 z2JZ2~#?VKahXGUBub9tjWwHIO(EIdrM`XES3i^DfkCuZ4#T77Cu=j?mI-*>mE(lAx zQWCdQDmnb&SkZCGbdt7f_ zk4JE?6h(~U)|GXAVwrkS``U#&N<>_AGlAwDiipccG_;0On8vC1%ON$vRBEi^WDf7k z^^MAW53J(sK>!B`C6xVe5|>`3NxZJg{;R!KU1Sr72yq*Bu_~xy7#vzr;O1#bL<*ZP zI)i@;3*RD)nXlxE!&k8DNt89B{E`xk($OY{vTcx|MA8-`7ETRd-%Bk%BVC**NMD{(s_>_~3Pb}=Gu1Z7d8l8!`MUGYq zO$;ZmRTyWP?Du>sJMnN}CvzaBecfyD zzLE%jFo~@YC@#2DI;AIYhog+<@r0&J{#mQs98K$>dcZ^Uwk?GPpv8p}6lf+wHAluZ z^)aw819AsSnZTjMwpCb+wX{{Ru{p9V5#xQ z;|eE3$xMwzTaS;LEm&{!{lMqaB46e3z2yZnUrQhqXVx_cnpYEs5vttZxX4C;SCac@ z@~R&qf&0R*me3iXV_jSiBseJA^`;Ka%jo)#C*T&e>^w+x;!A&lq;Z)?nUE8RhR#Tk zpC4i>5~^-ouM8~@RC`xiQKv>tl>p0zO|0|gC>RRR8@Mz0}e^8Kp?umEKM{;VJldZ~WN(3-fi_O?##dHz&_Z(V$R&!%Q={@OK zIkWutJE9^4^IdC4d`M3EV$)496!pNd$QexFct-V7oTAy?s-Y%G9lEo8FXH5%@O#Tf z(=QNhsH`y+_wMDfFNXvrK?zn-{?`=?IYvSFW@m)5Y+@4;h9~yf_pCv#z(b(35crge zEjI6tioHhHp>4JAQ;sE%jE<}qLD$#tCgL>mH?{+=h|UqP%~`Y6^z7^zLc@s+5{e{} zGMmMB(iUu%QU$zBoNqR&Z?{oRj7+gJbERvphjNT8OYGj}HtY}BbA2=?kyX7tJPPMK zObPRd3A4NL)PRW!Y@UKqJCZe6>MlxR1@pYZCUdx6r2Un86VuMw+E4C~n~8!C3@ZIH zpGcZ5kVXrQi)&w@$zzX8vZ&vy{Vmh+EE$#t^8Coju7M<_%Y$(!-cj-;TwO7&0sx!> zCj9zga7zl3Q$)ElV{cf=n>X=v(J^LW+UMWv>{3sQGoXl&@o~Ay=#6g&7k(=hq)g& zBz|W7HyOP=RdKROYraU*6z0fy60RJ?JoDYkxiW>IigG^>;Ob5dj-oMB2yEQp^bc}U zAqBG>9yPILqyjQ=Dd#pB;e6c)JM6+`gfQI#OWgS;qR5M!2G)9@6gBvrT z?c;t#E}ek^&|KCraz6nIRpD%?Z6pe-mmp316+(U{+uEOgt z8$V74;eZ>lwYK1o{>dcRgCMD}1GcMF4>$DVVP);6jS#fU1>;}Zr)1pO4WssVRSa^t zT{%c{u2DjM2Ioy|^r&a*(?d}#vC+7qELON|(;5iNbyXgDZSf_D_+}PEDn^~oELg=M z|CWW?i!Th-a$Il1`NBKm+#tHP;=?C3THF#VHJM-9^5amb)$x<%yZf-U2F;JeUm_?k zYzXDxx`Y2()j66VSCw&IT|zvZ`8{Am7!dRyv zpgX6hbNY_>U>{)0$&?#b()?zoEE{sq4G*{S_mZ8nnlWZX5FLPFfVN&w^|_T)(rd+^ zj3ia{&5A+N>5M~MIv9i@tOnuAE;~&vi<*^9>s2jG%RTrGQ5Idh=vs?}2{2gCFhTQu zpFS&+Kh%UPsJLR!DWgcAK(wXoGkfyP#XbzeTJcJqj(x8Eck3{1=~gj)jv+jj!9kFp z#?uoEZvq90nmH8?%iZ93XGcrwc)zC@m9&O5h}OAuew6ge_=fAE8--{Hzr)70l3OsY zj?H-FlhB&es5LS+Z8NJ8i|)V?ZY^nBsfynOb{HunIP;(i%QcQnt%Y?x<&@-)f8QF_ z99C*IbThRXpvpPazOE9)F6zGD_=JRAHKd{(dR>j|+!B66jDuCazU_w*RQe}9&n}Z! zkLO%HBttkb2*ade%VS}g&y(R`!?l7^b`?b;h0%!RU5PM$#t8KHWB1 z43*rYA4}eXt0&o1tox_ih5WvDq7z@t2x2=qj)o;+_|KQ}&G+$;F4>qyZgis-UR?QONSF-g+7f+OD!Fq; zIb5FYVP*d{%>d7sJWaZF&Kc+so&c1i}UA`)C=22(Q;2A?xx zo=U!HoG%D;bKZzeSUD(=e;%&lWf!8H^$oRs!Hm|a^wd20WkA6s*bQ%8)>1zyHmA?1+QwtleJ-i9z@(x|B zUw})cBJ^w0$U&4QH_}_nm}s5m%jZ%x_tNZfQ17$?5`w_CUFG?tdgDTDFQaLRc7erLMLdhZi^Vlt-|;woSgZe8Q+wX*Q?M6fDps zjMGJa&^F8XS1v6$tbx{f*6W&;c7kOda9XY*L!?_+JSixZfW_MQ$sQiNYh!I#h0Eek zeV-k>N?py2a?6q|_v(rO)jxu5B=wDYs`Vrk0@pK`m6n;b<`V=kZs&<+t4b=zV`y3a z?8+|0ItE)>Q~D|I3& z1<&9-j38o#5l@{H8cSqeaw}qMsIRBGm$;76{rh-xH91XV;GN}Tm^QUclW{7Be#{=| zk#(hx+h%el1Jcag{I|Ft!l$>+ommscgn^rqN?(@jGlfmFwt8pCe@KO>8>}n1M!Re} zT~jgoDZDQ>u8|x+x-ac8lZ_Ho(oQg#- z%450Al0R*(!N76;Y!Z)GnO33cv*F>ShXx2GQ!qY3uh2?JsAKeIhQ#drXoiKI;xWl; zv4Har7MZ}%3$BzZO{n2`JG?_rvEr!Gk!@y&tv_)U>8>lD4xDn7>o`2H1hHMZXKcvl z()_BIACGOJ8Y^$xxof3>2Zo?N-EKRVcKU2NhL#ae3}odn70cZ2ko7dTne@kK;gNPZ z9gQK%-4jN4NRa!=TwlD(6O`*dKe?oN(#}jIkUBH8 zI2&dg2Kp;eqtU|ykqb%ad=Npe&c0p(L#Hy_X7@wcAUB-G#aDHZrrm=8u-8R){>agZ zG=`nI+2jPY)=XyL_u-5_jqA5@wWh?k9`nJcl9g>0Xa4WNe}H%YDPR|hvihqSW%5VS zjBl|D$J1udKLm1fC;*V3 zf4gLM@X$zInx0x2dV|t@?J?95BS4rB%t0%lZUEX6HY+ve9#oVfrpm2wY#FaQH!P+7 zRPfsi{e2-s)9^Y^!#5z~&PVpaqY%{dXx8By3@^1aGt;u}z6W;jd#!V2;!8z{!S;Za zlQG2PNtcmiTscpquUJ*|pNT#e4a5YUbm9$8v#Z{=VG*-}Q$IZa^&B}2p34Tqqe9+3 zfovvo=U%+-VKBJqL9L16z6#P`f6pyeb5KH^Lh-$$$z+pG1l&gJ6Y&iNpS z^1sTc9G0s@4@x3qL&{8ZG--4wB;<^lx!{W-1Ynl^7&E#W2*6Xt8gg1l?mx{L0T-8?K>?nL&;3D&>RJ3#uyn>Z?omQT zy{4wwLjlyljR9+x(NXI6ybi}(T|ofQhQrrN#p2%UT$lBO%F!Mu!%imgtMNCnG2uR! zbaigVwgH2*;$QvBL1*;N`-Je+98}jswSg=`w1;>l1W1o1{m)#VKupW}82(BlT*ldS4Cy%9QN!O1+uv zlI;Dv5`JR9=v~RlIsMuttuav6!^Jmg)K>n2hXxYaWCp43fuD$p(RuE}rYjV&@cr98 zwpdebcz}GosYha}>z(GWD81e_j(9zuIGyL0Yf4SB zPaf>s@&SIZ6uV4cA}Q-}6;1~gB*Rg(d-TGk4>*mVwdBNw+BTyTw5=L27vgCRcNi5` z$?ziRlyx2XQwegjn9a-_S6w~Zaw{`gu`olv`knKDb5u?|q3L0T^2huP*5Ij{h?Z6< zu>Ug)kb63)9R`V?;B$16vnz^3a@PbbohGLjG~Jud{?;V&W~arGQYNBWa=VZyS(!|8 zTZO}FQw$d1B{_Q>TYsjI)i4WgM2Q&#BeP0dV5ycNmTVZjN7zqX2j|~EdaiBD`%k6; zicV9FyG$!GNV@i5tC-c&Hh>@R(mHFQ7D>$b%Y zkaB|+*(7>$|DkjwECkI_0#gHqFjD*1BF# zL**dWWTvz)f4!z0{wBsBrZO%sucTYudEEG2h}D~=O;j%Q-8(Y^W!2|7wvp`SCNv4s z=l)p;X3RViOI#K$wUh@44A$z@8!D$K<#^TG6U_^#-peU$u`u!-mQp@rm zjhuIji9I;_mH!pI+3EOv+xTsnM^C>+ZD)a#v?vp89pA!Dc^MEcZgQjSbt^@aYFaSV zjkY$R`MU}-sqvWniwE9fACunMK0^C&=vcBpKHy6N8p&em@7eYtQDTvp*hg=i-a^SZ6sc{t1$!ieyWR7lNa#rf@lx9 zMKK0KSl6hWxgt4VF4H()zClzMb#Rcj_UAJ#;HfyK9mMlO7O7G(8$s5715smv!6%yp zMa$(KGMgQa^GvFAEwCwRc%jj3C+<)Pu*%=v3V0l-f!<eVXezGG~pq0|GvaaSpu3)$&?nFTfjC$5KjHZ zlYOjE!ju4aC={A>0WQg`t6CB z3@bd>D*y^v4YSLNLYnMh`Q-U`ma5U6KKoqvV{0o9A=}w&&WIX}fbmWDFcN{sT4i~; z+{9BGw@g7f=JHo4u5&P4TuMl|eD)!l3#7MrEuM2{;fumIZ{xCZ-G_xoHO)YS`|39| zh;g<=uevH$H2Xq!xGc!OyCcG@46%5{>+bXk^&s}sY7<@78Cf{OJ5KNhm<_P^m8^@& zuu1nR>B~tEdFj4UY&S|=vu?Y0+EH_pX<>Sw$Y{LyR;R_=fJw zqW7Pd)?B)O^kTB1-NxrXL`v)#aD?x?KD0yruHvfkdxu3%o1k8k|0n9PEM|u6Cz?xi z@n|$hPqVQmv-)?J<5^#-Tr{u|Eyq9*(N)Gbxa#O8kcmIQ<40aEK zhh=+2MRvu-OOc+J_v=}8>zeFoWRO?=80`{|J|Gq|%loV@*9=(;cXjQ~Q<^Pp_tty; zRLJ}QDibjNCX>as)~TwjStvZ+SW#@qmrOV_JPqL=Bz^MbT6uDV)@G|j`3sM5HCdMG z;8zfP7^g1`Fgh>Zlm`o^%DfhqRKG;x;_CJ$Bq^zB?C)I!D~3QIF$w{dP~$-DhuI<< z?vE?z`k(5@;Tt@^u@p#ryJNV9LO_OxQ^w`k7z6_La3#(*SOTe-kylB#N|+Cz*`o96 zP1~_ZHcJYw8eTCpHSvqq)|>5a_tO=bwVM#4H#0Eo2?niburj zmYX9V?eZa>6Wawg&-PHCV0A0LLoe0&D#Exs=n>)lB&P71BKJ=@;XA5$v@uJ8kGD*P z!t@8sEDTXM5bHh?@?hgP1=H-em)8tdpb16(-{JZ7;!kI4jommxRc0Hg)0n7sfuqOH zCo+2_d|#DYcV^;PXmyd~ip5;$tZNH;=V3%3>XYo}<`=b4xRAitrakWub49IGgRM5L z2yu%$2JQzx6(RnO82?bdnbin~1oM;-~Y=PqB2ePQ5BK{xsaDFoohZExq(!pr6v~W<6BcBQ}zklXS{eHx8 zcsnmi8*td1-i`!33y+56kBlr7>`K_1G~gRJ2i8^eu^YnS=)Bxwc?xK&T^&B>X=`Er|AN|& z=hdH3&R3hY69xAVIK5di5%1MF;}h0%RWLC6(Ca;@eFz7wP2u5UV&t@(AemNfl@gtw z^s=5zt6)srV!Ch&h%Gs9Hr}#?rS|Fa2P*>8Zes~-?ptO4L$!ha=MQ$kS}Xf;dLEc$ z9ffZ*-~K|}(7Y@WX2*36NKnXo4CyVnq=Ub>;(cV-2hkq8i4uY%)a0=5J!8PeKYqE+ zA*md@s%)hr_`U7@z#{c>`BcflZQ&t%d8vm?Ebf?=9{zH_PF2`oux`ng2z{qON_u-! zl3O{Mv0l6~_Ys0Gl;+``R1Vr;0K*w-=m$-ZM=zE=0*oq@T{fs4!M~dQa~R)#r9!pT z@gu=_hqiK~F^f}88cyCjTZmy(F0UR}m7rI7lhU`ft`sW?Eg{>LZf<|=6z-~7r%4_w z^(Tl9ll*vB1*@EN+x3B%W$do4@-mY?l1>-*P<6}``5A7ZKlSS53gt(B@?J%)Lc4uE zd{P~=fi=VK1P+h=Fx?~u30;KMXK|)5Z92Ma-Z&AHm1D@AGZA4Zj#zr*3Qb3|n`blD z9DSMe4p9Z1_%=~yY*8ExV5+QIgwGd|CqQl77>JPIAe?l{=VO0=4qLg*=M1CuQln){ z{AbM~_xH2lN#P&7cpQn5;%8Qw9ZrqGH|V$hGw4SVWezy|1#5kzzkkQf{Aw8SiNKW- zmQq?>3;Vt;b`Nn?Am0O&#@~pkjyf_P@daiGIsKmu{;A)dUH2%1`{ukeeFq&G*^+Lc z7a5HR@#b}Pp_0`rkn`Rt8zI+V7io$sPoJ$+E9(`FI&bT@ZEg-bSF-)L#h_g-X8Sf)JxZZVE&hQ&(@p=SG0 z0E7mODqIE9Ax^$7I0~_O+=%K?+pm}?QKr!}9d=0TDB7szkrvPT(e~*~!pEG1+$61N z0V|M!F@Ep(?fUok!AhTNUFe<|oE&!Rt_b~ugY|$UJmzH{q5(){(H(#QtYs->pRV8$ zos~-dVRd%0nDL*w?*;nb?!3N!`z zp1jY%7UPsFJqminct4GF-WQi;aQB4BF2E$j;ASM^L0qY8-Talp5PJ6UFN9u|lw34^ zaJ!?aQ)Hf9L>?(yZfauD@{NWTJL@LhlVi&$KIKt?pj1LI+JYMPCQmdA95a$UH>U?v zB{JDLQ%R6D+UlVM+cpWE$f2dQOv?uQZ)wIea$&K)&$=D)RvTQ1Z*RH)KpmY4OPyA) zwQ{Dvj6O7N;%@ZDbo&1gB|=Kb8A}9#9?`EqmmZTpOKzp3tsj|R$;B^29BnBu2%^-L za$#Lu%r+LY3AG(Uw^Azjh~3->c@_Q?XVftM-uVY#>HZ7=j^1w?Ly0Xofn>L} z%KyWaRuqsJ3Mjb2Js~Is^QS=PxV+fnac#$jq}QHKg=-E@vvcIj3tjD>7=w-qy1khd z2x5=Fud2whru8Smm^4sjE58Fw9tA9~IF7vI6zUyjz3#9^aVK)A6dZDO3>BCq z)tEZ)?G6P6YI{pp!RkY!afz1$aNBHOs$2Npq>q?drkcF%Y#~hff-lRVxC}40WKA3Z zNZfO1l9_)%ZqzRxVVNe5a+66OTi2n20e=pcJ=`h;G2o?}UkwV@muYVs(2_v(^4ycd zig^sw!8f91Q#~aSk@bfgG!orNQ<2F3^5Yei@X6a0NdFI4N^e#CHzGH&St=waQ|It# z)bwN#tmBC{#}-OOL>;k@H<0F38Ja@99u7}H0EDJ7Jyroy7M9jbW>hp?{8ocVeG0fR zb7XwWFzp25(=9qZPAC|NREdaErHrrWG(YDxEc<<8Gj6ex`i`uPo%(f81St(NVN-1K z10(3r>~x2tTjQH(-tByMYp#4|r%Rc)6A-JoZf7M4V%VZJ$5~}kz|rNfs!JRLCz3a+ zNn_-C91_K!+xDs0Al(Yo2Uf~3%gE16x)2BfnE|-h4byWJBxxNpjsI%y(pM~prOg>> zJ|rC%t_(44ClsqxEg;-_DQjT>k9qAOqKltbS;W6(t1e)k=@M6F4~CxuxlCJ(pZt(@ z=RYV(TdOg%HCzZE);1o;=9ZeM9Yu zS*g4n<5f$7_6~_myepg;GH&L|3fTLcm#UKl%Z%=Zd%`-z)!s0~F^wP^nJcRf&GgA! z{{8c#dDsX`rq5_P)nU+P8fKN0f!E9<9VqgHP z7J+1k3w>sKaYr-jy8cxv7mXpzI@$Rzzgr_j^$%_>IzS9m63Uu;gKHfL6*;@MF;^$f z|Hx77Qrz{h3NqOcmN6C{ZL@NGItVY}r2m8jgz1)sr1W+7C%RAIy&PI*Dy`cgqCZ!s zc6#q4#LN@EzM94UU{C3Ex;NzLzUIMu#ha$!ejW6telT_zAjzv0CnlxiSwW#b?}@{A zX?BeftidDih(nQMY6Qlk=l?fvs40$%Dpd^7v7XEW2&@T1`}=ECDJ2t&Fd}&zaS$+Y zB+syY2PkGXr5b{0B^6$utirUdt%-$+>7^n1gzO?G1nHh5X`gI`&YeZD1SdkAn`4M@ zR70;?iWrP6kxa5Bx?k2+gKrN3phI%UOp33M788OK6`%i`ROj7_Vd*#M=X{*aVrP*& z8%?m!ZLzWO7{`-hGombyU`E&H8<6{RP;F2wizZ7MN= ziK-U@XT953Tb|4WdHR?=fBTCM6!|<%C(f!rJWPip901WJR1w_)L=h;hT1H-I4Z<0Y zC-Jj*YTys(KCZI!Qf%4oa&=rZ2Hv%r;8=-t6hp|fscQlnzpe?=5}hoPsl*=6%}pw( z<_yw_ATDN(j+)abYxQ z805Gb%1JkzhGm#fyhJPO75^{st!U8W$IX0{3*R3A9td4)lULS!x=^ZxM;&i#2h5nE z9^_=}{SP;i8-zS~1@cj(OoL9^yz^J#;`;4BK5Rxh?bD?m*JKM~;k<0Y^;IenWyZ%2 zN4CiikMUU{=ObA3d#}jN^JzEML3ELHV&r~@%^CO>|JeekmoK` zk0)4>SDtWv_qD?*^*D03Tt-?;IAIAwj0|hf$gWnTw^wwxNw>W$;_=~_VJQO_bas`P znnTgrC)=E5SFP4Kv`;ne*Gh*as#ab z9w-zlETVW*r@RtBaBN4kbEGwbo7$Eo`aPa5M4d#;DOVkaCS!7T)GxgH?et{)`ZE7FucfS@N74!#_75PP{;jWEk)vWW^47>e~ zej|j9Ga2e4XuG!!{%=N9q!x~xOSZQ#Un_~?$&#Eo=l67>2L{0@FLn!lN(22w`4L$7 zJ5^~pJk(FMgNZ-zKKdj8GS?|;Trs2Pj z8oV1#O;DqsIa6P3{TnvyLXJL0c~$d$sf4fxbxOnUm7JXXNA0IN$R?nAqu$kx4Z+K( z)pAokutI|V0zvNHi}&lHW(+oa-l1)NS#=W*R?x|&e7ZaJN8|5d)xxT{%gTVG@l+&P zb!xyi^o{m|>l!qE&D^J4K9?Q85nu5HVqRfkVLGMkWDzF}6COrgHrJfzu?wL~wzt2P zd@s8_ME;9B&B@fVrDp3yV2fRD60*v()Lb{z?95=wL45SRuJV?yrW4NAbuXK$yDz;y z*D6J#MlXVFY|a~Pb|obxhxRK9L#3b5lFam6s{O~9_|BNMQDj!7sxY_y%C|=Co{-3M zWhv({52xz7 zg=tPh_aF&Von`(wqC!Nk!5*Ivvox?{AxusU0^`QRP^K~ zbJ+8CWaJ_J{@Csxe-m4zRHhlX*)H7N-0be|Vo}Qo|1}w07xKB{aoT8u?1zEu;%RNs zXzka9oWAq>>eN(GxMnN)R0_s=2xPvIy*drR?^?V(>guWRLA&Deq~_sJ;e4yxBaKd3 zCW)-?Hn_5ON)zP0>AQRm+Kx##S&_davZ$!ng= z*de$83x=N7Q0n5XloR+=^96E^vx9}6`j9qD^|kcXb{gz=?c^z<<5cad2!u2{G7xwW5WwXLpaV{U5euO$S6m64GV zw-HiqY-(zXRpo=_^XG9%#yx83<^<=nMUL~Gv8N|T1Vf!)zdnc2CC$QP?TokY{9#VX zWOjCTp*!&b3{L&{@nbG@VPQc%Pvw@VM^(Y{Sr^5B!-UMFq@;5?hR4-h>aB0DjTY;w z!?jy_|C>7G^Ey3t?~Gw5pypAMlarfH5OKA4aM*ykqZ`)?bZ1-tJHF8w0j zYIyn5rC=&9^r*7%_BLP7&sJA6(gJI-9O> zK%r1G?+<)vMdx4`OGQP+_w2-VD=wIlb1*% z`_4*iQ4!~fa)@yx`FF^6{Th2_hXPd7<7MsX`pm;3D{)g~h0lqHs%oDfF2Ujc{*SS- zryzI!=!l7ljq_Uc(kkByVB}_$4P(Msj}(tpS$#*(wM#5|K)5qKgZV72x(G>pmy+%H zLrq0R#o;xGz9DQItuh?VO|tZN#B_Q(I$o|8=vEkMQ?=%oYxx#Vm#35{dD|oHv3C@K zR}MkXRjOLA+qZ9Tn*f4byD5-O4Y8QzR*uY3fH#+0RR7}F=Nm#KvXbkQwNj!a1%xi) z5Q0_aFzz?h6Xg$sZAB0;>@fC2`I#5!A1Q&XdlVspOnq3?wG zt2x9ZB>X5tiRI`?JSBA+%74nFBOxKdj;{q1eTEe<5jbzn?D{pFuF1H?&)*+Mcp0Yn zRJ-(-KBqSUW~fd}h8>i{OeW!VG8!7TL}Pg2gu(Ag{MM=ha6%r5^XT9;7pUhgIh?1R z;7Eb`yVKjk&TKiZQ=c5AgdUaI{d+k6*6&lA&!N@wU`~l1Mh_6ibx&16LD+qZNoce) zgelQuXJugK%@yM3&3HXmM|zS4mmLy$&2c6=Iuz{Z+f(4|r8LAk1_yazC{s1{QBY7& zMz8uY&-?|gATs93sj1~)-@WzooWmocm5Y?-Xf>i0{Q|%R;W*>X_CZNQV+h{0&++Cr zvv>pig4?IALOIlMC3w&b9R{W!D)GD&eH46Xim)oSKGWBiaB(L7&3Ek`?yN$Uq~O-m zIOfSQ9>A!a*hMl(o0yu0vpw|Kw%q!JCrg#>-If*=!$Y$&C$}@*E6(Nvx5z`($=2cxVE1&_gx_Vy(R zO~17{6e|-`|2$LTJ99g`Yi*ZpTVBpnnRCjn$J|AoehDInU`LjilTlLcZ2p!NZX0?Q zJR_+L)1S^R*xK3xd)99&fE#cRtYd@NDcYd)XvNZQ_{mI@Z`pVU`(lb#z8d}Iw1Vp` z*8S-hPfixoeA)OkHG5#lvwwy~ImvR4jn)dnv=`p#-p0%fV98u4%$L5wvb!lPnb7cA zk{D7#WNUZ_9s^)SJs&PZrIkJ4w_O=7s&QG>!peR4@F7YtO09neri{&hUgmeI1*`!( zbbhui1kgk=mGLnC5>`pmZoZvbR`%P|ESVC+x|e@{wsZ=)QuMROH|?%Z>DQ_vk%KVl zyd(|j?=;_O{_NR6u5$9)M2%`9FSC0gy|f>YjJn1#wcN4HU!58 z_!PH(wMH2FvDbct27`XJt*FO#dow*BqYgy@52~>qZ~>6+5kLpzA`As%t%o_R^{^lJ zg_bW|xb^jXFMzX^LhDCb_eh9N7#D`I;v}r{;0@uDBJDC5h&~53TRXehqX=W6hY$M+ z#*Io1ggov;b&+~URANxO)$-;F0G8*`E_cH!gg`GM`}i?{%($AjCE~oEez`h`OgA}ie^>q{W0hoDm3Rzs(wN4^o#{pjj)#6;8TBFo3#47pK?U* zI{5hbL(f!_`0#@lN9OFf^{UunYht+dcVTMS`Qy6Q1!?>($KPL}t}M4(hB-%Yl9P~# zPfdIcz1fkR!9C}!nj##F!)Z#F-$4qaohPw}!#4%(A9)`Rb#@j479R&;en|{WLYD9t zVkyYU)jyg@w`}2=nwoApKf;p12)4xS5s2NM?(Ra3g3lJ%_FI^L{s0hnA0K6_t&Ws1 z$|h&>43+^CM^q33>=V1ksi$v-&o2=>;|J$ydB;Z~s-6+co&o3bJvrQYa3*wo9cJGD z|L!hm>;s+xp;64WT2lNc1)>9vVz@y48!WQ2ULAa5U@$pSqQAF3b+o;#PC!6lV`Brc z3kSz%`=i`#a~7$emkL=i+2o7D5M4Xjhk0$Q!EE_PuLCANB}w2mjjeD*$pUs9JTp%y z*wl=N3pEc>V@JUL;J?+sT+`c%6Fc2E?foFMo$0x^o-F7P*IPvq^!`0l^02^sccN2A z6tnly?(j$X!wb}0y{>mOlLYL>fy|x{rvndybd4^OCh7tV>Cks{bQE%4QiI^m5qKai z_X6(oc&;NlQ#xc9(iGS%9Q|VeW;M0`(J~b5K4ZkZUMbKh82se;8b=KbAW(2=Se?#(w~^imJYG6rKRO} zl9iQJ(A4na*QGTnZG0CS7yu{zBc*(_w;|?pybm=BID_KeA~6C%%~M=d#(Z5yMkX~i zHAgX?r6qIb9v`1ZZ3YED1c1E2 z?7vlyB0jGzAiOg>U7DIUa2<)gQnkaso%(02vIge9a6*o` z3hd-b(Ye*OW0H5Z%8XKqwG@@_(jk~YR(N}P`JA2X!6pdy zw6;mCOUNnFE#a6X^g_3MnSAA+KYvz+3K-}2VlD+E^0Vb#<+>@}b zL(Tz$?58O*pmsUbrjWTxi4ex}=HdP{>Bh`bH=bnpY&q?LM2ft(_T%Gk08{F_M%ikc za1?F9l=_WcwaAjI8skL<}L7+j!~&G~`|Otxpr3GBjMd3SoSNVk$7qt3T96b{zG-oa`8g@!!340~t8clBi;FG0V9P{iRu-L@kCHwBVw9-o z%VF;&hEm;17JRC;+(}-$aXw(ogO7vRHrVcPXNAsnE*}JxI>K30zxXAIwWGRgq!hW+ z5zPvfy|Axubot8wYWRMq(_(Lf&xxK39pa{ootAJ0&ja`V6u%3HJ?vcRr6!OU4IVpD zBLcTf+x?_(kxm&xIaHpW1-``lq*Mz|Nxm{YVNJ4bzBfh0JuM+20b=`m2pO}2_&{DH zYIn7)3HeCQb6TU^Vdk-~uP@>zn1jyr96X?{lisNiC6Z|^JDZahiN<-IT} z1qo>T{5cgRr3p*jjnl(gm7&-2cDWw;8`+P^ zg0J{>zPb>6dmCb<^S&GQRZf*Ef>5_S|88be1|mw3h~}R0>G6SDw-f!{0#G5Kcc41* z9T+&10|Lg{t9bl|JB_XUcrNAJCQEPdTgPzeR)7?Az80x6FmD8;3wx325RH9fFo5zo z2yhNIQvasX^a}m>%89|yMU4`@SOb+q_I6@s2Ssbs;d>y$FJB>=Z19Z7UawHEC0T^( zvoX^YKVCJIZWQgKZ%#{+DPArG_f(nWiQ7uWg%ytdI03Xz9+i(`Mv3#g(X)mayt!}s zwSQ*rHKD$~KC)^q?JHn;dZW>c|k$clqK9otf;XQsUhMx zhE)3nt*7e`h6>bc-B`0FzMTcbCZJxzB2ZIwlKZ< zMG%L+r3G4!Hx2iE!3yZIgUxSr++19ICds|~a48UvJv}{@yl)eY^@sO~t%Y)`ngE~1huN#jP>q4Y+YnM)z z=+_t+8iM#XF*D27wZU98TmmrJ+1oo?&PxMRBhP?^y?1UH=rpj5LVGKCUt9BCnl;Be zqbMlhnkN^RzgIiV7&UsiuZ@+l%T++VS4L&P(wA*z*hV7=i;4>L7L9Ku%xZXG1mswF0pf@PWd76BnBp z?ZmeFfSg4sFgQ5){d*1J1TdI-dwZQ{5YGo8mtuCGDpxYT_0j~g<^FHMYSd)y=koFa zI7INQk?k_FvNcdS*L}?;i9{D6cL5W}!L*tGo?7({i4?yZIp}fOGaRk5T?jLei6}ISjSYDGdR0tc0AoqqQx|tLpxiN4hI6mgZ zoGJ{489!Of_cV%GF&m>CU+;Cmd*{wic!8Zbw<&bE4YAJ6uP#=QaG}?hW7vlg!QQKP`_g4F`E|2Es*C)_2JTED_Ke%E z#N7W8L={tgL!h_Pq30Yhrn7PowciSKqzhq*ve&`M+*xm2C$bL4deK2Mm{|D#!9@w z0|O%IzNrinN#?TSk&MrIUHDDsCAq=~hLB3-<(otI^BZJ@*aS_10c5eB`@2{a*fmz_n!8=x-em7YPHBUXg z_bjQSU>IK3TsxPrMGvkMq~-{`d zIkkhuI){h(fA21n45rXaz4Z?W$gz2Aabp94sf+B(;i^?qK2&=i+vo<4#kof&ICwof zO}hRcaHNimTyZ5j77LCC&IDdM6$bnoeMp*O7OFvdd|bE>NE}%wd zl*~pIm8Rc_hAq-TG-poe+^gIM5CVxZOL`w%AYrxxl(WsURACyFxV|L*u89c|_qX4G zAA(5X;Te#zsMh&tvbnhlzAFl7doMSoWCjW(L_y_K&52j9E@0J|s}v+5$K_n#0uO!p z=ZDMc$WsUTXJ@c-i;W9OwLw-6R{f06QK-=)pJO-JLFT8mG6@dYL--Tet@D;w*OaKM zPQ`9z(L~^QY)m%{J!N%x9~QQ|wS_F{kwE2H4rD%f-YvHqE8sBg1>LOS93eP>wXw=Y zFdTu*7fo(K`3ImYB0@9&+ne$Ijv7bN4IzTvos^UK5+7I)b+AzkQ(hsyt;DMLDAoIC z^F<^l0YM1(EDFZ?!XV8T|NNQElqN7ARRrhL4oGTFwc-tUra&k<(S7jT%22{rRyZ~C z@0oW}U_4nARTU&i3Mj4OLPM3IH3ckB8?p|coW-)szDEMNvoyfCMWQJf#aJMmMiqS9 z69m%saG`dYiV>50Es_-`Wp8239J0?28n#2FFGP!AHNry(tgwe7` zNLyu;E}hFQpA%trHx9}Zx$^c%M_1R;kM0FhskT7efxt+Ka=J9nvft3X0u_pxnbOO( zrfTTLsr+j^+d)OS7|o*Y+%Mq>J&+??usJJFYpYd2*LnYvRQ=ip$nZ5@v z%pAc2;CrtGUog|=6n*#q*wtvf@0Zhp^`~Wvx-aVXx4FAp$%2^(RQf+CHBfsx4-ZUP ze!1Ys(tI+uD&%kzmOJLsnN;Kg31KUy5{x7!kA{ zVp~CPE%vEeyntE-nt^hzlz^BxFSIZ(mT;odBHUP664(#!!2sBJAfmEFfAe20Q%rbI zPY{QrtI!vy{e3DomsZ~)HVC{}ELT4B}^l`87VF&u0;Tu2$D z{o+OWo%^Y|f3+g&>jx$$y};0j<NzppOaz+GBi``l(#~)0u5@t z9Of3#tWD`yJ#aGs?aqF-To#qD%(>}iD5(iq#itXmhF@z7vE1}>?MAIFBoGJeSY+vr zA*Uci_?aAv0=X&8X$?}B^#W(k#}|YDU>!gUbPs}O8h> z%ho7f?G;oLI3^BQ6Y2N{?^?b?6JSvcyL!9g1_0Xgk{DuCqZjEF6A-RpAtB#GFUrfy zgT2ypvYUKopeQnuw5?D!jP|^56A%i0%giQ74a&Kd%o=Ujgb1w#AhH>~-L0*r&>^50 zUirFD*t$xFxTn)HXe&_zyfL0blj9)l1U4XcbQJ1g3O|)rWMuB{G4bvW@i+AA-h^F; zV9cL4A}tvPgn)OTU%nLPhc+LxC>hfRF%c2VBB%R4dV6VL&TQa1mtIvq(VxD1@QN-# zMY}e_%!D)ikuCQQao5a@*y>fPA>40kLcL2?ZO7aDt$N(T$lXaCD(EHF@kPV7A}V2)~(?d~t|ZrpVU(zduKkI`mY# zXW-6I&SFP2{9-K}>sRN9$Sc75Lm_$j@+HgSQr-7roc@6(&&inHJ7tRbeNgeN%6T%z zE4(3o9Khfb;2PB*uW_KGp?L^(WR4s5Z(4sV;YY?tJjsIq2dhrWywt(jnUB3d+!Z2U z#ySUkKj#6PkL~AGvK68KiQ|WGt{z8l645r~f55&dYdRHnS&6A`3NX5F@+A-)^{B2a zt`$cpM4(r@KM1MUTP&=SA@|R_Zjp?#h)$cn6p?sBIV0jHeh+~eK#NX9L}Z?7ki{dU znS(4hiQmSM*d?B3L?wq<|F0}r$a4!hzdcgLI3*EPoF+PX(!_7a?O&w*@A_M#BN~R1*y4gB zIsw}s5au8*ns$2yvkQ2_e#_hoM*qy3O^%F0zO{6^)(}v}fS&Ch2~+Mw5!&`W zn^%U4r>UP@vSqp8Ai)u1z!S;1k-=xz2_2u8v@J<5S?^d-#hM|s%_fv6;27WapWPngVWDG`S(+`+TVy}^1yvEN$+|i2PS?}{m{_R zjQA9lJRPpM4zo$^GPS|MLBAi@(QjL4;~PHAaq7DsX5dMpci)HY&m&r-4 z<_}LEO?Z)-d3x3r6f6TOKuho3C@?A;wd5NRnOaz2k!c5N>?kZ}=HVfXM?C5x&l6u6 zwR=yB^V1h=OvRt&Ckz8X_`qGw8a@5QY=ui8rCu}~7Z+y)JySQg{Rr7g9j@QMf5Sh3 z`~Rj>@3CX8s!A+)WR7mF?4i~@@3%EJJ{A%21SG*=FolI2PdaICJ{6wYSskscsGudf zQrTe&>J*DT1TUgkbi1po>nJHa14CowYoQwN#nh~JB%;AVnaS~7|C->%*4M8jF*P+! zzGtcKqjXXv)&a@Y85t646EEGW4;b3viwn)ouf8vvO@CHYR$g0Q*D4x*O2*ZmIk866 zyP>128>DCLl#Rpp4BoE$obE#bC*J)b?JXXy?OMj$PMe9u4b>gTnj zq$Fc~M55AL_x5@8vksYK=fDz@s7i#Qf&z|>i&R85C6}MSBO!T=@uuxRX_DCHoE`Ai>9sFf~~M%Z2*CeOHD1+;E-CdQQT}w5as6&=u8mFsQxnXflaMt zJS`&ZSz=-$DE#|Ys!D;iJ)_UWiP4leqMxd(zp7p)dC&Op79E{M?1M}GR(C~2CVsu3 zA$&VMZDg*Otg*)InMgaF`4KtU-ieKvAfSICI&3=sQ5F`hL6XjQOOBEydp1&?*D4NGE$Rh z`AExpvNPMZ@iu&?^O2{pn#cZC(JS7M>BN$EeqZCz@xAKsPZO#%3KcGLuYA?P#l^+e zw%bUk5y1mj6J#R^z?LkdK$#xy`urCr0{Fk zt}X8zHp{*jzN-HB?R$zdsgL#bk1|9fjnn;h-u)FoU9G=);|3w#n>LeYsc+MH@v73_ zYpCyI4j2fWB?>fNIy;NYs2_9chRVDNTktUz|FTe2RAl4kMq|xP6>>QM8nnLqf1i~% zw1KdL&{s&%v2t~-sjMWoAXZ6qs2uB8DH_(((4cro^fk4grR#z`r%qp*7;$~i&rP>W zoYYE{2LBe}E-qN(_C$5f^CsGQc<6D&PGem-g|CI9_NxvUi2NS=_kqI|SeSl^pPwHN zV$%AFZR3jwVEOQ^9UN+t#O{h_asGA&zJ}~<95Sn#2`EJG6mJ+@`AA<{u2=H4*nOe< zI+yk>qHo~v+;cj1`A3$NOf@CN&CIy`@hKZ-$>Vz0&Ns7xX37 elFJ@0`cmB=HkvrTIRxw9FUU))JSmkl_WNHU{KNtP literal 0 HcmV?d00001 diff --git a/doc/images/JKQTPBuildColorPaletteLUTSorted.cdr b/doc/images/JKQTPBuildColorPaletteLUTSorted.cdr new file mode 100644 index 0000000000000000000000000000000000000000..83d63ce13af3327caad73d01c21148ee162cdbfc GIT binary patch literal 29183 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 C(+)fU delta 50 zcmZ3_c${&9IF|$m8v_G_XoIrKL`4b4%86D96YC{J<$SiV=sf1tF9OOjc)I$ztaD0e F0st;g450sJ%JQwfk$L90|Va?5N4dJ%_j|1 zCFAMh7*a9k?UaLk%?1L_^Mw~2|NGxxcgiK^#U@KjwqKGv?%$Pjo<+qX;=s4VM_M~4 zb~bi4ax)8?`ejye%4!&sBV^~+7-AB8NrD=xA*u2qF)VntPM zEZ=(FKW#hQ_c@;~KT`EU`x4jO`_IjnNGG*En|?vsWWR!L2dmRn%`+39>z$vNenF-@ z{YdHg{NJxHZ@>HRhy*$w8#$;i|j?Pxt&^%%!Afkr{nNa&qLn|K2BdF6`7hHEEl?@2-qX zD?FRkcz0!7SR&=0`BkVir1S4<<880Z`ad1F+Vbn(_4M~zufJ-p)&CfBvpW9CjjvZX z>3SQ!yjlJF*^9ld`%msVUNikx&GfBuze2xhmHyqg|Kz@tQA@As2j&O87QflO#2%o__t^ zfA#5x*Y@RQ+V%JE-P4@(>ZkSby|3G&|1P@ruK4)hn=)5JKdFc^dUP`|2q`l(9N}P4 gFl1uz=%E5vu1eNH_po_qFDR%zUHx3vIVCg!086!}&j0`b diff --git a/doc/images/palettes/palette_BWprint.png b/doc/images/palettes/palette_BWprint.png index 2084a9e14286da4491fd4bde852fe37c2cee6e22..2962563fa8144268053663ec2eb901fceb933da8 100644 GIT binary patch delta 131 zcmV-}0DS-D0n7oA7YYyv1^@s6`O~3Eks%mTen~_@RCt{2)IkcuP!L4H);~){#j=%r+W@qM^wT^ej&9DDR?A+})?v(6}{Q8f?&fR|VZj#)S+`f2z px_RUppq7!CACaCJk)8||_5wQSge!HPfvW%j002ovPDHLkV1n_4{Y-LCa{J=B myLsdcP)m`p9+8|47JC8IAcPzVMo*al0000Mv_^(k$l|TeE;vw$~>PLn_Y49>px=G?pSZ$&m{LGw=bT% on@7$7wUL(}k)0WloeUPS7coVID-~QBBme*a07*qoM6N<$f~xOrt1C@xtrbp*Z5>i(dwe< zYrdaR`7HJS_nWExH+Nli?=ih={iDjGao8MH;O*_4FUC{+U>(E2i zkLo#%-_BKiclS%`oeQ7VMQ%Q8_hQ}O$!=9AuHRdA^vFsE{CjV%k71Y~#>1ds zD8b;6WWdmHB!PjU^B@C*P%|Tg3L7(n2M-&=1PPD=Eo>^D@ykb?k-fcT880xP7(8A5 KT-G@yGywo`-;&w@ literal 385 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW zj6Gc(Ln`LHz2aSTM1jZkqI&7_Nsiy9{MFZ*z<5L9z|DqtD~l5CgnH(AZv7W=b-Q=G zTJ5eciI;9KEtiki+qubH#<_AiOYv);*- z_9VVH$xk=E9`ieK{nb_1&wSnWepPM#l{2-6qh5r%udjQ*OTBuQe(k)hHC}PwwtjeL zCSUz@!?*bLJFflfUQ(I+Hu785+;h`D?>e=x?A1!4dxHPHEiT`SOuD~zUyt>cJ=yDS zp0m3W`**q2%fx-})^4@Bv-st_YP;gJ*Nf^GH(Gx?I&Gsy zLC@QSL(8w&8qYkjNu=%B&96m##wX7_Ni$mier4JEz3c8h+kgLR-S+v#^)}Cp?6+>d zllsl(ym8cBs}~7u%JC3;yZ`?DO{%xK zqWSEvKKxp_F8R!vudglVK9Ad*Y-gQU)FPv3>1JDX`}3{KE5$c0|0}-t@0{EF{*|2j zw=OsK^7e`=x9|Gz{rqd=x92x4&Yyd&x%x@r^^o`B`&MjEUtj%yufO>39Nn3xw3cS= z?O&}|6<++l>g(BkTB*}EeJap@`Z)TzmG|l0H~rIXe+BQANz*R=t$V!c_j2}={wsGzT4@4@}Btn>f3*>eJ)=Wr^VRe%E)j~gF!)pm4Rh3LqmcHgFp`x nLz8hJgM$GV1BV+{*;)p^`Au{BH=le7bTNactDnm{r-UW|7=%(o delta 226 zcmaFO*vd3PoJ)d(je&tdv_V;AqM}6oc25__kcv5PuNd+jG7xY*7~9?yUHm10p_lcT z>n?lc$hftWzm?j)TC;i8V*mI*f7gG{|2;Q0-r)TA>UFEut$VlXUETa&h40U;zI*QX zkI(o2*zG%G{XHx0t=;n*H{_+i+ni4i`JVf+ZuYxM^YiPCkL`71+{nVv#L2)S%)p_> uAmHQ6pfH2M!GN(Lfr;TDiVS{<4eC4oHLdxV_pKJ_7Y0vPKbLh*2~7YHSz3+& diff --git a/doc/images/palettes/palette_HSV.png b/doc/images/palettes/palette_HSV.png index ae4949af4d464c115c6ddaf7eb694617203bf3a2..6a5c658325368ee5f34ec4dce7800d1d883a198c 100644 GIT binary patch delta 48 zcmcc3c!+U=IF|qi8v_Hw&&vxvCn`!XmQ1uN65GhXuc%pW^$gpaKp6&4S3j3^P6yXkk{ q_g&UM{-xh8c9_QCFoQC5L*BG^!MYrU;vYbVFnGH9xvX@hE&XXJHjXeebDj5PHLS_NMjc`%NaFQ8Axfxn6DN?3#=`@&3r`X6Ik|)>Yhkch&g*r|D;6 zfH*d7@4a*3zS}B)$$p>v_#ONFUF$C1_I}HsV{HH1cmBPNzvb`VULN+@;{42M=H|H- zpX--@emn25x@PdHGjZSl&A7YA-#U7I{FgxGsWZFcjCYBxeDT$P-`UM&)6?I|mAh&w zJ&P`$W_aFz^GCNMW~U$apMIbJFXNV7_4>-!!5{B^t(ft4pY!{zUq2e`ex=8t!Oh4J zAi>12z<`CpA(4Zj;gA3WL#rYK1D7)cgGd_#g9Z;22WQ% Jmvv4FO#q6YkADCF literal 377 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW zv^`xMLn`LHz2cq6WGK+`aMiXc#?R*Ml-sgd!uUqBvXX1$*Z;Xb_Bjc`|9<^>u`R_r z@wB0zH=nlLW(nJ9!N)Sz$M2S!-H-f!?R`hGhWm+&DgDMyWzoNGeO2C8{^i-)&GNoQ z9&*ov%w_8{Ugds&{g!eI>*Md;xK|wfK6Y=mRsD}O z=AUsVS_MFlD{B-;J z^Yh=|KmM-v&${X7{~Mo=)?!(p!^EJ`!@$6$%+PR%gJFRI6}Z3I{63{SvK((~1%<4q LtDnm{r-UW|B|enk diff --git a/doc/images/palettes/palette_RYGB.png b/doc/images/palettes/palette_RYGB.png index 0eeb5733a0e1f61d8e82eead93e447a4774e087b..3673599344c9a8d696af8ec4ccb347c6cad63c14 100644 GIT binary patch delta 48 zcmdnMG?{6FIF|qi8v_Hw&&vxvCn`!X9-U})SnLM-!HFm3zBqR+0m?9Vy85}Sb4q9e E0DU$PZ~y=R delta 49 zcmbQtw1H`YIF|$m8v_G_XoIrKL`4b4M-#0MPkbORl9F>$@9J7BOP~~kr>mdKI;Vst E07~W#hyVZp diff --git a/doc/images/palettes/palette_YeBl.png b/doc/images/palettes/palette_YeBl.png index bb403263a3b984bba808c8b26c459f51d33756d7..9d8f0e7df828b8065ee171f457b45ed70b44fede 100644 GIT binary patch delta 312 zcmeyxbc<<%IF|qi8v_Hw&&vxvCn`$R^LV;AhE&XXJH@k%Rgs6;_5OdWozb5@-9EL5 z^FGf>)|jn~{6cH4zV(bJkQ>>esk#SEA#JtG`hU>WBvBc z@2=lJX`g+pZdUHB=6gST>*m+&_WyT%i0OAs*}a9U2lK;|G7w} zY_aFH`uo;}Rqt=!Prqf-w{`i$&o4GjS6jc3bMO7$tK}E{Z-w~pzEw8==B3STYTI^- ztn7<;_qXR?+@EWY?}m-m@@ z^C$m*T`{j}?!CzD>;EObXV=?zAC8>0bFS;{SN~@}wYcIodCmUpM_=v*@4uh_eCC zelPbZkB?W}`)AGlY5SahZTV7Y9?KLU#>gPz#=y`j$l#F3!Vn-q1@2#l-}ZsF+=~SN Pf`Zo5)z4*}Q$iB}D*>8P diff --git a/doc/images/palettes/palette_YeGnBu.png b/doc/images/palettes/palette_YeGnBu.png index 88cde329e22a8061203f73c22a6824ce0143d228..2b97c32d096551751bb294789e7bf3c08102f098 100644 GIT binary patch delta 309 zcmaFQbe(B}IF|qi8v_Hw&&vxvCn`$Rb9%ZshE&XXJ0(!4S%Jr8`n~^6wmmoNL=+X? zvVOYPqddE%gX{L2?QbWfdQKCav^V3l=C&;Ds=KnYZ~1+Vet+@wue9H`d9__Tdn=aw zIloJF+2cC}!4Z#l1-+5_==*(^_Sxty?{3}vy>RQdzFOVc+v=V>y|&i*<$rFH(y#3| z)=xN8Z+EQr{P~}2&!3S0<-R_?&aL9rhFPDL()YAgNMP>)z4*}Q$iB}|JRSu literal 367 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW z6g^!WLn`LHy%L>w*nr37V&eDx2lbB4snggb7uK|3{~mS$ovul9Ee^K)&9+XBoOHW% z_1YQ|mj8X?diCc1*R?u-YwoGPeOx8~_^^+C zP}If$66Nc^9=`o=rF{N7@yFcrzgNG$TfDaVZRy{$KP~3ipFKQjZnDPqTi;{)<4%41 zc<09J!?wTwTy6#D#+lF$ifgH!N?%uMg?wtk@5ZAd|UHxg2L0&)z4*}Q$iB} DZ@iRd diff --git a/doc/images/palettes/palette_YeMaBl.png b/doc/images/palettes/palette_YeMaBl.png index 03ac3ac7e409d5c5385ae5c86cf693ff4ba7645e..66e45567c388baa98e7d45053ab161bcc2ee94de 100644 GIT binary patch delta 179 zcmeysc#Uy_IF|qi8v_Hw&&vxvCn`$RcX+xuhE&XXd*vWkQ-Vm##f{(Vqi?gky1%GH zY0ZKKN9Qm%PZXbi-{hFY$vIDEd_V7>_berP(%TO^3~m3X$LH?N+xdI%_Hy(6KaRas z3%-_8e!9E-|Bjt8rthXWH$*Wp9A#nX;$#pJX3$V$2=HN8FoVItkg*{NAt48oxgjZ) XsjheK*6sg5$1!-i`njxgN@xNAtWHYY delta 205 zcmcb{_B>Ar*7pUOC9s6d>Yy@%Nwq`?q>7cyDT; z#A&RNQE;uPd7^mx?%s>;SC?)(tA5@;@7bz-Azw51UyS>|dHuF~+im{Z-MV>Jf8WO) zE5ov{KAdL${$JtdSk-q?!HgSO7@9a4ScDlk)EESO7!+nOI2bTCBrq`?giBc9lz~fZ ZkgnaTZYOqaA}i3@44$rjF6*2UngAhMN@f56 diff --git a/doc/images/palettes/palette_autumn.png b/doc/images/palettes/palette_autumn.png new file mode 100644 index 0000000000000000000000000000000000000000..303cf7ee8428e3cf6143ed05d536fd5c52b90c74 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M z^zn3Y45^s&_6j2}g95|h4bAoE6;g7IxUKW6t!FQZD|eX2=rDsgbc21n8MCak!lM;H Pa~V8c{an^LB{Ts57ThT0 literal 0 HcmV?d00001 diff --git a/doc/images/palettes/palette_blue.png b/doc/images/palettes/palette_blue.png index 80be8563afda1174af4d0041f5046cb7251ef58e..36a96c2ff0fc2c81144a5d3ca8786f51993ee2cf 100644 GIT binary patch delta 48 zcmdnOIEQh9IF|qi8v_Hw&&vxvCn`!X`c1U*5qraYzmG}ojYua#PG!VL^S}f3urX@g5tWlwF&7J4ol}#(#JJWWU{b$FwcgI{Mx7ZyQg~ z`mi=_&x~l(!!wWD{ojy(@mIlF&(9S?`CO@IZcTHN-0QNkFLSn3d`4t=ue0~fYT@g} zQ$E+fa9+E(e9pmB=BFf<-zs|daL@HM-XZ_E%m40vx6*&s-l&o(w!hyge~nt|_l*B< zaZ1d$jrUWR-FfNxeNE)~h|jCf)%Y`HaIrC5kl*cnOBXa-xwaptg-`)M$_v*WIcjcZ|?SCsdA(cTOjWYC& Z`M^g;+Z)%8^a3qr@O1TaS?83{1OO3PF^d2I diff --git a/doc/images/palettes/palette_bluered.png b/doc/images/palettes/palette_bluered.png index 2a6165666823edc31c13bd882a60fe094d8c83a0..5c15976b6cbda2a4363a6aee690cac2990885d1e 100644 GIT binary patch delta 123 zcmdnWIG=HXIF|qi8v_Hw&&vxvCn`#$1$w$ThE&XXdxeqrfC0nd4S9bI>)C~(xmxGE s-McwI-9Ko>?(NnJrx_H^5QpBd7jZJ`p7z)I0JMa`)78&qol`;+0GNg7Fi*Ar*7pUSZ@t;2>~#!@nQJ`xrZQTb=HeZNEEjNyz=Y`wcqG4F;5<4f1vjjJC>O SE>{4pWbkzLb6Mw<&;$SlJutTb diff --git a/doc/images/palettes/palette_bluewhitered.png b/doc/images/palettes/palette_bluewhitered.png index 8080489bd66b61912a982ae4244230518449536b..e2b203f49a9e67ef3bb0a4d020aa85ecbb5e262a 100644 GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j|1 z#qa6j7*a9k?G(qnBL+Ooo=;W(#>8LOUw7m1tq$TUI`E>)bu0@isWK`EfRKcP!O8puqWJM`8*Gox1luxD`I{bc_-IhEW7{C zmxaZnLFfd_lnXZ|M*Rx)cc{AX|JlVEq18*j$!?zRClw?g_x69)hgI|H&spA^^E{l} y{MO}P$L~%TFgUj5C}V<8vJAs9lVfBto{7H_36}3oUFHA`F9uInKbLh*2~7aN`i?jN literal 386 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW zOgvp2Ln`LHz2cpB*np?ypvwsX3Cquq5AzUQ zc;on-XM$ZZ=Z??&R{7%W+@0^uUX?umch|keXlYMCT28V@f9Ahi{I+>n-+%7^dgi)t(7e?f%qcj{an^LB{Ts5^0}Z9 diff --git a/doc/images/palettes/palette_bone.png b/doc/images/palettes/palette_bone.png new file mode 100644 index 0000000000000000000000000000000000000000..d38ba0874482928763570690e1b40b078fa47250 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M zJmcx&7*a9k?UmDfhYWaJE^hq)e}3XbGksOf4bH{=EiTE&dz)rV_%g{!@UQyq@>Y}e zU(avd_fqmzw_NL%*?-@^53jtpKYr=F&wtyMqWjyP?{t6s$8~t6Sq{g>ERx88k4Ou5YYLYwEN zk5|T>V?H3p$RMH2z>v(skkG@x&?CsuV93N^;KsmkjDz8T1Xjs!Y*imwWDY)Xi3j?N N!PC{xWt~$(696`Aar^)P literal 0 HcmV?d00001 diff --git a/doc/images/palettes/palette_cool.png b/doc/images/palettes/palette_cool.png new file mode 100644 index 0000000000000000000000000000000000000000..efd59a46e16238532e7762e15b47f07ffb06e4f5 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M z^zn3Y45^s&_6j2}g8|0@gB|tfV@}*k5!+T=UTr+7YA@p^9)?3iB0JZEOggVM5Ap%c OW$<+Mb6Mw<&;$T>Nh%ru literal 0 HcmV?d00001 diff --git a/doc/images/palettes/palette_copper.png b/doc/images/palettes/palette_copper.png new file mode 100644 index 0000000000000000000000000000000000000000..f48153583d00d886fa5c995d676ffbb634ec1760 GIT binary patch literal 260 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M z+~(=x7*a9k?G;D9Lk0rQf!5#m8|!f8N(2eHzWH;%DN7(Yl5>-)t^aFVA#Nm3ta<=C9%UXLqbl+dtcO<<-t9mDb;1*yX<~e_oTm z^Y!0%bKdKe@4avL{Nuv!^Z!?^Izp qL7<0;p(&8T!GMc_!wsvXEu$YRbBfCH8CpOeFnGH9xvX?F|4e$T} diff --git a/doc/images/palettes/palette_cyanwhite.png b/doc/images/palettes/palette_cyanwhite.png index 5343f05849a363c37a1ec3869a53118f6c35d000..cef90025e2e9ca7d4878b12f4ca91bf58cc2e9cc 100644 GIT binary patch delta 47 zcmdnPxP)e_;2?kGBKbLh*2~7Z1 Co(}#1 delta 53 zcmZ3&xQB6qIF|$m8v_G_XoIrKL`4b4yopw!6C3y^HgJmW^?SggQ?u#$R-iP4r>mdK II;Vst0Cv+4l>h($ diff --git a/doc/images/palettes/palette_gray.png b/doc/images/palettes/palette_gray.png index 0b879e62615a91bd88de94a1b36436ee54dc8e42..1b988b46e921c43c31563ffa1efbe704ef1b2101 100644 GIT binary patch delta 48 zcmdnSIFE6HIF|qi8v_Hw&&vxvCn`!X228Z_6T87*f0RY0drm1YP=>+N)z4*}Q$iB} DPumU* delta 49 zcmbQoxQ%gwIF|$m8v_G_XoIrKL`4b4jEPo$6APq7Ja(|?oGlfr0!lG>y85}Sb4q9e E03Ck}c>n+a diff --git a/doc/images/palettes/palette_green.png b/doc/images/palettes/palette_green.png index cdb490c032b717385d083d0eed7e7cf2945c1deb..735b484493dab20572947bcd3e940c7e2529f23c 100644 GIT binary patch delta 48 zcmdnOIEQh9IF|qi8v_Hw&&vxvCn`!X`c1U*5qrb@pqEMR+1kx~Kp6&4S3j3^P6lQ> delta 58 zcmbQkxP@_oIF|$m8v_G_XoIrKL`4b4w24+e6C2oIh(qM+1tz_zVNdn})i8Lv`njxg HN@xNA!kQ5j diff --git a/doc/images/palettes/palette_greenblue.png b/doc/images/palettes/palette_greenblue.png index 4b16f6439588d64991061103ecb36d36524e9fe6..66ee04637f253d9baae54d7490e0c26d0233a480 100644 GIT binary patch delta 292 zcmcc0bd+g=IF|qi8v_Hw&&vxvCn}29Gko`SaSW-L^LEO{qQeF}&JX|nKVJ6wlCn|9 zHVN02#j!u**n-3wJ-*5I&A*?2``Qmrt-ViU_J2#Zt>*uD@A!1*b5Xax9t}3%_x|hC zJ?77YUY$3N3R-e(w$%07uZuRXUGds=|JSLPf;aWQNtfMKD|;*Xn(Ob*@T+lO?^vII zto+`z{^R|8KuPone743xh*42SdX#0S1O%MFs{bX9fn7HU@?a9!7=>5=;yW f3~?zq!)(U={qt0Q&rctLp~2wk>gTe~DWM4fV&8`e literal 341 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW z*gahwLn`LHy|P<~Nm0P%V%-1#$!C4mWHLLHiOPr0`fAJ8V{qVF*4MI~^Kzr#DrbgA zzq>#G^|#ts`+1+g`FKA5XP7J>_IuZ}v-7^%f1Cb%-_?lP{_w}~-@Lbl+~Qljb?er< zJKp?GeIKzsq|T;%O|I6~kN1|}+&^!2^)boz-+OoO|CRsb-?^;t{+~tF=jE&1V&lKu zsTMC@{d{G(?P}wAyVsvrXnk!yc6v@}^?}IU&*Yz7|ED#VML~>_fkm02A%TTKpof8> sNsz(8fQf;_je+4H2ZMqH>5^s49Yx>R<-&`B;lse->FVdQ&MBb@0KTk$^8f$< diff --git a/doc/images/palettes/palette_inferno.png b/doc/images/palettes/palette_inferno.png new file mode 100644 index 0000000000000000000000000000000000000000..5b8165a8d1a3828e2cc8eeb68ebee2185fadf0b8 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j|1 zW$5YR7*a9k?Uca2HwpsGr`z`a?`{7+v28-nx6J>Ao*dg}XBs(eTEHui(BhzX*TGG~ z*MGXcZ|;(|`?ft-=hgPC&cC&)_o6}C_ukW&OODMkn!9rA7D1u=Q8CX${)Ze2_`7=E zuWvs-Ejj&vzxh04iT=oIEAn?#Z!iCTO{TZ{*yBI%Y`2=csy-c$gr>peWdl|>Q&!eW0bR%7>FVdQ&MBb@0Q;;*+5i9m delta 206 zcmcc4_>pmfIF|$m8v_G_XoIrKL`8}E#hxyXAr*7pUfIaiY#`Bk(SG0m+qafZFp-sM zxs_Xoc$NM8@ZDCQyYuIy zNA(7t{<^R3d%yAV|Fd>f=dvCVV&G6?5b$A8n8Dy+z}S$$#Bh*>p^1}$MHnh!iBkqi aVqVd;pZdB=6+N)z4*}Q$iB} DXaNq> delta 49 zcmX@ic!zOxSer=IF|qi8v_Hw&&vxvCn`$RWqP_ehE&XXdu1bUgMo;%qw|f~TQ!9o4+?13 zsP8-%-c^3*WVPzeojqsSbMBovaVB)<*LsKdVPCGc1_F;9$tuki^7rl!c*- mlR-q7K|_rpzz0*}H$(EF1@rE0xv&LjIfJLGpUXO@geCx5XEtO2 literal 208 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{n@ zO`a}}Ar*7pUNPi5&1?zf_x*Y?$hQZU-&t;ucLK6TAjXq}p diff --git a/doc/images/palettes/palette_invRYGB.png b/doc/images/palettes/palette_invRYGB.png index edf40c0fc719bca214109fee9235e973ce8c4a1b..e8b7ad1414b190211b50e1af30b75c1b8323f4c8 100644 GIT binary patch delta 245 zcmdnWG=ph^IF|qi8v_Hw&&vxvCn`$RpYn8Z45^s&_R2w_Lkc{u7uhZT{r_&&vSUTq z6494d-_N8>T9){GlJ`0#-`C%s|35Xm=Hc54>)+?Zf90Ix{=H>`KX>h%^xaF&o;-Ic z?5pkk(o*yEsVbjO*8e|qwLSL!-rXPH&*k0yYSPxn`|e*gd-E+WB`#&{in7lOf6dPgg&ebxsLQ0I<|-VE_OC literal 309 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{n@ z&pllnLn`LHy>goGumX?EMa7W6|KG1=D8DGKs;T;Vr~9Ti7HQU+O9G}XEB*Po{^{AW zM{g^vf8X=_a&wRFo6CpnbiWkNdpk*vuguhT)t+aI*S&kTVp2%*Cwsf%&cy5AU*tWi z4sVa;T)FMBWq0GRL%)*e+!@$rZ$k1TO#9-jYz;KLo$&J?QCLhz=qN`*L^fH5| LtDnm{r-UW|mw diff --git a/doc/images/palettes/palette_invblue.png b/doc/images/palettes/palette_invblue.png index 9deb7aca62bf94de82acfe3b2fc4da4491428188..92029607c0390df7be0703bc3aed1eef879d33b9 100644 GIT binary patch delta 47 zcmdnQIE!(DIF|qi8v_Hw&&vxvCn`!X`b@O)7Oh^G!=U%M`X##S)|D8u0C>gTe~DWM4f DP3R5V delta 49 zcmbQsxRr5&IF|$m8v_G_XoIrKL`4b4^odr!6Z54+cy;Q0cR9Sy1WGY@y85}Sb4q9e E03Q|%!~g&Q diff --git a/doc/images/palettes/palette_invgray.png b/doc/images/palettes/palette_invgray.png index 1eef8e4982c0f531830d1121ec0d19eea9dbd391..686289367d82011a8f5654e455b499f780f4ce79 100644 GIT binary patch delta 47 zcmdnUIFoULIF|qi8v_Hw&&vxvCn`!XdQY_S60P3f@Xz*Z?2qq22?kGBKbLh*2~7ZH C;t)Cj delta 53 zcmbQqxRG&!IF|$m8v_G_XoIrKL`4b4mdK II;Vst0EH6}DgXcg diff --git a/doc/images/palettes/palette_invocean.png b/doc/images/palettes/palette_invocean.png index c53238236b59093cbd8251d4e8579e077b69d58c..5d4889f937947d5b6159ae4b279f8eb99b3fe6dc 100644 GIT binary patch delta 140 zcmX@bxPftkIF|qi8v_Hw&&vxvCn`#mCwaO!hE&XXd*vW+O8|qDW65v*$d8*;|418i zE^IE}`u4M#zjXb(%m3r*-&}r@RrFi=fA%|u%`6OUoD4j|3=(P#20jc4GZ+pSFg7GI fF&xH}*uY=w@PBRSdykVqTNylE{an^LB{Ts5&zLgx literal 202 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{n@ zHJ&bxAr*7pUOC9y>>$8$koCE|k&b+O!TxoV+$KB5@7{fW_vbf#_TM-E-}~>z`ExPW p#lMyR-`>f7LWqGwm@@R6LF)hiy@{T8!hr5z@O1TaS?83{1OO6UG0Fe{ diff --git a/doc/images/palettes/palette_invrainbow.png b/doc/images/palettes/palette_invrainbow.png index 4e2cb123d55dbba5d5751d63a94e9b5b38cc0168..3d8b79669b799ffbe1d34ae3662c0b09a42fbc37 100644 GIT binary patch delta 283 zcmcc3w1;VeIF|qi8v_Hw&&vxvCn}29GraS3aSW-L^LC13-w^{27HOmZ^&hf&zE3)v zaIEv2-_(`^zK@e{Pg%w{neTdTz3rQIaa*b$OP`PZzI?m)zMHXk!~Eafoc*OBe8=3U zUCP;+>C$Io6HEPW-S@rrI_GG5>hj+3%6OBdyVvMWEi2w`pRM*^C+gklHN9b4pQ7(a z&8eyvsaMJW7PItf^w)`{nQbQzJ#qeIQ0ZZ}=FI<>uF}8$SWXK2e!8Z-`dan#{lC@k zzj^&NxrosrnuDR?m;eJquOb73lrsZ^NgD%01`i{{1qmjG1%@mP4#~I_%!t>W@MZ4L UB25-x7%+IcviZ5Jb4q9e05)ZOJpcdz literal 347 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW zcs*SlLn`LHy>c+G#ek>f;l`Wa>mRI|5vO5#Z^NtFfBs!UYJA5#ovpUCZdoe#{d)WE zZ26ltle=dwx3#ZbKBaqicK>gm`@eHeYX?s)To;mSn_a%~gi)yBdEMW&mp@nb8Hzvl z>yG^Td*aHyuW#mV-JM)ozi#nadF9u?->z{r3;UYCH@)9f^mzs<~kX=nX;@AFH6 z3s(fZ3kuWlK4p9Cr~U5}Wqe delta 53 zcmbQmxQTIsIF|$m8v_G_XoIrKL`4b4l!;c}6AMHoj2Sqp8&@;f$!t3C6e!K$>FVdQ I&MBb@08law`Tzg` diff --git a/doc/images/palettes/palette_invtrafficlight.png b/doc/images/palettes/palette_invtrafficlight.png index ca438c2c201b5c326af346a0d0aecc6106687b8f..af7a5d959ed9ccce2ec24e3aff93836471f8cc02 100644 GIT binary patch literal 220 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M z?DKSS45^s&_KGLhVFLk{1BL(or|4R;G$p4T{l2a#jqRj*;;$K@o8v--W-XrfEHmzV z=&>|A&-gdbEARep{u~#YTm1cRTG-dZ`P+6%^PfAO6!*P;=IqMpQE%+~@7e8V5b$Dj nFkodkD8j%J%pl-Hh;xstebf9Yt`ZhNmoa#{`njxgN@xNA^ejoY delta 575 zcmcb^c$#H`c)bJ%8v_GlQoHab1_lPs0*}aI1_r*vAk26?e?OCNItL__18=yWPpj+RZ6jcU#{&aii0sQgq^U z>sqmm9PB&Vw0E@R7rZ;l`)tRKhWroA>k=6G3v_0lv}de0Kdii?{O4ZbiOPq>>JIz= z;1d^;JGicz#rp?q{R2KJJ0|zho${_7Fc>_UV-T$$6s2-g`wKl91q|_RUW-y#eWYTEoTp)vmlUXPD#{U?tt=c6QDGMr>mdK II;Vst0Dejjz5oCK diff --git a/doc/images/palettes/palette_magenta.png b/doc/images/palettes/palette_magenta.png index 91d82e7e085b46007fc579e8687ed5eb63cafbed..56051700da719af8ca60eb55c56add6b5fee013f 100644 GIT binary patch delta 48 zcmdnRxQKCrIF|qi8v_Hw&&vxvCn`!XhD@{y61%~_MUh#SPpbSpP=>+N)z4*}Q$iB} DM4kl|wqe#Slc;$Nlx6UA^>bP0 Hl+XkKN|6ne diff --git a/doc/images/palettes/palette_magentawhite.png b/doc/images/palettes/palette_magentawhite.png index 85ee8cafe33c2564a3362d52b7781f8875307243..6119bda17481d96fc9c213b4ba78cf4f46d64de6 100644 GIT binary patch delta 47 zcmdnZxR`N*IF|qi8v_Hw&&vxvCn`!XhEB8!5#8JRmPO`8r_C>*1cRrmpUXO@geCx3 CI}aiN delta 53 zcmZ3?xSMf;IF|$m8v_G_XoIrKL`4b4+=*5p6YKdW)^m#P^?Sgg6V*}^36y5=boFyt I=akR{0A`~OcmMzZ diff --git a/doc/images/palettes/palette_magentayellow.png b/doc/images/palettes/palette_magentayellow.png index 779a7ceca8cbd94bc0c9380e7a705fe062c90977..32446dc95a8e808c26db743ef5574e63ee4364e2 100644 GIT binary patch delta 122 zcmdnWIFE6HIF|qi8v_Hw&&vxvCn`#$26(zShE&XXdxeqrfC0~e4P}1}_p=K{bG5!X qd-sj`X7!a7Fi*Ar*7pUSZ@t;2>~#!@nQJ`xrZQTb=H`&D;If)9dTqeT?uG diff --git a/doc/images/palettes/palette_magma.png b/doc/images/palettes/palette_magma.png new file mode 100644 index 0000000000000000000000000000000000000000..1c96eb9c6c78dc68ce34e978e3be31e6fb6dcd13 GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j|1 zCF$wn7*a9k?UcyABMJh}xzGQlr`d5eEv){<^iw{BG6F6;{6&M;7976LZ3K%Hc ze%g5F`aE-S)<>4tSZ22_n8{tfCQ?^cF5^U&y9WYiD+(tu8;uGh0&rz2$tvb?Fr{pX+nZU0=WFQPuLR+uqq` zeJwv5nf-LtR;#LD>*75>ZPxw1QRjBsBP(Aab+(@0-OA6aKDshzzFx7o{>hhnqAM4h z-;=!lvU}gFjh|jy{&;bE%Thrnj@(YhmJ2f^95{N(WBg=pUaxn(@%lMFP&j(J`njxg HN@xNA90Qme literal 0 HcmV?d00001 diff --git a/doc/images/palettes/palette_ocean.png b/doc/images/palettes/palette_ocean.png index 89c8ff64b8c77763753d9f174f72c009a9aff39c..060c35caf5ace4578151ae4b2f4c31a9380d2d97 100644 GIT binary patch delta 47 zcmX@jxQTIsIF|qi8v_Hw&&vxvCn`!XrcAU-7Ok6iEK=tD)st_45)7WMelF{r5}E*N CZx9&( delta 49 zcmdnQc$#s7IF|$m8v_G_XoIrKL`4b4+KE=l6I-N2*1JXOw8;0*0ZK7=y85}Sb4q9e E0572pCIA2c diff --git a/doc/images/palettes/palette_plasma.png b/doc/images/palettes/palette_plasma.png new file mode 100644 index 0000000000000000000000000000000000000000..447592112e1735b2aed8abc17ef9b11045faa23d GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j|1 z#pmhb7*a9k?G(p6XGI>D<9llo4dvM*ipN>lcJKW0}JdwFuzS5G-_?ax6o&;Lq3pY*b9-NvlytNQ0( z{EXO~{&>$O`PK8QLe{76efF$p{m;+k^J>rjdA#@c{J*>QXx&?F|8I7*f9~C-k9%*O zyY_T%?X7oL{>k01J{?_?toHs&*|xs#%gp}f?y z#rn_V>UYL}zVXIw>&ito>ge-TC`Eze@1a#&_C5Qt7=DjzvEI7j*iahIO*>?Yr}{ z?$*97`~UO&>%`~jCs-HgGBITIFfd3dGc+9IU|3*C6!$l4#+q7P^(Gc6U>GoXy0ZDX JtaD0e0s#91g^2(F literal 346 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{oW zcsyMkLn`LHz2aEZV!-2aaodT##qX~uq%uqP8$4n78!xIFJt^|rkFe0ZrFTmH*WNw* z?%vg}zE=+KHtW9jK0kTh)_cLdS?MbmnJf}fJQ}&ZYJRd+f9QUZB5xXetKaIo{?@nea?|6_gneIrt2}=7-THr@t8V+N)z4*}Q$iB} DQ5y~n delta 49 zcmbQsxRr5&IF|$m8v_G_XoIrKL`4b4^odr!6Z54+uAOJnJ9^B12T+Q^)78&qol`;+ E05d@i$p8QV diff --git a/doc/images/palettes/palette_redblue.png b/doc/images/palettes/palette_redblue.png index 4bcbbc12f6fb7bbad4c42c918e30df2bd49ae8ed..02c37f05f3fc52c708c1073cc8f0608a5014a503 100644 GIT binary patch delta 121 zcmdnWIG1sPIF|qi8v_Hw&&vxvCn`#$_)C~(xmxFJ q-7Fi*Ar*7pUSZ@t;2>~#!@nQJ`xrZQTb=IZmfz0v4_cLfzd?t&!GJQfLEcJ%(N?Ff R+Zt#kgQu&X%Q~loCIFcDF53VA diff --git a/doc/images/palettes/palette_redgreenblue.png b/doc/images/palettes/palette_redgreenblue.png index 8247d4ef42a3f96620fbb944196c541b6fc08c18..6846bcedc24c1dafe99110c4a63e5f92beb9f4f9 100644 GIT binary patch delta 125 zcmdnTxR7yzIF|qi8v_Hw&&vxvCn`#01bezThE&XXd!>=L!GPz$hP*%ZMpK-Vyek#c u)4$mo&!2QQF17j@--J{Kfi&XKH)cH*M!gMYr>%h2FnGH9xvXWf+?V4@B&lx*RV{n*3 c8M?u~pNY}7f8Bm=Z%B&AOz++IzER};>@US0qH*!+8eT#=gYCvL3|ib>NBt?io@d}5-1@omxU`p

    X~|Sn^(}y=Wmu*{>=N8TK6!1Q&sV{->JFZ)?NRUJ%9Vt>y!7(Mt#5f<@LI^ z)9(IVyLa{Pxc>)A?M_e2eyLv*|7YICx^D}w-u-S}zd4A(K#Yqa!9axJK!OHC!@&Rs yhUSF~3~bJf3_NX23=%x73)f7m6&JU#u)gzxvS5AwM9Nc_D0-0t1BzO$}QkOUX{PSiCe1 diff --git a/doc/images/palettes/palette_seismic.png b/doc/images/palettes/palette_seismic.png new file mode 100644 index 0000000000000000000000000000000000000000..4cffa0be98bc462d7e7a46e9efe93b1794529daa GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M z%=dJ045^s&_R2xt!wx*mj!}h`FZa)sIrmfAkC8E*p^jzmcaMAFMxJroZSU6I{r|l@ zt!UoLyBqCJMor!Q?VR5#bH*%A1`%Nf4K;=UABF`p7#s{48%E5O zh$MrEF@r`LL%7OI2jl+N)z4*}Q$iB} DWn~U& delta 49 zcmcb?_>pmfIF|$m8v_G_XoIrKL`4b4#S^VMCa#ngxv#+4wSiZ49#D$G)78&qol`;+ E07jb)tpET3 diff --git a/doc/images/palettes/palette_stepsGnBl.png b/doc/images/palettes/palette_stepsGnBl.png index 0fdee278a1e62cf025636b3852f6ab87deeea18e..6b2fdd8e30fcbbc2c630494cdd764bae80fd58d5 100644 GIT binary patch delta 164 zcmaFBc${&9IF|qi8v_Hw&&vxvCn`$RS9-cQhE&XXdu1bU69a=wU@7DG`Q4{jvX~`Q z%>rhekO;q1%^g$x^ZMWIfAteT?{oVee_ZIU{Ql^Y`X6^T|33fb-fr3 z*&)oJp~ev4!?0imgM%SsLlP6iQ5J?SP6iPy5`MFPiCS;s-`Knj=o$u3S3j3^P6!BM4qIN)%(uU4|C$}vd!1YI z|KHBOclz(IzxelX=lr|&=iklm+x*{Jw}0c?yElvs{1_B`C_``f-!Y1MFZKKM4d^-s MPgg&ebxsLQ0Mg?{SO5S3 diff --git a/doc/images/palettes/palette_stepsPuOr.png b/doc/images/palettes/palette_stepsPuOr.png index face322f036eae2fa3a3086f18edf707b1e810e5..0d84f84abf15ab121201abd77e4617ebe4852d5c 100644 GIT binary patch delta 48 zcmaFOc!_a>IF|qi8v_Hw&&vxvCn`!XwoJ5Y68p<&d68$|(`PY22?hpFS3j3^P6mdKI;Vst E08Wk$hyVZp diff --git a/doc/images/palettes/palette_stepsYeGnBu.png b/doc/images/palettes/palette_stepsYeGnBu.png index c66a0b03c2a0f57c8f4e523a7ff5aff83373a9ac..0b7cb565af46baff77e87cb66cdbc2442ead555f 100644 GIT binary patch delta 48 zcmaFDc$#s7IF|qi8v_Hw&&vxvCn`!X)=spl7TahqEhohDuaEyaP=>+N)z4*}Q$iB} DVBrpi delta 49 zcmX@j_=ItSIF|$m8v_G_XoIrKL`4b4X%nrgC(e-;$=xg@!#`V;2Pnnh>FVdQ&MBb@ E052>Ia{vGU diff --git a/doc/images/palettes/palette_terrain.png b/doc/images/palettes/palette_terrain.png new file mode 100644 index 0000000000000000000000000000000000000000..feb0ba208aca777c9ddb131010d779d3a3de67d9 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M z+~n!v7*a9k?GX!fUUW{=mZNdY$siH}~VT;yjlvDDN5CFQ7!PC{xWt~$( F699BYNU#6^ delta 212 zcmcc1_?>ZrIF|$m8v_G_XoIrKL`8}Em7Xq+Ar*7pUUBR?Y#`uranqCL=MS7Gxtbl! z5PARFHe=Vs?a$;ZpG=(?^ZduH>(!>oo8O;_xpV(_)p_an#VXIA-Ih67sbc)w()|9h z-tQZ4T>pJtX7=CvDTVrbC)xPk{Zso-alsS@2Sdh&BqoNVEDT+o3?jk|8fpvyJ`4+H iFgV!bltGvH#%6Y_QSXW0xqCp@GkCiCxvX0sJ%JQwfk$L90|Va?5N4dJ%_j|1 z#o_7V7*a9k?UaoZj~MVUi-%;#ANn5ORoa+x^Gc=7bm7?oDvDMg9qNC*_wZm;3|J6Z ztlu%C^w)B=%)RGTt2kUfecSqc_4~rhCyn#Ily;X|zkjw{;d|BV${pWh^a+ie^BSm{qx9VfoE{{1UJ<* q`RT_bg2mVy3|k8sB!VT#V$9%wz|yG^-(GME6l|WZelF{r5}E+q#*n7~ literal 0 HcmV?d00001 diff --git a/doc/images/palettes/palette_whitecyan.png b/doc/images/palettes/palette_whitecyan.png index 584aee50f0531dabb3bb0f89a19f6f4827ab32cf..ed1a56a291550b8fbb1cc15d064892c846ef1306 100644 GIT binary patch delta 48 zcmdnXxRh~%IF|qi8v_Hw&&vxvCn`!XhEKE#726dL4ygTe~DWM4f DK%)&A delta 54 zcmZ3=xR-H)IF|$m8v_G_XoIrKL`4b4{E1ef6C3y^HgJl4V|pUaXfy5lnu$Pp22WQ% Jmvv4FO#p#p4~_r; diff --git a/doc/images/palettes/palette_whiteyellow.png b/doc/images/palettes/palette_whiteyellow.png index 6710920bbc9ba820aaa63fcb4db3bcb9ea3c5987..6619d5e83f9c092a60865c44877dee75714dc9d2 100644 GIT binary patch delta 47 zcmdnPxP) delta 53 zcmZ3&xQB6qIF|$m8v_G_XoIrKL`4b4yopw!6C3y^HgJmWe$LKl^EOK|8z{}->FVdQ I&MBb@0B0@^aR2}S diff --git a/doc/images/palettes/palette_yellow.png b/doc/images/palettes/palette_yellow.png index 2a73c69ce119063589649550b148473fa80fb414..cfc39662641a2cf99b887f036ac70ab0248ac6c4 100644 GIT binary patch delta 47 zcmdnZxR`N*IF|qi8v_Hw&&vxvCn`!XhEB8!5v|**z$_a(rSl3FVdQ I&MBb@09+jo3IG5A diff --git a/doc/images/palettes/palette_yellowmagenta.png b/doc/images/palettes/palette_yellowmagenta.png index 97f49232389dcc1bb559305e3016ca1c29bae0bb..0cb0cee2c955f512c799629d9077ba2355b8ec74 100644 GIT binary patch delta 121 zcmdnWIG1sPIF|qi8v_Hw&&vxvCn`#$_A!QkoY=d#Wzp$PzyX(uiK literal 181 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5BskcBq-cY(3XtL~@Q5sCVBk9f!i-b3`J{n@ z>7Fi*Ar*7pUSZ@t;2>~#!@nQJ`xrZQTb=IR&D;KV-ja~}`xqnH7!oN&_TRgiY&OWv RISsUu!PC{xWt~$(69BHbD(V0L diff --git a/doc/images/palettes/palette_yellowwhite.png b/doc/images/palettes/palette_yellowwhite.png index 364174f8ea1631fefe8c19e901af4d34cf73a189..df09f46e17ea38012951e29df2a6991e853fcbe7 100644 GIT binary patch delta 48 zcmdnZxR`N*IF|qi8v_Hw&&vxvCn`!XhEB8!7TX}+`j$oJL80*upbUejtDnm{r-UW| DTQ&~C delta 54 zcmZ3?xSMf;IF|$m8v_G_XoIrKL`4b4+=*7f6YKaV)^Un$5chk)qGMNHei|sx;OXk; Jvd$@?2>^1U4#WTe diff --git a/doc/template_verbatimgraph.txt b/doc/template_verbatimgraph.txt new file mode 100644 index 0000000000..36ec0b49fd --- /dev/null +++ b/doc/template_verbatimgraph.txt @@ -0,0 +1,19 @@ + \verbatim + colval + ^ + | + 250 - + | + 200 - + | + 150 - + | + 100 - + | + 50 - + | + 0 - + | + ---|----|----|----|----|----|----|----|----|----|----|--> position + 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 + \endverbatim diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7223e7c7db..1e1c9adbf0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -29,6 +29,7 @@ add_subdirectory(filledgraphs) add_subdirectory(functionplot) add_subdirectory(geometric) add_subdirectory(imageplot) +add_subdirectory(imageplot_userpal) add_subdirectory(imageplot_modifier) add_subdirectory(imageplot_nodatastore) add_subdirectory(imageplot_opencv) diff --git a/examples/README.md b/examples/README.md index 47408179b2..9bbc0b546c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -42,6 +42,7 @@ All test-projects are Qt-projects that use qmake to build. You can load them int |:-------------:| ------------- | ------------- | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/rgbimageplot_qt_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/rgbimageplot_qt) | [`QImage` as a Graph](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/rgbimageplot_qt) | `JKQTPImage`
    `QImage` drawn onto a plot with arbitrary scaling
    inverted coordinate axes | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot) | [Basic 1-channel Raw C Image Plot](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot) | `JKQTPColumnMathImage`
    image data copied from C-style row-major array into a single column of the internal datastore
    Describes several options of the image plotting classes (different ways of color coding, what to do with data above/below the limits etc.) | +| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_userpal_program_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_userpal) | [Image Plots with User-Defined Palettes](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_userpal) | `JKQTPColumnMathImage`
    user-defines palettes
    palettes from files | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_modifier_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_modifier) | [Modifier-Feature of Image Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_modifier) | `JKQTPColumnMathImage`
    image data copied from C-style row-major array into a single column of the internal datastore
    Image is modified by a second image to display two data dimensions at the same time | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_nodatastore_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_nodatastore) | [Basic 1-channel Raw C Image Plot
    without the internal datastore](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_nodatastore) | `JKQTPMathImage`
    image data in a C-style row-major array, not using internal datastore | | [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/rgbimageplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/rgbimageplot) | [Simple 3-channel Math RGB/CMY Image Plot](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/rgbimageplot) | `JKQTPColumnRGBMathImage`
    image data in a C-style row-major array, not using internal datastore
    RGB/CMY color compositing | diff --git a/examples/imageplot_userpal/CMakeLists.txt b/examples/imageplot_userpal/CMakeLists.txt new file mode 100644 index 0000000000..b5b800b322 --- /dev/null +++ b/examples/imageplot_userpal/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.0) + +set(EXAMPLE_NAME imageplot_userpal) +set(EXENAME jkqtptest_${EXAMPLE_NAME}) + +message( STATUS ".. Building Example ${EXAMPLE_NAME}" ) + + +# Set up source files +set(SOURCES ${EXAMPLE_NAME}.cpp) +set(HEADERS ) +set(RESOURCES imageplot_userpal.qrc ) +set(UIS ) + +add_executable(${EXENAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} ${UIS}) +target_include_directories(${EXENAME} PRIVATE ../../lib) +if(BUILD_STATIC_LIBS) + target_link_libraries(${EXENAME} JKQTPlotterLib) +elseif(BUILD_SHARED_LIBS) + target_link_libraries(${EXENAME} JKQTPlotterSharedLib) +endif() + + + +# Installation +if(LIB_INSTALL) + install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif(LIB_INSTALL) diff --git a/examples/imageplot_userpal/README.md b/examples/imageplot_userpal/README.md new file mode 100644 index 0000000000..e724cd2daf --- /dev/null +++ b/examples/imageplot_userpal/README.md @@ -0,0 +1,210 @@ +# Example (JKQTPlotter): Image Plots with Custom Palettes {#JKQTPlotterImagePlotUserPalette} + +This project (see `./examples/imageplot_userpal/`) demonstrates how to use user-defined color-palettes for image plots. +The source code of the main application is (see [`imageplot_userpal.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_userpal/imageplot_userpal.cpp)). + +# Build Palettes Programmatically + +JKQTPlotter comes with a large set of predefined color palettes, which are enumerated in `JKQTPMathImageColorPalette`. +In addition you can build your own palettes as simple lookup-tables of type `JKQTPImageTools::LUTType` (which is a `QVector`) and register them in the system (using `JKQTPImageTools::registerPalette()`). There are several options available for building such a palette: +1. you can simply define a palette from single colors: +```.cpp + JKQTPImageTools::LUTType pal{ + QColor("blue").rgb(), + QColor("green").rgb(), + QColor("white").rgb(), + QColor("yellow").rgb(), + QColor("red").rgb(), + QColor("red").rgb() + }; +``` + Such a palette will have exactly as many entries, as you specified: ![palsimple](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_userpal_palsimple.png) +2. Alternatively you can build a palette from a set of colors with assocziated positions on the values axis (typically 0..1 as these are in any way later mapped to the actual data range): +```.cpp + QList > palsteps2; + palsteps2<(0.00, QColor("blue").rgba()); + palsteps2<(0.05, QColor("green").rgba()); + palsteps2<(0.45, QColor("white").rgba()); + palsteps2<(0.55, QColor("yellow").rgba()); + palsteps2<(0.95, QColor("red").rgba()); + palsteps2<(1.00, QColor("red").rgba()); + + pal=JKQTPBuildColorPaletteLUT(palsteps2, JKQTPImageTools::LUTSIZE); +``` + Such a palette will have `JKQTPImageTools::LUTSIZE (=255)` entries and the colors are not spaced equally: ![palsteps2](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_userpal_palsteps2.png) +3. The palettes so far had steps, but you can also give a series of nodes with positions (on the value axis) and RGB-colors there (e.g. `palsteps2` above) but then linearly interpolate between these by calling: +```.cpp + pal=JKQTPBuildColorPaletteLUTLinInterpolate(palsteps2, JKQTPImageTools::LUTSIZE); +``` + The resulting LUT is then: ![imageplot_userpal_2_linear](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_userpal_2_linear.png) +4. Finally there is a second way of linear interpolation, where linear segments are given for the three color channels separately. To use such a definition, call `JKQTPBuildColorPaletteLUTLinSegments` instead (see documenttaion there). + +For each of these options, you finally call `JKQTPImageTools::registerPalette()` to make them known to the system: +```.cpp + int userpalette_id=JKQTPImageTools::registerPalette("userpal_computer_readable_name", pal, QObject::tr("User Palette Human-Readable Name")); +``` +This function returns an integer, which you can cast to a `JKQTPMathImageColorPalette` to use your new palette: +```.cpp + JKQTPColumnMathImage* graph=new JKQTPColumnMathImage(plot); + // ... + graph->setPalette(static_cast(userpalette_id)); +``` + +# Load Palettes from Files + +In addition to building palettes/LUTs programmatically, as shown above, you can simply load palettes from files using: +```.cpp + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/All_idl_cmaps.xml"); +``` + +This function may load different file formats (discriminated by the extension): +1. XML-files (extension `.xml`) may contain one or more color palettes and should be formatted as follows: +```.xml + + + + ... + +``` + or with several palettes in one file: +```.xml + + + + + ... + + + + + ... + + ... + +``` + +2. CSV-files (extensions `.csv`, `.rgb`, `.pal`) are simply a list of 3 or 4 comma-separated values: +``` + red, green, blue + red, green, blue + ... +``` + or: +``` + scalar, red, green, blue + scalar, red, green, blue + ... +``` + +By default the palettes are simply read from the files as raw data. Alternatively you can linearly interpolate between the nodes in the file by calling +```.cpp + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/All_idl_cmaps.xml", true); +``` + +Examples for such palette files can be found here: [/examples/imageplot_userpal/palettes/](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_userpal/palettes/) + +# Main Program of the Example (GUI) + +The rest of the example program [`imageplot_userpal.cpp`](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/imageplot_userpal/imageplot_userpal.cpp) just generates a 2D function plot as a color-map and displays it ... +```.cpp + // 1. create a window containing a plotter and a combobox to select the color palette + // ... and get a pointer to the internal datastore (for convenience) + QWidget win; + QVBoxLayout* lay=new QVBoxLayout(); + win.setLayout(lay); + JKQTPMathImageColorPaletteComboBox* cmbPalette=new JKQTPMathImageColorPaletteComboBox(&win); + lay->addWidget(cmbPalette); + JKQTPlotter* plot=new JKQTPlotter(&win); + lay->addWidget(plot); + JKQTPDatastore* ds=plot->getDatastore(); + + // 2. now we create data for the charts (taken from https://commons.wikimedia.org/wiki/File:Energiemix_Deutschland.svg) + const int NX=100; // image dimension in x-direction [pixels] + const int NY=NX; // image dimension in x-direction [pixels] + const double dx=0.6e-2; // size of a pixel in x-direction [micrometers] + const double dy=0.6e-2; // size of a pixel in x-direction [micrometers] + + // 2.1 Parameters for airy disk plot (see https://en.wikipedia.org/wiki/Airy_disk) + double NA=1.1; // numerical aperture of lens + double wavelength=488e-3; // wavelength of the light [micrometers] + + // 2.2 calculate image of airy disk in a row-major array and immediately store the values + // in a new image column cAiryDisk + size_t cAiryDisk=ds->addCalculatedImageColumn(NX, NY, [&](size_t ix, size_t iy)->double { + double x=static_cast(static_cast(ix)-NX/2)*dx; + double y=static_cast(static_cast(iy)-NY/2)*dy; + const double r=sqrt(x*x+y*y); + const double v=2.0*M_PI*NA*r/wavelength; + if (ix==NX/2 && iy==NY/2) return 1.0; + else return pow(2.0*j1(v)/v, 2); + }, "imagedata"); + + + + + // 3. create a graph (JKQTPColumnMathImage) with the column created above as data + // The data is color-coded with the color-palette JKQTPMathImageMATLAB + // the converted range of data is determined automatically because setAutoImageRange(true) + JKQTPColumnMathImage* graph=new JKQTPColumnMathImage(plot); + graph->setTitle("default MATLAB palette"); + // set the image column with the data + graph->setImageColumn(cAiryDisk); + // where does the image start in the plot, given in plot-axis-coordinates (bottom-left corner) + graph->setX(0); + graph->setY(0); + // width and height of the image in plot-axis-coordinates + graph->setWidth(1); + graph->setHeight(1); + // color-map is taken from cmbPalette + plot->connect(cmbPalette, &JKQTPMathImageColorPaletteComboBox::currentPaletteChanged,[&](JKQTPMathImageColorPalette p) { graph->setPalette(p); plot->redrawPlot(); }); + cmbPalette->setCurrentColorPalette(graph->getPalette()); + + + // 4. add the graphs to the plot, so it is actually displayed + plot->addGraph(graph); + + + // 5. fix axis and plot aspect ratio to 1 + plot->getPlotter()->setMaintainAspectRatio(true); + plot->getPlotter()->setMaintainAxisAspectRatio(true); + + // 6. autoscale the plot so the graph is contained + plot->zoomToFit(); + + + // 8. show plotter and make it a decent size + win.show(); + win.resize(500,550); + win.setWindowTitle("JKQTPColumnMathImage, User Palettes"); +``` +...along with a `JKQTPMathImageColorPaletteComboBox` to select a colormap and redraw the plot: +```.cpp + JKQTPMathImageColorPaletteComboBox* cmbPalette=new JKQTPMathImageColorPaletteComboBox(&win); + // ... + plot->connect(cmbPalette, &JKQTPMathImageColorPaletteComboBox::currentPaletteChanged,[&](JKQTPMathImageColorPalette p) { graph->setPalette(p); plot->redrawPlot(); }); + cmbPalette->setCurrentColorPalette(graph->getPalette()); +``` + +It also adds two `QPushButton`s that allow to save the current or all registered color-palettes to small PNG-Files: +```.cpp + QPushButton* btnSavePal=new QPushButton(QObject::tr("save current palette"), &win); + btnSavePal->connect(btnSavePal, &QPushButton::clicked, [&]() { + auto img=JKQTPImageTools::GetPaletteImage(cmbPalette->currentColorPalette(), JKQTPImageTools::LUTSIZE, 16); + img.save(JKQTPImageTools::JKQTPMathImageColorPalette2String(cmbPalette->currentColorPalette())+".png"); + }); + lay->addWidget(btnSavePal); + QPushButton* btnSaveAllPal=new QPushButton(QObject::tr("save all palettes"), &win); + btnSavePal->connect(btnSaveAllPal, &QPushButton::clicked, [&]() { + for (auto pn: JKQTPImageTools::getPredefinedPalettes()) { + auto p=JKQTPImageTools::String2JKQTPMathImageColorPalette(pn); + auto img=JKQTPImageTools::GetPaletteImage(p, JKQTPImageTools::LUTSIZE, 16); + img.save("palette_"+JKQTPImageTools::JKQTPMathImageColorPalette2String(p)+".png"); + } + }); + lay->addWidget(btnSaveAllPal); +``` + +The whole program looks like this: + +![imageplot_userpal_program](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/imageplot_userpal_program.png) + diff --git a/examples/imageplot_userpal/imageplot_userpal.cpp b/examples/imageplot_userpal/imageplot_userpal.cpp new file mode 100644 index 0000000000..b8c28b4ca0 --- /dev/null +++ b/examples/imageplot_userpal/imageplot_userpal.cpp @@ -0,0 +1,173 @@ +/** \example imageplot_userpal.cpp + * Shows how to plot colored math images/matrices with JKQTPlotter, using user-defined image palettes + * + * \ref JKQTPlotterImagePlot + */ + +#include +#include +#include +#include +#include +#include "jkqtplotter/jkqtplotter.h" +#include "jkqtplotter/graphs/jkqtpimage.h" +#include "jkqtplotter/gui/jkqtpcomboboxes.h" +#include "jkqtcommon/jkqtpbasicimagetools.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + // 0. tell the library where to find additional palettes. + // this needs to be done BEFORE first using JKQTPlotter + // 0.1 first we want to build a user-defined palette with five colors + // from a simple list of these colors: + JKQTPImageTools::LUTType pal{ + QColor("blue").rgb(), + QColor("green").rgb(), + QColor("white").rgb(), + QColor("yellow").rgb(), + QColor("red").rgb(), + QColor("red").rgb() + }; + JKQTPImageTools::registerPalette("userpal_list", pal, QObject::tr("User Palette simple list")); + + // 0.2 first we want to build a user-defined palette with five colors + // the function JKQTPBuildColorPaletteLUT builds a full-sized palette + // with steps from the given 5 colors. + // Note that you need to double the last color in order to define its range's + // beginning and end + QList > palsteps1; + palsteps1<(0.0, QColor("blue").rgba()); + palsteps1<(0.2, QColor("green").rgba()); + palsteps1<(0.4, QColor("white").rgba()); + palsteps1<(0.6, QColor("yellow").rgba()); + palsteps1<(0.8, QColor("red").rgba()); + palsteps1<(1.0, QColor("red").rgba()); + JKQTPImageTools::registerPalette("userpal_1_steps", JKQTPBuildColorPaletteLUT(palsteps1), QObject::tr("User Palette 1, steps")); + + + // With the double value (first argument), you can determine where the next color + // band starts, with respect to the other colors. As an example, we make the central + // white band narrow, as well as the bands at the borders: + QList > palsteps2; + palsteps2<(0.00, QColor("blue").rgba()); + palsteps2<(0.05, QColor("green").rgba()); + palsteps2<(0.45, QColor("white").rgba()); + palsteps2<(0.55, QColor("yellow").rgba()); + palsteps2<(0.95, QColor("red").rgba()); + palsteps2<(1.00, QColor("red").rgba()); + int userpalette_id=JKQTPImageTools::registerPalette("userpal_2_steps", JKQTPBuildColorPaletteLUT(palsteps2), QObject::tr("User Palette 2, steps")); + + + // 0.2 If we use JKQTPBuildColorPaletteLUTLinInterpolate() instead of JKQTPBuildColorPaletteLUT(), + // the palettes will be smooth (linearly interpolated between the single given colors: + JKQTPImageTools::registerPalette("userpal_1_linear", JKQTPBuildColorPaletteLUTLinInterpolate(palsteps1), QObject::tr("User Palette 1, linear")); + JKQTPImageTools::registerPalette("userpal_2_linear", JKQTPBuildColorPaletteLUTLinInterpolate(palsteps2), QObject::tr("User Palette 2, linear")); + + // 0.3 Now we load a whole set of additional palettes from an XML-file: + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/All_idl_cmaps.xml"); + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/All_mpl_cmaps.xml"); + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/CoolWarmUChar33.csv"); + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/CoolWarmUChar257.csv"); + JKQTPImageTools::registerPalettesFromFile(":/usercolorpalettes/palettes/NSW_Discrete_Z_ColorMap.xml"); + + + // 1. create a window containing a plotter and a combobox to select the color palette + // ... and get a pointer to the internal datastore (for convenience) + QWidget win; + QVBoxLayout* lay=new QVBoxLayout(); + win.setLayout(lay); + JKQTPMathImageColorPaletteComboBox* cmbPalette=new JKQTPMathImageColorPaletteComboBox(&win); + lay->addWidget(cmbPalette); + JKQTPlotter* plot=new JKQTPlotter(&win); + lay->addWidget(plot); + JKQTPDatastore* ds=plot->getDatastore(); + + // 2. now we create data for the charts (taken from https://commons.wikimedia.org/wiki/File:Energiemix_Deutschland.svg) + const int NX=100; // image dimension in x-direction [pixels] + const int NY=NX; // image dimension in x-direction [pixels] + const double dx=0.6e-2; // size of a pixel in x-direction [micrometers] + const double dy=0.6e-2; // size of a pixel in x-direction [micrometers] + + // 2.1 Parameters for airy disk plot (see https://en.wikipedia.org/wiki/Airy_disk) + double NA=1.1; // numerical aperture of lens + double wavelength=488e-3; // wavelength of the light [micrometers] + + // 2.2 calculate image of airy disk in a row-major array and immediately store the values + // in a new image column cAiryDisk + size_t cAiryDisk=ds->addCalculatedImageColumn(NX, NY, [&](size_t ix, size_t iy)->double { + double x=static_cast(static_cast(ix)-NX/2)*dx; + double y=static_cast(static_cast(iy)-NY/2)*dy; + const double r=sqrt(x*x+y*y); + const double v=2.0*M_PI*NA*r/wavelength; + if (ix==NX/2 && iy==NY/2) return 1.0; + else return pow(2.0*j1(v)/v, 2); + }, "imagedata"); + + + + + // 3. create a graph (JKQTPColumnMathImage) with the column created above as data + // The data is color-coded with the color-palette JKQTPMathImageMATLAB + // the converted range of data is determined automatically because setAutoImageRange(true) + JKQTPColumnMathImage* graph=new JKQTPColumnMathImage(plot); + graph->setTitle("default MATLAB palette"); + // set the image column with the data + graph->setImageColumn(cAiryDisk); + // where does the image start in the plot, given in plot-axis-coordinates (bottom-left corner) + graph->setX(0); + graph->setY(0); + // width and height of the image in plot-axis-coordinates + graph->setWidth(1); + graph->setHeight(1); + // color-map is taken from cmbPalette + plot->connect(cmbPalette, &JKQTPMathImageColorPaletteComboBox::currentPaletteChanged,[&](JKQTPMathImageColorPalette p) { graph->setPalette(p); plot->redrawPlot(); }); + graph->setPalette(static_cast(userpalette_id)); + cmbPalette->setCurrentColorPalette(graph->getPalette()); + + + // 4. add the graphs to the plot, so it is actually displayed + plot->addGraph(graph); + + + // 5. fix axis and plot aspect ratio to 1 + plot->getPlotter()->setMaintainAspectRatio(true); + plot->getPlotter()->setMaintainAxisAspectRatio(true); + + // 6. autoscale the plot so the graph is contained + plot->zoomToFit(); + + + // 7. Finally we add two buttons that save the current palette to a PNG-file and all loaded palettes: + QPushButton* btnSavePal=new QPushButton(QObject::tr("save current palette"), &win); + btnSavePal->connect(btnSavePal, &QPushButton::clicked, [&]() { + auto img=JKQTPImageTools::GetPaletteImage(cmbPalette->currentColorPalette(), JKQTPImageTools::LUTSIZE, 16); + img.save(JKQTPImageTools::JKQTPMathImageColorPalette2String(cmbPalette->currentColorPalette())+".png"); + }); + lay->addWidget(btnSavePal); + QPushButton* btnSaveAllPal=new QPushButton(QObject::tr("save all palettes"), &win); + btnSavePal->connect(btnSaveAllPal, &QPushButton::clicked, [&]() { + for (auto pn: JKQTPImageTools::getPredefinedPalettes()) { + auto p=JKQTPImageTools::String2JKQTPMathImageColorPalette(pn); + auto img=JKQTPImageTools::GetPaletteImage(p, JKQTPImageTools::LUTSIZE, 16); + img.save("palette_"+JKQTPImageTools::JKQTPMathImageColorPalette2String(p)+".png"); + } + }); + lay->addWidget(btnSaveAllPal); + + + + // 8. show plotter and make it a decent size + win.show(); + win.resize(500,550); + win.setWindowTitle("JKQTPColumnMathImage, USer Palettes"); + + + return app.exec(); +} diff --git a/examples/imageplot_userpal/imageplot_userpal.pro b/examples/imageplot_userpal/imageplot_userpal.pro new file mode 100644 index 0000000000..35df32608b --- /dev/null +++ b/examples/imageplot_userpal/imageplot_userpal.pro @@ -0,0 +1,27 @@ +# source code for this simple demo +SOURCES = imageplot_userpal.cpp + +# configure Qt +CONFIG += link_prl qt +QT += core gui xml svg +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport + +# output executable name +TARGET = imageplot_userpal + +# include JKQTPlotter source code +DEPENDPATH += ../../lib ../../qmake/staticlib/jkqtplotterlib +INCLUDEPATH += ../../lib +CONFIG (debug, debug|release) { + LIBS += -L../../qmake/staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug +} else { + LIBS += -L../../qmake/staticlib/jkqtplotterlib/release -ljkqtplotterlib +} +message("LIBS = $$LIBS") + +win32-msvc*: DEFINES += _USE_MATH_DEFINES +win32-msvc*: DEFINES += NOMINMAX + + + + diff --git a/examples/imageplot_userpal/imageplot_userpal.qrc b/examples/imageplot_userpal/imageplot_userpal.qrc new file mode 100644 index 0000000000..4a46b408b7 --- /dev/null +++ b/examples/imageplot_userpal/imageplot_userpal.qrc @@ -0,0 +1,9 @@ + + + palettes/All_idl_cmaps.xml + palettes/All_mpl_cmaps.xml + palettes/CoolWarmUChar33.csv + palettes/CoolWarmUChar257.csv + palettes/NSW_Discrete_Z_ColorMap.xml + + diff --git a/examples/imageplot_userpal/imageplot_userpal_and_lib.pro b/examples/imageplot_userpal/imageplot_userpal_and_lib.pro new file mode 100644 index 0000000000..cd086ab132 --- /dev/null +++ b/examples/imageplot_userpal/imageplot_userpal_and_lib.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs + +SUBDIRS += jkqtplotterlib imageplot + +jkqtplotterlib.file = ../../qmake/staticlib/jkqtplotterlib/jkqtplotterlib.pro + +imageplot.file=$$PWD/imageplot.pro +imageplot.depends = jkqtplotterlib diff --git a/examples/imageplot_userpal/palettes/All_idl_cmaps.xml b/examples/imageplot_userpal/palettes/All_idl_cmaps.xml new file mode 100644 index 0000000000..3df5a00bbe --- /dev/null +++ b/examples/imageplot_userpal/palettes/All_idl_cmaps.xml @@ -0,0 +1,10581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/imageplot_userpal/palettes/All_mpl_cmaps.xml b/examples/imageplot_userpal/palettes/All_mpl_cmaps.xml new file mode 100644 index 0000000000..efc094000c --- /dev/null +++ b/examples/imageplot_userpal/palettes/All_mpl_cmaps.xml @@ -0,0 +1,12903 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/imageplot_userpal/palettes/CoolWarmUChar257.csv b/examples/imageplot_userpal/palettes/CoolWarmUChar257.csv new file mode 100644 index 0000000000..b1e2c5679b --- /dev/null +++ b/examples/imageplot_userpal/palettes/CoolWarmUChar257.csv @@ -0,0 +1,258 @@ +Scalar,R,G,B +0,59,76,192 +0.00390625,60,78,194 +0.0078125,61,80,195 +0.01171875,62,81,197 +0.015625,63,83,198 +0.01953125,64,85,200 +0.0234375,66,87,201 +0.02734375,67,88,203 +0.03125,68,90,204 +0.03515625,69,92,206 +0.0390625,70,93,207 +0.04296875,71,95,209 +0.046875,73,97,210 +0.05078125,74,99,211 +0.0546875,75,100,213 +0.05859375,76,102,214 +0.0625,77,104,215 +0.06640625,79,105,217 +0.0703125,80,107,218 +0.07421875,81,109,219 +0.078125,82,110,221 +0.08203125,84,112,222 +0.0859375,85,114,223 +0.08984375,86,115,224 +0.09375,87,117,225 +0.09765625,89,119,226 +0.1015625,90,120,228 +0.10546875,91,122,229 +0.109375,93,123,230 +0.11328125,94,125,231 +0.1171875,95,127,232 +0.12109375,96,128,233 +0.125,98,130,234 +0.12890625,99,131,235 +0.1328125,100,133,236 +0.13671875,102,135,237 +0.140625,103,136,238 +0.14453125,104,138,239 +0.1484375,106,139,239 +0.15234375,107,141,240 +0.15625,108,142,241 +0.16015625,110,144,242 +0.1640625,111,145,243 +0.16796875,112,147,243 +0.171875,114,148,244 +0.17578125,115,150,245 +0.1796875,116,151,246 +0.18359375,118,153,246 +0.1875,119,154,247 +0.19140625,120,156,247 +0.1953125,122,157,248 +0.19921875,123,158,249 +0.203125,124,160,249 +0.20703125,126,161,250 +0.2109375,127,163,250 +0.21484375,129,164,251 +0.21875,130,165,251 +0.22265625,131,167,252 +0.2265625,133,168,252 +0.23046875,134,169,252 +0.234375,135,171,253 +0.23828125,137,172,253 +0.2421875,138,173,253 +0.24609375,140,174,254 +0.25,141,176,254 +0.25390625,142,177,254 +0.2578125,144,178,254 +0.26171875,145,179,254 +0.265625,147,181,255 +0.26953125,148,182,255 +0.2734375,149,183,255 +0.27734375,151,184,255 +0.28125,152,185,255 +0.28515625,153,186,255 +0.2890625,155,187,255 +0.29296875,156,188,255 +0.296875,158,190,255 +0.30078125,159,191,255 +0.3046875,160,192,255 +0.30859375,162,193,255 +0.3125,163,194,255 +0.31640625,164,195,254 +0.3203125,166,196,254 +0.32421875,167,197,254 +0.328125,168,198,254 +0.33203125,170,199,253 +0.3359375,171,199,253 +0.33984375,172,200,253 +0.34375,174,201,253 +0.34765625,175,202,252 +0.3515625,176,203,252 +0.35546875,178,204,251 +0.359375,179,205,251 +0.36328125,180,205,251 +0.3671875,182,206,250 +0.37109375,183,207,250 +0.375,184,208,249 +0.37890625,185,208,248 +0.3828125,187,209,248 +0.38671875,188,210,247 +0.390625,189,210,247 +0.39453125,190,211,246 +0.3984375,192,212,245 +0.40234375,193,212,245 +0.40625,194,213,244 +0.41015625,195,213,243 +0.4140625,197,214,243 +0.41796875,198,214,242 +0.421875,199,215,241 +0.42578125,200,215,240 +0.4296875,201,216,239 +0.43359375,203,216,238 +0.4375,204,217,238 +0.44140625,205,217,237 +0.4453125,206,217,236 +0.44921875,207,218,235 +0.453125,208,218,234 +0.45703125,209,219,233 +0.4609375,210,219,232 +0.46484375,211,219,231 +0.46875,213,219,230 +0.47265625,214,220,229 +0.4765625,215,220,228 +0.48046875,216,220,227 +0.484375,217,220,225 +0.48828125,218,220,224 +0.4921875,219,220,223 +0.49609375,220,221,222 +0.5,221,221,221 +0.50390625,222,220,219 +0.5078125,223,220,218 +0.51171875,224,219,216 +0.515625,225,219,215 +0.51953125,226,218,214 +0.5234375,227,218,212 +0.52734375,228,217,211 +0.53125,229,216,209 +0.53515625,230,216,208 +0.5390625,231,215,206 +0.54296875,232,215,205 +0.546875,232,214,203 +0.55078125,233,213,202 +0.5546875,234,212,200 +0.55859375,235,212,199 +0.5625,236,211,197 +0.56640625,236,210,196 +0.5703125,237,209,194 +0.57421875,238,209,193 +0.578125,238,208,191 +0.58203125,239,207,190 +0.5859375,240,206,188 +0.58984375,240,205,187 +0.59375,241,204,185 +0.59765625,241,203,184 +0.6015625,242,202,182 +0.60546875,242,201,181 +0.609375,243,200,179 +0.61328125,243,199,178 +0.6171875,244,198,176 +0.62109375,244,197,174 +0.625,245,196,173 +0.62890625,245,195,171 +0.6328125,245,194,170 +0.63671875,245,193,168 +0.640625,246,192,167 +0.64453125,246,191,165 +0.6484375,246,190,163 +0.65234375,246,188,162 +0.65625,247,187,160 +0.66015625,247,186,159 +0.6640625,247,185,157 +0.66796875,247,184,156 +0.671875,247,182,154 +0.67578125,247,181,152 +0.6796875,247,180,151 +0.68359375,247,178,149 +0.6875,247,177,148 +0.69140625,247,176,146 +0.6953125,247,174,145 +0.69921875,247,173,143 +0.703125,247,172,141 +0.70703125,247,170,140 +0.7109375,247,169,138 +0.71484375,247,167,137 +0.71875,247,166,135 +0.72265625,246,164,134 +0.7265625,246,163,132 +0.73046875,246,161,131 +0.734375,246,160,129 +0.73828125,245,158,127 +0.7421875,245,157,126 +0.74609375,245,155,124 +0.75,244,154,123 +0.75390625,244,152,121 +0.7578125,244,151,120 +0.76171875,243,149,118 +0.765625,243,147,117 +0.76953125,242,146,115 +0.7734375,242,144,114 +0.77734375,241,142,112 +0.78125,241,141,111 +0.78515625,240,139,109 +0.7890625,240,137,108 +0.79296875,239,136,106 +0.796875,238,134,105 +0.80078125,238,132,103 +0.8046875,237,130,102 +0.80859375,236,129,100 +0.8125,236,127,99 +0.81640625,235,125,97 +0.8203125,234,123,96 +0.82421875,233,121,95 +0.828125,233,120,93 +0.83203125,232,118,92 +0.8359375,231,116,90 +0.83984375,230,114,89 +0.84375,229,112,88 +0.84765625,228,110,86 +0.8515625,227,108,85 +0.85546875,227,106,83 +0.859375,226,104,82 +0.86328125,225,102,81 +0.8671875,224,100,79 +0.87109375,223,98,78 +0.875,222,96,77 +0.87890625,221,94,75 +0.8828125,220,92,74 +0.88671875,218,90,73 +0.890625,217,88,71 +0.89453125,216,86,70 +0.8984375,215,84,69 +0.90234375,214,82,67 +0.90625,213,80,66 +0.91015625,212,78,65 +0.9140625,210,75,64 +0.91796875,209,73,62 +0.921875,208,71,61 +0.92578125,207,69,60 +0.9296875,205,66,59 +0.93359375,204,64,57 +0.9375,203,62,56 +0.94140625,202,59,55 +0.9453125,200,57,54 +0.94921875,199,54,53 +0.953125,198,51,52 +0.95703125,196,49,50 +0.9609375,195,46,49 +0.96484375,193,43,48 +0.96875,192,40,47 +0.97265625,190,37,46 +0.9765625,189,34,45 +0.98046875,188,30,44 +0.984375,186,26,43 +0.98828125,185,22,41 +0.9921875,183,17,40 +0.99609375,181,11,39 +1,180,4,38 \ No newline at end of file diff --git a/examples/imageplot_userpal/palettes/CoolWarmUChar33.csv b/examples/imageplot_userpal/palettes/CoolWarmUChar33.csv new file mode 100644 index 0000000000..5bc9c68283 --- /dev/null +++ b/examples/imageplot_userpal/palettes/CoolWarmUChar33.csv @@ -0,0 +1,34 @@ +Scalar,R,G,B +0,59,76,192 +0.03125,68,90,204 +0.0625,77,104,215 +0.09375,87,117,225 +0.125,98,130,234 +0.15625,108,142,241 +0.1875,119,154,247 +0.21875,130,165,251 +0.25,141,176,254 +0.28125,152,185,255 +0.3125,163,194,255 +0.34375,174,201,253 +0.375,184,208,249 +0.40625,194,213,244 +0.4375,204,217,238 +0.46875,213,219,230 +0.5,221,221,221 +0.53125,229,216,209 +0.5625,236,211,197 +0.59375,241,204,185 +0.625,245,196,173 +0.65625,247,187,160 +0.6875,247,177,148 +0.71875,247,166,135 +0.75,244,154,123 +0.78125,241,141,111 +0.8125,236,127,99 +0.84375,229,112,88 +0.875,222,96,77 +0.90625,213,80,66 +0.9375,203,62,56 +0.96875,192,40,47 +1,180,4,38 \ No newline at end of file diff --git a/examples/imageplot_userpal/palettes/NSW_Discrete_Z_ColorMap.xml b/examples/imageplot_userpal/palettes/NSW_Discrete_Z_ColorMap.xml new file mode 100644 index 0000000000..79ebaae4d8 --- /dev/null +++ b/examples/imageplot_userpal/palettes/NSW_Discrete_Z_ColorMap.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/jkqtcommon/CMakeLists.txt b/lib/jkqtcommon/CMakeLists.txt index 42c9d64690..af14ab1a20 100644 --- a/lib/jkqtcommon/CMakeLists.txt +++ b/lib/jkqtcommon/CMakeLists.txt @@ -73,7 +73,7 @@ if(BUILD_SHARED_LIBS) add_library(${libsh_name} SHARED ${SOURCES} ${HEADERS}) set_property(TARGET ${libsh_name} PROPERTY VERSION "${PROJECT_VERSION}") set_property(TARGET ${libsh_name} PROPERTY OUTPUT_NAME "${libsh_name_decorated}") - target_link_libraries(${libsh_name} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::PrintSupport) + target_link_libraries(${libsh_name} Qt5::Core Qt5::Gui Qt5::Xml Qt5::Widgets Qt5::PrintSupport) target_compile_definitions(${libsh_name} PUBLIC JKQTCOMMON_LIB_IN_DLL) target_compile_definitions(${libsh_name} PRIVATE JKQTCOMMON_LIB_EXPORT_LIBRARY) set_property(TARGET ${libsh_name} PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS "ON") @@ -86,7 +86,7 @@ if(BUILD_STATIC_LIBS) add_library(${lib_name} STATIC ${SOURCES} ${HEADERS}) set_property(TARGET ${lib_name} PROPERTY VERSION "${PROJECT_VERSION}") set_property(TARGET ${lib_name} PROPERTY OUTPUT_NAME "${lib_name_decorated}") - target_link_libraries(${lib_name} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::PrintSupport) + target_link_libraries(${lib_name} Qt5::Core Qt5::Gui Qt5::Xml Qt5::Widgets Qt5::PrintSupport) write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${lib_name}Version.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) diff --git a/lib/jkqtcommon/jkqtpbasicimagetools.cpp b/lib/jkqtcommon/jkqtpbasicimagetools.cpp index af2fa32605..b6dc9dfbe2 100644 --- a/lib/jkqtcommon/jkqtpbasicimagetools.cpp +++ b/lib/jkqtcommon/jkqtpbasicimagetools.cpp @@ -30,1732 +30,2760 @@ const int JKQTPImageTools::PALETTE_ICON_WIDTH = 64; const int JKQTPImageTools::PALETTE_IMAGEICON_HEIGHT = 64; const int JKQTPImageTools::LUTSIZE = 256; -QList JKQTPImageTools::global_jkqtpimagetools_lutstore = QList(); +QMap JKQTPImageTools::global_jkqtpimagetools_lutstore = JKQTPImageTools::getDefaultLUTs(); +int JKQTPImageTools::global_next_userpalette = JKQTPMathImageFIRST_REGISTERED_USER_PALETTE; -bool JKQTPImagePlot_buildDefinedPaletteLessThan(const QPair &s1, const QPair &s2) - { - return s1.first > items, int lut_size) { - qSort(items.begin(), items.end(), JKQTPImagePlot_buildDefinedPaletteLessThan); + + + + + + + + +QMap JKQTPImageTools::getDefaultLUTs() { + QMap lutstore; + + { + auto palette=JKQTPMathImageRED; + QString palN="red"; + QString palNT=QObject::tr("red"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(static_cast(255.0*v), 0, 0); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageGREEN; + QString palN="green"; + QString palNT=QObject::tr("green"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(0, static_cast(255.0*v), 0); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageBLUE; + QString palN="blue"; + QString palNT=QObject::tr("blue"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(0, 0, static_cast(255.0*v)); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageGRAY; + QString palN="gray"; + QString palNT=QObject::tr("gray"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(static_cast(255.0*v), + static_cast(255.0*v), + static_cast(255.0*v)); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageALPHA; + QString palN="alpha"; + QString palNT=QObject::tr("alpha"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgba(255,255,255, + static_cast(255.0*v)); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageINVERTED_ALPHA; + QString palN="invAlpha"; + QString palNT=QObject::tr("inv. alpha"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgba(255,255,255, + static_cast(255.0*v)); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageINVERTEDRED; + QString palN="invred"; + QString palNT=QObject::tr("inv. red"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(static_cast(255.0*(1.0-v)), 0, 0); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageINVERTEDGREEN; + QString palN="invgreen"; + QString palNT=QObject::tr("inv. green"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(0, static_cast(255.0*(1.0-v)), 0); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageINVERTEDBLUE; + QString palN="invblue"; + QString palNT=QObject::tr("inv. blue"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=qRgb(0, 0, static_cast(255.0*(1.0-v))); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageINVERTEDGRAY; + QString palN="invgray"; + QString palNT=QObject::tr("inv. gray"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=1.0-(l/static_cast(JKQTPImageTools::LUTSIZE)); + plut[l]=qRgb(static_cast(255.0*v), + static_cast(255.0*v), + static_cast(255.0*v)); + } + plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; + } + } + + + { + auto palette=JKQTPMathImageMATLAB; + QString palN="Matlab"; + QString palNT=QObject::tr("Matlab"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = 382.5 - 1020.0 * std::abs(v - 0.75); + if (r > 255.0) + r = 255.0; + else if (r < 0.0) + r = 0.0; + + double g = 382.5 - 1020.0 * std::abs(v - 0.5); + if (g > 255.0) + g = 255.0; + else if (g < 0.0) + g = 0.0; + + double b = 382.5 - 1020.0 * std::abs(v - 0.25); + if (b > 255.0) + b = 255.0; + else if (b < 0.0) + b = 0.0; + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_MATLAB; + QString palN="invMatlab"; + QString palNT=QObject::tr("inv. Matlab"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 382.5 - 1020.0 * std::abs(v - 0.75); + if (r > 255.0) + r = 255.0; + else if (r < 0.0) + r = 0.0; + + double g = 382.5 - 1020.0 * std::abs(v - 0.5); + if (g > 255.0) + g = 255.0; + else if (g < 0.0) + g = 0.0; + + double b = 382.5 - 1020.0 * std::abs(v - 0.25); + if (b > 255.0) + b = 255.0; + else if (b < 0.0) + b = 0.0; + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageRYGB; + QString palN="RYGB"; + QString palNT=QObject::tr("RYGB"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = 796.875*v - 199.21875; + if (r > 255.0) + r = 255.0; + else if (r < 0.0) + r = 0.0; + + double g = 255.0 * std::sin(M_PI*v); + + double b = 255.0 - 765.0 * v; + if (b < 0.0) + b = 0.0; + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_RYGB; + QString palN="invRYGB"; + QString palNT=QObject::tr("inv. RYGB"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); if (plut!=nullptr) { + for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 796.875*v - 199.21875; + if (r > 255.0) + r = 255.0; + else if (r < 0.0) + r = 0.0; + + double g = 255.0 * std::sin(M_PI*v); + + double b = 255.0 - 765.0 * v; + if (b < 0.0) + b = 0.0; + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageHSV; + QString palN="HSV"; + QString palNT=QObject::tr("HSV"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + int h = static_cast(floor(6*v)); + double f = 6*v-double(h); + + switch (h) + { + case 0: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; + case 1: plut[l]=qRgb(static_cast(255.0*(1-f)), 255, 0); break; + case 2: plut[l]=qRgb(0, 255, static_cast(255.0*f)); break; + case 3: plut[l]=qRgb(0, static_cast(255.0*(1-f)), 255); break; + case 4: plut[l]=qRgb(static_cast(255.0*f), 0, 255); break; + case 5: plut[l]=qRgb(255, 0, static_cast(255.0*(1-f))); break; + case 6: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; + } + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_HSV; + QString palN="invHSV"; + QString palNT=QObject::tr("inv. HSV"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + int h = static_cast(floor(6.0-6.0*v)); + double f = 6.0-6.0*v-double(h); + + switch (h) + { + case 0: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; + case 1: plut[l]=qRgb(static_cast(255.0*(1-f)), 255, 0); break; + case 2: plut[l]=qRgb(0, 255, static_cast(255.0*f)); break; + case 3: plut[l]=qRgb(0, static_cast(255.0*(1-f)), 255); break; + case 4: plut[l]=qRgb(static_cast(255.0*f), 0, 255); break; + case 5: plut[l]=qRgb(255, 0, static_cast(255.0*(1-f))); break; + case 6: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; + } + } + } + } + + + { + auto palette=JKQTPMathImageRAINBOW; + QString palN="rainbow"; + QString palNT=QObject::tr("rainbow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = 255.0*std::abs(2.0*v-0.5); + if (r > 255.0) + r = 255.0; + + double g = 255.0*sin(M_PI*v); + + double b = 255.0*cos(0.5*M_PI*v); + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_RAINBOW; + QString palN="invrainbow"; + QString palNT=QObject::tr("inv. rainbow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 255.0*std::abs(2.0*v-0.5); + if (r > 255.0) + r = 255.0; + + double g = 255.0*sin(M_PI*v); + + double b = 255.0*cos(0.5*M_PI*v); + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageHOT; + QString palN="AFMhot"; + QString palNT=QObject::tr("AFM hot"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = 765.0*v; + if (r > 255.0) + r = 255.0; + + double g = 765.0*v-255.0; + if (g > 255.0) + g = 255.0; + else if (g < 0.0) + g = 0.0; + + double b = 765.0*v-510.0; + if (b < 0.0) + b = 0.0; + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_HOT; + QString palN="invAFMhot"; + QString palNT=QObject::tr("inv. AFM hot"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 765.0*v; + if (r > 255.0) + r = 255.0; + + double g = 765.0*v-255.0; + if (g > 255.0) + g = 255.0; + else if (g < 0.0) + g = 0.0; + + double b = 765.0*v-510.0; + if (b < 0.0) + b = 0.0; + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageOCEAN; + QString palN="ocean"; + QString palNT=QObject::tr("ocean"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = 765.0*v-510.0; + if (r < 0.0) + r = 0.0; + + double g = std::abs(382.5*v-127.5); + + double b = 255.0*v; + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_OCEAN; + QString palN="invocean"; + QString palNT=QObject::tr("inv. ocean"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 765.0*v-510.0; + if (r < 0.0) + r = 0.0; + + double g = std::abs(382.5*v-127.5); + + double b = 255.0*v; + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageBLUEMAGENTAYELLOW; + QString palN="BlMaYe"; + QString palNT=QObject::tr("blue-magenta-yellow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = (v/0.32-0.78125); + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + + double g = 2.0*v-0.84; + if (g < 0.0) g = 0.0; + if (g > 1.0) g = 1.0; + + double b = 4.0*v; + if (b>1 || b<0) b = -2.0*v+1.84; + if (b>1 || b<0) b = v/0.08-11.5; + if (b>1 || b<0) b=1; + + if (b < 0.0) b = 0.0; + if (b > 1.0) b = 1.0; + plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW; + QString palN="YeMaBl"; + QString palNT=QObject::tr("yellow-magenta-blue"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = (v/0.32-0.78125); + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + + double g = 2.0*v-0.84; + if (g < 0.0) g = 0.0; + if (g > 1.0) g = 1.0; + + double b = 4.0*v; + if (b>1 || b<0) b = -2.0*v+1.84; + if (b>1 || b<0) b = v/0.08-11.5; + if (b>1 || b<0) b=1; + + if (b < 0.0) b = 0.0; + if (b > 1.0) b = 1.0; + plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); + } + } + } + + + { + auto palette=JKQTPMathImageBLUEYELLOW; + QString palN="BlYe"; + QString palNT=QObject::tr("blue-yellow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = sqrt(sqrt(v)); + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + + double g = sin(M_PI/2.0*v); + if (g < 0.0) g = 0.0; + if (g > 1.0) g = 1.0; + + double b = cos(M_PI/2.0*v); + if (b < 0.0) b = 0.0; + if (b > 1.0) b = 1.0; + + plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_BLUEYELLOW; + QString palN="YeBl"; + QString palNT=QObject::tr("yellow-blue"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = sqrt(sqrt(v)); + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + + double g = sin(M_PI/2.0*v); + if (g < 0.0) g = 0.0; + if (g > 1.0) g = 1.0; + + double b = cos(M_PI/2.0*v); + if (b < 0.0) b = 0.0; + if (b > 1.0) b = 1.0; + + plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); + } + } + } + + + { + auto palette=JKQTPMathImageCYAN; + QString palN="cyan"; + QString palNT=QObject::tr("cyan"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = v*0.5; + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + + double g = v; + if (g < 0.0) g = 0.0; + if (g > 1.0) g = 1.0; + + double b = v; + if (b < 0.0) b = 0.0; + if (b > 1.0) b = 1.0; + plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_CYAN; + QString palN="invcyan"; + QString palNT=QObject::tr("inv. cyan"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = v*0.5; + if (r < 0.0) r = 0.0; + if (r > 1.0) r = 1.0; + + double g = v; + if (g < 0.0) g = 0.0; + if (g > 1.0) g = 1.0; + + double b = v; + if (b < 0.0) b = 0.0; + if (b > 1.0) b = 1.0; + plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); + } + } + } + + + { + auto palette=JKQTPMathImageTRAFFICLIGHT; + QString palN="trafficlight"; + QString palNT=QObject::tr("trafficlight"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=l/static_cast(JKQTPImageTools::LUTSIZE); + double r = (v < 0.5) ? 128.0*sin(M_PI*(2.0*v-0.5))+128.0 : 255.0; + if (r > 255.0) + r = 255.0; + + double g = (v < 0.5) ? 512.0*v+128.0 : 512.0-512.0*v; + if (g > 255.0) + g = 255.0; + plut[l]=qRgb(static_cast(r), static_cast(g), 0); + } + } + } + + + { + auto palette=JKQTPMathImageINVERTED_TRAFFICLIGHT; + QString palN="invtrafficlight"; + QString palNT=QObject::tr("inv. trafficlight"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = (v < 0.5) ? 128.0*sin(M_PI*(2.0*v-0.5))+128.0 : 255.0; + if (r > 255.0) + r = 255.0; + + double g = (v < 0.5) ? 512.0*v+128.0 : 512.0-512.0*v; + if (g > 255.0) + g = 255.0; + plut[l]=qRgb(static_cast(r), static_cast(g), 0); + } + } + } + + + { + auto palette=JKQTPMathImageBLUEWHITERED; + QString palN="bluewhitered"; + QString palNT=QObject::tr("blue-white-red"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QList > lst; + lst<(8.0, 0xFFB2182B); + lst<(7.0, 0xFFD6604D); + lst<(6.0, 0xFFF4A582); + lst<(5.0, 0xFFFDDBC7); + lst<(4.0, 0xFFD1E5F0); + lst<(3.0, 0xFF92C5DE); + lst<(2.0, 0xFF4393C3); + lst<(1.0, 0xFF2166AC); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst, JKQTPImageTools::LUTSIZE+1); + } + + + { + auto palette=JKQTPMathImageREDWHITEBLUE; + QString palN="redwhiteblue"; + QString palNT=QObject::tr("red-white-blue"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + + QList > lst; + lst<(0.0, 0xFFB2182B); + lst<(1.0, 0xFFD6604D); + lst<(2.0, 0xFFF4A582); + lst<(3.0, 0xFFFDDBC7); + lst<(4.0, 0xFFD1E5F0); + lst<(5.0, 0xFF92C5DE); + lst<(6.0, 0xFF4393C3); + lst<(7.0, 0xFF2166AC); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst, JKQTPImageTools::LUTSIZE+1); + + } + + + { + auto palette=JKQTPMathImageBLACKBLUEREDYELLOW; + QString palN="BBlRdYe"; + QString palNT=QObject::tr("black-blue-red-yellow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 255.0*qBound(0.0,sqrt(v),1.0); + double g = 255.0*qBound(0.0,v*v*v,1.0); + double b = 255.0*qBound(0.0,sin(2.0*M_PI*v),1.0); + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageGREENREDVIOLET; + QString palN="GnRdVi"; + QString palNT=QObject::tr("green-red-violet"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 255.0*qBound(0.0,v,1.0); + double g = 255.0*qBound(0.0,fabs(v-0.5),1.0); + double b = 255.0*qBound(0.0,v*v*v*v,1.0); + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageBLACKBLUEWHITEYELLOWWHITE; + QString palN="BWprint"; + QString palNT=QObject::tr("black-blue-white-yellow-white"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 255.0*qBound(0.0,v/0.32-0.78125,1.0); + double g = 255.0*qBound(0.0,v/0.32-0.78125,1.0); + double b = 255.0*qBound(0.0,(v<0.25)?4*v:(v<0.42)?1.0:(v<0.92)?-2.0*v+1.84:v/0.08-11.5,1.0); + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageWHITEYELLOWWHITEBLUEBLACK; + QString palN="invBWprint"; + QString palNT=QObject::tr("white-yellow-white-blue-black"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + double r = 255.0*qBound(0.0,v/0.32-0.78125,1.0); + double g = 255.0*qBound(0.0,v/0.32-0.78125,1.0); + double b = 255.0*qBound(0.0,(v<0.25)?4*v:(v<0.42)?1.0:(v<0.92)?-2.0*v+1.84:v/0.08-11.5,1.0); + + plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + } + } + } + + + { + auto palette=JKQTPMathImageBR_GR; + QString palN="BrBG"; + QString palNT=QObject::tr("BrBG"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(0.0, qRgb(0x8C, 0x51, 0x0A)); + lst<(1.0, qRgb(0xBF, 0x81, 0x2D)); + lst<(2.0, qRgb(0xDF, 0xC2, 0x7D)); + lst<(3.0, 0xFFF6E8C3); + lst<(4.0, 0xFFC7EAE5); + lst<(5.0, 0xFF80CDC1); + lst<(6.0, 0xFF35978F); + lst<(7.0, 0xFF01665E); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageBR_GR_STEP; + QString palN="stepsBrBG"; + QString palNT=QObject::tr("steps: BrBG"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + + QList > lst; + lst<(0.0, qRgb(0x8C, 0x51, 0x0A)); + lst<(1.0, qRgb(0xBF, 0x81, 0x2D)); + lst<(2.0, qRgb(0xDF, 0xC2, 0x7D)); + lst<(3.0, 0xFFF6E8C3); + lst<(4.0, 0xFFC7EAE5); + lst<(5.0, 0xFF80CDC1); + lst<(6.0, 0xFF35978F); + lst<(7.0, 0xFF01665E); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUT(lst); + + } + + + { + auto palette=JKQTPMathImagePU_OR; + QString palN="PuOr"; + QString palNT=QObject::tr("PuOr"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(0.0, 0xFFB35806); + lst<(1.0, 0xFFE08214); + lst<(2.0, 0xFFFDB863); + lst<(3.0, 0xFFFEE0B6); + lst<(4.0, 0xFFF7F7F7); + lst<(5.0, 0xFFD8DAEB); + lst<(6.0, 0xFFB2ABD2); + lst<(7.0, 0xFF8073AC); + lst<(8.0, 0xFF542788); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImagePU_OR_STEP; + QString palN="stepsPuOr"; + QString palNT=QObject::tr("steps: PuOr"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(0.0, 0xFFB35806); + lst<(1.0, 0xFFE08214); + lst<(2.0, 0xFFFDB863); + lst<(3.0, 0xFFFEE0B6); + lst<(4.0, 0xFFF7F7F7); + lst<(5.0, 0xFFD8DAEB); + lst<(6.0, 0xFFB2ABD2); + lst<(7.0, 0xFF8073AC); + lst<(8.0, 0xFF542788); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUT(lst); + } + + + { + auto palette=JKQTPMathImageYL_GN_BU; + QString palN="YeGnBu"; + QString palNT=QObject::tr("YeGnBu"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(0.0, 0xFFFFFFD9); + lst<(1.0, 0xFFEDF8B1); + lst<(2.0, 0xFFC7E9B4); + lst<(3.0, 0xFF7FCDBB); + lst<(4.0, 0xFF41B6C4); + lst<(5.0, 0xFF1D91C0); + lst<(6.0, 0xFF225EA8); + lst<(7.0, 0xFF253494); + lst<(8.0, 0xFF081D58); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageYL_GN_BU_STEP; + QString palN="stepsYeGnBu"; + QString palNT=QObject::tr("steps: YeGnBu"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(0.0, 0xFFFFFFD9); + lst<(1.0, 0xFFEDF8B1); + lst<(2.0, 0xFFC7E9B4); + lst<(3.0, 0xFF7FCDBB); + lst<(4.0, 0xFF41B6C4); + lst<(5.0, 0xFF1D91C0); + lst<(6.0, 0xFF225EA8); + lst<(7.0, 0xFF253494); + lst<(8.0, 0xFF081D58); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUT(lst); + } + + + { + auto palette=JKQTPMathImageGN_BU; + QString palN="greenblue"; + QString palNT=QObject::tr("green-blue"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(0.0, 0xFFF7FCF0); + lst<(1.0, 0xFFE0F3DB); + lst<(2.0, 0xFFCCEBC5); + lst<(3.0, 0xFFA8DDB5); + lst<(4.0, 0xFF7BCCC4); + lst<(5.0, 0xFF4EB3D3); + lst<(6.0, 0xFF2B8CBE); + lst<(7.0, 0xFF0868AC); + lst<(8.0, 0xFF084081); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageGN_BU_STEP; + QString palN="stepsGnBl"; + QString palNT=QObject::tr("steps: green-blue"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(0.0, 0xFFF7FCF0); + lst<(1.0, 0xFFE0F3DB); + lst<(2.0, 0xFFCCEBC5); + lst<(3.0, 0xFFA8DDB5); + lst<(4.0, 0xFF7BCCC4); + lst<(5.0, 0xFF4EB3D3); + lst<(6.0, 0xFF2B8CBE); + lst<(7.0, 0xFF0868AC); + lst<(8.0, 0xFF084081); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUT(lst); + } + + + { + auto palette=JKQTPMathImageBU_GN; + QString palN="bluegreen"; + QString palNT=QObject::tr("blue-green"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(8.0, 0xFFF7FCF0); + lst<(7.0, 0xFFE0F3DB); + lst<(6.0, 0xFFCCEBC5); + lst<(5.0, 0xFFA8DDB5); + lst<(4.0, 0xFF7BCCC4); + lst<(3.0, 0xFF4EB3D3); + lst<(2.0, 0xFF2B8CBE); + lst<(1.0, 0xFF0868AC); + lst<(0.0, 0xFF084081); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageBU_GN_STEP; + QString palN="stepsBlGn"; + QString palNT=QObject::tr("steps: blue-green"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(8.0, 0xFFF7FCF0); + lst<(7.0, 0xFFE0F3DB); + lst<(6.0, 0xFFCCEBC5); + lst<(5.0, 0xFFA8DDB5); + lst<(4.0, 0xFF7BCCC4); + lst<(3.0, 0xFF4EB3D3); + lst<(2.0, 0xFF2B8CBE); + lst<(1.0, 0xFF0868AC); + lst<(0.0, 0xFF084081); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUT(lst); + } + + + { + auto palette=JKQTPMathImageINVERTED_MAGENTA; + QString palN="invmagenta"; + QString palNT=QObject::tr("inv. magenta"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,1,0,v).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageMAGENTA; + QString palN="magenta"; + QString palNT=QObject::tr("magenta"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,1,0,v).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageINVERTED_YELLOW; + QString palN="invyellow"; + QString palNT=QObject::tr("inv. yellow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,0,1,v).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageYELLOW; + QString palN="yellow"; + QString palNT=QObject::tr("yellow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,0,1,v).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageINVERTED_MAGENTAWHITE; + QString palN="whitemagenta"; + QString palNT=QObject::tr("white-magenta"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,v,0,0).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageMAGENTAWHITE; + QString palN="magentawhite"; + QString palNT=QObject::tr("magenta-white"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,v,0,0).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageINVERTED_YELLOWWHITE; + QString palN="whiteyellow"; + QString palNT=QObject::tr("white-yellow"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,0,v,0).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageYELLOWWHITE; + QString palN="yellowwhite"; + QString palNT=QObject::tr("yellow-white"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(0,0,v,0).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageINVERTED_CYANWHITE; + QString palN="whitecyan"; + QString palNT=QObject::tr("white-cyan"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(v,0,0,0).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageCYANWHITE; + QString palN="cyanwhite"; + QString palNT=QObject::tr("cyan-white"); + lutstore[palette]=JKQTPImageTools::LUTData(QVector(JKQTPImageTools::LUTSIZE+1, 0), palN, palNT); + QRgb* plut=lutstore[palette].lut.data(); //std::cout<<"!!! creating rainbow lut\n"; + if (plut!=nullptr) { + for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { + double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); + plut[l]=QColor::fromCmykF(v,0,0,0).rgba(); + } + + } + } + + + { + auto palette=JKQTPMathImageBlueGreenRed; + QString palN="bluegreenred"; + QString palNT=QObject::tr("blue-green-red"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(1.0, QColor("blue").rgb()); + lst<(2.0, QColor("green").rgb()); + lst<(3.0, QColor("red").rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageRedGreenBlue; + QString palN="redgreenblue"; + QString palNT=QObject::tr("red-green-blue"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(1.0, QColor("red").rgb()); + lst<(2.0, QColor("green").rgb()); + lst<(3.0, QColor("blue").rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageMagentaYellow; + QString palN="magentayellow"; + QString palNT=QObject::tr("magenta-yellow"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(1.0, QColor("magenta").rgb()); + lst<(2.0, QColor("yellow").rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageYellowMagenta; + QString palN="yellowmagenta"; + QString palNT=QObject::tr("yellow-magenta"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(1.0, QColor("yellow").rgb()); + lst<(2.0, QColor("magenta").rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageRedBlue; + QString palN="redblue"; + QString palNT=QObject::tr("red-blue"); + lutstore[palette]=JKQTPImageTools::LUTData(palN, palNT); + QList > lst; + lst<(1.0, QColor("red").rgb()); + lst<(2.0, QColor("blue").rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + + { + auto palette=JKQTPMathImageBlueRed; + QString palN="bluered"; + QString palNT=QObject::tr("blue-red"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(1.0, QColor("blue").rgb()); + lst<(2.0, QColor("red").rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + { + auto palette=JKQTPMathImageSeismic; + QString palN="seismic"; + QString palNT=QObject::tr("seismic"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(0, QColor::fromRgbF(0.0, 0.0, 0.3).rgb()); + lst<(1, QColor::fromRgbF(0.0, 0.0, 1.0).rgb()); + lst<(2, QColor::fromRgbF(1.0, 1.0, 1.0).rgb()); + lst<(3, QColor::fromRgbF(1.0, 0.0, 0.0).rgb()); + lst<(4, QColor::fromRgbF(0.5, 0.0, 0.0).rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + { + auto palette=JKQTPMathImageTerrain; + QString palN="terrain"; + QString palNT=QObject::tr("terrain"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList > lst; + lst<(0.00, QColor::fromRgbF(0.2, 0.2, 0.6).rgb()); + lst<(0.15, QColor::fromRgbF(0.0, 0.6, 1.0).rgb()); + lst<(0.25, QColor::fromRgbF(0.0, 0.8, 0.4).rgb()); + lst<(0.50, QColor::fromRgbF(1.0, 1.0, 0.6).rgb()); + lst<(0.75, QColor::fromRgbF(0.5, 0.36, 0.33).rgb()); + lst<(1.00, QColor::fromRgbF(1.0, 1.0, 1.0).rgb()); + + lutstore[palette].lut=JKQTPBuildColorPaletteLUTLinInterpolate(lst); + } + + { + auto palette=JKQTPMathImageBone; + QString palN="bone"; + QString palNT=QObject::tr("bone"); + lutstore[palette]=JKQTPImageTools::LUTData( palN, palNT); + QList lstR,lstG,lstB; + lstR< lstR,lstG,lstB; + lstR< lstR,lstG,lstB; + lstR< lstR,lstG,lstB; + lstR< &s1, const QPair &s2) +{ + return s1.first > items, int lut_size) { + qSort(items.begin(), items.end(), JKQTPBuildColorPaletteLUTLessThan); + return JKQTPBuildColorPaletteLUTLinInterpolateSorted(items, lut_size); +} + + + +JKQTPImageTools::LUTType JKQTPBuildColorPaletteLUT(QList > items, int lut_size) { + qSort(items.begin(), items.end(), JKQTPBuildColorPaletteLUTLessThan); + return JKQTPBuildColorPaletteLUTSorted(items, lut_size); +} + +JKQTPImageTools::LUTType JKQTPBuildColorPaletteLUTLinSegments( QList itemsR, QList itemsG, QList itemsB, int lut_size) +{ + qSort(itemsR.begin(), itemsR.end(), JKQTPBuildColorPaletteLUTLinSegLessThan); + qSort(itemsG.begin(), itemsG.end(), JKQTPBuildColorPaletteLUTLinSegLessThan); + qSort(itemsB.begin(), itemsB.end(), JKQTPBuildColorPaletteLUTLinSegLessThan); + return JKQTPBuildColorPaletteLUTLinSegmentsSorted(itemsR, itemsG, itemsB, lut_size); +} + +JKQTPImageTools::LUTType JKQTPBuildColorPaletteLUTLinSegmentsSorted(const QList &itemsR, const QList &itemsG, const QList &itemsB, int lut_size) +{ + JKQTPImageTools::LUTType lut(lut_size, qRgb(255,255,255)); + if (itemsR.size()<=0 && itemsG.size()<=0 && itemsB.size()<=0) return lut; + + auto buildChannel=[](JKQTPImageTools::LUTType& lut, const QList &items, int channel) { + if (items.size()==1) { + for (int i=0; i(lut.size()-2); + double v=dmin; + int j1=0; + for (int i=0; i(static_cast(items[j2].colval_endprevious-items[j1].colval_startnext)*local_relV); + + JKQTPSetColorChannel(lut[i], channel, jkqtp_bounded(0, newCol, 255)); + //qDebug()<<"i="< lut[i]=0x"<=items[j1].position && v>=items[j2].position && j1 > &items, int lut_size) +{ + JKQTPImageTools::LUTType lut(lut_size, 0); + if (items.size()<=1) return lut; + double dmin=items.first().first; + double dmax=items.last().first; + double delta=(dmax-dmin)/static_cast(lut_size-2); + double v=dmin; + int j1=0; + for (int i=0; i(r), static_cast(g), static_cast(b)); + v+=delta; + // advance over items, if v crosses items[j2].first + while (v>=items[j1].first && v>=items[j2].first && j1 > &items, int lut_size) +{ + JKQTPImageTools::LUTType lut(lut_size+1, 0); double dmin=items.first().first; double dmax=items.last().first; double delta=(dmax-dmin)/double(lut_size); int i=0; int j=0; for (double v=dmin; v<=dmax; v=v+delta) { - double r=0; - double g=0; - double b=0; - if (j+1=items[j+1].first) j++; - } else { - r=double(qRed(items.last().second)); - g=double(qGreen(items.last().second)); - b=double(qBlue(items.last().second)); - } - if (i<=lut_size) lut[i]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - i++; + double r=0; + double g=0; + double b=0; + if (j+1=items[j+1].first) j++; + } + if (i<=lut_size) lut[i]=qRgb(static_cast(r), static_cast(g), static_cast(b)); + i++; } -} - -void JKQTPImagePlot_buildDefinedPaletteLinInterpolate(int* lut, int N, ...) { - QList > items; - - va_list args; - va_start(args, N); - - for (int i=0; i > items) { - qSort(items.begin(), items.end(), JKQTPImagePlot_buildDefinedPaletteLessThan); - - double dmin=items.first().first; - double dmax=items.last().first; - double delta=(dmax-dmin)/double(JKQTPImageTools::LUTSIZE); - int i=0; - int j=0; - for (double v=dmin; v<=dmax; v=v+delta) { - double r=0; - double g=0; - double b=0; - if (j+1=items[j+1].first) j++; - } - if (i<=JKQTPImageTools::LUTSIZE) lut[i]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - i++; +JKQTPImageTools::LUTType JKQTPBuildColorPaletteLUTLinInterpolate(const QMap &items, int lut_size) +{ + QList > itemsi; + for (auto it=items.begin(); it!=items.end(); ++it) { + itemsi.append(qMakePair(it.key(), it.value())); } + return JKQTPBuildColorPaletteLUTLinInterpolateSorted(itemsi, lut_size); } -void JKQTPImagePlot_buildDefinedPalette(int* lut, int N, ...) { - QList > items; - - va_list args; - va_start(args, N); - - for (int i=0; i &items, int lut_size) +{ + QList > itemsi; + for (auto it=items.begin(); it!=items.end(); ++it) { + itemsi.append(qMakePair(it.key(), it.value())); } - - va_end(args); - - JKQTPImagePlot_buildDefinedPalette(lut, items); + return JKQTPBuildColorPaletteLUTSorted(itemsi, lut_size); } double JKQTPImagePlot_QStringToDouble(QString value) { QString v=value; if (value.contains(',')) { - v=value.replace(',', '.'); + v=value.replace(',', '.'); } QLocale loc=QLocale::c(); loc.setNumberOptions(QLocale::OmitGroupSeparator); return loc.toDouble(v) ; } -static QStringList JKQTPImagePlot_palettesSearchPaths=QStringList(); -static QMap > > JKQTPImagePlot_lutsFromFiles; + template bool JKQTPImagePlot_QPairCompareFirst(const QPair &s1, const QPair &s2) { return s1.first < s2.first; } -QStringList JKQTPImagePlot_getPredefinedPalettes() { +QStringList JKQTPImageTools::getPredefinedPalettes() { static QStringList sl; - if (JKQTPImagePlot_palettesSearchPaths.isEmpty()) { - JKQTPImagePlot_palettesSearchPaths<<":/colorpalettes/"; - JKQTPImagePlot_palettesSearchPaths<<(QApplication::applicationDirPath()+"/colorpalettes/"); - JKQTPImagePlot_palettesSearchPaths<<(QApplication::applicationDirPath()+"/assets/colorpalettes/"); + if (sl.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) { + sl.clear(); + for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) { + if (it.key()>=0 && it.key()<=JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE) { + if (it.value().nameT.size()!=0) sl< > pal; - QRegExp rx3("\\s*([0-9eE.+-]+)\\s*([,\\t ])\\s*([0-9eE.+-]+)\\s*\\2\\s*([0-9eE.+-]+)\\s*", Qt::CaseInsensitive); - rx3.setMinimal(false); - QRegExp rx4("\\s*([0-9eE.+-]+)\\s*([,\\t ])\\s*([0-9eE.+-]+)\\s*\\2\\s*([0-9eE.+-]+)\\s*\\2\\s*([0-9eE.+-]+)\\s*", Qt::CaseInsensitive); - rx4.setMinimal(false); - // determine format - for (int i=slt.size()-1; i>=0; i--) { - slt[i]=slt[i].trimmed(); - if (rx4.indexIn(slt[i])>=0) { - has4=true; - double r=JKQTPImagePlot_QStringToDouble(rx4.cap(3)); - double g=JKQTPImagePlot_QStringToDouble(rx4.cap(4)); - double b=JKQTPImagePlot_QStringToDouble(rx4.cap(5)); - if (r>1.0 || g>1.0 || b>1.0) { - rgb255=true; - } - } else if (rx3.indexIn(slt[i])>=0) { - has4=false; - double r=JKQTPImagePlot_QStringToDouble(rx3.cap(1)); - double g=JKQTPImagePlot_QStringToDouble(rx3.cap(3)); - double b=JKQTPImagePlot_QStringToDouble(rx3.cap(4)); - if (r>1.0 || g>1.0 || b>1.0) { - rgb255=true; - } - } else { - slt.removeAt(i); - } - } - // read data - bool ok=true; - for (int i=0; i=0) { - x=JKQTPImagePlot_QStringToDouble(rx4.cap(1)); - r=JKQTPImagePlot_QStringToDouble(rx4.cap(3)); - g=JKQTPImagePlot_QStringToDouble(rx4.cap(4)); - b=JKQTPImagePlot_QStringToDouble(rx4.cap(5)); - } else if (!has4 && rx3.indexIn(slt[i])>=0) { - x=i; - r=JKQTPImagePlot_QStringToDouble(rx3.cap(1)); - g=JKQTPImagePlot_QStringToDouble(rx3.cap(3)); - b=JKQTPImagePlot_QStringToDouble(rx3.cap(4)); - //qDebug()<(round(255*r)), 255), qBound(0,static_cast(round(255*g)), 255), qBound(0,static_cast(round(255*b)), 255))); - } else { - pal<(round(r)), 255), qBound(0,static_cast(round(g)), 255), qBound(0,static_cast(round(b)), 255))); - } - } - } - //qDebug()<<"read: "< > pal; - if (colorspace=="rgb"){ - QDomElement e = n.firstChildElement("Point"); - while(!e.isNull()) { - double x=JKQTPImagePlot_QStringToDouble(e.attribute("x", "0")); - //double o=JKQTPImagePlot_QStringToDouble(e.attribute("o", "0")); - double r=JKQTPImagePlot_QStringToDouble(e.attribute("r", "0")); - double g=JKQTPImagePlot_QStringToDouble(e.attribute("g", "0")); - double b=JKQTPImagePlot_QStringToDouble(e.attribute("b", "0")); - pal<(round(255*r)), 255), qBound(0,static_cast(round(255*g)), 255), qBound(0,static_cast(round(255*b)), 255))); - e = e.nextSiblingElement("Point"); - } - if (pal.size()>1) { - sl<); - JKQTPImagePlot_lutsFromFiles[sl.size()-1]=pal; - palID=sl.size(); - //qDebug()<<"read "< &lutstore) { - QList ls=lutstore; - lutstore.clear(); - for (int i=0; i& lutstore, JKQTPMathImageColorPalette palette) { - int* lut_used=nullptr; +QStringList JKQTPImageTools::getPredefinedPalettesMachineReadable() { + static QStringList sl; - if (palette == JKQTPMathImageRED) - { - //int*& plut=lutstore[palette]; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(static_cast(255.0*v), 0, 0); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageGREEN) - { - //int*& plut=&lut_green; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(0, static_cast(255.0*v), 0); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageBLUE) - { - //int*& plut=&lut_blue; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(0, 0, static_cast(255.0*v)); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageGRAY) - { - //int*& plut=&lut_gray; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(static_cast(255.0*v), - static_cast(255.0*v), - static_cast(255.0*v)); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageALPHA) - { - //int*& plut=&lut_gray; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgba(255,255,255, - static_cast(255.0*v)); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTED_ALPHA) - { - //int*& plut=&lut_gray; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgba(255,255,255, - static_cast(255.0*v)); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTEDRED) - { - //int*& plut=&lut_invred; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(static_cast(255.0*(1.0-v)), 0, 0); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageINVERTEDGREEN) - { - //int*& plut=&lut_invgreen; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(0, static_cast(255.0*(1.0-v)), 0); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTEDBLUE) - { - //int*& plut=&lut_invblue; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=qRgb(0, 0, static_cast(255.0*(1.0-v))); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTEDGRAY) - { - //int*& plut=&lut_invgray; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=1.0-(l/static_cast(JKQTPImageTools::LUTSIZE)); - plut[l]=qRgb(static_cast(255.0*v), - static_cast(255.0*v), - static_cast(255.0*v)); - } - plut[JKQTPImageTools::LUTSIZE+1]=plut[JKQTPImageTools::LUTSIZE]; - } - } - lut_used=lutstore[palette]; - } - - else if (palette == JKQTPMathImageMATLAB) - { - //int*& plut=&lut_matlab; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = 382.5 - 1020.0 * std::abs(v - 0.75); - if (r > 255.0) - r = 255.0; - else if (r < 0.0) - r = 0.0; - - double g = 382.5 - 1020.0 * std::abs(v - 0.5); - if (g > 255.0) - g = 255.0; - else if (g < 0.0) - g = 0.0; - - double b = 382.5 - 1020.0 * std::abs(v - 0.25); - if (b > 255.0) - b = 255.0; - else if (b < 0.0) - b = 0.0; - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } - - else if (palette == JKQTPMathImageINVERTED_MATLAB) - { - //int*& plut=&lut_matlab_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 382.5 - 1020.0 * std::abs(v - 0.75); - if (r > 255.0) - r = 255.0; - else if (r < 0.0) - r = 0.0; - - double g = 382.5 - 1020.0 * std::abs(v - 0.5); - if (g > 255.0) - g = 255.0; - else if (g < 0.0) - g = 0.0; - - double b = 382.5 - 1020.0 * std::abs(v - 0.25); - if (b > 255.0) - b = 255.0; - else if (b < 0.0) - b = 0.0; - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageRYGB) //gnuplot: 30,-13,-23 - { - //int*& plut=&lut_rygb; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = 796.875*v - 199.21875; - if (r > 255.0) - r = 255.0; - else if (r < 0.0) - r = 0.0; - - double g = 255.0 * std::sin(M_PI*v); - - double b = 255.0 - 765.0 * v; - if (b < 0.0) - b = 0.0; - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageINVERTED_RYGB) //gnuplot: 30,-13,-23 - { - //int*& plut=&lut_rygb_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 796.875*v - 199.21875; - if (r > 255.0) - r = 255.0; - else if (r < 0.0) - r = 0.0; - - double g = 255.0 * std::sin(M_PI*v); - - double b = 255.0 - 765.0 * v; - if (b < 0.0) - b = 0.0; - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageHSV) - { - //int*& plut=&lut_hsv; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - int h = static_cast(floor(6*v)); - double f = 6*v-double(h); - - switch (h) - { - case 0: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; - case 1: plut[l]=qRgb(static_cast(255.0*(1-f)), 255, 0); break; - case 2: plut[l]=qRgb(0, 255, static_cast(255.0*f)); break; - case 3: plut[l]=qRgb(0, static_cast(255.0*(1-f)), 255); break; - case 4: plut[l]=qRgb(static_cast(255.0*f), 0, 255); break; - case 5: plut[l]=qRgb(255, 0, static_cast(255.0*(1-f))); break; - case 6: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; - } - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTED_HSV) - { - //int*& plut=&lut_invhsv; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - int h = static_cast(floor(6.0-6.0*v)); - double f = 6.0-6.0*v-double(h); - - switch (h) - { - case 0: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; - case 1: plut[l]=qRgb(static_cast(255.0*(1-f)), 255, 0); break; - case 2: plut[l]=qRgb(0, 255, static_cast(255.0*f)); break; - case 3: plut[l]=qRgb(0, static_cast(255.0*(1-f)), 255); break; - case 4: plut[l]=qRgb(static_cast(255.0*f), 0, 255); break; - case 5: plut[l]=qRgb(255, 0, static_cast(255.0*(1-f))); break; - case 6: plut[l]=qRgb(255, static_cast(255.0*f), 0); break; - } - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageRAINBOW) //gnuplot: 33,13,10 - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = 255.0*std::abs(2.0*v-0.5); - if (r > 255.0) - r = 255.0; - - double g = 255.0*sin(M_PI*v); - - double b = 255.0*cos(0.5*M_PI*v); - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageINVERTED_RAINBOW) //gnuplot: 33,13,10 - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 255.0*std::abs(2.0*v-0.5); - if (r > 255.0) - r = 255.0; - - double g = 255.0*sin(M_PI*v); - - double b = 255.0*cos(0.5*M_PI*v); - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageHOT) //gnuplot: 21,22,23 - { - //int*& plut=&lut_hot; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = 765.0*v; - if (r > 255.0) - r = 255.0; - - double g = 765.0*v-255.0; - if (g > 255.0) - g = 255.0; - else if (g < 0.0) - g = 0.0; - - double b = 765.0*v-510.0; - if (b < 0.0) - b = 0.0; - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTED_HOT) //gnuplot: 21,22,23 - { - //int*& plut=&lut_hot_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 765.0*v; - if (r > 255.0) - r = 255.0; - - double g = 765.0*v-255.0; - if (g > 255.0) - g = 255.0; - else if (g < 0.0) - g = 0.0; - - double b = 765.0*v-510.0; - if (b < 0.0) - b = 0.0; - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageOCEAN) //gnuplot: 23,28,3 - { - //int*& plut=&lut_ocean; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = 765.0*v-510.0; - if (r < 0.0) - r = 0.0; - - double g = std::abs(382.5*v-127.5); - - double b = 255.0*v; - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTED_OCEAN) //gnuplot: 23,28,3 - { - //int*& plut=&lut_ocean_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=JKQTPImageTools::LUTSIZE; l>=0; l--) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 765.0*v-510.0; - if (r < 0.0) - r = 0.0; - - double g = std::abs(382.5*v-127.5); - - double b = 255.0*v; - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBLUEMAGENTAYELLOW) //gnuplot: 30,31,32 - { - //int*& plut=&lut_bluemagentayellow; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = (v/0.32-0.78125); - if (r < 0.0) r = 0.0; - if (r > 1.0) r = 1.0; - - double g = 2.0*v-0.84; - if (g < 0.0) g = 0.0; - if (g > 1.0) g = 1.0; - - double b = 4.0*v; - if (b>1 || b<0) b = -2.0*v+1.84; - if (b>1 || b<0) b = v/0.08-11.5; - if (b>1 || b<0) b=1; - - if (b < 0.0) b = 0.0; - if (b > 1.0) b = 1.0; - plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW) //gnuplot: 30,31,32 - { - //int*& plut=&lut_bluemagentayellow_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = (v/0.32-0.78125); - if (r < 0.0) r = 0.0; - if (r > 1.0) r = 1.0; - - double g = 2.0*v-0.84; - if (g < 0.0) g = 0.0; - if (g > 1.0) g = 1.0; - - double b = 4.0*v; - if (b>1 || b<0) b = -2.0*v+1.84; - if (b>1 || b<0) b = v/0.08-11.5; - if (b>1 || b<0) b=1; - - if (b < 0.0) b = 0.0; - if (b > 1.0) b = 1.0; - plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); - } + if (sl.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) { + sl.clear(); + for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) { + if (it.key()>=0) { + if (it.value().name.size()!=0) sl<(JKQTPImageTools::LUTSIZE); - double r = sqrt(sqrt(v)); - if (r < 0.0) r = 0.0; - if (r > 1.0) r = 1.0; - - double g = sin(M_PI/2.0*v); - if (g < 0.0) g = 0.0; - if (g > 1.0) g = 1.0; - - double b = cos(M_PI/2.0*v); - if (b < 0.0) b = 0.0; - if (b > 1.0) b = 1.0; - - plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); - } - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImageINVERTED_BLUEYELLOW) //gnuplot: 8,9,10 - { - //int*& plut=&lut_blueyellow_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = sqrt(sqrt(v)); - if (r < 0.0) r = 0.0; - if (r > 1.0) r = 1.0; - - double g = sin(M_PI/2.0*v); - if (g < 0.0) g = 0.0; - if (g > 1.0) g = 1.0; - - double b = cos(M_PI/2.0*v); - if (b < 0.0) b = 0.0; - if (b > 1.0) b = 1.0; - - plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); - } - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImageCYAN) - { - //int*& plut=&lut_cyan; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = v*0.5; - if (r < 0.0) r = 0.0; - if (r > 1.0) r = 1.0; - - double g = v; - if (g < 0.0) g = 0.0; - if (g > 1.0) g = 1.0; - - double b = v; - if (b < 0.0) b = 0.0; - if (b > 1.0) b = 1.0; - plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); - } - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageINVERTED_CYAN) - { - //int*& plut=&lut_cyan_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = v*0.5; - if (r < 0.0) r = 0.0; - if (r > 1.0) r = 1.0; - - double g = v; - if (g < 0.0) g = 0.0; - if (g > 1.0) g = 1.0; - - double b = v; - if (b < 0.0) b = 0.0; - if (b > 1.0) b = 1.0; - plut[l]=qRgb(static_cast(255.0*r), static_cast(255.0*g), static_cast(255.0*b)); - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageTRAFFICLIGHT) - { - //int*& plut=&lut_trafficlight; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=l/static_cast(JKQTPImageTools::LUTSIZE); - double r = (v < 0.5) ? 128.0*sin(M_PI*(2.0*v-0.5))+128.0 : 255.0; - if (r > 255.0) - r = 255.0; - - double g = (v < 0.5) ? 512.0*v+128.0 : 512.0-512.0*v; - if (g > 255.0) - g = 255.0; - plut[l]=qRgb(static_cast(r), static_cast(g), 0); - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageINVERTED_TRAFFICLIGHT) - { - //int*& plut=&lut_trafficlight_inverted; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = (v < 0.5) ? 128.0*sin(M_PI*(2.0*v-0.5))+128.0 : 255.0; - if (r > 255.0) - r = 255.0; - - double g = (v < 0.5) ? 512.0*v+128.0 : 512.0-512.0*v; - if (g > 255.0) - g = 255.0; - plut[l]=qRgb(static_cast(r), static_cast(g), 0); - } - } - } - lut_used=lutstore[palette]; - - } - else if (palette == JKQTPMathImageBLUEWHITERED) //gnuplot: 34,13,-34 - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(8.0, 0xFFB2182B); - lst<(7.0, 0xFFD6604D); - lst<(6.0, 0xFFF4A582); - lst<(5.0, 0xFFFDDBC7); - lst<(4.0, 0xFFD1E5F0); - lst<(3.0, 0xFF92C5DE); - lst<(2.0, 0xFF4393C3); - lst<(1.0, 0xFF2166AC); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - } - else if (palette == JKQTPMathImageREDWHITEBLUE) //gnuplot: https://github.com/aschn/gnuplot-colorbrewer/blob/master/diverging/RdBu.plt - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFB2182B); - lst<(1.0, 0xFFD6604D); - lst<(2.0, 0xFFF4A582); - lst<(3.0, 0xFFFDDBC7); - lst<(4.0, 0xFFD1E5F0); - lst<(5.0, 0xFF92C5DE); - lst<(6.0, 0xFF4393C3); - lst<(7.0, 0xFF2166AC); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - - - } else if (palette == JKQTPMathImageBLACKBLUEREDYELLOW) //gnuplot: 7,5,15 - { -// int*& plut=&lut_BLACKBLUEREDYELLOW; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 255.0*qBound(0.0,sqrt(v),1.0); - double g = 255.0*qBound(0.0,v*v*v,1.0); - double b = 255.0*qBound(0.0,sin(2.0*M_PI*v),1.0); - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageGREENREDVIOLET) //gnuplot: 3,11,6 - { - //int*& plut=&lut_GREENREDVIOLET; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 255.0*qBound(0.0,v,1.0); - double g = 255.0*qBound(0.0,fabs(v-0.5),1.0); - double b = 255.0*qBound(0.0,v*v*v*v,1.0); - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBLACKBLUEWHITEYELLOWWHITE) //gnuplot: 30,31,32 - { - //int*& plut=&lut_BLACKBLUEVIOLETYELLOWWHITE; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 255.0*qBound(0.0,v/0.32-0.78125,1.0); - double g = 255.0*qBound(0.0,v/0.32-0.78125,1.0); - double b = 255.0*qBound(0.0,(v<0.25)?4*v:(v<0.42)?1.0:(v<0.92)?-2.0*v+1.84:v/0.08-11.5,1.0); - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageWHITEYELLOWWHITEBLUEBLACK) //gnuplot: 30,31,32 - { - //int*& plut=&lut_WHITEYELLOWVIOLETBLUEBLACK; - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - double r = 255.0*qBound(0.0,v/0.32-0.78125,1.0); - double g = 255.0*qBound(0.0,v/0.32-0.78125,1.0); - double b = 255.0*qBound(0.0,(v<0.25)?4*v:(v<0.42)?1.0:(v<0.92)?-2.0*v+1.84:v/0.08-11.5,1.0); - - plut[l]=qRgb(static_cast(r), static_cast(g), static_cast(b)); - } - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBR_GR) //https://github.com/aschn/gnuplot-colorbrewer/blob/master/diverging/BrBG.plt - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, qRgb(0x8C, 0x51, 0x0A)); - lst<(1.0, qRgb(0xBF, 0x81, 0x2D)); - lst<(2.0, qRgb(0xDF, 0xC2, 0x7D)); - lst<(3.0, 0xFFF6E8C3); - lst<(4.0, 0xFFC7EAE5); - lst<(5.0, 0xFF80CDC1); - lst<(6.0, 0xFF35978F); - lst<(7.0, 0xFF01665E); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBR_GR_STEP) //https://github.com/aschn/gnuplot-colorbrewer/blob/master/diverging/BrBG.plt - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, qRgb(0x8C, 0x51, 0x0A)); - lst<(1.0, qRgb(0xBF, 0x81, 0x2D)); - lst<(2.0, qRgb(0xDF, 0xC2, 0x7D)); - lst<(3.0, 0xFFF6E8C3); - lst<(4.0, 0xFFC7EAE5); - lst<(5.0, 0xFF80CDC1); - lst<(6.0, 0xFF35978F); - lst<(7.0, 0xFF01665E); - - JKQTPImagePlot_buildDefinedPalette(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImagePU_OR) //https://github.com/aschn/gnuplot-colorbrewer/blob/master/diverging/PuOr.plt - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFB35806); - lst<(1.0, 0xFFE08214); - lst<(2.0, 0xFFFDB863); - lst<(3.0, 0xFFFEE0B6); - lst<(4.0, 0xFFF7F7F7); - lst<(5.0, 0xFFD8DAEB); - lst<(6.0, 0xFFB2ABD2); - lst<(7.0, 0xFF8073AC); - lst<(8.0, 0xFF542788); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImagePU_OR_STEP) //https://github.com/aschn/gnuplot-colorbrewer/blob/master/diverging/PuOr.plt - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFB35806); - lst<(1.0, 0xFFE08214); - lst<(2.0, 0xFFFDB863); - lst<(3.0, 0xFFFEE0B6); - lst<(4.0, 0xFFF7F7F7); - lst<(5.0, 0xFFD8DAEB); - lst<(6.0, 0xFFB2ABD2); - lst<(7.0, 0xFF8073AC); - lst<(8.0, 0xFF542788); - - JKQTPImagePlot_buildDefinedPalette(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageYL_GN_BU) //http://colorbrewer2.org/ - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFFFFFD9); - lst<(1.0, 0xFFEDF8B1); - lst<(2.0, 0xFFC7E9B4); - lst<(3.0, 0xFF7FCDBB); - lst<(4.0, 0xFF41B6C4); - lst<(5.0, 0xFF1D91C0); - lst<(6.0, 0xFF225EA8); - lst<(7.0, 0xFF253494); - lst<(8.0, 0xFF081D58); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageYL_GN_BU_STEP) //http://colorbrewer2.org/ - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFFFFFD9); - lst<(1.0, 0xFFEDF8B1); - lst<(2.0, 0xFFC7E9B4); - lst<(3.0, 0xFF7FCDBB); - lst<(4.0, 0xFF41B6C4); - lst<(5.0, 0xFF1D91C0); - lst<(6.0, 0xFF225EA8); - lst<(7.0, 0xFF253494); - lst<(8.0, 0xFF081D58); - - JKQTPImagePlot_buildDefinedPalette(plut, lst); - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImageGN_BU) //http://colorbrewer2.org/ - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFF7FCF0); - lst<(1.0, 0xFFE0F3DB); - lst<(2.0, 0xFFCCEBC5); - lst<(3.0, 0xFFA8DDB5); - lst<(4.0, 0xFF7BCCC4); - lst<(5.0, 0xFF4EB3D3); - lst<(6.0, 0xFF2B8CBE); - lst<(7.0, 0xFF0868AC); - lst<(8.0, 0xFF084081); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageGN_BU_STEP) //http://colorbrewer2.org/ - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFFF7FCF0); - lst<(1.0, 0xFFE0F3DB); - lst<(2.0, 0xFFCCEBC5); - lst<(3.0, 0xFFA8DDB5); - lst<(4.0, 0xFF7BCCC4); - lst<(5.0, 0xFF4EB3D3); - lst<(6.0, 0xFF2B8CBE); - lst<(7.0, 0xFF0868AC); - lst<(8.0, 0xFF084081); - - JKQTPImagePlot_buildDefinedPalette(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBU_GN) //http://colorbrewer2.org/ - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(8.0, 0xFFF7FCF0); - lst<(7.0, 0xFFE0F3DB); - lst<(6.0, 0xFFCCEBC5); - lst<(5.0, 0xFFA8DDB5); - lst<(4.0, 0xFF7BCCC4); - lst<(3.0, 0xFF4EB3D3); - lst<(2.0, 0xFF2B8CBE); - lst<(1.0, 0xFF0868AC); - lst<(0.0, 0xFF084081); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBU_GN_STEP) //http://colorbrewer2.org/ - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(8.0, 0xFFF7FCF0); - lst<(7.0, 0xFFE0F3DB); - lst<(6.0, 0xFFCCEBC5); - lst<(5.0, 0xFFA8DDB5); - lst<(4.0, 0xFF7BCCC4); - lst<(3.0, 0xFF4EB3D3); - lst<(2.0, 0xFF2B8CBE); - lst<(1.0, 0xFF0868AC); - lst<(0.0, 0xFF084081); - - JKQTPImagePlot_buildDefinedPalette(plut, lst); - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageINVERTED_MAGENTA) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,1,0,v).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageMAGENTA) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,1,0,v).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageINVERTED_YELLOW) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,0,1,v).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageYELLOW) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,0,1,v).rgba(); - } - - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImageINVERTED_MAGENTAWHITE) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,v,0,0).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageMAGENTAWHITE) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,v,0,0).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageINVERTED_YELLOWWHITE) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,0,v,0).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageYELLOWWHITE) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(0,0,v,0).rgba(); - } - - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImageINVERTED_CYANWHITE) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(v,0,0,0).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageCYANWHITE) // from CMYK model - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - for (int l=0; l<=JKQTPImageTools::LUTSIZE; l++) { - double v=(JKQTPImageTools::LUTSIZE-l)/static_cast(JKQTPImageTools::LUTSIZE); - plut[l]=QColor::fromCmykF(v,0,0,0).rgba(); - } - - } - } - lut_used=lutstore[palette]; - } else if (palette == JKQTPMathImageBlueGreenRed) - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(1.0, QColor("blue").rgb()); - lst<(2.0, QColor("green").rgb()); - lst<(3.0, QColor("red").rgb()); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImageRedGreenBlue) - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(1.0, QColor("red").rgb()); - lst<(2.0, QColor("green").rgb()); - lst<(3.0, QColor("blue").rgb()); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - - } else if (palette == JKQTPMathImagePREDEFINED_PALETTES_COUNT) - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(1.0, QColor("magenta").rgb()); - lst<(2.0, QColor("yellow").rgb()); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImagePREDEFINED_PALETTES_COUNT+1) - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(1.0, QColor("yellow").rgb()); - lst<(2.0, QColor("magenta").rgb()); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImagePREDEFINED_PALETTES_COUNT+2) - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(1.0, QColor("red").rgb()); - lst<(2.0, QColor("blue").rgb()); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - } else if (palette == JKQTPMathImagePREDEFINED_PALETTES_COUNT+3) - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(1.0, QColor("blue").rgb()); - lst<(2.0, QColor("red").rgb()); - - JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, lst); - } - } - lut_used=lutstore[palette]; - - - /* - } else if (palette == JKQTPMathImagePU_OR) //https://github.com/aschn/gnuplot-colorbrewer/blob/master/diverging/PuOr.plt - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - QList > lst; - lst<(0.0, 0xFF); - lst<(1.0, 0xFF); - lst<(2.0, 0xFF); - lst<(3.0, 0xFF); - lst<(4.0, 0xFF); - lst<(5.0, 0xFF); - lst<(6.0, 0xFF); - lst<(7.0, 0xFF); - lst<(8.0, 0xFF); - - JKQTPImagePlot_buildDefinedPalette(plut, lst); - } - } - lut_used=lutstore[palette]; - - */ - - } else if (JKQTPImagePlot_lutsFromFiles.contains(palette)) // LUTs read from files in JKQTPImagePlot_lutsFromFiles - { - if (lutstore[palette]==nullptr) { - lutstore[palette]=(int*)malloc((JKQTPImageTools::LUTSIZE+2)*sizeof(int)); - int* plut=lutstore[palette]; - //std::cout<<"!!! creating rainbow lut\n"; - if (plut!=nullptr) { - if (JKQTPImagePlot_lutsFromFiles[palette].size()>220) JKQTPImagePlot_buildDefinedPalette(plut, JKQTPImagePlot_lutsFromFiles[palette]); - else JKQTPImagePlot_buildDefinedPaletteLinInterpolate(plut, JKQTPImagePlot_lutsFromFiles[palette]); - } - } - lut_used=lutstore[palette]; - } - return lut_used; + return sl; } -QImage JKQTPMathImageGetPaletteImage(int i, int width) + + + +QString JKQTPImageTools::JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p) { - return JKQTPMathImageGetPaletteImage(i, width, 1); + auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.find(p); + if (it==JKQTPImageTools::global_jkqtpimagetools_lutstore.end()) return QString::number(static_cast(p)); + else { + if (it.value().name.size()>0) return it.value().name; + else return QString::number(static_cast(p)); + } } -QImage JKQTPMathImageGetPaletteImage(int i, int width, int height) +JKQTPMathImageColorPalette JKQTPImageTools::String2JKQTPMathImageColorPalette(const QString &p) +{ + for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) { + if (QString::compare(p, it.value().name, Qt::CaseInsensitive)==0) { + return static_cast(it.key()); + } + } + + for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) { + if (QString::compare(p, it.value().nameT, Qt::CaseInsensitive)==0) { + return static_cast(it.key()); + } + } + + bool ok=false; + JKQTPMathImageColorPalette res = static_cast(p.toInt(&ok)); + if (!ok) return JKQTPMathImageMATLAB; + else return res; +} + + + + + + + + + + + + + +const JKQTPImageTools::LUTType& JKQTPImageTools::getLUTforPalette(QMap& lutstore, JKQTPMathImageColorPalette palette) { + static JKQTPImageTools::LUTType empty(JKQTPImageTools::LUTSIZE, 0); + + auto it=lutstore.find(static_cast(palette)); + if (it==lutstore.end()) { + return empty; + } else { + return it.value().lut; + } +} + + + +QImage JKQTPImageTools::GetPaletteImage(int i, int width) +{ + return JKQTPImageTools::GetPaletteImage(i, width, 1); +} + +QImage JKQTPImageTools::GetPaletteImage(int i, int width, int height) { QImage img; - double* pic=static_cast(malloc(width*height*sizeof(double))); + QVector pic(width*height,0); for (int j=0; j(pic, width, height, img, (JKQTPMathImageColorPalette)i, Qt::black, Qt::black); - free(pic); + JKQTPImageTools::array2image(pic.data(), width, height, img, static_cast(i), Qt::black, Qt::black); return img; } -QImage JKQTPMathImageGetPaletteImage(JKQTPMathImageColorPalette palette, int width) +QImage JKQTPImageTools::GetPaletteImage(JKQTPMathImageColorPalette palette, int width) { - return JKQTPMathImageGetPaletteImage(static_cast(palette), width); + return JKQTPImageTools::GetPaletteImage(static_cast(palette), width); } -QImage JKQTPMathImageGetPaletteImage(JKQTPMathImageColorPalette palette, int width, int height) +QImage JKQTPImageTools::GetPaletteImage(JKQTPMathImageColorPalette palette, int width, int height) { - return JKQTPMathImageGetPaletteImage(static_cast(palette), width, height); + return JKQTPImageTools::GetPaletteImage(static_cast(palette), width, height); } -QImage JKQTPMathImageGetPaletteImage(int *lut, int lut_size, int width) +QImage JKQTPImageTools::GetPaletteImage(const JKQTPImageTools::LUTType& lut, int width) { QImage img; - double* pic=static_cast(malloc(width*sizeof(double))); + QVector pic(width); for (int j=0; j(pic, width, 1, img, lut, lut_size, Qt::black, Qt::black); - free(pic); + JKQTPImageTools::array2image(pic.data(), pic.size(), 1, img, lut, Qt::black, Qt::black); return img; } -QIcon JKQTPMathImageGetPaletteIcon(int i) { - QImage img=JKQTPMathImageGetPaletteImage(i, JKQTPImageTools::PALETTE_ICON_WIDTH); +QIcon JKQTPImageTools::GetPaletteIcon(int i) { + QImage img=JKQTPImageTools::GetPaletteImage(i, JKQTPImageTools::PALETTE_ICON_WIDTH); QPixmap pix(JKQTPImageTools::PALETTE_ICON_WIDTH,8); QRect r(0,0,JKQTPImageTools::PALETTE_ICON_WIDTH-1,7); QPainter p(&pix); @@ -1767,8 +2795,8 @@ QIcon JKQTPMathImageGetPaletteIcon(int i) { } -QIcon JKQTPMathImageGetPaletteIcon(JKQTPMathImageColorPalette palette) { - return JKQTPMathImageGetPaletteIcon(static_cast(palette)); +QIcon JKQTPImageTools::GetPaletteIcon(JKQTPMathImageColorPalette palette) { + return JKQTPImageTools::GetPaletteIcon(static_cast(palette)); } @@ -1777,190 +2805,169 @@ QIcon JKQTPMathImageGetPaletteIcon(JKQTPMathImageColorPalette palette) { -QImage JKQTPMathImageGetAlphaPaletteImage(int *lut, int lut_size, int width, int height) + + +int JKQTPImageTools::registerPalette(const QString &name, const JKQTPImageTools::LUTType &paletteLut, const QString &nameT) { - QImage img; - if (!lut || lut_size<=0 || width<=0 || height<=0) return img; - double* pic=static_cast(malloc(width*sizeof(double))); - for (int j=0; j l1(lut_size, QColor("white").rgba()); - for (int i=0; i(pic, width, 1, img, l1.data(), lut_size, Qt::black, Qt::black); - free(pic); - QImage img2(width, height, QImage::Format_ARGB32); - QPainter p(&img2); - QBrush b; - b.setStyle(Qt::TexturePattern); - b.setTextureImage(img1); - p.setBrush(b); - p.fillRect(QRect(0,0,width,height), b); - p.drawImage(QRect(0,0,width,height), img); - p.end(); - return img2; + int id=JKQTPImageTools::global_next_userpalette++; + JKQTPImageTools::global_jkqtpimagetools_lutstore[id].name=name; + JKQTPImageTools::global_jkqtpimagetools_lutstore[id].nameT=((nameT.size()>0)?nameT:name); + JKQTPImageTools::global_jkqtpimagetools_lutstore[id].lut=paletteLut; + return id; } - - - - -QString JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p) +QVector JKQTPImageTools::registerPalettesFromFile(const QString &filename, bool interpolatePalette) { - switch (p) { - case JKQTPMathImageGRAY: return QString("gray"); - case JKQTPMathImageINVERTEDGRAY: return QString("invgray"); - case JKQTPMathImageRED: return QString("red"); - case JKQTPMathImageINVERTEDRED: return QString("invred"); - case JKQTPMathImageGREEN: return QString("green"); - case JKQTPMathImageINVERTEDGREEN: return QString("invgreen"); - case JKQTPMathImageBLUE: return QString("blue"); - case JKQTPMathImageINVERTEDBLUE: return QString("invblue"); - case JKQTPMathImageCYAN: return QString("cyan"); - case JKQTPMathImageINVERTED_CYAN: return QString("invcyan"); - case JKQTPMathImageYELLOW: return QString("yellow"); - case JKQTPMathImageINVERTED_YELLOW: return QString("invyellow"); - case JKQTPMathImageMAGENTA: return QString("magenta"); - case JKQTPMathImageINVERTED_MAGENTA: return QString("invmagenta"); + QVector ids; + QString ext=QFileInfo(filename).suffix().toLower(); + if (ext=="rgb" || ext=="pal" || ext=="csv") { + QFile file(filename); + if (file.open(QIODevice::ReadOnly|QIODevice::Text)) { + QString txt=file.readAll(); + QStringList slt=txt.split('\n'); + bool has4=false; + bool rgb255=false; + QList > pal; + QRegExp rx3("\\s*([0-9eE.+-]+)\\s*([,\\t ])\\s*([0-9eE.+-]+)\\s*\\2\\s*([0-9eE.+-]+)\\s*", Qt::CaseInsensitive); + rx3.setMinimal(false); + QRegExp rx4("\\s*([0-9eE.+-]+)\\s*([,\\t ])\\s*([0-9eE.+-]+)\\s*\\2\\s*([0-9eE.+-]+)\\s*\\2\\s*([0-9eE.+-]+)\\s*", Qt::CaseInsensitive); + rx4.setMinimal(false); + // determine format + for (int i=slt.size()-1; i>=0; i--) { + slt[i]=slt[i].trimmed(); + if (rx4.indexIn(slt[i])>=0) { + has4=true; + double r=JKQTPImagePlot_QStringToDouble(rx4.cap(3)); + double g=JKQTPImagePlot_QStringToDouble(rx4.cap(4)); + double b=JKQTPImagePlot_QStringToDouble(rx4.cap(5)); + if (r>1.0 || g>1.0 || b>1.0) { + rgb255=true; + } + } else if (rx3.indexIn(slt[i])>=0) { + has4=false; + double r=JKQTPImagePlot_QStringToDouble(rx3.cap(1)); + double g=JKQTPImagePlot_QStringToDouble(rx3.cap(3)); + double b=JKQTPImagePlot_QStringToDouble(rx3.cap(4)); + if (r>1.0 || g>1.0 || b>1.0) { + rgb255=true; + } + } else { + slt.removeAt(i); + } + } + // read data + bool ok=true; + for (int i=0; i=0) { + x=JKQTPImagePlot_QStringToDouble(rx4.cap(1)); + r=JKQTPImagePlot_QStringToDouble(rx4.cap(3)); + g=JKQTPImagePlot_QStringToDouble(rx4.cap(4)); + b=JKQTPImagePlot_QStringToDouble(rx4.cap(5)); + } else if (!has4 && rx3.indexIn(slt[i])>=0) { + x=i; + r=JKQTPImagePlot_QStringToDouble(rx3.cap(1)); + g=JKQTPImagePlot_QStringToDouble(rx3.cap(3)); + b=JKQTPImagePlot_QStringToDouble(rx3.cap(4)); + //qDebug()<(round(255*r)), 255), qBound(0,static_cast(round(255*g)), 255), qBound(0,static_cast(round(255*b)), 255))); + } else { + pal<(round(r)), 255), qBound(0,static_cast(round(g)), 255), qBound(0,static_cast(round(b)), 255))); + } + } + } + if (ok && pal.size()>1) { + if (interpolatePalette) ids<(p)); + } } +#ifdef QT_XML_LIB + else if (ext=="xml") { + int cnt=1; + QDomDocument doc("palette"); + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { + if (doc.setContent(&file)) { + file.close(); + QDomElement docElem = doc.documentElement(); + + QDomElement n = docElem.firstChildElement("ColorMap"); + if (docElem.nodeName()=="ColorMap") n=docElem; + while(!n.isNull()) { + QString name=n.attribute("name", QString("%2_palette%1").arg(cnt).arg(QFileInfo(filename).fileName())); + QString nameT=n.attribute("name", QObject::tr("%2: Palette #%1").arg(cnt).arg(QFileInfo(filename).fileName())); + QString colorspace=n.attribute("space", "RGB").toLower(); + QList > pal; + if (colorspace=="rgb"){ + QDomElement e = n.firstChildElement("Point"); + while(!e.isNull()) { + double x=JKQTPImagePlot_QStringToDouble(e.attribute("x", "0")); + double r=JKQTPImagePlot_QStringToDouble(e.attribute("r", "0")); + double g=JKQTPImagePlot_QStringToDouble(e.attribute("g", "0")); + double b=JKQTPImagePlot_QStringToDouble(e.attribute("b", "0")); + pal<(round(255*r)), 255), qBound(0,static_cast(round(255*g)), 255), qBound(0,static_cast(round(255*b)), 255))); + e = e.nextSiblingElement("Point"); + } + if (pal.size()>1) { + if (interpolatePalette) ids<(0, y1*255.0, 255), jkqtp_boundedRoundTo(0, y2*255.0, 255)); +} + + +JKQTPColorPaletteSingleColorLinSegment::JKQTPColorPaletteSingleColorLinSegment(): + position(0), colval_endprevious(0), colval_startnext(0) { - if (QString::compare(p, "gray", Qt::CaseInsensitive)==0) return JKQTPMathImageGRAY; - if (QString::compare(p, "invgray", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTEDGRAY; - if (QString::compare(p, "red", Qt::CaseInsensitive)==0) return JKQTPMathImageRED; - if (QString::compare(p, "invred", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTEDRED; - if (QString::compare(p, "green", Qt::CaseInsensitive)==0) return JKQTPMathImageGREEN; - if (QString::compare(p, "invgreen", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTEDGREEN; - if (QString::compare(p, "blue", Qt::CaseInsensitive)==0) return JKQTPMathImageBLUE; - if (QString::compare(p, "invblue", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTEDBLUE; - if (QString::compare(p, "cyan", Qt::CaseInsensitive)==0) return JKQTPMathImageCYAN; - if (QString::compare(p, "invcyan", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_CYAN; - if (QString::compare(p, "yellow", Qt::CaseInsensitive)==0) return JKQTPMathImageYELLOW; - if (QString::compare(p, "invyellow", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_YELLOW; - if (QString::compare(p, "magenta", Qt::CaseInsensitive)==0) return JKQTPMathImageMAGENTA; - if (QString::compare(p, "invmagenta", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_MAGENTA; - - - if (QString::compare(p, "Matlab", Qt::CaseInsensitive)==0) return JKQTPMathImageMATLAB; - if (QString::compare(p, "invMatlab", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_MATLAB; - if (QString::compare(p, "RYGB", Qt::CaseInsensitive)==0) return JKQTPMathImageRYGB; - if (QString::compare(p, "invRYGB", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_RYGB; - if (QString::compare(p, "HSV", Qt::CaseInsensitive)==0) return JKQTPMathImageHSV; - if (QString::compare(p, "invHSV", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_HSV; - if (QString::compare(p, "rainbow", Qt::CaseInsensitive)==0) return JKQTPMathImageRAINBOW; - if (QString::compare(p, "invrainbow", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_RAINBOW; - if (QString::compare(p, "AFMhot", Qt::CaseInsensitive)==0) return JKQTPMathImageHOT; - if (QString::compare(p, "invAFMhot", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_HOT; - if (QString::compare(p, "ocean", Qt::CaseInsensitive)==0) return JKQTPMathImageOCEAN; - if (QString::compare(p, "invocean", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_OCEAN; - if (QString::compare(p, "trafficlight", Qt::CaseInsensitive)==0) return JKQTPMathImageTRAFFICLIGHT; - if (QString::compare(p, "invtrafficlight", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_TRAFFICLIGHT; - if (QString::compare(p, "BlMaYe", Qt::CaseInsensitive)==0) return JKQTPMathImageBLUEMAGENTAYELLOW; - if (QString::compare(p, "YeMaBl", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW; - if (QString::compare(p, "BlYe", Qt::CaseInsensitive)==0) return JKQTPMathImageBLUEYELLOW; - if (QString::compare(p, "YeBl", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_BLUEYELLOW; - - if (QString::compare(p, "bluewhitered", Qt::CaseInsensitive)==0) return JKQTPMathImageBLUEWHITERED; - if (QString::compare(p, "redwhiteblue", Qt::CaseInsensitive)==0) return JKQTPMathImageREDWHITEBLUE; - - if (QString::compare(p, "BBlRdYe", Qt::CaseInsensitive)==0) return JKQTPMathImageBLACKBLUEREDYELLOW; - if (QString::compare(p, "GnRdVi", Qt::CaseInsensitive)==0) return JKQTPMathImageGREENREDVIOLET; - if (QString::compare(p, "BWprint", Qt::CaseInsensitive)==0) return JKQTPMathImageBLACKBLUEWHITEYELLOWWHITE; - if (QString::compare(p, "invBWprint", Qt::CaseInsensitive)==0) return JKQTPMathImageWHITEYELLOWWHITEBLUEBLACK; - if (QString::compare(p, "BrBG", Qt::CaseInsensitive)==0) return JKQTPMathImageBR_GR; - if (QString::compare(p, "PuOr", Qt::CaseInsensitive)==0) return JKQTPMathImagePU_OR; - if (QString::compare(p, "greenblue", Qt::CaseInsensitive)==0) return JKQTPMathImageGN_BU; - if (QString::compare(p, "bluegreen", Qt::CaseInsensitive)==0) return JKQTPMathImageBU_GN; - if (QString::compare(p, "YeGnBu", Qt::CaseInsensitive)==0) return JKQTPMathImageYL_GN_BU; - - if (QString::compare(p, "stepsBrBG", Qt::CaseInsensitive)==0) return JKQTPMathImageBR_GR_STEP; - if (QString::compare(p, "stepsPuOr", Qt::CaseInsensitive)==0) return JKQTPMathImagePU_OR_STEP; - if (QString::compare(p, "stepsGnBl", Qt::CaseInsensitive)==0) return JKQTPMathImageGN_BU_STEP; - if (QString::compare(p, "stepsBlGn", Qt::CaseInsensitive)==0) return JKQTPMathImageBU_GN_STEP; - if (QString::compare(p, "stepsYeGnBu", Qt::CaseInsensitive)==0) return JKQTPMathImageYL_GN_BU_STEP; - - - if (QString::compare(p, "cyanwhite", Qt::CaseInsensitive)==0) return JKQTPMathImageCYANWHITE; - if (QString::compare(p, "whitecyan", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_CYANWHITE; - if (QString::compare(p, "yellowwhite", Qt::CaseInsensitive)==0) return JKQTPMathImageYELLOWWHITE; - if (QString::compare(p, "whiteyellow", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_YELLOWWHITE; - if (QString::compare(p, "magentawhite", Qt::CaseInsensitive)==0) return JKQTPMathImageMAGENTAWHITE; - if (QString::compare(p, "whitemagenta", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_MAGENTAWHITE; - if (QString::compare(p, "bluegreenred", Qt::CaseInsensitive)==0) return JKQTPMathImageBlueGreenRed; - if (QString::compare(p, "redgreenblue", Qt::CaseInsensitive)==0) return JKQTPMathImageRedGreenBlue; - if (QString::compare(p, "alpha", Qt::CaseInsensitive)==0) return JKQTPMathImageALPHA; - if (QString::compare(p, "invAlpha", Qt::CaseInsensitive)==0) return JKQTPMathImageINVERTED_ALPHA; - - bool ok=false; - JKQTPMathImageColorPalette res = static_cast(p.toInt(&ok)); - if (!ok) return JKQTPMathImageMATLAB; - else return res; } diff --git a/lib/jkqtcommon/jkqtpbasicimagetools.h b/lib/jkqtcommon/jkqtpbasicimagetools.h index fec5134880..9c5a5a5678 100644 --- a/lib/jkqtcommon/jkqtpbasicimagetools.h +++ b/lib/jkqtcommon/jkqtpbasicimagetools.h @@ -24,38 +24,40 @@ #include #include #include -#include "jkqtcommon/jkqtcommon_imexport.h" #include #include #include #include +#include "jkqtcommon/jkqtcommon_imexport.h" +#include "jkqtcommon/jkqtpmathtools.h" -/*! \brief tool structure that summarizes several static properties - \ingroup jkqtptools_qt - \internal -*/ -struct JKQTPImageTools { - /*! \brief Width of the Palette-Icons, generated e.g. by JKQTPMathImageGetPaletteIcon() - \ingroup jkqtptools_qt */ - static JKQTCOMMON_LIB_EXPORT const int PALETTE_ICON_WIDTH; - /*! \brief Height of the Palette-Icons, generated e.g. by JKQTPMathImageGetPaletteIcon() - \ingroup jkqtptools_qt */ - static JKQTCOMMON_LIB_EXPORT const int PALETTE_IMAGEICON_HEIGHT; - - /*! \brief size of the lookup tables used by JKQTFPimagePlot_array2image() - \ingroup jkqtplotter_imagelots_tools - */ - static JKQTCOMMON_LIB_EXPORT const int LUTSIZE; - - /*! \brief internal global storage object for lookup-tables - \ingroup jkqtplotter_imagelots_tools - \internal - */ - static JKQTCOMMON_LIB_EXPORT QList global_jkqtpimagetools_lutstore; - -}; +/*! \brief retrieve an R/G/B/Alpha (\a ch == 0/1/2/3) value from the \c QRgb value \a rgb + \ingroup jkqtplotter_imagelots_tools + */ +inline int JKQTPGetColorChannel(QRgb rgb, int ch) +{ + switch(ch) { + case 0: return qRed(rgb); + case 1: return qGreen(rgb); + case 2: return qBlue(rgb); + case 3: return qAlpha(rgb); + } + return qGray(rgb); +} +/*! \brief set the R/G/B/Alpha (\a ch == 0/1/2/3) value in the \c QRgb value \a rgb to \a val (0..255!) + \ingroup jkqtplotter_imagelots_tools + */ +inline void JKQTPSetColorChannel(QRgb& rgb, int ch, int val) +{ + switch(ch) { + case 0: rgb= qRgba(val, qGreen(rgb), qBlue(rgb), qAlpha(rgb)); break; + case 1: rgb= qRgba(qRed(rgb), val, qBlue(rgb), qAlpha(rgb)); break; + case 2: rgb= qRgba(qRed(rgb), qGreen(rgb), val, qAlpha(rgb)); break; + case 3: rgb= qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), val); break; + } +} /*! \brief available palettes for coloring an image \ingroup jkqtplotter_imagelots_tools @@ -91,10 +93,25 @@ enum JKQTPMathImageColorPalette { JKQTPMathImageINVERTED_OCEAN, /*!< \image html palettes/palette_invocean.png */ JKQTPMathImageTRAFFICLIGHT, /*!< \image html palettes/palette_trafficlight.png */ JKQTPMathImageINVERTED_TRAFFICLIGHT, /*!< \image html palettes/palette_invtrafficlight.png */ + + JKQTPMathImageBone, /*!< \image html palettes/palette_bone.png */ + JKQTPMathImageCool, /*!< \image html palettes/palette_cool.png */ + JKQTPMathImageCopper, /*!< \image html palettes/palette_copper.png */ + JKQTPMathImageAutumn, /*!< \image html palettes/palette_autumn.png */ + JKQTPMathImageSeismic, /*!< \image html palettes/palette_seismic.png */ + JKQTPMathImageTerrain, /*!< \image html palettes/palette_terrain.png */ + JKQTPMathImageViridis, /*!< \image html palettes/palette_viridis.png \see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */ + JKQTPMathImageMagma, /*!< \image html palettes/palette_magma.png \see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */ + JKQTPMathImageInferno, /*!< \image html palettes/palette_inferno.png \see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */ + JKQTPMathImagePlasma, /*!< \image html palettes/palette_plasma.png \see from https://github.com/BIDS/colormap/blob/master/colormaps.py https://github.com/BIDS/colormap/blob/master/colormaps.py */ + + JKQTPMathImageBLUEMAGENTAYELLOW, /*!< \image html palettes/palette_BlMaYe.png */ JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW, /*!< \image html palettes/palette_YeMaBl.png */ + JKQTPMathImageYELLOWMAGENTABLUE=JKQTPMathImageINVERTED_BLUEMAGENTAYELLOW, /*!< \image html palettes/palette_YeMaBl.png */ JKQTPMathImageBLUEYELLOW, /*!< \image html palettes/palette_BlYe.png */ JKQTPMathImageINVERTED_BLUEYELLOW, /*!< \image html palettes/palette_YeBl.png */ + JKQTPMathImageYELLOWBLUE=JKQTPMathImageINVERTED_BLUEYELLOW, /*!< \image html palettes/palette_YeBl.png */ JKQTPMathImageBLUEWHITERED, /*!< \image html palettes/palette_bluewhitered.png */ JKQTPMathImageREDWHITEBLUE, /*!< \image html palettes/palette_redwhiteblue.png */ @@ -104,10 +121,15 @@ enum JKQTPMathImageColorPalette { JKQTPMathImageBLACKBLUEWHITEYELLOWWHITE, /*!< \image html palettes/palette_BWprint.png */ JKQTPMathImageWHITEYELLOWWHITEBLUEBLACK, /*!< \image html palettes/palette_invBWprint.png */ JKQTPMathImageBR_GR, /*!< \image html palettes/palette_BrBG.png */ + JKQTPMathImageBrownGreen=JKQTPMathImageBR_GR, /*!< \image html palettes/palette_BrBG.png */ JKQTPMathImagePU_OR, /*!< \image html palettes/palette_PuOr.png */ + JKQTPMathImageOrangeWhitePurple=JKQTPMathImagePU_OR, /*!< \image html palettes/palette_PuOr.png */ JKQTPMathImageGN_BU, /*!< \image html palettes/palette_greenblue.png */ + JKQTPMathImageGreenBlue=JKQTPMathImageGN_BU, /*!< \image html palettes/palette_greenblue.png */ JKQTPMathImageBU_GN, /*!< \image html palettes/palette_bluegreen.png */ + JKQTPMathImageBlueGreen=JKQTPMathImageBU_GN, /*!< \image html palettes/palette_bluegreen.png */ JKQTPMathImageYL_GN_BU, /*!< \image html palettes/palette_YeGnBu.png */ + JKQTPMathImageYellowGreenBlue=JKQTPMathImageYL_GN_BU, /*!< \image html palettes/palette_YeGnBu.png */ JKQTPMathImageBR_GR_STEP, /*!< \image html palettes/palette_stepsBrBG.png */ JKQTPMathImagePU_OR_STEP, /*!< \image html palettes/palette_stepsPuOr.png */ @@ -118,38 +140,33 @@ enum JKQTPMathImageColorPalette { JKQTPMathImageCYANWHITE, /*!< \image html palettes/palette_cyanwhite.png */ JKQTPMathImageINVERTED_CYANWHITE, /*!< \image html palettes/palette_whitecyan.png */ + JKQTPMathImageWHITECYAN=JKQTPMathImageINVERTED_CYANWHITE, /*!< \image html palettes/palette_whitecyan.png */ JKQTPMathImageYELLOWWHITE, /*!< \image html palettes/palette_yellowwhite.png */ JKQTPMathImageINVERTED_YELLOWWHITE, /*!< \image html palettes/palette_whiteyellow.png */ + JKQTPMathImageWHITEYELLOW=JKQTPMathImageINVERTED_YELLOWWHITE, /*!< \image html palettes/palette_whiteyellow.png */ JKQTPMathImageMAGENTAWHITE, /*!< \image html palettes/palette_magentawhite.png */ JKQTPMathImageINVERTED_MAGENTAWHITE, /*!< \image html palettes/palette_whitemagenta.png */ + JKQTPMathImageWHITEMAGENTA=JKQTPMathImageINVERTED_MAGENTAWHITE, /*!< \image html palettes/palette_whitemagenta.png */ JKQTPMathImageBlueGreenRed, /*!< \image html palettes/palette_bluegreenred.png */ JKQTPMathImageRedGreenBlue, /*!< \image html palettes/palette_redgreenblue.png */ + JKQTPMathImageMagentaYellow, /*!< \image html palettes/palette_magentayellow.png */ + JKQTPMathImageYellowMagenta, /*!< \image html palettes/palette_yellowmagenta.png */ + JKQTPMathImageRedBlue, /*!< \image html palettes/palette_redblue.png */ + JKQTPMathImageBlueRed, /*!< \image html palettes/palette_bluered.png */ - JKQTPMathImagePREDEFINED_PALETTES_COUNT, + JKQTPMathImagePREDEFINED_PALETTES_COUNT, /*!< \brief the number of predefined palettes */ - JKQTPMathImageUSER_PALETTE=65000, + JKQTPMathImageUSER_PALETTE=65000, /*!< \brief special value for JKQTPImageTools::array2image(), which signals the usage of a provided user-defined palette */ - JKQTPMathImageALPHA=JKQTPMathImageUSER_PALETTE-2, - JKQTPMathImageINVERTED_ALPHA=JKQTPMathImageUSER_PALETTE-1 + JKQTPMathImageALPHA=JKQTPMathImageUSER_PALETTE-2, /*!< \brief special palette with increasing alpha values */ + JKQTPMathImageINVERTED_ALPHA=JKQTPMathImageUSER_PALETTE-1, /*!< \brief special palette with decreasing alpha values */ + + JKQTPMathImageFIRST_REGISTERED_USER_PALETTE=JKQTPMathImagePREDEFINED_PALETTES_COUNT, /*!< \brief the ID of the first user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */ + JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE=JKQTPMathImageUSER_PALETTE-10, /*!< \brief the ID of the first user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */ }; - -/*! \brief convert the palette \a p to a string - \ingroup jkqtplotter_imagelots_tools - \see String2JKQTPMathImageColorPalette() - */ -JKQTCOMMON_LIB_EXPORT QString JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p); - -/*! \brief convert the palette name \a p to JKQTPMathImageColorPalette (compatible with String2JKQTPMathImageColorPalette() ) - \ingroup jkqtplotter_imagelots_tools - \see JKQTPMathImageColorPalette2String() - */ -JKQTCOMMON_LIB_EXPORT JKQTPMathImageColorPalette String2JKQTPMathImageColorPalette(const QString& p); - - - /*! \brief modes available for image pixels that are above/below the pixel value range \ingroup jkqtplotter_imagelots_tools */ @@ -159,6 +176,316 @@ enum JKQTPMathImageColorRangeFailAction { JKQTPMathImageTransparent=2 /*!< set transparent */ }; +/*! \brief tool structure that summarizes several static properties of JKQTPlotters palette system, + also provides functions to work with palettes and register user-defined palettes. + \ingroup jkqtptools_qt + + \see \ref JKQTPlotterImagePlot +*/ +struct JKQTPImageTools { + + /*! \brief Datatype to store lookup-tables used to map data values (scales to 0..size-1) onto RGB-colors + \ingroup jkqtptools_qt */ + typedef QVector LUTType; + + /*! \brief Width of the Palette-Icons, generated e.g. by JKQTPImageTools::GetPaletteIcon() + \ingroup jkqtptools_qt */ + static JKQTCOMMON_LIB_EXPORT const int PALETTE_ICON_WIDTH; + /*! \brief Height of the Palette-Icons, generated e.g. by JKQTPImageTools::GetPaletteIcon() + \ingroup jkqtptools_qt */ + static JKQTCOMMON_LIB_EXPORT const int PALETTE_IMAGEICON_HEIGHT; + + /*! \brief size of the lookup tables used by JKQTFPimagePlot_array2image() + */ + static JKQTCOMMON_LIB_EXPORT const int LUTSIZE; + + /*! \brief loads all palettes defined in the given palette files \a filename into global_jkqtpimagetools_userluts + and assigns a new LUT-ID >=JKQTPMathImageFIRST_REGISTERED_USER_PALETTE to each palette + All new IDs are returned as a list + + + The file might either be a palette XML-file or a CSV-file: + + \b CSV-files need to have one of the following two formats (RED/GREEN/BLUE: 0..255): + \verbatim + scalar, red, green, blue + scalar, red, green, blue + ... + \endverbatim + or simply + \verbatim + red, green, blue + red, green, blue + ... + \endverbatim + The parser will also allow tabs and whitespaces as column separators. + + + \b CML-files need to have one of the following two formats (RED/GREEN/BLUE/OPACITY: 0..1): + \verbatim + + + + ... + + \endverbatim + optionally several \c ... definitions may be put below an arbitrarily named + document node, e.g.: + \verbatim + + + + + ... + + + + + ... + + ... + + \endverbatim + + \note In both cases, the palette will be formed without interpolation, i.e. using JKQTPBuildColorPaletteLUT() . + If in addition \a interpolatePalette is set to \c true, the function JKQTPBuildColorPaletteLUTLinInterpolate() + is used instead. + + \see \ref JKQTPlotterImagePlot , JKQTPBuildColorPaletteLUT() + */ + static JKQTCOMMON_LIB_EXPORT QVector registerPalettesFromFile(const QString& filename, bool interpolatePalette=false); + + /*! \brief registers a new LUT defined by \a paletteLut and with the given \a name (computer-readable) for later use, optionally stores also the human-readable and localized name \a nameT + and assigns a new LUT-ID >=JKQTPMathImageFIRST_REGISTERED_USER_PALETTE to the palette and returns it + + \see \ref JKQTPlotterImagePlot, JKQTPBuildColorPaletteLUTLinInterpolate(), JKQTPBuildColorPaletteLUT(), JKQTPBuildColorPaletteLUTLinInterpolateSorted(), JKQTPBuildColorPaletteLUTSorted(), JKQTPBuildColorPaletteLUTLinInterpolate(), JKQTPBuildColorPaletteLUT() + */ + static JKQTCOMMON_LIB_EXPORT int registerPalette(const QString& name, const LUTType &paletteLut, const QString &nameT=QString()); + + + + + + + + + /*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette) + + \param dbl_in pointer to a 1D array of template type \c T representing the image to plot. This array has to be of size \a width * \a height + \param width width of the array in \a dbl + \param height height of the array in \a dbl + \param[out] img the QImage object to draw to (should be initialized as \c QImage::Format_ARGB32 ) + \param palette the color palette to use for the display + \param minColor lower boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. + \param maxColor upper boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. + \param paletteMinFail specifies what shell happen, when a value in \a dbl is below \a minColor + \param paletteMaxFail specifies what shell happen, when a value in \a dbl is above \a maxColor + \param minFailColor color to use for pixels that are below \a minColor for some settings of \a paletteMinFail + \param maxFailColor color to use for pixels that are below \a maxColor for some settings of \a paletteMaxFail + \param nanColor color to use for pixels that are not-a-number + \param infColor color to use for pixels that are infinity + \param logScale create a log-scaled image + \param logBase base for the logarithm used when \c logScale==true + \param lutUser user define LUT, used if \a palette \c ==JKQTPMathImageUSER_PALETTE + \note There is a variant of this function that is called with a userLUT directly, instead of \a palette + */ + template + static inline void array2image(const T* dbl_in, int width, int height, QImage &img, JKQTPMathImageColorPalette palette, double minColor, double maxColor, JKQTPMathImageColorRangeFailAction paletteMinFail=JKQTPMathImageLastPaletteColor, JKQTPMathImageColorRangeFailAction paletteMaxFail=JKQTPMathImageLastPaletteColor, QColor minFailColor=QColor("black"), QColor maxFailColor=QColor("black"), QColor nanColor=QColor("black"), QColor infColor=QColor("black"), bool logScale=false, double logBase=10.0, const LUTType& lutUser=LUTType()) + { + if (!dbl_in || width<=0 || height<=0) + return; + + double min = *dbl_in; + double max = *dbl_in; + if (jkqtp_approximatelyEqual(minColor, maxColor, JKQTP_DOUBLE_EPSILON)) { + bool first=true; + for (int i=1; i(v)) || std::isinf(static_cast(v)))) { + if (first) { + min=max=v; + first=false; + } else { + if (v < min) + min = v; + else if (v > max) + max = v; + } + } + } + + } else { + min = minColor; + max = maxColor; + } + + const T* dbl=dbl_in; + QVector dbl1; + if (logScale) { + double logB=log10(logBase); + dbl1=QVector(width*height, 0); + for (int i=0; i0) { + // LUT found: collor the image accordingly + for (int j=0; j(img.scanLine(height-1-j)); + for (int i=0; i((val-min)/delta*static_cast(lutSize-1)); + const int vv = (v < 0) ? 0 : ( (v >= lutSize) ? (lutSize-1) : v); + line[i]=lut_used[vv]; + if ((v<0)&&(paletteMinFail==JKQTPMathImageGivenColor)) { + line[i]=minFailColor.rgba(); + } else if ((v>lutSize)&&(paletteMaxFail==JKQTPMathImageGivenColor)) { + line[i]=maxFailColor.rgba(); + } else if ((v<0)&&(paletteMinFail==JKQTPMathImageTransparent)) { + line[i]=QColor(Qt::transparent).rgba(); + } else if ((v>lutSize)&&(paletteMaxFail==JKQTPMathImageTransparent)) { + line[i]=QColor(Qt::transparent).rgba(); + } + } + } + } + } else { + // no LUT found: paint a black image! + img.fill(0); + } + } + + } + + /*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette) + + \param dbl_in pointer to a 1D array of template type \c T representing the image to plot. This array has to be of size \a width * \a height + \param width width of the array in \a dbl + \param height height of the array in \a dbl + \param[out] img the QImage object to draw to (should be initialized as \c QImage::Format_ARGB32 ) + \param lutUser user-defined lookup-table + \param minColor lower boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. + \param maxColor upper boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. + \param paletteMinFail specifies what shell happen, when a value in \a dbl is below \a minColor + \param paletteMaxFail specifies what shell happen, when a value in \a dbl is above \a maxColor + \param minFailColor color to use for pixels that are below \a minColor for some settings of \a paletteMinFail + \param maxFailColor color to use for pixels that are below \a maxColor for some settings of \a paletteMaxFail + \param nanColor color to use for pixels that are not-a-number + \param infColor color to use for pixels that are infinity + \param logScale create a log-scaled image + \param logBase base for the logarithm used when \c logScale==true + */ + template + static inline void array2image(const T* dbl_in, int width, int height, QImage &img, const LUTType& lutUser, double minColor, double maxColor, JKQTPMathImageColorRangeFailAction paletteMinFail=JKQTPMathImageLastPaletteColor, JKQTPMathImageColorRangeFailAction paletteMaxFail=JKQTPMathImageLastPaletteColor, QColor minFailColor=QColor("black"), QColor maxFailColor=QColor("black"), QColor nanColor=QColor("black"), QColor infColor=QColor("black"), bool logScale=false, double logBase=10.0) + { + array2image(dbl_in, width, height, img, JKQTPMathImageUSER_PALETTE, minColor, maxColor, paletteMinFail, paletteMaxFail, minFailColor, maxFailColor, nanColor, infColor, logScale, logBase, lutUser); + } + + + + /*! \brief return a list of all globally available LUTs, human-readable/localized form */ + static QStringList JKQTCOMMON_LIB_EXPORT getPredefinedPalettes(); + + /*! \brief return a list of all globally available LUTs, machine-readable form */ + static QStringList JKQTCOMMON_LIB_EXPORT getPredefinedPalettesMachineReadable(); + + /*! \brief convert the palette \a p to a string + \see JKQTPImageTools::String2JKQTPMathImageColorPalette() + */ + static JKQTCOMMON_LIB_EXPORT QString JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p); + + /*! \brief convert the palette name \a p to JKQTPMathImageColorPalette (compatible with JKQTPImageTools::String2JKQTPMathImageColorPalette() ) + \see JKQTPImageTools::JKQTPMathImageColorPalette2String() + */ + static JKQTCOMMON_LIB_EXPORT JKQTPMathImageColorPalette String2JKQTPMathImageColorPalette(const QString& p); + + + /*! \brief generates a QImage with width \a width and height 1 for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) */ + static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(int i, int width); + /*! \brief generates a QImage with width \a width and height \a height for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) */ + static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(int i, int width, int height); + /*! \brief generates a QImage with width \a width and height 1 for a specific JKQTPMathImageColorPalette */ + static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(JKQTPMathImageColorPalette palette, int width); + /*! \brief generates a QImage with width \a width and height \a height for a specific JKQTPMathImageColorPalette */ + static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(JKQTPMathImageColorPalette palette, int width, int height); + /*! \brief generates a QImage with width \a width and height 1 for a lookup-table \a lut */ + static QImage JKQTCOMMON_LIB_EXPORT GetPaletteImage(const LUTType& lut, int width); + + /*! \brief generates a QIcon for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) */ + static QIcon JKQTCOMMON_LIB_EXPORT GetPaletteIcon(int i) ; + + + /*! \brief generates a QIcon for a specific JKQTPMathImageColorPalette */ + static QIcon JKQTCOMMON_LIB_EXPORT GetPaletteIcon(JKQTPMathImageColorPalette palette) ; + + private: + + /*! \brief internal datatype, representing a lookup-table and its metadata inside global_jkqtpimagetools_lutstore + \internal + */ + struct LUTData { + LUTData(); + LUTData(const LUTType& _lut, const QString& _name, const QString& _nameT); + LUTData(const QString& _name, const QString& _nameT); + /** \brief the LUT itself */ + LUTType lut; + /** \brief name for the LUT (machine-readable) */ + QString name; + /** \brief name for the LUT (localized, human-readable) */ + QString nameT; + }; + + /*! \brief internal global storage object for lookup-tables + \internal + */ + static JKQTCOMMON_LIB_EXPORT QMap global_jkqtpimagetools_lutstore; + + /*! \brief storage for the next ID to assign to a user-defined palette, registered with registerPalette() or registerPalettesFromFile() + \internal + + \see registerPalette() registerPalettesFromFile() + */ + static JKQTCOMMON_LIB_EXPORT int global_next_userpalette; + + /*! \brief returns data of the default LUTs, used to initialize global_jkqtpimagetools_lutstore + \internal + */ + static JKQTCOMMON_LIB_EXPORT QMap getDefaultLUTs(); + + + /*! \brief create a LUT for a given JKQTPMathImageColorPalette, store it in \a lutstore and return it + \internal + */ + static JKQTCOMMON_LIB_EXPORT const LUTType& getLUTforPalette(QMap &lutcache, JKQTPMathImageColorPalette palette); + +}; + + + + + + + /*! \brief modes available for RGB images \ingroup jkqtplotter_imagelots_tools @@ -175,19 +502,6 @@ enum JKQTPRGBMathImageRGBMode { }; -/*! \brief returns a vector containing all elements of the given array - \ingroup jkqtplotter_imagelots_tools - -*/ -template -inline QVector JKQTPImagePlot_arrayToVector(const T* input, int N) { - if (!input || N<=0) return QVector(); - T dummy; - QVector out(N, dummy); - memcpy(out.data(), input, N*sizeof(T)); - return out; -} - /*! \brief returns a vector containing all elements of the given array as doubles \ingroup jkqtplotter_imagelots_tools @@ -302,7 +616,7 @@ inline void JKQTPImagePlot_array2RGBimage(T* dbl_in, int width, int height, QIma double min = *dbl_in; double max = *dbl_in; bool first=true; - if (minColor == maxColor) { + if (jkqtp_approximatelyEqual(minColor, maxColor, JKQTP_DOUBLE_EPSILON)) { for (int i=1; i(malloc(width*height*sizeof(T))); //memcpy(dbl, dbl_in, width*height*sizeof(T)); for (int i=0; i -inline QList JKQTPImagePlot_makeQList(const T& defaultVal, int N=1) { - QList l; - for (int i=0; i > items, int lut_size=JKQTPImageTools::LUTSIZE); - -/*! \brief build a linearly interpolated palette in \a lut with \a N entries that are provided as (double, QRgb) value pairss in the variable arguments - \ingroup jkqtplotter_imagelots_tools - - The entries in \a items are sorted by the first (double) argument and the full range is distributed - over 0 ... lut_size. Values in the LUT in between are generated by linear interpolations - - \a lut needs to have \c lut_size) entries -*/ -void JKQTCOMMON_LIB_EXPORT JKQTPImagePlot_buildDefinedPaletteLinInterpolate(int* lut, int N, ...); - -/*! \brief build a palette in \a lut with \a N entries that are provided in \a items - \ingroup jkqtplotter_imagelots_tools - - The entries in \a items are sorted by the first (double) argument and the full range is distributed - over 0 ... JKQTPImageTools::LUTSIZE. - - \a lut needs to have \c JKQTPImageTools::LUTSIZE) entries -*/ -void JKQTCOMMON_LIB_EXPORT JKQTPImagePlot_buildDefinedPalette(int* lut, QList > items); - -/*! \brief build a palette in \a lut with \a N entries that are provided as as (double, QRgb) value pairss in the variable arguments - \ingroup jkqtplotter_imagelots_tools -*/ -void JKQTCOMMON_LIB_EXPORT JKQTPImagePlot_buildDefinedPalette(int* lut, int N, ...); - -/*! \brief return a list of all globally available LUTs - \ingroup jkqtplotter_imagelots_tools */ -QStringList JKQTCOMMON_LIB_EXPORT JKQTPImagePlot_getPredefinedPalettes(); - - - -/*! \brief create a LUT for a given JKQTPMathImageColorPalette, store it in \a lutstore and return it - \ingroup jkqtplotter_imagelots_tools - \internal - */ -JKQTCOMMON_LIB_EXPORT int* JKQTPImagePlot_getCreateLUT(QList &lutstore, JKQTPMathImageColorPalette palette); -/*! \brief frees a list of LUTs - \ingroup jkqtplotter_imagelots_tools - \internal - */ -void JKQTCOMMON_LIB_EXPORT JKQTPImagePlot_freeLUTs(QList &lutstore); - - -/*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette) - \ingroup jkqtplotter_imagelots_tools - - This method uses lookup tables which are saved as static variables to convert the 2D array into - an image. The luts are only created once, and stored then, so mor CPU time is saved. The precompiler define - JKQTPImageTools::LUTSIZE sets the size of the LUTs. Note that if you don't use a specific color palette, - the according LUT won't be calculated and stored! - - \param dbl_in pointer to a 1D array of template type \c T representing the image to plot. This array has to be of size \a width * \a height - \param width width of the array in \a dbl - \param height height of the array in \a dbl - \param[out] img the QImage object to draw to (should be initialized as \c QImage::Format_ARGB32 ) - \param palette the color palette to use for the display - \param minColor lower boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. - \param maxColor upper boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. - \param paletteMinFail specifies what shell happen, when a value in \a dbl is below \a minColor - \param paletteMaxFail specifies what shell happen, when a value in \a dbl is above \a maxColor - \param minFailColor color to use for pixels that are below \a minColor for some settings of \a paletteMinFail - \param maxFailColor color to use for pixels that are below \a maxColor for some settings of \a paletteMaxFail - \param nanColor color to use for pixels that are not-a-number - \param infColor color to use for pixels that are infinity - \param logScale create a log-scaled image - \param logBase base for the logarithm used when \c logScale==true - \param lutUser user define LUT - \param lutUserSize size of the LUT in lutUser -*/ -template -inline void JKQTPImagePlot_array2image(const T* dbl_in, int width, int height, QImage &img, JKQTPMathImageColorPalette palette, double minColor, double maxColor, JKQTPMathImageColorRangeFailAction paletteMinFail=JKQTPMathImageLastPaletteColor, JKQTPMathImageColorRangeFailAction paletteMaxFail=JKQTPMathImageLastPaletteColor, QColor minFailColor=QColor("black"), QColor maxFailColor=QColor("black"), QColor nanColor=QColor("black"), QColor infColor=QColor("black"), bool logScale=false, double logBase=10.0, const int* lutUser=0, int lutUserSize=0) -{ - if (!dbl_in || width<=0 || height<=0) - return; - - double min = *dbl_in; - double max = *dbl_in; - if (minColor == maxColor) { - bool first=true; - for (int i=1; i(v)) || std::isinf(static_cast(v)))) { - if (first) { - min=max=v; - first=false; - } else { - if (v < min) - min = v; - else if (v > max) - max = v; - } - } - } - - } else { - min = minColor; - max = maxColor; - } - - const T* dbl=dbl_in; - T* dbl1=nullptr; - if (logScale) { - double logB=log10(logBase); - dbl1=(T*)malloc(width*height*sizeof(T)); - //memcpy(dbl, dbl_in, width*height*sizeof(T)); - for (int i=0; i(nullptr, JKQTPImagePlot_getPredefinedPalettes().size()+2); - - - img = QImage(width, height, QImage::Format_ARGB32); - if (min == max) - img.fill(0); - else - { - - if (palette==JKQTPMathImageUSER_PALETTE) { - lut_used=lutUser; - lutSize=lutUserSize; - //qDebug()<<"user palette "<0) { - const unsigned int* lut_usedui=reinterpret_cast(lut_used); - // LUT found: collor the image accordingly - for (int j=0; j(img.scanLine(height-1-j)); - for (int i=0; i((val-min)/delta*static_cast(lutSize)); - const int vv = (v < 0) ? 0 : ( (v > lutSize) ? (lutSize) : v); - line[i]=lut_usedui[vv]; - if ((v<0)&&(paletteMinFail==JKQTPMathImageGivenColor)) { - line[i]=minFailColor.rgba(); - } else if ((v>lutSize)&&(paletteMaxFail==JKQTPMathImageGivenColor)) { - line[i]=maxFailColor.rgba(); - } else if ((v<0)&&(paletteMinFail==JKQTPMathImageTransparent)) { - line[i]=QColor(Qt::transparent).rgba(); - } else if ((v>lutSize)&&(paletteMaxFail==JKQTPMathImageTransparent)) { - line[i]=QColor(Qt::transparent).rgba(); - } - } - } - } - } else { - // no LUT found: paint a black image! - img.fill(0); - } - } - - if (dbl1) free(dbl1); - +struct JKQTPColorPaletteSingleColorLinSegment { + JKQTPColorPaletteSingleColorLinSegment(double p, uint8_t y1, uint8_t y2); + static JKQTPColorPaletteSingleColorLinSegment makeDbl_0_1(double p, double y1, double y2); + JKQTPColorPaletteSingleColorLinSegment(); + /** \brief scalar position of the element on the value axis */ + double position; + /** \brief color-channel-value that ends the prevoius segment (ignored for the first entry in a table) */ + uint8_t colval_endprevious; + /** \brief color-channel-value that starts the next segment (ignored for the last entry in a table) */ + uint8_t colval_startnext; }; -/*! \brief convert a 2D image (as 1D array) into a QImage with given palette (see JKQTFPColorPalette) - \ingroup jkqtplotter_imagelots_tools +/*! \brief build an interpolated palette with \a lut_size entries from the linear segments defined for the color channels R, G and B in \a itemsR, \a itemG and \a itemB respectively + \b NOTE: The entries in \a itemsR, \a itemsG, \a itemsB are assumed to be sorted by the position entry. + \ingroup jkqtplotter_imagelots_tools_LUTS - This method uses lookup tables which are saved as static variables to convert the 2D array into - an image. The luts are only created once, and stored then, so mor CPU time is saved. The precompiler define - JKQTPImageTools::LUTSIZE sets the size of the LUTs. Note that if you don't use a specific color palette, - the according LUT won't be calculated and stored! - \param dbl_in pointer to a 1D array of template type \c T representing the image to plot. This array has to be of size \a width * \a height - \param width width of the array in \a dbl - \param height height of the array in \a dbl - \param[out] img the QImage object to draw to (should be initialized as \c QImage::Format_ARGB32 ) - \param lutUser user-defined lookup-table - \param lutUserSize number of entries in \a lutUser - \param minColor lower boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. - \param maxColor upper boundary of color range in \a dbl pixels, if \a minColor == \a maxColor then this function will extract the image min and image max. - \param paletteMinFail specifies what shell happen, when a value in \a dbl is below \a minColor - \param paletteMaxFail specifies what shell happen, when a value in \a dbl is above \a maxColor - \param minFailColor color to use for pixels that are below \a minColor for some settings of \a paletteMinFail - \param maxFailColor color to use for pixels that are below \a maxColor for some settings of \a paletteMaxFail - \param nanColor color to use for pixels that are not-a-number - \param infColor color to use for pixels that are infinity - \param logScale create a log-scaled image - \param logBase base for the logarithm used when \c logScale==true + + + This is used to build a table of linear segments as a \c QList : + \verbatim + i position colval1 colval2 + ~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ + 0 0.0 0 (IGNORED) 0 + 1 0.5 100 100 + 2 0.8 255 255 + 3 1.0 255 255 (IGNORED) + \endverbatim + + This will build a graph: + \verbatim + colval + ^ + | + 250 - #**********# + | *** + 200 - *** + | *** + 150 - ** + | ** + 100 - *****# + | **** + 50 - ***** + | ***** + 0 - #***** + | + ---|----|----|----|----|----|----|----|----|----|----|--> position + 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 + \endverbatim + + You can also build graphs with a jump at a certain position + \verbatim + i position colval1 colval2 + ~~~ ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ + 0 0.0 0 (IGNORED) 0 + 1 0.5 100 0 + 2 1.0 255 255 (IGNORED) + \endverbatim + + This results in: + + \verbatim + colval + ^ + | + 250 - **# + | ** + 200 - ** + | ** + 150 - *** + | ** + 100 - # ** + | ****** ** + 50 - ****** ** + | ****** ** + 0 - #****** #** + | + ---|----|----|----|----|----|----|----|----|----|----|--> position + 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 + \endverbatim + + \see JKQTPBuildColorPaletteLUTLinSegments(), \ref JKQTPlotterImagePlotUserPalette , https://matplotlib.org/api/_as_gen/matplotlib.colors.LinearSegmentedColormap.html#matplotlib.colors.LinearSegmentedColormap */ -template -inline void JKQTPImagePlot_array2image(const T* dbl_in, int width, int height, QImage &img, const int* lutUser, int lutUserSize, double minColor, double maxColor, JKQTPMathImageColorRangeFailAction paletteMinFail=JKQTPMathImageLastPaletteColor, JKQTPMathImageColorRangeFailAction paletteMaxFail=JKQTPMathImageLastPaletteColor, QColor minFailColor=QColor("black"), QColor maxFailColor=QColor("black"), QColor nanColor=QColor("black"), QColor infColor=QColor("black"), bool logScale=false, double logBase=10.0) -{ - JKQTPImagePlot_array2image(dbl_in, width, height, img, JKQTPMathImageUSER_PALETTE, minColor, maxColor, paletteMinFail, paletteMaxFail, minFailColor, maxFailColor, nanColor, infColor, logScale, logBase, lutUser, lutUserSize); -} +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinSegmentsSorted(const QList& itemsR, const QList& itemsG, const QList& itemsB, int lut_size=JKQTPImageTools::LUTSIZE); + + + +/*! \brief build a linearly interpolated palette (as a look-up table) with \a lut_size entries by linearly interpolating between the nodes in \a items . + \b NOTE: \a items is assumed to be sorted by the first component of the \c QPair entries! + \ingroup jkqtplotter_imagelots_tools_LUTS + + The LUT is built following these rules: + - the final LUT has \a lut_size entries + - the first color in the lut is given by \c items.first().second + - the last color in the lut is given by \c items.last().second + - in between the colors are interpolated between the nodes in \a items and the color-nodes are + distributed according to the first component of the \c QPair entries:
    + \image html JKQTPBuildColorPaletteLUTLinInterpolateSorted.png + . + + \see JKQTPBuildColorPaletteLUTLinInterpolate(), \ref JKQTPlotterImagePlotUserPalette + +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinInterpolateSorted(const QList >& items, int lut_size=JKQTPImageTools::LUTSIZE); + + +/*! \brief build a palette (as a look-up table) with \a lut_size entries that step between the nodes provided in \a items. + \b NOTE: \a items is assumed to be sorted by the first component of the \c QPair entries! + \ingroup jkqtplotter_imagelots_tools_LUTS + + The LUT is built following these rules: + - the final LUT has \a lut_size entries + - the first color in the lut is given by \c items.first().second + - the last color in the lut is given by \c items.last().second + - in between the colors are stepped between the nodes in \a items and the color-nodes are + distributed according to the first component of the \c QPair entries:
    + \image html JKQTPBuildColorPaletteLUTSorted.png + . + + \see JKQTPBuildColorPaletteLUT(), \ref JKQTPlotterImagePlotUserPalette + +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTSorted(const QList >& items, int lut_size=JKQTPImageTools::LUTSIZE); + +/*! \brief like JKQTPBuildColorPaletteLUTLinInterpolateSorted(), but sorts \a items before processing it! + \ingroup jkqtplotter_imagelots_tools_LUTS + + \copydetails JKQTPBuildColorPaletteLUTLinInterpolateSorted() +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinInterpolate(QList > items, int lut_size=JKQTPImageTools::LUTSIZE); + + +/*! \brief like JKQTPBuildColorPaletteLUTSorted(), but sorts \a items before processing it! + \ingroup jkqtplotter_imagelots_tools_LUTS + + \copydetails JKQTPBuildColorPaletteLUTSorted() +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUT(QList > items, int lut_size=JKQTPImageTools::LUTSIZE); + +/*! \brief like JKQTPBuildColorPaletteLUTLinSegmentsSorted(), but sorts \a itemsR, \a itemB, \a itemsG before processing them! + \ingroup jkqtplotter_imagelots_tools_LUTS + + \copydetails JKQTPBuildColorPaletteLUTLinSegmentsSorted() + +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinSegments(QList itemsR, QList itemsG, QList itemsB, int lut_size=JKQTPImageTools::LUTSIZE); + + +/*! \brief like JKQTPBuildColorPaletteLUTLinInterpolateSorted(), but accepts a \c QMap as parameter instead of \c QList> + \ingroup jkqtplotter_imagelots_tools_LUTS + + \copydetails JKQTPBuildColorPaletteLUTLinInterpolateSorted() + +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUTLinInterpolate(const QMap& items, int lut_size=JKQTPImageTools::LUTSIZE); + + +/*! \brief like JKQTPBuildColorPaletteLUTSorted(), but accepts a \c QMap as parameter instead of \c QList> + \ingroup jkqtplotter_imagelots_tools_LUTS + + \copydetails JKQTPBuildColorPaletteLUTSorted() +*/ +JKQTPImageTools::LUTType JKQTCOMMON_LIB_EXPORT JKQTPBuildColorPaletteLUT(const QMap& items, int lut_size=JKQTPImageTools::LUTSIZE); -/*! \brief generates a QImage with width \a width and height 1 for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) - \ingroup jkqtplotter_imagelots_tools */ -QImage JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteImage(int i, int width); -/*! \brief generates a QImage with width \a width and height \a height for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) - \ingroup jkqtplotter_imagelots_tools */ -QImage JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteImage(int i, int width, int height); -/*! \brief generates a QImage with width \a width and height 1 for a specific JKQTPMathImageColorPalette - \ingroup jkqtplotter_imagelots_tools */ -QImage JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteImage(JKQTPMathImageColorPalette palette, int width); -/*! \brief generates a QImage with width \a width and height \a height for a specific JKQTPMathImageColorPalette - \ingroup jkqtplotter_imagelots_tools */ -QImage JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteImage(JKQTPMathImageColorPalette palette, int width, int height); -/*! \brief generates a QImage with width \a width and height 1 for a lookup-table \a lut with \a lut_size entries - \ingroup jkqtplotter_imagelots_tools */ -QImage JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteImage(int* lut, int lut_size, int width); -/*! \brief generates a QImage with width \a width and height \a height for a lookup-table \a lut with \a lut_size entries - \ingroup jkqtplotter_imagelots_tools */ -QImage JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetAlphaPaletteImage(int* lut, int lut_size, int width, int height); - -/*! \brief generates a QIcon for the i-th color palette (\a i is based on the list returned by JKQTPImagePlot_getPredefinedPalettes() ) - \ingroup jkqtplotter_imagelots_tools */ -QIcon JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteIcon(int i) ; - - -/*! \brief generates a QIcon for a specific JKQTPMathImageColorPalette - \ingroup jkqtplotter_imagelots_tools */ -QIcon JKQTCOMMON_LIB_EXPORT JKQTPMathImageGetPaletteIcon(JKQTPMathImageColorPalette palette) ; diff --git a/lib/jkqtplotter/graphs/jkqtpimage.cpp b/lib/jkqtplotter/graphs/jkqtpimage.cpp index 68332483a3..f22227e41e 100644 --- a/lib/jkqtplotter/graphs/jkqtpimage.cpp +++ b/lib/jkqtplotter/graphs/jkqtpimage.cpp @@ -1225,7 +1225,7 @@ QImage JKQTPMathImage::drawOutsidePalette(uint8_t steps) } QImage b(h,200, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(d,h,steps, b, palette, 0, steps-1); + JKQTPImageTools::array2image(d,h,steps, b, palette, 0, steps-1); //b.save("c:/temp/b1.png"); if (modifierMode!=ModifyNone) { modifyImage(b, dd, DoubleArray, h,steps, 0, h-1); @@ -1265,7 +1265,7 @@ void JKQTPMathImage::drawKeyMarker(JKQTPEnhancedPainter &painter, QRectF &rect) } QStringList JKQTPMathImage::getPalettes() { - return JKQTPImagePlot_getPredefinedPalettes(); + return JKQTPImageTools::getPredefinedPalettes(); } int JKQTPMathImage::getPalettesCount() @@ -1297,7 +1297,7 @@ QImage JKQTPMathImage::getPaletteImage(int i, int width, int height) for (int j=0; j(pic, width, qMax(1,height), img, (JKQTPMathImageColorPalette)i, 0, width-1); + JKQTPImageTools::array2image(pic, width, qMax(1,height), img, static_cast(i), 0, width-1); free(pic); return img; } @@ -1346,7 +1346,7 @@ QImage JKQTPMathImage::getPaletteKeyImage(int i, int width, int height) pic[j]=exp(-0.5*(double((x-x01)*double(x-x01))/w1x+double((y-y01)*double(y-y01))/w1y))+0.7*exp(-0.5*(double((x-x02)*double(x-x02))/w2x+double((y-y02)*double(y-y02))/w2y)); if (pic[j]>mmax) mmax=pic[j]; } - JKQTPImagePlot_array2image(pic, width, height, img, (JKQTPMathImageColorPalette)i, 0, mmax); + JKQTPImageTools::array2image(pic, width, height, img, static_cast(i), 0, mmax); free(pic); return img; } @@ -1616,16 +1616,16 @@ QImage JKQTPMathImage::drawImage() { QImage img(Nx, Ny, QImage::Format_ARGB32); getDataMinMax(internalDataMin, internalDataMax); switch(datatype) { - case JKQTPMathImageBase::DoubleArray: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::FloatArray: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::UInt8Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::UInt16Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::UInt32Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::UInt64Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::Int8Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::Int16Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::Int32Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; - case JKQTPMathImageBase::Int64Array: JKQTPImagePlot_array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::DoubleArray: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::FloatArray: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::UInt8Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::UInt16Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::UInt32Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::UInt64Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::Int8Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::Int16Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::Int32Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; + case JKQTPMathImageBase::Int64Array: JKQTPImageTools::array2image(static_cast(data), Nx, Ny, img, palette, internalDataMin, internalDataMax, rangeMinFailAction, rangeMaxFailAction, rangeMinFailColor, rangeMaxFailColor, nanColor, infColor); break; } modifyImage(img); return img; diff --git a/lib/jkqtplotter/graphs/jkqtpimage.h b/lib/jkqtplotter/graphs/jkqtpimage.h index d222f0f2a8..577e8245d2 100644 --- a/lib/jkqtplotter/graphs/jkqtpimage.h +++ b/lib/jkqtplotter/graphs/jkqtpimage.h @@ -552,6 +552,8 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPMathImage: public JKQTPMathImageBase { /*! \copydoc palette */ void setPalette(const JKQTPMathImageColorPalette & __value); /*! \copydoc palette */ + void setPalette(int pal); + /*! \copydoc palette */ JKQTPMathImageColorPalette getPalette() const; /*! \copydoc rangeMinFailAction */ void setRangeMinFailAction(const JKQTPMathImageColorRangeFailAction & __value); @@ -654,7 +656,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPMathImage: public JKQTPMathImageBase { /*! \copydoc modifierMax */ double getModifierMax() const; - void setPalette(int pal); + /*! \brief if the graph plots outside the actual plot field of view (e.g. color bars, scale bars, ...) diff --git a/lib/jkqtplotter/graphs/jkqtpimagergb.cpp b/lib/jkqtplotter/graphs/jkqtpimagergb.cpp index fde195b34b..2877136d95 100644 --- a/lib/jkqtplotter/graphs/jkqtpimagergb.cpp +++ b/lib/jkqtplotter/graphs/jkqtpimagergb.cpp @@ -290,15 +290,15 @@ void JKQTPRGBMathImage::drawOutside(JKQTPEnhancedPainter& painter, QRect /*leftS if (rgbMode==JKQTPRGBMathImageModeRGBMode) { d.palette=JKQTPMathImageRED; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } else if (rgbMode==JKQTPRGBMathImageModeCMYMode) { d.palette=JKQTPMathImageINVERTED_CYANWHITE; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } else if (rgbMode==JKQTPRGBMathImageModeHSVMode || rgbMode==JKQTPRGBMathImageModeHSLMode) { d.palette=JKQTPMathImageHSV; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } l<(pd, 1, pd_size, d.paletteImage, d.palette, 0, 199); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, 199); if (rgbMode==JKQTPRGBMathImageModeRGBMode) { d.palette=JKQTPMathImageGREEN; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } else if (rgbMode==JKQTPRGBMathImageModeCMYMode) { d.palette=JKQTPMathImageINVERTED_MAGENTAWHITE; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } else if (rgbMode==JKQTPRGBMathImageModeHSVMode) { d.palette=JKQTPMathImageGRAY; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - //JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); + //JKQTPImageTools::JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); QRgb* line=reinterpret_cast(d.paletteImage.scanLine(0)); for (int i=0; i(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); + //JKQTPImageTools::JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); QRgb* line=reinterpret_cast(d.paletteImage.scanLine(0)); for (int i=0; i(pd, 1, pd_size, d.paletteImage, d.palette, 0, 199); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, 199); if (rgbMode==JKQTPRGBMathImageModeRGBMode) { d.palette=JKQTPMathImageBLUE; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } else if (rgbMode==JKQTPRGBMathImageModeCMYMode) { d.palette=JKQTPMathImageINVERTED_YELLOWWHITE; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); + JKQTPImageTools::array2image(pd, 1, pd_size, d.paletteImage, d.palette, 0, pd_size-1); } else if (rgbMode==JKQTPRGBMathImageModeHSVMode) { d.palette=JKQTPMathImageGRAY; d.paletteImage=QImage(1, pd_size, QImage::Format_ARGB32); - //JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); + //JKQTPImageTools::JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); QRgb* line=reinterpret_cast(d.paletteImage.scanLine(0)); for (int i=0; i(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); + //JKQTPImageTools::JKQTPImagePlot_array2image(pd, 1, pd_size, d.paletteImage, l[li].palette, 0, pd_size-1); QRgb* line=reinterpret_cast(d.paletteImage.scanLine(0)); for (int i=0; i(colorval, 2, 1, img, getPalette(), double(0.0), double(1.0)); + JKQTPImageTools::array2image(colorval, 2, 1, img, getPalette(), double(0.0), double(1.0)); color1=img.pixel(0,0); color2=img.pixel(1,0); } @@ -852,7 +852,7 @@ QColor JKQTPXYParametrizedScatterGraph::getLocalColor(int i) const colMin=intColMin; colMax=intColMax; } - JKQTPImagePlot_array2image(&colorval, 1, 1, img, palette, colMin, colMax); + JKQTPImageTools::array2image(&colorval, 1, 1, img, palette, colMin, colMax); return img.pixel(0,0); } diff --git a/lib/jkqtplotter/gui/jkqtpcomboboxes.cpp b/lib/jkqtplotter/gui/jkqtpcomboboxes.cpp index 5c7f6b82b7..ad2a26f7b9 100644 --- a/lib/jkqtplotter/gui/jkqtpcomboboxes.cpp +++ b/lib/jkqtplotter/gui/jkqtpcomboboxes.cpp @@ -31,10 +31,10 @@ JKQTPMathImageColorPaletteComboBox::JKQTPMathImageColorPaletteComboBox(QWidget * QComboBox(parent) { setIconSize(QSize(JKQTPImageTools::PALETTE_ICON_WIDTH,16)); - QStringList pal=JKQTPImagePlot_getPredefinedPalettes(); + QStringList pal=JKQTPImageTools::getPredefinedPalettes(); clear(); for (int i=0; i &f, const QString &name) +{ + size_t col=addImageColumn(cols, rows, name); + JKQTPColumn& colref = columns[col]; + for (size_t y=0; y &f, const QString &name) { diff --git a/lib/jkqtplotter/jkqtpdatastorage.h b/lib/jkqtplotter/jkqtpdatastorage.h index 5244dff385..17dc5e9527 100644 --- a/lib/jkqtplotter/jkqtpdatastorage.h +++ b/lib/jkqtplotter/jkqtpdatastorage.h @@ -1229,6 +1229,21 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPDatastore{ * \see addColumnCalculatedFromColumn(), \ref JKQTPlotterBasicJKQTPDatastore */ size_t addCalculatedColumn(size_t rows, const std::function& f, const QString& name=QString("")); + /** \brief add an image column with width \a cols and height \a rows (i.e. \a rows * \a cols entries), that is calculated by calling \a f for each entry + * + * Pseudocode: + * \code + * for (y=0; y& f, const QString& name=QString("")); /** \brief add a column with the same number of entries, as in the other column \a otherColumn , that are calculated by calling \a f for each entry in \a otherColumn * * Pseudocode: diff --git a/lib/jkqtplotter/jkqtpimagetools.cpp b/lib/jkqtplotter/jkqtpimagetools.cpp index 1ab4f0094a..35c06e4ff4 100644 --- a/lib/jkqtplotter/jkqtpimagetools.cpp +++ b/lib/jkqtplotter/jkqtpimagetools.cpp @@ -131,7 +131,7 @@ void JKQTPColorPaletteStyleAndToolsMixin::cbDrawOutside(JKQTPEnhancedPainter& pa } } QImage b(h, 200, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(d, h, 200, b, palette, 0, 199); + JKQTPImageTools::array2image(d, h, 200, b, palette, 0, 199); QSizeF names=cbParent->getTextSizeSize(imageNameFontName, imageNameFontSize*cbParent->getFontSizeMultiplier(), imageName, painter); @@ -183,7 +183,7 @@ void JKQTPColorPaletteStyleAndToolsMixin::cbDrawOutside(JKQTPEnhancedPainter& pa } } QImage b(h,200, QImage::Format_ARGB32); - JKQTPImagePlot_array2image(d,h,200, b, palette, 0, 199); + JKQTPImageTools::array2image(d,h,200, b, palette, 0, 199); QSizeF names=cbParent->getTextSizeSize(imageNameFontName, imageNameFontSize*cbParent->getFontSizeMultiplier(), imageName, painter); @@ -229,7 +229,7 @@ void JKQTPColorPaletteStyleAndToolsMixin::cbDrawOutside(JKQTPEnhancedPainter& pa QStringList JKQTPColorPaletteStyleAndToolsMixin::getPalettes() { - return JKQTPImagePlot_getPredefinedPalettes(); + return JKQTPImageTools::getPredefinedPalettes(); } int JKQTPColorPaletteStyleAndToolsMixin::getPalettesCount() @@ -261,7 +261,7 @@ QImage JKQTPColorPaletteStyleAndToolsMixin::getPaletteImage(int i, int width) for (int j=0; j(pic, width, 1, img, (JKQTPMathImageColorPalette)i, 0, width-1); + JKQTPImageTools::array2image(pic, width, 1, img, static_cast(i), 0, width-1); free(pic); return img; } @@ -310,7 +310,7 @@ QImage JKQTPColorPaletteStyleAndToolsMixin::getPaletteKeyImage(int i, int width, pic[j]=exp(-0.5*(double((x-x01)*double(x-x01))/w1x+double((y-y01)*double(y-y01))/w1y))+0.7*exp(-0.5*(double((x-x02)*double(x-x02))/w2x+double((y-y02)*double(y-y02))/w2y)); if (pic[j]>mmax) mmax=pic[j]; } - JKQTPImagePlot_array2image(pic, width, height, img, (JKQTPMathImageColorPalette)i, 0, mmax); + JKQTPImageTools::array2image(pic, width, height, img, static_cast(i), 0, mmax); free(pic); return img; } @@ -322,7 +322,7 @@ QImage JKQTPColorPaletteStyleAndToolsMixin::getPaletteKeyImage(JKQTPMathImageCol void JKQTPColorPaletteStyleAndToolsMixin::setPalette(int pal) { - palette=(JKQTPMathImageColorPalette)pal; + palette=static_cast(pal); } void JKQTPColorPaletteStyleAndToolsMixin::cbSetParent(JKQTBasePlotter* parent) { diff --git a/screenshots/imageplot_userpal.png b/screenshots/imageplot_userpal.png new file mode 100644 index 0000000000000000000000000000000000000000..89633d32df37b0af26cad7ea792ae9199e1e3b22 GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K51UT4$0sJ%JQwfk$L90|Va?5N4dJ%_j{M zO!9Pb45^s&_R2-h1_J@sgBg!+RjyHNY}jD@pPilmn^f|-jgR+kJ70sJ%JQwfk$L90|Va?5N4dJ%_j{M ztnhSk45^s&_KG9lAqO6ogD3TV|Nk$fP}8KL6s#I)cWe2*Nsmuds1^Gkt9xhn^O)KF z$mG0sJ%JQwfk$L90|Va?5N4dJ%_j{M zoaE`^7*a9k?UjvOM-&8HFPajhx>UWt9>orpC&c*GS|1n;0`I6)}STJS;$zZtH~rUY*sjdb hV93NEK|HmaLDs8Z?xDw~8$j1Fc)I$ztaD0e0sz|{Ma}>K literal 0 HcmV?d00001 diff --git a/screenshots/imageplot_userpal_palsimple.png b/screenshots/imageplot_userpal_palsimple.png new file mode 100644 index 0000000000000000000000000000000000000000..9ea21cfc4af393337b8fa03655df03318ae63cb8 GIT binary patch literal 176 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 W`co2$ZNOCEKS+{MlFpVgc=A7puT#SS literal 0 HcmV?d00001 diff --git a/screenshots/imageplot_userpal_program_small.png b/screenshots/imageplot_userpal_program_small.png new file mode 100644 index 0000000000000000000000000000000000000000..1cdf1b26722fd4d1b01ef8a6ef03c9e6d2045caf GIT binary patch literal 15264 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 mGbb+U5G_dn0000