From 5a3511bb584b69ff46aa9ed86118439bb432a766 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Wed, 29 Jul 2026 12:30:40 +0800 Subject: [PATCH] =?UTF-8?q?=E5=91=BD=E5=90=8D=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Demo_Gallery/Afterglow_Plot.h | 51 ++ Demo_Gallery/Audio_Plot.h | 50 + .../Demo_Gallery.cpp | 112 +-- .../Demo_Gallery.h | 30 +- .../Normal_test.h | 64 +- Demo_Gallery/Planisphere_Plot.h | 52 ++ Demo_Gallery/Spectrum_Plot.h | 62 ++ Demo_Gallery/Sweep_Frequent_Plot.h | 55 ++ Demo_Gallery/Waterfall_Plot.h | 56 ++ .../base/Axis_Test.h | 24 +- .../base/Time_Axis_Test.h | 18 +- .../Demo_Gallery => Demo_Gallery}/export.h | 8 +- .../Axis/Abs_Axis.cpp | 100 +- {YSGraphic_Core => Renderive}/Axis/Abs_Axis.h | 19 +- .../Axis/Abs_Axis_p.h | 57 +- {YSGraphic_Core => Renderive}/Axis/Axis.cpp | 10 +- {YSGraphic_Core => Renderive}/Axis/Axis.h | 26 +- {YSGraphic_Core => Renderive}/Axis/Axis_p.h | 57 +- Renderive/Axis/Frequency_Axis.cpp | 30 + .../Axis/Frequency_Axis.h | 23 +- Renderive/Axis/Frequency_Axis_p.h | 79 ++ .../Axis/Time_Axis.cpp | 22 +- .../Axis/Time_Axis.h | 11 +- Renderive/Axis/Time_Axis_p.h | 254 ++++++ {YSGraphic_Core => Renderive}/Axis/export.h | 2 +- {YSGraphic_Core => Renderive}/Axis/global.h | 0 .../Generate_Mock_Data.cpp | 20 +- Renderive/Generate_Mock_Data.h | 8 + {YSGraphic_Core => Renderive}/algorithm.hpp | 42 +- Renderive/architecture/Bounded_Input_Buffer.h | 175 ++++ Renderive/architecture/Plot.cpp | 863 ++++++++++++++++++ .../architecture/Plot.h | 46 +- .../architecture/Plot_Render_Context.h | 22 +- Renderive/architecture/Plot_p.h | 37 + .../architecture/Render_Config.h | 6 +- .../architecture/Render_Data.cpp | 38 +- .../architecture/Render_Data.h | 161 ++-- .../architecture/Render_Lease.h | 61 +- .../architecture/Render_Pipeline.cpp | 44 +- .../architecture/Render_Utils.cpp | 18 +- Renderive/architecture/Renderable.cpp | 395 ++++++++ .../architecture/Renderable.h | 0 .../architecture/Renderable_Core.h | 77 +- .../architecture/Triple_Buffer.cpp | 0 .../architecture/Triple_Buffer.h | 4 +- .../architecture/export.h | 0 .../architecture/global.h | 16 +- Renderive/base/Tool.h | 783 ++++++++++++++++ Renderive/base/global.cpp | 185 ++++ {YSGraphic_Core => Renderive}/base/global.h | 20 +- {YSGraphic_Core => Renderive}/export.cpp | 16 +- Renderive/export.h | 11 + {YSGraphic_Core => Renderive}/main.cpp | 16 +- .../plottable/Afterglow.cpp | 144 +-- .../plottable/Afterglow.h | 54 +- Renderive/plottable/Afterglow_p.h | 159 ++++ Renderive/plottable/Audio_Frequency.cpp | 102 +++ .../plottable/Audio_Frequency.h | 28 +- Renderive/plottable/Audio_Frequency_p.h | 103 +++ .../plottable/Hover_Info.cpp | 20 +- .../plottable/Hover_Info.h | 40 +- .../plottable/Interpolation.h | 4 +- .../plottable/Interpolation_p.h | 4 +- Renderive/plottable/Multi_Select_Rect.cpp | 78 ++ .../plottable/Multi_Select_Rect.h | 22 +- Renderive/plottable/Multi_Select_Rect_p.h | 128 +++ .../plottable/Performance_Shower.cpp | 38 +- Renderive/plottable/Performance_Shower_p.h | 551 +++++++++++ .../plottable/Planisphere.cpp | 74 +- .../plottable/Planisphere.h | 18 +- Renderive/plottable/Planisphere_p.h | 125 +++ Renderive/plottable/Spectrum.cpp | 556 +++++++++++ .../plottable/Spectrum.h | 86 +- Renderive/plottable/Spectrum_p.h | 196 ++++ Renderive/plottable/Sweep_Frequency.cpp | 118 +++ .../plottable/Sweep_Frequency.h | 55 +- Renderive/plottable/Sweep_Frequency_p.h | 120 +++ .../plottable/Waterfall.cpp | 96 +- .../plottable/Waterfall.h | 44 +- Renderive/plottable/Waterfall_p.h | 355 +++++++ .../plottable/export.h | 6 +- .../plottable/global.h | 0 .../primitive/Band_Region.cpp | 38 +- .../primitive/Band_Region.h | 9 +- .../primitive/Color_Bar.cpp | 42 +- .../primitive/Color_Bar.h | 6 +- .../primitive/Color_Map.h | 36 +- .../primitive/Curve.cpp | 84 +- .../primitive/Curve.h | 86 +- .../primitive/Fill_Area.cpp | 78 +- .../primitive/Fill_Area.h | 9 +- .../primitive/Grid.cpp | 60 +- .../primitive/Grid.h | 11 +- .../primitive/Label.cpp | 84 +- .../primitive/Label.h | 11 +- .../primitive/Marker.cpp | 82 +- .../primitive/Marker.h | 11 +- .../primitive/Point_Set.cpp | 90 +- .../primitive/Point_Set.h | 11 +- .../primitive/Raster_Image.cpp | 78 +- .../primitive/Raster_Image.h | 61 +- .../primitive/export.h | 0 Renderive/resource/resource.qrc | 6 + .../resource/turbo.color_map | 0 .../Qt/File_Gather_Widget.cpp | 0 .../Qt/File_Gather_Widget.h | 0 .../Qt/File_Player_Widget.cpp | 0 .../Qt/File_Player_Widget.h | 0 {YSGraphic_Core => Widget}/Qt/File_Tool.cpp | 4 +- {YSGraphic_Core => Widget}/Qt/File_Tool.h | 0 {YSGraphic_Core => Widget}/Qt/File_Tool2.h | 4 +- {YSGraphic_Core => Widget}/Qt/Message.cpp | 14 +- {YSGraphic_Core => Widget}/Qt/Message.h | 0 {YSGraphic_Core => Widget}/Qt/Text_Shower.cpp | 28 +- {YSGraphic_Core => Widget}/Qt/Text_Shower.h | 0 .../Qt/Value_Select.cpp | 0 {YSGraphic_Core => Widget}/Qt/Value_Select.h | 0 {YSGraphic_Core => Widget}/Qt/export.h | 0 {YSGraphic_Core => Widget}/Qt/global.cpp | 0 {YSGraphic_Core => Widget}/Qt/global.h | 0 {YSGraphic_Core => Widget}/Qt/功能性ui.txt | 0 .../base/Circular_Linked_List.hpp | 54 +- .../base/File_Dialog/File_Dialog.cpp | 17 +- .../base/File_Dialog/File_Dialog.h | 10 +- .../base/File_Dialog/icon/FileFolder.qrc | 0 .../base/File_Dialog/icon/arrowDown.png | Bin .../base/File_Dialog/icon/fileFolder.png | Bin {YSGraphic_Core => Widget}/base/Graphic.cpp | 13 +- {YSGraphic_Core => Widget}/base/Graphic.h | 34 +- {YSGraphic_Core => Widget}/base/Node.hpp | 24 +- Widget/base/Roll_Object.h | 77 ++ .../Select_ColorDialog_p.h | 201 ++-- .../Select_Color_Dialog.cpp | 862 +++++++++++++++++ .../Select_Color_Dialog/Select_Color_Dialog.h | 10 +- Widget/base/Singleton_Widget.hpp | 28 + .../base/Virtual_Keyboard/Input_Core.cpp | 26 +- .../base/Virtual_Keyboard/Input_Core.h | 13 +- .../Virtual_Keyboard/Virtual_Keyboard.cpp | 97 +- .../base/Virtual_Keyboard/Virtual_Keyboard.h | 148 +-- .../base/Virtual_Keyboard/dict/dict.qrc | 0 .../Virtual_Keyboard/dict/dict_pinyin.dat | Bin .../dict/dict_pinyin_user.dat | Bin .../googlepinyin/atomdictbase.h | 0 .../googlepinyin/dictbuilder.cpp | 0 .../googlepinyin/dictbuilder.h | 0 .../Virtual_Keyboard/googlepinyin/dictdef.h | 0 .../googlepinyin/dictlist.cpp | 0 .../Virtual_Keyboard/googlepinyin/dictlist.h | 0 .../googlepinyin/dicttrie.cpp | 0 .../Virtual_Keyboard/googlepinyin/dicttrie.h | 0 .../googlepinyin/googlepinyin.pro | 0 .../googlepinyin/lpicache.cpp | 0 .../Virtual_Keyboard/googlepinyin/lpicache.h | 0 .../googlepinyin/matrixsearch.cpp | 0 .../googlepinyin/matrixsearch.h | 0 .../googlepinyin/mystdlib.cpp | 0 .../Virtual_Keyboard/googlepinyin/mystdlib.h | 0 .../Virtual_Keyboard/googlepinyin/ngram.cpp | 0 .../Virtual_Keyboard/googlepinyin/ngram.h | 0 .../googlepinyin/pinyinime.cpp | 0 .../Virtual_Keyboard/googlepinyin/pinyinime.h | 0 .../googlepinyin/searchutility.cpp | 0 .../googlepinyin/searchutility.h | 0 .../googlepinyin/spellingtable.cpp | 0 .../googlepinyin/spellingtable.h | 0 .../googlepinyin/spellingtrie.cpp | 0 .../googlepinyin/spellingtrie.h | 0 .../googlepinyin/splparser.cpp | 0 .../Virtual_Keyboard/googlepinyin/splparser.h | 0 .../Virtual_Keyboard/googlepinyin/sync.cpp | 0 .../base/Virtual_Keyboard/googlepinyin/sync.h | 0 .../googlepinyin/userdict.cpp | 0 .../Virtual_Keyboard/googlepinyin/userdict.h | 0 .../googlepinyin/utf16char.cpp | 0 .../Virtual_Keyboard/googlepinyin/utf16char.h | 0 .../googlepinyin/utf16reader.cpp | 0 .../googlepinyin/utf16reader.h | 0 {YSGraphic_Core => Widget}/base/algorithm.hpp | 46 +- {YSGraphic_Core => Widget}/base/export.h | 1 - .../component/Background.h | 48 +- .../component/Base/Base.h | 0 .../component/Base/Delegate.h | 2 +- .../component/Base/Layout.cpp | 8 +- .../component/Base/Layout.h | 0 .../component/Base/export.h | 0 .../component/Base/global.h | 4 +- {YSGraphic_Core => Widget}/component/Button.h | 0 .../component/Combo_Box.h | 22 +- .../component/Content.h | 0 {YSGraphic_Core => Widget}/component/Input.h | 20 +- {YSGraphic_Core => Widget}/component/SVG.cpp | 10 +- {YSGraphic_Core => Widget}/component/SVG.h | 0 .../component/Table/Base_Info.cpp | 8 +- .../component/Table/Base_Info.h | 0 .../component/Table/Base_Table_Data.cpp | 9 +- .../component/Table/Base_Table_Data.h | 4 +- .../component/Table/Base_Table_Model.cpp | 7 +- .../component/Table/Base_Table_Model.h | 4 +- .../component/Table/Table_View.cpp | 78 +- .../component/Table/Table_View.h | 8 +- .../component/Table/export.h | 0 .../component/Table/global.cpp | 0 .../component/Table/global.h | 0 .../component/Table/scroll.cpp | 12 +- .../component/Table/scroll.h | 6 +- .../component/Tree/Tree_Model.cpp | 6 +- .../component/Tree/Tree_Model.h | 2 +- .../component/Tree/Tree_View.cpp | 16 +- .../component/Tree/Tree_View.h | 6 +- .../component/Tree/export.h | 0 .../component/effect.cpp | 8 +- {YSGraphic_Core => Widget}/component/effect.h | 2 +- {YSGraphic_Core => Widget}/component/export.h | 0 .../component/frameless/Frame_Less_Widget.cpp | 104 +-- .../component/frameless/Frame_Less_Widget.h | 30 +- .../component/frameless/export.h | 0 {YSGraphic_Core => Widget}/component/global.h | 10 +- .../component/simple_widget.cpp | 20 +- .../component/simple_widget.h | 14 +- .../component/style文档.md | 0 {YSGraphic_Core => Widget}/resource/icon | 0 .../resource/resource.qrc | 1 - .../resource/you_jian_tou.svg | 0 YSGraphic_Core/Axis/Frequent_Axis.cpp | 30 - YSGraphic_Core/Axis/Frequent_Axis_p.h | 79 -- YSGraphic_Core/Axis/Time_Axis_p.h | 255 ------ YSGraphic_Core/Demo_Gallery/Afterglow_Plot.h | 51 -- YSGraphic_Core/Demo_Gallery/Audio_Plot.h | 50 - .../Demo_Gallery/Planisphere_Plot.h | 52 -- YSGraphic_Core/Demo_Gallery/Spectrum_Plot.h | 62 -- .../Demo_Gallery/Sweep_Frequent_Plot.h | 55 -- YSGraphic_Core/Demo_Gallery/Tool.h | 675 -------------- YSGraphic_Core/Demo_Gallery/Waterfall_Plot.h | 56 -- .../Demo_Gallery/base/Frequent_Axis.h | 35 - .../Demo_Gallery/base/Frequent_Axis_Test.h | 36 - .../Demo_Gallery/base/Muti_Select_Test.h | 43 - YSGraphic_Core/Generate_Mock_Data.h | 8 - .../architecture/Bounded_Input_Buffer.h | 177 ---- YSGraphic_Core/architecture/Plot.cpp | 863 ------------------ YSGraphic_Core/architecture/Plot_p.h | 37 - YSGraphic_Core/architecture/Renderable.cpp | 397 -------- YSGraphic_Core/base/Roll_Object.h | 78 -- .../Select_Color_Dialog.cpp | 863 ------------------ YSGraphic_Core/base/Singleton_Widget.hpp | 29 - YSGraphic_Core/base/global.cpp | 185 ---- YSGraphic_Core/export.h | 14 - YSGraphic_Core/plottable/Afterglow_p.h | 159 ---- YSGraphic_Core/plottable/Audio_Frequent.cpp | 102 --- YSGraphic_Core/plottable/Audio_Frequent_p.h | 103 --- YSGraphic_Core/plottable/Muti_Select_Rect.cpp | 78 -- YSGraphic_Core/plottable/Muti_Select_Rect_p.h | 140 --- .../plottable/Performance_Shower_p.h | 552 ----------- YSGraphic_Core/plottable/Planisphere_p.h | 125 --- YSGraphic_Core/plottable/Spectrum.cpp | 556 ----------- YSGraphic_Core/plottable/Spectrum_p.h | 198 ---- YSGraphic_Core/plottable/Sweep_Frequent.cpp | 118 --- YSGraphic_Core/plottable/Sweep_Frequent_p.h | 121 --- YSGraphic_Core/plottable/Waterfall_p.h | 356 -------- .../main.cpp => demo_gallery_main.cpp | 19 +- main.cmake | 56 +- tests/Renderable_Lifecycle_Stress.cpp | 61 +- 261 files changed, 8776 insertions(+), 8831 deletions(-) create mode 100644 Demo_Gallery/Afterglow_Plot.h create mode 100644 Demo_Gallery/Audio_Plot.h rename {YSGraphic_Core/Demo_Gallery => Demo_Gallery}/Demo_Gallery.cpp (56%) rename {YSGraphic_Core/Demo_Gallery => Demo_Gallery}/Demo_Gallery.h (54%) rename YSGraphic_Core/Demo_Gallery/Norml_test.h => Demo_Gallery/Normal_test.h (79%) create mode 100644 Demo_Gallery/Planisphere_Plot.h create mode 100644 Demo_Gallery/Spectrum_Plot.h create mode 100644 Demo_Gallery/Sweep_Frequent_Plot.h create mode 100644 Demo_Gallery/Waterfall_Plot.h rename {YSGraphic_Core/Demo_Gallery => Demo_Gallery}/base/Axis_Test.h (56%) rename {YSGraphic_Core/Demo_Gallery => Demo_Gallery}/base/Time_Axis_Test.h (62%) rename {YSGraphic_Core/Demo_Gallery => Demo_Gallery}/export.h (66%) rename {YSGraphic_Core => Renderive}/Axis/Abs_Axis.cpp (76%) rename {YSGraphic_Core => Renderive}/Axis/Abs_Axis.h (87%) rename {YSGraphic_Core => Renderive}/Axis/Abs_Axis_p.h (74%) rename {YSGraphic_Core => Renderive}/Axis/Axis.cpp (88%) rename {YSGraphic_Core => Renderive}/Axis/Axis.h (78%) rename {YSGraphic_Core => Renderive}/Axis/Axis_p.h (58%) create mode 100644 Renderive/Axis/Frequency_Axis.cpp rename YSGraphic_Core/Axis/Frequent_Axis.h => Renderive/Axis/Frequency_Axis.h (61%) create mode 100644 Renderive/Axis/Frequency_Axis_p.h rename {YSGraphic_Core => Renderive}/Axis/Time_Axis.cpp (79%) rename {YSGraphic_Core => Renderive}/Axis/Time_Axis.h (86%) create mode 100644 Renderive/Axis/Time_Axis_p.h rename {YSGraphic_Core => Renderive}/Axis/export.h (56%) rename {YSGraphic_Core => Renderive}/Axis/global.h (100%) rename {YSGraphic_Core => Renderive}/Generate_Mock_Data.cpp (51%) create mode 100644 Renderive/Generate_Mock_Data.h rename {YSGraphic_Core => Renderive}/algorithm.hpp (66%) create mode 100644 Renderive/architecture/Bounded_Input_Buffer.h create mode 100644 Renderive/architecture/Plot.cpp rename {YSGraphic_Core => Renderive}/architecture/Plot.h (66%) rename {YSGraphic_Core => Renderive}/architecture/Plot_Render_Context.h (52%) create mode 100644 Renderive/architecture/Plot_p.h rename {YSGraphic_Core => Renderive}/architecture/Render_Config.h (96%) rename {YSGraphic_Core => Renderive}/architecture/Render_Data.cpp (55%) rename {YSGraphic_Core => Renderive}/architecture/Render_Data.h (56%) rename {YSGraphic_Core => Renderive}/architecture/Render_Lease.h (74%) rename {YSGraphic_Core => Renderive}/architecture/Render_Pipeline.cpp (58%) rename {YSGraphic_Core => Renderive}/architecture/Render_Utils.cpp (68%) create mode 100644 Renderive/architecture/Renderable.cpp rename {YSGraphic_Core => Renderive}/architecture/Renderable.h (100%) rename {YSGraphic_Core => Renderive}/architecture/Renderable_Core.h (77%) rename {YSGraphic_Core => Renderive}/architecture/Triple_Buffer.cpp (100%) rename {YSGraphic_Core => Renderive}/architecture/Triple_Buffer.h (99%) rename {YSGraphic_Core => Renderive}/architecture/export.h (100%) rename {YSGraphic_Core => Renderive}/architecture/global.h (96%) create mode 100644 Renderive/base/Tool.h create mode 100644 Renderive/base/global.cpp rename {YSGraphic_Core => Renderive}/base/global.h (87%) rename {YSGraphic_Core => Renderive}/export.cpp (56%) create mode 100644 Renderive/export.h rename {YSGraphic_Core => Renderive}/main.cpp (79%) rename {YSGraphic_Core => Renderive}/plottable/Afterglow.cpp (50%) rename {YSGraphic_Core => Renderive}/plottable/Afterglow.h (62%) create mode 100644 Renderive/plottable/Afterglow_p.h create mode 100644 Renderive/plottable/Audio_Frequency.cpp rename YSGraphic_Core/plottable/Audio_Frequent.h => Renderive/plottable/Audio_Frequency.h (74%) create mode 100644 Renderive/plottable/Audio_Frequency_p.h rename {YSGraphic_Core => Renderive}/plottable/Hover_Info.cpp (67%) rename {YSGraphic_Core => Renderive}/plottable/Hover_Info.h (79%) rename {YSGraphic_Core => Renderive}/plottable/Interpolation.h (94%) rename {YSGraphic_Core => Renderive}/plottable/Interpolation_p.h (99%) create mode 100644 Renderive/plottable/Multi_Select_Rect.cpp rename YSGraphic_Core/plottable/Muti_Select_Rect.h => Renderive/plottable/Multi_Select_Rect.h (79%) create mode 100644 Renderive/plottable/Multi_Select_Rect_p.h rename {YSGraphic_Core => Renderive}/plottable/Performance_Shower.cpp (72%) create mode 100644 Renderive/plottable/Performance_Shower_p.h rename {YSGraphic_Core => Renderive}/plottable/Planisphere.cpp (67%) rename {YSGraphic_Core => Renderive}/plottable/Planisphere.h (86%) create mode 100644 Renderive/plottable/Planisphere_p.h create mode 100644 Renderive/plottable/Spectrum.cpp rename {YSGraphic_Core => Renderive}/plottable/Spectrum.h (68%) create mode 100644 Renderive/plottable/Spectrum_p.h create mode 100644 Renderive/plottable/Sweep_Frequency.cpp rename YSGraphic_Core/plottable/Sweep_Frequent.h => Renderive/plottable/Sweep_Frequency.h (56%) create mode 100644 Renderive/plottable/Sweep_Frequency_p.h rename {YSGraphic_Core => Renderive}/plottable/Waterfall.cpp (56%) rename {YSGraphic_Core => Renderive}/plottable/Waterfall.h (71%) create mode 100644 Renderive/plottable/Waterfall_p.h rename {YSGraphic_Core => Renderive}/plottable/export.h (63%) rename {YSGraphic_Core => Renderive}/plottable/global.h (100%) rename {YSGraphic_Core => Renderive}/primitive/Band_Region.cpp (76%) rename {YSGraphic_Core => Renderive}/primitive/Band_Region.h (92%) rename {YSGraphic_Core => Renderive}/primitive/Color_Bar.cpp (75%) rename {YSGraphic_Core => Renderive}/primitive/Color_Bar.h (96%) rename {YSGraphic_Core => Renderive}/primitive/Color_Map.h (56%) rename {YSGraphic_Core => Renderive}/primitive/Curve.cpp (69%) rename {YSGraphic_Core => Renderive}/primitive/Curve.h (55%) rename {YSGraphic_Core => Renderive}/primitive/Fill_Area.cpp (65%) rename {YSGraphic_Core => Renderive}/primitive/Fill_Area.h (93%) rename {YSGraphic_Core => Renderive}/primitive/Grid.cpp (75%) rename {YSGraphic_Core => Renderive}/primitive/Grid.h (95%) rename {YSGraphic_Core => Renderive}/primitive/Label.cpp (72%) rename {YSGraphic_Core => Renderive}/primitive/Label.h (95%) rename {YSGraphic_Core => Renderive}/primitive/Marker.cpp (68%) rename {YSGraphic_Core => Renderive}/primitive/Marker.h (94%) rename {YSGraphic_Core => Renderive}/primitive/Point_Set.cpp (71%) rename {YSGraphic_Core => Renderive}/primitive/Point_Set.h (93%) rename {YSGraphic_Core => Renderive}/primitive/Raster_Image.cpp (68%) rename {YSGraphic_Core => Renderive}/primitive/Raster_Image.h (60%) rename {YSGraphic_Core => Renderive}/primitive/export.h (100%) create mode 100644 Renderive/resource/resource.qrc rename YSGraphic_Core/resource/turbo.colorMap => Renderive/resource/turbo.color_map (100%) rename {YSGraphic_Core => Widget}/Qt/File_Gather_Widget.cpp (100%) rename {YSGraphic_Core => Widget}/Qt/File_Gather_Widget.h (100%) rename {YSGraphic_Core => Widget}/Qt/File_Player_Widget.cpp (100%) rename {YSGraphic_Core => Widget}/Qt/File_Player_Widget.h (100%) rename {YSGraphic_Core => Widget}/Qt/File_Tool.cpp (98%) rename {YSGraphic_Core => Widget}/Qt/File_Tool.h (100%) rename {YSGraphic_Core => Widget}/Qt/File_Tool2.h (97%) rename {YSGraphic_Core => Widget}/Qt/Message.cpp (97%) rename {YSGraphic_Core => Widget}/Qt/Message.h (100%) rename {YSGraphic_Core => Widget}/Qt/Text_Shower.cpp (79%) rename {YSGraphic_Core => Widget}/Qt/Text_Shower.h (100%) rename {YSGraphic_Core => Widget}/Qt/Value_Select.cpp (100%) rename {YSGraphic_Core => Widget}/Qt/Value_Select.h (100%) rename {YSGraphic_Core => Widget}/Qt/export.h (100%) rename {YSGraphic_Core => Widget}/Qt/global.cpp (100%) rename {YSGraphic_Core => Widget}/Qt/global.h (100%) rename {YSGraphic_Core => Widget}/Qt/功能性ui.txt (100%) rename {YSGraphic_Core => Widget}/base/Circular_Linked_List.hpp (69%) rename {YSGraphic_Core => Widget}/base/File_Dialog/File_Dialog.cpp (73%) rename {YSGraphic_Core => Widget}/base/File_Dialog/File_Dialog.h (64%) rename {YSGraphic_Core => Widget}/base/File_Dialog/icon/FileFolder.qrc (100%) rename {YSGraphic_Core => Widget}/base/File_Dialog/icon/arrowDown.png (100%) rename {YSGraphic_Core => Widget}/base/File_Dialog/icon/fileFolder.png (100%) rename {YSGraphic_Core => Widget}/base/Graphic.cpp (68%) rename {YSGraphic_Core => Widget}/base/Graphic.h (54%) rename {YSGraphic_Core => Widget}/base/Node.hpp (84%) create mode 100644 Widget/base/Roll_Object.h rename {YSGraphic_Core => Widget}/base/Select_Color_Dialog/Select_ColorDialog_p.h (66%) create mode 100644 Widget/base/Select_Color_Dialog/Select_Color_Dialog.cpp rename {YSGraphic_Core => Widget}/base/Select_Color_Dialog/Select_Color_Dialog.h (62%) create mode 100644 Widget/base/Singleton_Widget.hpp rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/Input_Core.cpp (84%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/Input_Core.h (86%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/Virtual_Keyboard.cpp (64%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/Virtual_Keyboard.h (75%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/dict/dict.qrc (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/dict/dict_pinyin.dat (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/dict/dict_pinyin_user.dat (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/atomdictbase.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dictbuilder.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dictbuilder.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dictdef.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dictlist.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dictlist.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dicttrie.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/dicttrie.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/googlepinyin.pro (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/lpicache.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/lpicache.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/matrixsearch.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/matrixsearch.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/mystdlib.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/mystdlib.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/ngram.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/ngram.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/pinyinime.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/pinyinime.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/searchutility.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/searchutility.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/spellingtable.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/spellingtable.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/spellingtrie.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/spellingtrie.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/splparser.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/splparser.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/sync.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/sync.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/userdict.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/userdict.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/utf16char.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/utf16char.h (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/utf16reader.cpp (100%) rename {YSGraphic_Core => Widget}/base/Virtual_Keyboard/googlepinyin/utf16reader.h (100%) rename {YSGraphic_Core => Widget}/base/algorithm.hpp (65%) rename {YSGraphic_Core => Widget}/base/export.h (93%) rename {YSGraphic_Core => Widget}/component/Background.h (70%) rename {YSGraphic_Core => Widget}/component/Base/Base.h (100%) rename {YSGraphic_Core => Widget}/component/Base/Delegate.h (92%) rename {YSGraphic_Core => Widget}/component/Base/Layout.cpp (97%) rename {YSGraphic_Core => Widget}/component/Base/Layout.h (100%) rename {YSGraphic_Core => Widget}/component/Base/export.h (100%) rename {YSGraphic_Core => Widget}/component/Base/global.h (97%) rename {YSGraphic_Core => Widget}/component/Button.h (100%) rename {YSGraphic_Core => Widget}/component/Combo_Box.h (90%) rename {YSGraphic_Core => Widget}/component/Content.h (100%) rename {YSGraphic_Core => Widget}/component/Input.h (90%) rename {YSGraphic_Core => Widget}/component/SVG.cpp (90%) rename {YSGraphic_Core => Widget}/component/SVG.h (100%) rename {YSGraphic_Core => Widget}/component/Table/Base_Info.cpp (61%) rename {YSGraphic_Core => Widget}/component/Table/Base_Info.h (100%) rename {YSGraphic_Core => Widget}/component/Table/Base_Table_Data.cpp (84%) rename {YSGraphic_Core => Widget}/component/Table/Base_Table_Data.h (89%) rename {YSGraphic_Core => Widget}/component/Table/Base_Table_Model.cpp (98%) rename {YSGraphic_Core => Widget}/component/Table/Base_Table_Model.h (97%) rename {YSGraphic_Core => Widget}/component/Table/Table_View.cpp (90%) rename {YSGraphic_Core => Widget}/component/Table/Table_View.h (96%) rename {YSGraphic_Core => Widget}/component/Table/export.h (100%) rename {YSGraphic_Core => Widget}/component/Table/global.cpp (100%) rename {YSGraphic_Core => Widget}/component/Table/global.h (100%) rename {YSGraphic_Core => Widget}/component/Table/scroll.cpp (79%) rename {YSGraphic_Core => Widget}/component/Table/scroll.h (92%) rename {YSGraphic_Core => Widget}/component/Tree/Tree_Model.cpp (97%) rename {YSGraphic_Core => Widget}/component/Tree/Tree_Model.h (98%) rename {YSGraphic_Core => Widget}/component/Tree/Tree_View.cpp (94%) rename {YSGraphic_Core => Widget}/component/Tree/Tree_View.h (92%) rename {YSGraphic_Core => Widget}/component/Tree/export.h (100%) rename {YSGraphic_Core => Widget}/component/effect.cpp (55%) rename {YSGraphic_Core => Widget}/component/effect.h (76%) rename {YSGraphic_Core => Widget}/component/export.h (100%) rename {YSGraphic_Core => Widget}/component/frameless/Frame_Less_Widget.cpp (67%) rename {YSGraphic_Core => Widget}/component/frameless/Frame_Less_Widget.h (79%) rename {YSGraphic_Core => Widget}/component/frameless/export.h (100%) rename {YSGraphic_Core => Widget}/component/global.h (96%) rename {YSGraphic_Core => Widget}/component/simple_widget.cpp (90%) rename {YSGraphic_Core => Widget}/component/simple_widget.h (81%) rename {YSGraphic_Core => Widget}/component/style文档.md (100%) rename {YSGraphic_Core => Widget}/resource/icon (100%) rename {YSGraphic_Core => Widget}/resource/resource.qrc (72%) rename {YSGraphic_Core => Widget}/resource/you_jian_tou.svg (100%) delete mode 100644 YSGraphic_Core/Axis/Frequent_Axis.cpp delete mode 100644 YSGraphic_Core/Axis/Frequent_Axis_p.h delete mode 100644 YSGraphic_Core/Axis/Time_Axis_p.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Afterglow_Plot.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Audio_Plot.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Planisphere_Plot.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Spectrum_Plot.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Sweep_Frequent_Plot.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Tool.h delete mode 100644 YSGraphic_Core/Demo_Gallery/Waterfall_Plot.h delete mode 100644 YSGraphic_Core/Demo_Gallery/base/Frequent_Axis.h delete mode 100644 YSGraphic_Core/Demo_Gallery/base/Frequent_Axis_Test.h delete mode 100644 YSGraphic_Core/Demo_Gallery/base/Muti_Select_Test.h delete mode 100644 YSGraphic_Core/Generate_Mock_Data.h delete mode 100644 YSGraphic_Core/architecture/Bounded_Input_Buffer.h delete mode 100644 YSGraphic_Core/architecture/Plot.cpp delete mode 100644 YSGraphic_Core/architecture/Plot_p.h delete mode 100644 YSGraphic_Core/architecture/Renderable.cpp delete mode 100644 YSGraphic_Core/base/Roll_Object.h delete mode 100644 YSGraphic_Core/base/Select_Color_Dialog/Select_Color_Dialog.cpp delete mode 100644 YSGraphic_Core/base/Singleton_Widget.hpp delete mode 100644 YSGraphic_Core/base/global.cpp delete mode 100644 YSGraphic_Core/export.h delete mode 100644 YSGraphic_Core/plottable/Afterglow_p.h delete mode 100644 YSGraphic_Core/plottable/Audio_Frequent.cpp delete mode 100644 YSGraphic_Core/plottable/Audio_Frequent_p.h delete mode 100644 YSGraphic_Core/plottable/Muti_Select_Rect.cpp delete mode 100644 YSGraphic_Core/plottable/Muti_Select_Rect_p.h delete mode 100644 YSGraphic_Core/plottable/Performance_Shower_p.h delete mode 100644 YSGraphic_Core/plottable/Planisphere_p.h delete mode 100644 YSGraphic_Core/plottable/Spectrum.cpp delete mode 100644 YSGraphic_Core/plottable/Spectrum_p.h delete mode 100644 YSGraphic_Core/plottable/Sweep_Frequent.cpp delete mode 100644 YSGraphic_Core/plottable/Sweep_Frequent_p.h delete mode 100644 YSGraphic_Core/plottable/Waterfall_p.h rename Demo_Gallery/main.cpp => demo_gallery_main.cpp (95%) diff --git a/Demo_Gallery/Afterglow_Plot.h b/Demo_Gallery/Afterglow_Plot.h new file mode 100644 index 0000000..b80e9cb --- /dev/null +++ b/Demo_Gallery/Afterglow_Plot.h @@ -0,0 +1,51 @@ +#pragma once +#include "../Renderive/base/Tool.h" +static QWidget* create_afterglow() { + class Afterglow_Plot : public renderive::Plot { + public: + std::shared_ptr x_axis{}; + std::shared_ptr y_axis{}; + std::shared_ptr ag{}; + std::shared_ptr msr{}; + QMenu* menu{}; + void init() override { + Plot::init(); + object_name = "Afterglow_Plot"; + auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); + auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); + x_axis = renderive::Frequency_Axis::Builder(axis, Qt::Horizontal).build(); + y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); + ag = renderive::Afterglow::Builder(data, x_axis, y_axis) + .set_frequency_range({0, 100}) + .set_power_range({0, 100}) + .build(); + msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); + } + protected: + void resizeEvent(QResizeEvent* event) override { + x_axis->set_x(0); + x_axis->set_y(height() - 1); + x_axis->set_pixel_size(width()); + y_axis->set_x(0); + y_axis->set_y(0); + y_axis->set_pixel_size(height()); + ag->set_frequency_point_size(ag->frequency_axis()->get_pixel_point_size()); + ag->set_power_point_size(ag->power_axis()->get_pixel_point_size()); + } + void contextMenuEvent(QContextMenuEvent* event) override { + if (!menu) { + auto ws = + bw(cw(ag.get(), -1), "余辉图") + + bw(cw(x_axis.get()), "频率轴") + + bw(cw(y_axis.get()), "功率概率轴") + + bw(cw(msr.get()), "多选框"); + menu = create_menu(this, ws); + } + menu->exec(event->globalPos()); + } + }; + auto w = new Afterglow_Plot; + w->init(); + return w; +} diff --git a/Demo_Gallery/Audio_Plot.h b/Demo_Gallery/Audio_Plot.h new file mode 100644 index 0000000..bf5a287 --- /dev/null +++ b/Demo_Gallery/Audio_Plot.h @@ -0,0 +1,50 @@ +#pragma once +#include "../Renderive/base/Tool.h" +static QWidget* create_audio_plot() { + class Audio_Plot : public renderive::Plot { + public: + std::shared_ptr x_axis{}; + std::shared_ptr y_axis{}; + std::shared_ptr audio{}; + std::shared_ptr msr{}; + QMenu* menu{}; + void init() override { + Plot::init(); + object_name = "Audio_Plot"; + auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); + auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); + x_axis = renderive::Time_Axis::Builder(axis, Qt::Horizontal) + .set_tick_length(-10) + .set_sub_tick_length(-5) + .build(); + y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); + audio = renderive::Audio_Frequency::Builder(data, x_axis, y_axis).build(); + msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); + } + protected: + void resizeEvent(QResizeEvent* event) override { + x_axis->set_x(0); + x_axis->set_y(height() - 1); + x_axis->set_pixel_size(width()); + y_axis->set_x(0); + y_axis->set_y(0); + y_axis->set_pixel_size(height()); + audio->set_time_point_size(x_axis->get_pixel_point_size()); + } + void contextMenuEvent(QContextMenuEvent* event) override { + if (!menu) { + auto ws = + bw(cw(audio.get(), -1), "音频图") + + bw(cw(y_axis.get()), "功率y轴") + + bw(cw(x_axis.get()), "时间轴") + + bw(cw(msr.get()), "多选框"); + menu = create_menu(this, ws); + } + menu->exec(event->globalPos()); + } + }; + auto w = new Audio_Plot; + w->init(); + return w; +} diff --git a/YSGraphic_Core/Demo_Gallery/Demo_Gallery.cpp b/Demo_Gallery/Demo_Gallery.cpp similarity index 56% rename from YSGraphic_Core/Demo_Gallery/Demo_Gallery.cpp rename to Demo_Gallery/Demo_Gallery.cpp index 80e6d43..15879b7 100644 --- a/YSGraphic_Core/Demo_Gallery/Demo_Gallery.cpp +++ b/Demo_Gallery/Demo_Gallery.cpp @@ -1,110 +1,110 @@ #include "Demo_Gallery.h" #include -#include "YSGraphic_Core/Qt/export.h" +#include "Widget/Qt/export.h" using namespace Psc; -QStandardItem* Demo_Gallery::getFromData(const TData& data) { +QStandardItem* Demo_Gallery::get_from_data(const T_Data& data) { auto w = new QWidget; auto l = new QVBoxLayout(w); l->setContentsMargins({0, 0, 0, 0}); l->setSpacing(0); - l->addWidget(data.mPlot); + l->addWidget(data.plot); // l->addStretch(); - mDataMap[data.mName] = w; - return new QStandardItem(data.mName); + data_map[data.name] = w; + return new QStandardItem(data.name); } -QList Demo_Gallery::getList(const QVector& datas) { +QList Demo_Gallery::get_list(const QVector& datas) { QList ret; - for (const TData& data : datas) { - ret.append(getFromData(data)); + for (const T_Data& data : datas) { + ret.append(get_from_data(data)); } return ret; } void Demo_Gallery::change_to(const QString& name) { - if (mDataMap.contains(name)) { - QWidget* associatedWidget = mDataMap[name]; - int i = mTabWidget->indexOf(associatedWidget); + if (data_map.contains(name)) { + QWidget* associatedWidget = data_map[name]; + int i = tab_widget->indexOf(associatedWidget); if (i == -1) { // 标签页不存在,添加新的标签页 - mTabWidget->addTab(associatedWidget, name); - mTabWidget->setCurrentIndex(mTabWidget->indexOf(associatedWidget)); + tab_widget->addTab(associatedWidget, name); + tab_widget->setCurrentIndex(tab_widget->indexOf(associatedWidget)); } else { // 标签页已经存在,设置为当前标签页 - mTabWidget->setCurrentIndex(i); + tab_widget->setCurrentIndex(i); } } } -class ComboBoxExample : public QWidget { +class Combo_Box_Example : public QWidget { public: - ComboBoxExample(QWidget* parent = nullptr) : QWidget(parent) { + Combo_Box_Example(QWidget* parent = nullptr) : QWidget(parent) { // 创建一个QComboBox - QComboBox* comboBox = new QComboBox(this); + QComboBox* combo_box = new QComboBox(this); // 向QComboBox添加一些选项 - comboBox->addItem("Option 1"); - comboBox->addItem("Option 2"); - comboBox->addItem("Option 3"); + combo_box->addItem("Option 1"); + combo_box->addItem("Option 2"); + combo_box->addItem("Option 3"); // 创建一个标签用来显示选中的选项 QLabel* label = new QLabel("Selected: ", this); - QObject::connect(comboBox, QOverload::of(&QComboBox::currentIndexChanged), [=](int index) { + QObject::connect(combo_box, QOverload::of(&QComboBox::currentIndexChanged), [=](int index) { // 这里你可以获取当前选择项的索引 - label->setText("Selected: " + comboBox->currentText()); + label->setText("Selected: " + combo_box->currentText()); }); // 布局 QVBoxLayout* layout = new QVBoxLayout; - layout->addWidget(comboBox); + layout->addWidget(combo_box); layout->addWidget(label); setLayout(layout); } }; Demo_Gallery::Demo_Gallery() : - treeView(new QTreeView(this)), - standardModel(new QStandardItemModel(this)), - mTabWidget(new QTabWidget) { - mMainLayout = new QHBoxLayout(this); - mMainLayout->setContentsMargins(0, 0, 0, 0); - mMainLayout->setSpacing(0); - treeView->setFixedWidth(200); - treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); - mMainLayout->addWidget(treeView); - mTabWidget->setTabsClosable(true); - mMainLayout->addWidget(mTabWidget); - // treeView->setItemDelegate(new Delegate); - treeView->setHeaderHidden(true); - QStandardItem* root = standardModel->invisibleRootItem(); + tree_view(new QTreeView(this)), + standard_model(new QStandardItemModel(this)), + tab_widget(new QTabWidget) { + main_layout = new QHBoxLayout(this); + main_layout->setContentsMargins(0, 0, 0, 0); + main_layout->setSpacing(0); + tree_view->setFixedWidth(200); + tree_view->setEditTriggers(QAbstractItemView::NoEditTriggers); + main_layout->addWidget(tree_view); + tab_widget->setTabsClosable(true); + main_layout->addWidget(tab_widget); + // tree_view->setItemDelegate(new Delegate); + tree_view->setHeaderHidden(true); + QStandardItem* root = standard_model->invisibleRootItem(); auto plottable = new QStandardItem("plottable"); - plottable->appendRows(getList({ - {"余晖图", createAfterglow()}, - {"音频图", createAudioPlot()}, + plottable->appendRows(get_list({ + {"余晖图", create_afterglow()}, + {"音频图", create_audio_plot()}, {"星座图", create_planisphere_plot()}, {"频谱图", create_spectrun_plot()}, - {"瀑布图", create_Water_Fall_Plot()}, + {"瀑布图", create_water_fall_plot()}, {"扫频图", create_sweep_frequent_plot()}, })); auto base = new QStandardItem("基础元素"); - base->appendRows(getList({ - {"轴测试", createAxisTestPlot()}, + base->appendRows(get_list({ + {"轴测试", create_axis_test_plot()}, {"时间轴测试", create_time_axis_test_plot()}, {"频率轴测试", create_frequent_axis_test_plot()}, - {"多选框测试", create_Muti_Select_Plot()}, + {"多选框测试", create_Multi_Select_Plot()}, })); auto t1 = new Byte_Select; auto t2 = new Test_File_Gather_Widget; auto t3 = new Test_File_Play_Widget; auto custom_widget = new QStandardItem("自定义控件"); - custom_widget->appendRows(getList({ + custom_widget->appendRows(get_list({ {"Enum_Select", t1}, {"Test_File_Gather_Widget", t2}, {"Test_File_Play_Widget", t3}, - {"表格", create_Table_View()}, + {"表格", create_table_view()}, {"树", create_Tree_View()}, })); auto Qt_raw_widget = new QStandardItem("Qt原生元素"); - Qt_raw_widget->appendRows(getList({ + Qt_raw_widget->appendRows(get_list({ // QSizeGrip 一个改变大小的注脚 // QDesktopWidget 不知道干嘛的 // QFocusFrame 不知道干嘛的 {"QKeySequenceEdit", new QKeySequenceEdit}, - {"ComboBoxExample", new ComboBoxExample}, + {"Combo_Box_Example", new Combo_Box_Example}, // 像QWidget 但不知到有什么区别 {"QPushButton", new QPushButton}, {"QFrame", new QFrame}, @@ -139,19 +139,19 @@ Demo_Gallery::Demo_Gallery() : change_to("Test_File_Gather_Widget"); // change_to("树"); root->appendRows({plottable, base, custom_widget, Qt_raw_widget}); - treeView->setModel(standardModel); - treeView->expandAll(); - QObject::connect(mTabWidget, &QTabWidget::tabCloseRequested, [this](int index) { + tree_view->setModel(standard_model); + tree_view->expandAll(); + QObject::connect(tab_widget, &QTabWidget::tabCloseRequested, [this](int index) { // 处理标签页关闭请求 qDebug() << "Closing tab at index:" << index; // 从 QTabWidget 中移除指定的标签页 - mTabWidget->removeTab(index); + tab_widget->removeTab(index); }); - QObject::connect(treeView, &QTreeView::clicked, [this](const QModelIndex& index) { - QStandardItem* item = this->standardModel->itemFromIndex(index); + QObject::connect(tree_view, &QTreeView::clicked, [this](const QModelIndex& index) { + QStandardItem* item = this->standard_model->itemFromIndex(index); if (item) { - QString itemName = item->text(); - change_to(itemName); + QString item_name = item->text(); + change_to(item_name); } }); } diff --git a/YSGraphic_Core/Demo_Gallery/Demo_Gallery.h b/Demo_Gallery/Demo_Gallery.h similarity index 54% rename from YSGraphic_Core/Demo_Gallery/Demo_Gallery.h rename to Demo_Gallery/Demo_Gallery.h index ef32c56..1b3efb4 100644 --- a/YSGraphic_Core/Demo_Gallery/Demo_Gallery.h +++ b/Demo_Gallery/Demo_Gallery.h @@ -7,17 +7,17 @@ #include #include #include -#include "../component/export.h" +#include "../Widget/component/export.h" #include "Afterglow_Plot.h" #include "Audio_Plot.h" -#include "Norml_test.h" +#include "Normal_test.h" #include "Planisphere_Plot.h" #include "Spectrum_Plot.h" #include "Sweep_Frequent_Plot.h" #include "Waterfall_Plot.h" #include "base/Axis_Test.h" -#include "base/Frequent_Axis_Test.h" -#include "base/Muti_Select_Test.h" +#include "base/Frequency_Axis_Test.h" +#include "base/Multi_Select_Test.h" #include "base/Time_Axis_Test.h" class QTreeView; class QStandardItemModel; @@ -25,17 +25,17 @@ class QStandardItem; class Demo_Gallery : public QWidget { public: Demo_Gallery(); - QTreeView* treeView; - QStandardItemModel* standardModel; - QHBoxLayout* mMainLayout; - QTabWidget* mTabWidget{}; - QWidget* mCurWidget{}; - struct TData { - QString mName; - QWidget* mPlot; + QTreeView* tree_view; + QStandardItemModel* standard_model; + QHBoxLayout* main_layout; + QTabWidget* tab_widget{}; + QWidget* cur_widget{}; + struct T_Data { + QString name; + QWidget* plot; }; - QMap mDataMap; - QStandardItem* getFromData(const TData& data); - QList getList(const QVector& datas); + QMap data_map; + QStandardItem* get_from_data(const T_Data& data); + QList get_list(const QVector& datas); void change_to(const QString& name); }; diff --git a/YSGraphic_Core/Demo_Gallery/Norml_test.h b/Demo_Gallery/Normal_test.h similarity index 79% rename from YSGraphic_Core/Demo_Gallery/Norml_test.h rename to Demo_Gallery/Normal_test.h index be8ad82..78249d8 100644 --- a/YSGraphic_Core/Demo_Gallery/Norml_test.h +++ b/Demo_Gallery/Normal_test.h @@ -1,30 +1,30 @@ #pragma once -#include "../component/Table/export.h" -#include "Tool.h" +#include "../Widget/component/Table/export.h" +#include "../Renderive/base/Tool.h" namespace Psc { // // static QVector cw(Table_View* view) { // QVector ret; // ret.append({ -// YSG::createEditWidget("隐藏行", [view, m](const int& value) { +// renderive::create_edit_widget("隐藏行", [view, m](const int& value) { // m->row_info_list[value]->hide = true; // view->update(); // }, 1), -// YSG::createEditWidget("显示行", [view, m](const int& value) { +// renderive::create_edit_widget("显示行", [view, m](const int& value) { // m->row_info_list[value]->hide = false; // view->update(); // }, 1), -// YSG::createEditWidget("隐藏列", [view, m](const int& value) { +// renderive::create_edit_widget("隐藏列", [view, m](const int& value) { // m->col_info_list[value]->hide = true; // view->update(); // }, 1), -// YSG::createEditWidget("显示列", [view, m](const int& value) { +// renderive::create_edit_widget("显示列", [view, m](const int& value) { // m->col_info_list[value]->hide = false; // view->update(); // }, 1), // // -// YSG::createEditWidget_List("合并单元格", [view, m](const QVector& values) { +// renderive::create_edit_widget_list("合并单元格", [view, m](const QVector& values) { // int row = values[0]; // int col = values[1]; // int row_span = values[2]; @@ -32,7 +32,7 @@ namespace Psc { // m->merge(row, col, row_span, col_span); // view->update(); // }, {4, 4, 4, 4}), -// YSG::createEditWidget_List("拆分单元格", [view, m](const QVector& values) { +// renderive::create_edit_widget_list("拆分单元格", [view, m](const QVector& values) { // int row = values[0]; // int col = values[1]; // int row_span = values[2]; @@ -41,7 +41,7 @@ namespace Psc { // view->update(); // }, {4, 4, 2, 4}), // -// YSG::createEditWidget_List("添加行", [view, m](const QVector& values) { +// renderive::create_edit_widget_list("添加行", [view, m](const QVector& values) { // int pos = values[0]; // int num = values[1]; // int col_num = m->col_info_list.size(); @@ -68,7 +68,7 @@ namespace Psc { // view->update(); // }, {4, 1}), // -// YSG::createEditWidget_List("添加列", [view, m](const QVector& values) { +// renderive::create_edit_widget_list("添加列", [view, m](const QVector& values) { // int pos = values[0]; // int num = values[1]; // int row_num = m->row_info_list.size(); @@ -95,7 +95,7 @@ namespace Psc { // view->update(); // }, {5, 1}), // -// YSG::createEditWidget_List("重新设置所有行列内容", [view, m](const QVector& values) { +// renderive::create_edit_widget_list("重新设置所有行列内容", [view, m](const QVector& values) { // for (int i = 0; i < m->total_col(); i++) // { // m->col_info_list[i]->content = QString("%1").arg(i); @@ -123,33 +123,33 @@ static QVector cw(Table_View* view) { QVector ret; auto m = dynamic_cast(view->model); ret.append({ - YSG::createEditWidget("隐藏行", [view, m](const int& value) { + renderive::create_edit_widget("隐藏行", [view, m](const int& value) { m->get_row_info(value)->hide = true; view->update(); }, 1), - YSG::createEditWidget("显示行", [view, m](const int& value) { + renderive::create_edit_widget("显示行", [view, m](const int& value) { m->get_row_info(value)->hide = false; view->update(); }, 1), - YSG::createEditWidget("隐藏列", [view, m](const int& value) { + renderive::create_edit_widget("隐藏列", [view, m](const int& value) { m->get_col_info(value)->hide = true; view->update(); }, 1), - YSG::createEditWidget("显示列", [view, m](const int& value) { + renderive::create_edit_widget("显示列", [view, m](const int& value) { m->get_col_info(value)->hide = false; view->update(); }, 1), - YSG::createEditWidget_List("合并单元格", [view, m](const QVector& values) { + renderive::create_edit_widget_list("合并单元格", [view, m](const QVector& values) { int row = values[0]; int col = values[1]; int row_span = values[2]; int col_span = values[3]; m->merge(row, col, row_span, col_span); view->update(); }, {4, 4, 4, 4}), - YSG::createEditWidget_List("拆分单元格", [view, m](const QVector& values) { + renderive::create_edit_widget_list("拆分单元格", [view, m](const QVector& values) { int row = values[0]; int col = values[1]; int row_span = values[2]; int col_span = values[3]; m->split(row, col, row_span, col_span); view->update(); }, {4, 4, 2, 4}), - YSG::createEditWidget_List("添加行", [view, m](const QVector& values) { + renderive::create_edit_widget_list("添加行", [view, m](const QVector& values) { int pos = values[0]; int num = values[1]; int col_num = m->total_col(); @@ -170,7 +170,7 @@ static QVector cw(Table_View* view) { } m->insert_row(pos, row_infos, data, Edge_Expand_Type::None); view->update(); }, {4, 1}), - YSG::createEditWidget_List("添加列", [view, m](const QVector& values) { + renderive::create_edit_widget_list("添加列", [view, m](const QVector& values) { int pos = values[0]; int num = values[1]; int row_num = m->total_row(); @@ -191,7 +191,7 @@ static QVector cw(Table_View* view) { } m->insert_col(pos, col_infos, data, Edge_Expand_Type::None); view->update(); }, {5, 1}), - YSG::createEditWidget_List("重新设置所有行列内容", [view, m](const QVector& values) { + renderive::create_edit_widget_list("重新设置所有行列内容", [view, m](const QVector& values) { for (int i = 0; i < m->total_col(); i++) { m->get_col_info(i)->content = QString("%1").arg(i); } @@ -208,15 +208,15 @@ static QVector cw(Table_View* view) { }); return ret; } -inline Table_View* create_Table_View2() { +inline Table_View* create_table_view2() { struct Table_View2 : Table_View { - QMenu* mMenu{}; + QMenu* menu{}; void contextMenuEvent(QContextMenuEvent* event) override { - if (!mMenu) { - // mMenu = createMenu_Normal(this, cw(this)); - mMenu = createMenu_Normal(this, cw(this)); + if (!menu) { + // menu = create_menu_normal(this, cw(this)); + menu = create_menu_normal(this, cw(this)); } - mMenu->exec(event->globalPos()); + menu->exec(event->globalPos()); } }; auto ret = new Table_View2; @@ -246,15 +246,15 @@ inline Table_View* create_Table_View2() { } return ret; } -inline Table_View* create_Table_View() { +inline Table_View* create_table_view() { struct Table_View2 : Table_View { - QMenu* mMenu{}; + QMenu* menu{}; void contextMenuEvent(QContextMenuEvent* event) override { - if (!mMenu) { - // mMenu = createMenu_Normal(this, cw(this)); - mMenu = createMenu_Normal(this, cw(this)); + if (!menu) { + // menu = create_menu_normal(this, cw(this)); + menu = create_menu_normal(this, cw(this)); } - mMenu->exec(event->globalPos()); + menu->exec(event->globalPos()); } }; auto ret = new Table_View2; diff --git a/Demo_Gallery/Planisphere_Plot.h b/Demo_Gallery/Planisphere_Plot.h new file mode 100644 index 0000000..f561304 --- /dev/null +++ b/Demo_Gallery/Planisphere_Plot.h @@ -0,0 +1,52 @@ +#pragma once +#include "../Renderive/base/Tool.h" +static QWidget* create_planisphere_plot() { + class Time_Axis; + class Planisphere_Plot : public renderive::Plot { + public: + std::shared_ptr x_axis{}; + std::shared_ptr y_axis{}; + std::shared_ptr planisphere{}; + std::shared_ptr msr{}; + QMenu* menu{}; + void init() override { + Plot::init(); + object_name = "PlanispherePlot"; + auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); + auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); + x_axis = renderive::Axis::Builder(axis, Qt::Horizontal) + .set_tick_length(-10) + .set_sub_tick_length(-5) + .build(); + y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); + planisphere = renderive::Planisphere::Builder(data, x_axis, y_axis) + .set_continue_millisecond(2000) + .build(); + msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); + } + protected: + void resizeEvent(QResizeEvent* event) override { + x_axis->set_x(0); + x_axis->set_y(height() - 1); + x_axis->set_pixel_size(width()); + y_axis->set_x(0); + y_axis->set_y(0); + y_axis->set_pixel_size(height()); + planisphere->set_to_axis_center(); + } + void contextMenuEvent(QContextMenuEvent* event) override { + if (!menu) { + auto ws = + bw(cw(planisphere.get(), -1), "星座图") + + bw(cw(x_axis.get()), "I轴") + + bw(cw(y_axis.get()), "Q轴"); + menu = create_menu(this, ws); + } + menu->exec(event->globalPos()); + } + }; + auto w = new Planisphere_Plot; + w->init(); + return w; +} diff --git a/Demo_Gallery/Spectrum_Plot.h b/Demo_Gallery/Spectrum_Plot.h new file mode 100644 index 0000000..e9581df --- /dev/null +++ b/Demo_Gallery/Spectrum_Plot.h @@ -0,0 +1,62 @@ +#pragma once +#include "../Renderive/base/Tool.h" +static QWidget* create_spectrun_plot() { + class Spectrum_Plot : public renderive::Plot { + public: + std::shared_ptr x_axis{}; + std::shared_ptr y_axis{}; + std::shared_ptr msr{}; + std::shared_ptr sp{}; + QMenu* menu{}; + void init() override { + Plot::init(); + object_name = "Spectrum_Plot"; + auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); + auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); + x_axis = renderive::Frequency_Axis::Builder(axis, Qt::Horizontal) + .set_coord_range({0, 100}) + .set_tick_length(-10) + .set_sub_tick_length(-5) + .set_use_wheel(true) + .set_use_drag(true) + .build(); + y_axis = renderive::Axis::Builder(axis, Qt::Vertical) + .set_coord_range({100, 0}) + .set_unit_text("功率") + .set_use_drag(true) + .build(); + sp = renderive::Spectrum::Builder(data, x_axis, y_axis) + .set_frequency_range({0, 100}) + .build(); + msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); + } + protected: + void resizeEvent(QResizeEvent* event) override { + int left_margin = 20, right_margin = 20, top_margin = 20, bottom_margin = 20; + int w = width() - left_margin - right_margin; + int h = height() - top_margin - bottom_margin; + x_axis->set_x(left_margin); + x_axis->set_y(height() - bottom_margin); + x_axis->set_pixel_size(w); + y_axis->set_x(left_margin); + y_axis->set_y(top_margin); + y_axis->set_pixel_size(h); + sp->set_frequency_point_size(sp->frequency_axis()->get_pixel_point_size()); + } + void contextMenuEvent(QContextMenuEvent* event) override { + if (!menu) { + auto ws = + bw(cw(sp.get(), -1), "频谱图") + + bw(cw(x_axis.get()), "频率x轴") + + bw(cw(y_axis.get()), "功率y轴") + + bw(cw(msr.get()), "多选框"); + menu = create_menu(this, ws); + } + menu->exec(event->globalPos()); + } + }; + auto w = new Spectrum_Plot; + w->init(); + return w; +} diff --git a/Demo_Gallery/Sweep_Frequent_Plot.h b/Demo_Gallery/Sweep_Frequent_Plot.h new file mode 100644 index 0000000..32dffb6 --- /dev/null +++ b/Demo_Gallery/Sweep_Frequent_Plot.h @@ -0,0 +1,55 @@ +#pragma once +#include "../Renderive/base/Tool.h" +static QWidget* create_sweep_frequent_plot() { + class Sweep_Frequent_Plot : public renderive::Plot { + public: + std::shared_ptr x_axis{}; + std::shared_ptr y_axis{}; + std::shared_ptr msr{}; + std::shared_ptr sf{}; + QMenu* menu{}; + void init() override { + Plot::init(); + object_name = "Axis_Test_Plot"; + auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); + auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); + x_axis = renderive::Axis::Builder(axis, Qt::Horizontal) + .set_coord_range({0, 100}) + .set_tick_length(-10) + .build(); + y_axis = renderive::Axis::Builder(axis, Qt::Vertical) + .set_coord_range({100, 0}) + .build(); + sf = renderive::Sweep_Frequency::Builder(data, x_axis, y_axis) + .set_block_num(200) + .set_block_frequency_point_size(20) + .set_frequency_range({0, 100}) + .build(); + msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); + } + protected: + void resizeEvent(QResizeEvent* event) override { + x_axis->set_x(0); + x_axis->set_y(height() - 1); + x_axis->set_pixel_size(width()); + y_axis->set_x(0); + y_axis->set_y(0); + y_axis->set_pixel_size(height()); + } + void contextMenuEvent(QContextMenuEvent* event) override { + if (!menu) { + auto ws = + bw(cw(sf.get(), -1), "扫频图") + + bw(cw(x_axis.get()), "x轴") + + bw(cw(y_axis.get()), "y轴") + + bw(cw(msr.get()), "多选框"); + menu = create_menu(this, ws); + } + menu->exec(event->globalPos()); + } + }; + auto w = new Sweep_Frequent_Plot; + w->init(); + return w; +} diff --git a/Demo_Gallery/Waterfall_Plot.h b/Demo_Gallery/Waterfall_Plot.h new file mode 100644 index 0000000..41db70d --- /dev/null +++ b/Demo_Gallery/Waterfall_Plot.h @@ -0,0 +1,56 @@ +#pragma once +#include "../Renderive/base/Tool.h" +static QWidget* create_water_fall_plot() { + class Waterfall_Plot : public renderive::Plot { + public: + std::shared_ptr x_axis{}; + std::shared_ptr y_axis{}; + std::shared_ptr msr{}; + std::shared_ptr wf{}; + QMenu* menu{}; + void init() override { + Plot::init(); + object_name = "Water_Fall_Plot"; + auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); + auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); + x_axis = renderive::Frequency_Axis::Builder(axis, Qt::Horizontal) + .set_tick_length(-10) + .set_sub_tick_length(-5) + .build(); + y_axis = renderive::Time_Axis::Builder(axis, Qt::Vertical) + .set_time_point_size(800) + .build(); + wf = renderive::Waterfall::Builder(data, x_axis, y_axis) + .set_frequency_range({0, 20}) + .build(); + msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); + } + protected: + void resizeEvent(QResizeEvent* event) override { + x_axis->set_x(0); + x_axis->set_y(height()); + x_axis->set_pixel_size(width()); + y_axis->set_x(0); + y_axis->set_y(0); + y_axis->set_pixel_size(height()); + y_axis->set_time_point_size(height()); + // wf->set_frequency_point_size(wf->frequency_axis()->get_pixel_point_size()); + wf->set_frequency_point_size(width()); + } + void contextMenuEvent(QContextMenuEvent* event) override { + if (!menu) { + auto ws = + bw(cw(wf.get(), -1), "瀑布图") + + bw(cw(x_axis.get()), "频率轴") + + bw(cw(y_axis.get()), "时间轴") + + bw(cw(msr.get()), "多选框"); + menu = create_menu(this, ws); + } + menu->exec(event->globalPos()); + } + }; + auto w = new Waterfall_Plot; + w->init(); + return w; +} diff --git a/YSGraphic_Core/Demo_Gallery/base/Axis_Test.h b/Demo_Gallery/base/Axis_Test.h similarity index 56% rename from YSGraphic_Core/Demo_Gallery/base/Axis_Test.h rename to Demo_Gallery/base/Axis_Test.h index 6b95e60..27076d6 100644 --- a/YSGraphic_Core/Demo_Gallery/base/Axis_Test.h +++ b/Demo_Gallery/base/Axis_Test.h @@ -1,15 +1,15 @@ #pragma once -#include "../Tool.h" -static QWidget* createAxisTestPlot() { - class AxisTestPlot : public YSG::Plot { +#include "../../Renderive/base/Tool.h" +static QWidget* create_axis_test_plot() { + class Axis_Test_Plot : public renderive::Plot { public: - std::shared_ptr axis{}; - QMenu* mMenu{}; + std::shared_ptr axis{}; + QMenu* menu{}; void init() override { Plot::init(); - object_name = "AxisTestPlot"; - auto axisNode = create_renderable_node(root_renderable(), "AxisRenderable"); - axis = YSG::Axis::Builder(axisNode, Qt::Horizontal) + object_name = "Axis_Test_Plot"; + auto axis_node = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + axis = renderive::Axis::Builder(axis_node, Qt::Horizontal) .set_tick_length(-10) .set_sub_tick_length(-5) .set_coord_range({-12000, 12000}) @@ -24,15 +24,15 @@ static QWidget* createAxisTestPlot() { axis->set_pixel_size(width() - space * 2); } void contextMenuEvent(QContextMenuEvent* event) override { - if (!mMenu) { + if (!menu) { auto ws = bw(cw(axis.get()), "轴"); - mMenu = createMenu(this, ws); + menu = create_menu(this, ws); } - mMenu->exec(event->globalPos()); + menu->exec(event->globalPos()); } }; - auto w = new AxisTestPlot; + auto w = new Axis_Test_Plot; w->init(); return w; } diff --git a/YSGraphic_Core/Demo_Gallery/base/Time_Axis_Test.h b/Demo_Gallery/base/Time_Axis_Test.h similarity index 62% rename from YSGraphic_Core/Demo_Gallery/base/Time_Axis_Test.h rename to Demo_Gallery/base/Time_Axis_Test.h index c9c7238..e2edcc2 100644 --- a/YSGraphic_Core/Demo_Gallery/base/Time_Axis_Test.h +++ b/Demo_Gallery/base/Time_Axis_Test.h @@ -1,15 +1,15 @@ #pragma once -#include "../Tool.h" +#include "../../Renderive/base/Tool.h" static QWidget* create_time_axis_test_plot() { - class Axis_Test_Plot : public YSG::Plot { + class Axis_Test_Plot : public renderive::Plot { public: - std::shared_ptr axis{}; - QMenu* mMenu{}; + std::shared_ptr axis{}; + QMenu* menu{}; void init() override { Plot::init(); object_name = "TimeAxisTestPlot"; - auto axisNode = create_renderable_node(root_renderable(), "AxisRenderable"); - axis = YSG::Time_Axis::Builder(axisNode, Qt::Horizontal) + auto axis_node = create_renderable_node(get_root_renderable(), "Axis_Renderable"); + axis = renderive::Time_Axis::Builder(axis_node, Qt::Horizontal) .set_tick_length(-10) .set_sub_tick_length(-5) .build(); @@ -22,11 +22,11 @@ static QWidget* create_time_axis_test_plot() { axis->set_pixel_size(width() - space * 2); } void contextMenuEvent(QContextMenuEvent* event) override { - if (!mMenu) { + if (!menu) { auto ws = bw(cw(axis.get(), 30), "时间轴"); - mMenu = createMenu(this, ws); + menu = create_menu(this, ws); } - mMenu->exec(event->globalPos()); + menu->exec(event->globalPos()); } }; auto w = new Axis_Test_Plot; diff --git a/YSGraphic_Core/Demo_Gallery/export.h b/Demo_Gallery/export.h similarity index 66% rename from YSGraphic_Core/Demo_Gallery/export.h rename to Demo_Gallery/export.h index 358b443..ded23fe 100644 --- a/YSGraphic_Core/Demo_Gallery/export.h +++ b/Demo_Gallery/export.h @@ -2,13 +2,13 @@ #include "Afterglow_Plot.h" #include "Audio_Plot.h" #include "Demo_Gallery.h" -#include "Norml_test.h" +#include "Normal_test.h" #include "Planisphere_Plot.h" #include "Spectrum_Plot.h" #include "Sweep_Frequent_Plot.h" -#include "Tool.h" +#include "../Renderive/base/Tool.h" #include "Waterfall_Plot.h" #include "base/Axis_Test.h" -#include "base/Frequent_Axis_Test.h" -#include "base/Muti_Select_Test.h" +#include "base/Frequency_Axis_Test.h" +#include "base/Multi_Select_Test.h" #include "base/Time_Axis_Test.h" diff --git a/YSGraphic_Core/Axis/Abs_Axis.cpp b/Renderive/Axis/Abs_Axis.cpp similarity index 76% rename from YSGraphic_Core/Axis/Abs_Axis.cpp rename to Renderive/Axis/Abs_Axis.cpp index 7433acd..a1729db 100644 --- a/YSGraphic_Core/Axis/Abs_Axis.cpp +++ b/Renderive/Axis/Abs_Axis.cpp @@ -1,22 +1,22 @@ #include #include #include "Abs_Axis_p.h" -namespace YSG { -using AbsAxis_Binding = Renderable_Binding; +namespace renderive { +using Abs_Axis_Binding = Renderable_Binding; Abs_Axis::Abs_Axis() { - AbsAxis_Binding::init(this, "AbsAxis"); + Abs_Axis_Binding::init(this, "AbsAxis"); } Abs_Axis_Private* Abs_Axis::d() { - return AbsAxis_Binding::d(this); + return Abs_Axis_Binding::d(this); } Render_Data* Abs_Axis::create_render_data() { - return AbsAxis_Binding::create_render_data(); + return Abs_Axis_Binding::create_render_data(); } Render_State* Abs_Axis::create_render_state() { - return AbsAxis_Binding::create_render_state(); + return Abs_Axis_Binding::create_render_state(); } Input_Data* Abs_Axis::create_input_data() { - return AbsAxis_Binding::create_input_data(); + return Abs_Axis_Binding::create_input_data(); } int Abs_Axis::x(SRC src) { return d()->state_value(&Abs_Axis_Render_State::x, src); @@ -108,23 +108,23 @@ double Abs_Axis::pixel_to_coord(double pixel, SRC src) { double Abs_Axis::coord_to_pixel(double coord, SRC src) { return d()->coord_to_pixel(coord, src); } -QVector Abs_Axis_Private::create_tick_vector(double tickStep, const Range& range) { - double mTickOrigin = render_state()->coord_start; +QVector Abs_Axis_Private::create_tick_vector(double tick_step, const Range& range) { + double tick_origin = render_state()->coord_start; QVector result; - // Generate tick positions according to tickStep: + // Generate tick positions according to tick_step: // do not use qFloor here, or we'll lose 64 bit precision - // qDebug() << "tickStep:" << tickStep; + // qDebug() << "tick_step:" << tick_step; // - auto firstStep = qint64(floor(qAbs((range.origin - mTickOrigin) / tickStep))); - auto lastStep = qint64(ceil((qAbs(range.target - mTickOrigin) / tickStep))); - int tickcount = int(qAbs(lastStep - firstStep) + 1); - if (tickcount < 0) - tickcount = 0; + auto first_step = qint64(floor(qAbs((range.origin - tick_origin) / tick_step))); + auto last_step = qint64(ceil((qAbs(range.target - tick_origin) / tick_step))); + int tick_count = int(qAbs(last_step - first_step) + 1); + if (tick_count < 0) + tick_count = 0; if (range.origin > range.target) - tickStep = -tickStep; - result.resize(tickcount); - for (int i = 0; i < tickcount; ++i) { - result[i] = mTickOrigin + (double)(firstStep + i) * tickStep; + tick_step = -tick_step; + result.resize(tick_count); + for (int i = 0; i < tick_count; ++i) { + result[i] = tick_origin + (double)(first_step + i) * tick_step; } // while (!result.empty() && !range.contain(result.last())) { // result.removeLast(); @@ -134,38 +134,38 @@ QVector Abs_Axis_Private::create_tick_vector(double tickStep, const Rang QVector Abs_Axis_Private::create_label_vector(const QVector& ticks, SRC src) { QVector result; result.reserve(ticks.size()); - foreach (double tickCoord, ticks) - result.append(get_tick_label(tickCoord, src)); + foreach(double tick_coord, ticks) + result.append(get_tick_label(tick_coord, src)); return result; } -QVector Abs_Axis_Private::create_sub_tick_vector(int subTickCount, const QVector& ticks, const Range& range) { +QVector Abs_Axis_Private::create_sub_tick_vector(int sub_tick_count, const QVector& ticks, const Range& range) { QVector result; - if (subTickCount <= 0 || ticks.size() < 2) + if (sub_tick_count <= 0 || ticks.size() < 2) return result; - result.reserve((ticks.size() - 1) * subTickCount); + result.reserve((ticks.size() - 1) * sub_tick_count); for (int i = 1; i < ticks.size(); ++i) { - double subTickStep = (ticks.at(i) - ticks.at(i - 1)) / double(subTickCount + 1); - for (int k = 1; k <= subTickCount; ++k) - result.append(ticks.at(i - 1) + k * subTickStep); + double sub_tick_step = (ticks.at(i) - ticks.at(i - 1)) / double(sub_tick_count + 1); + for (int k = 1; k <= sub_tick_count; ++k) + result.append(ticks.at(i - 1) + k * sub_tick_step); } while (!result.empty() && !range.contain(result.last())) { result.removeLast(); } return result; } -int Abs_Axis_Private::get_sub_tick_count(double tickStep) { +int Abs_Axis_Private::get_sub_tick_count(double tick_step) { int result = 1; // default to 1, if no proper value can be found // separate integer and fractional part of mantissa: double epsilon = 0.01; - double intPartf; - int intPart; - double fracPart = modf(getMantissa(tickStep), &intPartf); - intPart = int(intPartf); + double int_partf; + int int_part; + double frac_part = modf(get_mantissa(tick_step), &int_partf); + int_part = int(int_partf); // handle cases with (almost) integer mantissa: - if (fracPart < epsilon || 1.0 - fracPart < epsilon) { - if (1.0 - fracPart < epsilon) - ++intPart; - switch (intPart) { + if (frac_part < epsilon || 1.0 - frac_part < epsilon) { + if (1.0 - frac_part < epsilon) + ++int_part; + switch (int_part) { case 1: result = 4; break; // 1.0 -> 0.2 substep @@ -197,9 +197,9 @@ int Abs_Axis_Private::get_sub_tick_count(double tickStep) { } else { // handle cases with significantly fractional mantissa: - if (qAbs(fracPart - 0.5) < epsilon) // *.5 mantissa + if (qAbs(frac_part - 0.5) < epsilon) // *.5 mantissa { - switch (intPart) { + switch (int_part) { case 1: result = 2; break; // 1.5 -> 0.5 substep @@ -233,7 +233,7 @@ int Abs_Axis_Private::get_sub_tick_count(double tickStep) { } return result; } -double Abs_Axis_Private::getMantissa(double input, double* magnitude) { +double Abs_Axis_Private::get_mantissa(double input, double* magnitude) { const double mag = std::pow(10.0, std::floor(std::log10(input))); if (magnitude) *magnitude = mag; @@ -241,10 +241,10 @@ double Abs_Axis_Private::getMantissa(double input, double* magnitude) { } double Abs_Axis_Private::clean_mantissa(double input) { double magnitude; - const double mantissa = getMantissa(input, &magnitude); - return pickClosest(mantissa, QVector() << 1.0 << 2.0 << 2.5 << 5.0 << 10.0) * magnitude; + const double mantissa = get_mantissa(input, &magnitude); + return pick_closest(mantissa, QVector() << 1.0 << 2.0 << 2.5 << 5.0 << 10.0) * magnitude; } -double Abs_Axis_Private::pickClosest(double target, const QVector& candidates) { +double Abs_Axis_Private::pick_closest(double target, const QVector& candidates) { if (candidates.empty()) return target; if (candidates.size() == 1) @@ -287,8 +287,8 @@ int Abs_Axis::get_pixel_point_size(SRC src) { double Abs_Axis::get_tick_step(const Range& range) { return d()->get_tick_step(range); } -int Abs_Axis::get_sub_tick_count(double tickStep) { - return d()->get_sub_tick_count(tickStep); +int Abs_Axis::get_sub_tick_count(double tick_step) { + return d()->get_sub_tick_count(tick_step); } QString Abs_Axis::get_tick_label(double tick, SRC src) { return d()->get_tick_label(tick, src); @@ -296,10 +296,10 @@ QString Abs_Axis::get_tick_label(double tick, SRC src) { QVector Abs_Axis::create_label_vector(const QVector& ticks, SRC src) { return d()->create_label_vector(ticks, src); } -QVector Abs_Axis::create_tick_vector(double tickStep, const Range& range) { - return d()->create_tick_vector(tickStep, range); +QVector Abs_Axis::create_tick_vector(double tick_step, const Range& range) { + return d()->create_tick_vector(tick_step, range); } -QVector Abs_Axis::create_sub_tick_vector(int subTickCount, const QVector& ticks, const Range& range) { - return d()->create_sub_tick_vector(subTickCount, ticks, range); +QVector Abs_Axis::create_sub_tick_vector(int sub_tick_count, const QVector& ticks, const Range& range) { + return d()->create_sub_tick_vector(sub_tick_count, ticks, range); } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Abs_Axis.h b/Renderive/Axis/Abs_Axis.h similarity index 87% rename from YSGraphic_Core/Axis/Abs_Axis.h rename to Renderive/Axis/Abs_Axis.h index 956700d..51c0db3 100644 --- a/YSGraphic_Core/Axis/Abs_Axis.h +++ b/Renderive/Axis/Abs_Axis.h @@ -1,7 +1,7 @@ #pragma once #include "global.h" -namespace YSG { -struct AbsAxis_Prop { +namespace renderive { +struct Abs_Axis_Prop { int x{}; int y{}; Qt::Orientation orientation = Qt::Horizontal; @@ -27,9 +27,7 @@ public: Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: Abs_Axis(); -public: PROP(int, x) PROP(int, y) PROP(Qt::Orientation, orientation) @@ -52,13 +50,13 @@ public: /// 根据当前范围计算主刻度步长。 [[nodiscard]] virtual double get_tick_step(const Range& range); /// 根据主刻度步长计算子刻度数量。 - [[nodiscard]] virtual int get_sub_tick_count(double tickStep); + [[nodiscard]] virtual int get_sub_tick_count(double tick_step); /// 生成指定刻度的显示文本。 virtual QString get_tick_label(double tick, SRC); /// 生成主刻度向量。 - virtual QVector create_tick_vector(double tickStep, const Range& range); + virtual QVector create_tick_vector(double tick_step, const Range& range); /// 生成子刻度向量。 - virtual QVector create_sub_tick_vector(int subTickCount, const QVector& ticks, const Range& range); + virtual QVector create_sub_tick_vector(int sub_tick_count, const QVector& ticks, const Range& range); /// 生成刻度文本向量。 virtual QVector create_label_vector(const QVector& ticks, SRC); /// 返回轴起点坐标。 @@ -72,10 +70,10 @@ public: /// 返回当前坐标范围对应的像素点数量。 int get_pixel_point_size(SRC = SRC::Edit); template - struct BuilderT; + struct Builder_T; }; template -struct Abs_Axis::BuilderT : protected AbsAxis_Prop { +struct Abs_Axis::Builder_T : protected Abs_Axis_Prop { PROP_BT(int, x) PROP_BT(int, y) PROP_BT(Qt::Orientation, orientation) @@ -90,9 +88,8 @@ struct Abs_Axis::BuilderT : protected AbsAxis_Prop { PROP_BT(QPen, unit_text_pen) PROP_BT(QBrush, unit_text_background_brush) PROP_BT(int, rotate) // 不旋转 -protected: std::shared_ptr parent{}; size_t pixel_size{}; void set(Abs_Axis* ret); }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Abs_Axis_p.h b/Renderive/Axis/Abs_Axis_p.h similarity index 74% rename from YSGraphic_Core/Axis/Abs_Axis_p.h rename to Renderive/Axis/Abs_Axis_p.h index 8c87dcb..a08dc01 100644 --- a/YSGraphic_Core/Axis/Abs_Axis_p.h +++ b/Renderive/Axis/Abs_Axis_p.h @@ -1,13 +1,13 @@ #pragma once #include #include "Abs_Axis.h" -namespace YSG { -struct Abs_Axis_Render_State : Render_State, AbsAxis_Prop { +namespace renderive { +struct Abs_Axis_Render_State : Render_State, Abs_Axis_Prop { size_t pixel_size{}; int number_precision = 2; double coord_start = 0; double coord_length = 20; - void scaleRange(double factor, double center) { + void scale_range(double factor, double center) { coord_start = (coord_start - center) * factor + center; coord_length *= factor; } @@ -15,29 +15,29 @@ struct Abs_Axis_Render_State : Render_State, AbsAxis_Prop { struct Abs_Axis_Input_Data : Input_Data {}; struct Abs_Axis_Private : Typed_Render_Data { friend class Abs_Axis; - int mTickCount = 2; - std::atomic pixelStart{}; - double getMantissa(double input, double* magnitude = nullptr); + int tick_count = 2; + std::atomic pixel_start{}; + double get_mantissa(double input, double* magnitude = nullptr); [[nodiscard]] double clean_mantissa(double input); - [[nodiscard]] double pickClosest(double target, const QVector& candidates); + [[nodiscard]] double pick_closest(double target, const QVector& candidates); void prepare_data(const Plot_Render_Snapshot&) override { sync_state_pipeline(); } void draw(QPainter* painter, const Plot_Render_Snapshot&) override { Abs_Axis_Render_State* s = render_state(); - pixelStart = s->orientation == Qt::Horizontal ? s->x : s->y; + pixel_start = s->orientation == Qt::Horizontal ? s->x : s->y; Range range = {s->coord_start, s->coord_start + s->coord_length}; Abs_Axis* q = this->q(); - double tickStep = q->get_tick_step(range); - QVector ticks = q->create_tick_vector(tickStep, range); - int subTickCount = q->get_sub_tick_count(tickStep); - QVector subTicks = q->create_sub_tick_vector(subTickCount, ticks, range); + double tick_step = q->get_tick_step(range); + QVector ticks = q->create_tick_vector(tick_step, range); + int sub_tick_count = q->get_sub_tick_count(tick_step); + QVector sub_ticks = q->create_sub_tick_vector(sub_tick_count, ticks, range); QVector labels = q->create_label_vector(ticks, SRC::Render); while (!ticks.empty() && !range.contain(ticks.last())) { ticks.removeLast(); } - while (!subTicks.empty() && !range.contain(subTicks.last())) { - subTicks.removeLast(); + while (!sub_ticks.empty() && !range.contain(sub_ticks.last())) { + sub_ticks.removeLast(); } QFontMetrics fm(painter->font()); int h = fm.height(); @@ -56,7 +56,7 @@ struct Abs_Axis_Private : Typed_Render_DatadrawText(0, 0, label); painter->resetTransform(); } - for (double tick : subTicks) { + for (double tick : sub_ticks) { double x = q->coord_to_pixel(tick, SRC::Render); painter->drawLine((int)x, s->y, (int)x, s->y + s->sub_tick_length); } @@ -75,19 +75,19 @@ struct Abs_Axis_Private : Typed_Render_DatadrawText(0, 0, label); painter->resetTransform(); } - for (double tick : subTicks) { + for (double tick : sub_ticks) { double y = q->coord_to_pixel(tick, SRC::Render); painter->drawLine(s->x, (int)y, s->x + s->sub_tick_length, (int)y); } } else { - qDebug() << "error s->mOrientation == " << s->orientation; + qDebug() << "error s->orientation == " << s->orientation; } if (s->unit_text.isEmpty()) return; double w = fm.horizontalAdvance(s->unit_text); if (s->orientation == Qt::Horizontal) { - double x = pixelStart + s->pixel_size - w; + double x = pixel_start + s->pixel_size - w; double y = s->y - h; QRectF area(x, y, w, h); painter->fillRect(area, s->unit_text_background_brush); @@ -97,7 +97,7 @@ struct Abs_Axis_Private : Typed_Render_Dataorientation == Qt::Vertical) { double x = s->x; - double y = pixelStart; + double y = pixel_start; QRectF area(x, y, w, h); painter->fillRect(area, s->unit_text_background_brush); painter->setPen(s->unit_text_pen); @@ -105,27 +105,26 @@ struct Abs_Axis_Private : Typed_Render_DatadrawText(area, Qt::AlignCenter, s->unit_text); } } -protected: [[nodiscard]] virtual double pixel_to_coord(double pixel, SRC src) { auto s = static_cast(state(src)); - return s->coord_start + s->coord_length * (pixel - (double)pixelStart) / (double)s->pixel_size; + return s->coord_start + s->coord_length * (pixel - (double)pixel_start) / (double)s->pixel_size; } [[nodiscard]] virtual double coord_to_pixel(double coord, SRC src) { auto s = static_cast(state(src)); - return pixelStart + (double)s->pixel_size * (coord - s->coord_start) / s->coord_length; + return pixel_start + (double)s->pixel_size * (coord - s->coord_start) / s->coord_length; } virtual double get_tick_step(const Range& range) { - double exactStep = range.size() / double(mTickCount + 1e-10); // mTickCount ticks on average, the small addition is to prevent jitter on exact integers - return clean_mantissa(exactStep); + double exact_step = range.size() / double(tick_count + 1e-10); + return clean_mantissa(exact_step); } - virtual int get_sub_tick_count(double tickStep); - virtual QVector create_tick_vector(double tickStep, const Range& range); - virtual QVector create_sub_tick_vector(int subTickCount, const QVector& ticks, const Range& range); + virtual int get_sub_tick_count(double tick_step); + virtual QVector create_tick_vector(double tick_step, const Range& range); + virtual QVector create_sub_tick_vector(int sub_tick_count, const QVector& ticks, const Range& range); virtual QString get_tick_label(double tick, SRC); virtual QVector create_label_vector(const QVector& ticks, SRC); }; template -void Abs_Axis::BuilderT::set(Abs_Axis* ret) { +void Abs_Axis::Builder_T::set(Abs_Axis* ret) { ret->init(parent); Abs_Axis_Private* pd = ret->d(); Abs_Axis_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); @@ -144,4 +143,4 @@ void Abs_Axis::BuilderT::set(Abs_Axis* ret) { sc->unit_text_background_brush = this->unit_text_background_brush; sc->rotate = this->rotate; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Axis.cpp b/Renderive/Axis/Axis.cpp similarity index 88% rename from YSGraphic_Core/Axis/Axis.cpp rename to Renderive/Axis/Axis.cpp index 14dc84c..639c052 100644 --- a/YSGraphic_Core/Axis/Axis.cpp +++ b/Renderive/Axis/Axis.cpp @@ -1,5 +1,5 @@ #include "Axis_p.h" -namespace YSG { +namespace renderive { using Axis_Binding = Renderable_Binding; Axis::Axis() { Axis_Binding::init(this, "Axis"); @@ -44,13 +44,13 @@ void Axis::set_coord_range(Range range) { edit->coord_length = range.target - range.origin; } Axis::Builder::Builder(std::shared_ptr parent, Qt::Orientation orientation) { - ASSERT(parent && parent->mPlot, "Axis build error! parent invalid"); + ASSERT(parent && parent->plot, "Axis build error! parent invalid"); this->parent = parent; this->orientation = orientation; } std::shared_ptr Axis::Builder::build() { - std::shared_ptr ret(new Axis()); - Axis::BuilderT::set(ret.get()); + std::shared_ptr < Axis > ret(new Axis()); + Axis::Builder_T::set(ret.get()); return ret; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Axis.h b/Renderive/Axis/Axis.h similarity index 78% rename from YSGraphic_Core/Axis/Axis.h rename to Renderive/Axis/Axis.h index a543bee..46edef7 100644 --- a/YSGraphic_Core/Axis/Axis.h +++ b/Renderive/Axis/Axis.h @@ -1,7 +1,7 @@ #pragma once #include "Abs_Axis.h" #include -namespace YSG { +namespace renderive { struct Axis_Render_State; struct Axis_Input_Data; struct Axis_Private; @@ -13,20 +13,18 @@ public: Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: Axis(); -public: PROP(int, number_precision) PROP(double, coord_start) PROP(double, coord_length) /// 设置轴坐标范围。 void set_coord_range(Range range); template - struct BuilderT; + struct Builder_T; struct Builder; }; template -struct Axis::BuilderT : Abs_Axis::BuilderT { +struct Axis::Builder_T : Abs_Axis::Builder_T { PROP_BT(int, number_precision) // PROP_BT(double, coord_start) // PROP_BT(double, coord_length) @@ -38,26 +36,26 @@ struct Axis::BuilderT : Abs_Axis::BuilderT { t.coord_length = std::move(r.length()); return t; } - That& set_use_wheel(bool useWheel) { + That& set_use_wheel(bool use_wheel) { That& t = *static_cast(this); - this->useWheel = useWheel; + this->use_wheel = use_wheel; return t; } - That& set_use_drag(bool useDrag) { + That& set_use_drag(bool use_drag) { That& t = *static_cast(this); - this->useDrag = useDrag; + this->use_drag = use_drag; return t; } -protected: void set(Axis* ret); int number_precision = 2; - bool useWheel = false; - bool useDrag = false; + bool use_wheel = false; + bool use_drag = false; }; -struct LIB_DECL Axis::Builder : BuilderT { +struct LIB_DECL Axis::Builder : Builder_T{ /// 创建数值轴构造器。 Builder(std::shared_ptr parent, Qt::Orientation orientation); /// 构建并返回数值轴对象。 std::shared_ptr build(); + }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Axis_p.h b/Renderive/Axis/Axis_p.h similarity index 58% rename from YSGraphic_Core/Axis/Axis_p.h rename to Renderive/Axis/Axis_p.h index f0e4c4c..d7005a5 100644 --- a/YSGraphic_Core/Axis/Axis_p.h +++ b/Renderive/Axis/Axis_p.h @@ -2,62 +2,61 @@ #include #include "Abs_Axis_p.h" #include "Axis.h" -namespace YSG { +namespace renderive { struct Axis_Render_State : Abs_Axis_Render_State {}; struct Axis_Input_Data : Abs_Axis_Input_Data {}; struct Axis_Private : Typed_Render_Data_Base { friend class Axis; - bool useWheel = false; - bool useDrag = false; -protected: + bool use_wheel = false; + bool use_drag = false; bool select_test(const QPointF& pos) override { return true; } void wheelEvent(QWheelEvent* event) override { - if (useWheel) { + if (use_wheel) { Render_Edit_Lease edit(this); const double delta = event->angleDelta().y(); - double wheelSteps = delta / 120.0; - double factor = std::pow(0.8, wheelSteps); + double wheel_steps = delta / 120.0; + double factor = std::pow(0.8, wheel_steps); double cursor_coord = pixel_to_coord(event->position().x(), SRC::Edit); - double new_coordLength = edit->coord_length * factor; - double new_coordStart = cursor_coord - new_coordLength * (cursor_coord - edit->coord_start) / edit->coord_length; - edit->coord_start = new_coordStart; - edit->coord_length = new_coordLength; + double new_coord_length = edit->coord_length * factor; + double new_coord_start = cursor_coord - new_coord_length * (cursor_coord - edit->coord_start) / edit->coord_length; + edit->coord_start = new_coord_start; + edit->coord_length = new_coord_length; } } bool dragging = false; - QPoint startGlobalPos, startPos; - double startCoordValue; - double pixelPreCoord; + QPoint start_global_pos, start_pos; + double start_coord_value; + double pixel_pre_coord; void mousePressEvent(QMouseEvent* event) override { - if (!useDrag) + if (!use_drag) return; if (event->button() != Qt::LeftButton) return; if (dragging) return; dragging = true; - startGlobalPos = QCursor::pos(); - startPos = event->pos(); + start_global_pos = QCursor::pos(); + start_pos = event->pos(); Render_State_Lease state(this); - startCoordValue = state->coord_start; - pixelPreCoord = state->coord_length / static_cast(state->pixel_size); + start_coord_value = state->coord_start; + pixel_pre_coord = state->coord_length / static_cast(state->pixel_size); } void mouseMoveEvent(QMouseEvent* event) override { - if (!useDrag) + if (!use_drag) return; if (!(event->buttons() & Qt::LeftButton)) return; if (!dragging) return; Render_Edit_Lease edit(this); - QPoint delt = startGlobalPos - QCursor::pos(); - auto coordDelt = pixelPreCoord * (edit->orientation == Qt::Horizontal ? delt.x() : delt.y()); - edit->coord_start = startCoordValue + coordDelt; + QPoint delta = start_global_pos - QCursor::pos(); + auto coord_delta = pixel_pre_coord * (edit->orientation == Qt::Horizontal ? delta.x() : delta.y()); + edit->coord_start = start_coord_value + coord_delta; } void mouseReleaseEvent(QMouseEvent* event) override { - if (!useDrag) + if (!use_drag) return; if (event->button() != Qt::LeftButton) return; @@ -67,8 +66,8 @@ protected: } }; template -void Axis::BuilderT::set(Axis* ret) { - Abs_Axis::BuilderT::set(ret); +void Axis::Builder_T::set(Axis* ret) { + Abs_Axis::Builder_T::set(ret); Axis_Private* pd = ret->d(); Axis_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); PROP_RT(int, number_precision) @@ -76,7 +75,7 @@ void Axis::BuilderT::set(Axis* ret) { PROP_RT(double, coord_length) if (sc->coord_length == 0.0) sc->coord_length = 1.0; - pd->useWheel = useWheel; - pd->useDrag = useDrag; + pd->use_wheel = use_wheel; + pd->use_drag = use_drag; } -} // namespace YSG +} // namespace renderive diff --git a/Renderive/Axis/Frequency_Axis.cpp b/Renderive/Axis/Frequency_Axis.cpp new file mode 100644 index 0000000..ce22f57 --- /dev/null +++ b/Renderive/Axis/Frequency_Axis.cpp @@ -0,0 +1,30 @@ +#include "Axis_p.h" +#include "Frequency_Axis_p.h" +namespace renderive { +using Frequency_Axis_Binding = Renderable_Binding; +Frequency_Axis::Frequency_Axis() { + Frequency_Axis_Binding::init(this, "Frequency_Axis"); +} +Frequency_Axis_Private* Frequency_Axis::d() { + return Frequency_Axis_Binding::d(this); +} +Render_Data* Frequency_Axis::create_render_data() { + return Frequency_Axis_Binding::create_render_data(); +} +Render_State* Frequency_Axis::create_render_state() { + return Frequency_Axis_Binding::create_render_state(); +} +Input_Data* Frequency_Axis::create_input_data() { + return Frequency_Axis_Binding::create_input_data(); +} +Frequency_Axis::Builder::Builder(std::shared_ptr parent, Qt::Orientation orientation) { + ASSERT(parent && parent->plot, "Frequency_Axis build error! parent invalid"); + this->parent = parent; + this->orientation = orientation; +} +std::shared_ptr Frequency_Axis::Builder::build() { + std::shared_ptr < Frequency_Axis > ret(new Frequency_Axis()); + set(ret.get()); + return ret; +} +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Frequent_Axis.h b/Renderive/Axis/Frequency_Axis.h similarity index 61% rename from YSGraphic_Core/Axis/Frequent_Axis.h rename to Renderive/Axis/Frequency_Axis.h index 6603701..23a80a5 100644 --- a/YSGraphic_Core/Axis/Frequent_Axis.h +++ b/Renderive/Axis/Frequency_Axis.h @@ -1,25 +1,28 @@ #pragma once #include "Axis.h" #include -namespace YSG { -struct Frequent_Axis_Private; +namespace renderive { +struct Frequency_Axis_Private; /// 频率轴,负责频率单位显示。 -class LIB_DECL Frequent_Axis : public Axis { +class LIB_DECL Frequency_Axis : public Axis { public: /// 返回私有渲染数据。 - Frequent_Axis_Private* d(); + Frequency_Axis_Private* d(); Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: - Frequent_Axis(); -public: + Frequency_Axis(); struct Builder; }; -struct LIB_DECL Frequent_Axis::Builder : BuilderT { +struct LIB_DECL Frequency_Axis::Builder : Builder_T{ /// 创建频率轴构造器。 Builder(std::shared_ptr parent, Qt::Orientation orientation); /// 构建并返回频率轴对象。 - std::shared_ptr build(); + std::shared_ptr build(); + + + + + }; -} // namespace YSG +} // namespace renderive diff --git a/Renderive/Axis/Frequency_Axis_p.h b/Renderive/Axis/Frequency_Axis_p.h new file mode 100644 index 0000000..02d088e --- /dev/null +++ b/Renderive/Axis/Frequency_Axis_p.h @@ -0,0 +1,79 @@ +#pragma once +#include "Abs_Axis_p.h" +#include "Axis_p.h" +#include "Frequency_Axis.h" +namespace renderive { +struct Frequency_Axis_Input_Data : Axis_Input_Data {}; +struct Frequency_Axis_Render_State : Axis_Render_State {}; +struct Frequency_Axis_Private : Typed_Render_Data_Base { + friend class Frequency_Axis; + enum X_Unit_Type { + Unknown = -1, + Hz = 0, + KHz = 3, + MHz = 6, + GHz = 9 + } x_unit_type = Unknown; + static QString get_x_unit_type_string(X_Unit_Type unit_type) { + switch (unit_type) { + case Hz: + return "Hz"; + case KHz: + return "KHz"; + case MHz: + return "MHz"; + case GHz: + return "GHz"; + default: + return "Unknown"; + } + } + QVector create_label_vector(const QVector& ticks, SRC src) override { + if (!ticks.empty()) { + double range = ticks.last() - ticks.first(); + X_Unit_Type before_unit_type = x_unit_type; + if (range >= 1e9) { + x_unit_type = GHz; + } + else if (range >= 1e6) { + x_unit_type = MHz; + } + else if (range >= 1e3) { + x_unit_type = KHz; + } + else { + x_unit_type = Hz; + } + if (before_unit_type != x_unit_type) { + render_state()->unit_text = "频率/" + get_x_unit_type_string(x_unit_type); + } + } + QVector result; + result.reserve(ticks.size()); + for (const double& tick_coord : ticks) { + result.append(get_true_value(get_tick_label(tick_coord, src))); + } + return result; + } + QString get_true_value(QString value) { + value.replace(",", ""); + int move_num = x_unit_type; + Abs_Axis_Render_State* s = render_state(); + int precision = s->number_precision; + int dot_index = value.indexOf('.'); + if (dot_index == -1) { + dot_index = value.size(); + } + QString number = value.left(dot_index) + value.mid(dot_index + 1); + int after_dot_index = dot_index - move_num; + if (after_dot_index < 1) { + for (int i = 0; i < 1 - after_dot_index; ++i) { + number.prepend('0'); + } + after_dot_index = 1; + } + number.insert(after_dot_index, '.'); + return QString::number(number.toDouble(), 'd', precision); + } +}; +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Time_Axis.cpp b/Renderive/Axis/Time_Axis.cpp similarity index 79% rename from YSGraphic_Core/Axis/Time_Axis.cpp rename to Renderive/Axis/Time_Axis.cpp index cac260e..fdfc021 100644 --- a/YSGraphic_Core/Axis/Time_Axis.cpp +++ b/Renderive/Axis/Time_Axis.cpp @@ -1,20 +1,20 @@ #include "Time_Axis_p.h" -namespace YSG { -using TimeAxis_Binding = Renderable_Binding; +namespace renderive { +using Time_Axis_Binding = Renderable_Binding; Time_Axis::Time_Axis() { - TimeAxis_Binding::init(this, "TimeAxis"); + Time_Axis_Binding::init(this, "time_axis"); } Time_Axis_Private* Time_Axis::d() { - return TimeAxis_Binding::d(this); + return Time_Axis_Binding::d(this); } Render_Data* Time_Axis::create_render_data() { - return TimeAxis_Binding::create_render_data(); + return Time_Axis_Binding::create_render_data(); } Render_State* Time_Axis::create_render_state() { - return TimeAxis_Binding::create_render_state(); + return Time_Axis_Binding::create_render_state(); } Input_Data* Time_Axis::create_input_data() { - return TimeAxis_Binding::create_input_data(); + return Time_Axis_Binding::create_input_data(); } int Time_Axis::time_point_size(SRC src) { return d()->state_value(&Time_Axis_Render_State::time_point_size, src); @@ -44,7 +44,7 @@ int Time_Axis::give_data(QTime time) { if (!ok()) return -1; Time_Axis_Private* pd = d(); - std::pair ret = pd->mTimeTicker.getNewDataTickInfo(); + std::pair ret = pd->time_ticker.get_new_data_tick_info(); Render_Input_Lease input(pd); input->push_time(time); if (ret.second) { @@ -58,12 +58,12 @@ QTime Time_Axis::tick_to_time(int tick, SRC src) { return d()->time_by_offset(offset); } Time_Axis::Builder::Builder(std::shared_ptr parent, Qt::Orientation orientation) { - ASSERT(parent && parent->mPlot, "Time_Axis build error! parent invalid"); + ASSERT(parent && parent->plot, "Time_Axis build error! parent invalid"); this->parent = parent; this->orientation = orientation; } std::shared_ptr Time_Axis::Builder::build() { - std::shared_ptr ret(new Time_Axis()); + std::shared_ptr < Time_Axis > ret(new Time_Axis()); set(ret.get()); Time_Axis_Private* pd = ret->d(); Time_Axis_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); @@ -75,4 +75,4 @@ std::shared_ptr Time_Axis::Builder::build() { sc->tick_pixel_space = qMax(1, sc->tick_pixel_space); return ret; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/Axis/Time_Axis.h b/Renderive/Axis/Time_Axis.h similarity index 86% rename from YSGraphic_Core/Axis/Time_Axis.h rename to Renderive/Axis/Time_Axis.h index e8956e1..796a90c 100644 --- a/YSGraphic_Core/Axis/Time_Axis.h +++ b/Renderive/Axis/Time_Axis.h @@ -1,7 +1,7 @@ #pragma once #include "Abs_Axis.h" #include -namespace YSG { +namespace renderive { struct Time_Axis_Private; struct Time_Ticker; /// 时间轴,输入 tick 后按格式显示时间标签。 @@ -12,9 +12,7 @@ public: Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: Time_Axis(); -public: PROP(int, time_point_size) PROP(int, tick_pixel_space) PROP(QString, time_format) @@ -31,8 +29,9 @@ struct Time_Axis_Prop { QString time_format = "mm:ss.zzz"; QFont font; }; -struct LIB_DECL Time_Axis::Builder : Abs_Axis::BuilderT, - protected Time_Axis_Prop { +struct LIB_DECL Time_Axis::Builder : Abs_Axis::Builder_T, +public +Time_Axis_Prop { PROP_B(int, time_point_size) PROP_B(int, tick_pixel_space) PROP_B(QString, time_format) @@ -42,4 +41,4 @@ struct LIB_DECL Time_Axis::Builder : Abs_Axis::BuilderT, /// 构建并返回时间轴对象。 std::shared_ptr build(); }; -} // namespace YSG +} // namespace renderive diff --git a/Renderive/Axis/Time_Axis_p.h b/Renderive/Axis/Time_Axis_p.h new file mode 100644 index 0000000..3d1763c --- /dev/null +++ b/Renderive/Axis/Time_Axis_p.h @@ -0,0 +1,254 @@ +#pragma once +#include +#include +#include +#include +#include "../architecture/Bounded_Input_Buffer.h" +#include "Abs_Axis_p.h" +#include "Core/Base/RingBuffer.hpp" +#include "Time_Axis.h" +namespace renderive { +struct Time_Ticker { + bool start_coord_to_end_coord = true; + // 最小值的范围 lower在这里面循环变化 + int lower = 0, time_point_size{}; + int lower_min{}, lower_max{}; // 闭区间 + int tick_start = 0, tick_space = 4; + [[nodiscard]] int upper() const { + return lower - 1 + time_point_size; + } + void set_tick_space(int tick_space) { + if (tick_space == tick_space) + return; + tick_space = tick_space; + tick_start = 0; + } + void set_time_point_size(int value) { + if (time_point_size == value) + return; + time_point_size = value; + lower_min = std::numeric_limits::min() / 2; + lower_max = std::numeric_limits::max() / 2 - time_point_size + 1; + tick_start = 0; + } + std::pair get_new_data_tick_info() { + { + // 获取 坐标轴的起点 + if (start_coord_to_end_coord) { + if (lower != lower_min) + lower--; + else { + lower = lower_max; + } + } + else { + if (lower != lower_max) + lower++; + else { + lower = lower_min; + } + } + } + tick_start = ++tick_start % tick_space; + int end_index = lower + time_point_size - 1; + auto start_index = lower; + if (tick_start == 1) { + return {start_coord_to_end_coord ? start_index : end_index, true}; + } + return {start_coord_to_end_coord ? start_index : end_index, false}; + } +}; +struct Time_Tick { + QTime time; + int tick{}; +}; +struct Time_Axis_Input_Data : Abs_Axis_Input_Data { + static constexpr std::size_t Max_Pending_Time_Count = 32; + static constexpr std::size_t Max_Pending_Tick_Count = 32; + Bounded_Input_Buffer data; + Bounded_Input_Buffer all_time; + void push_time(const QTime& time) { + all_time.push(&time, sizeof(time), Max_Pending_Time_Count); + } + void push_tick(const Time_Tick& tick) { + data.push(&tick, sizeof(tick), Max_Pending_Tick_Count); + } + template + void read_all_time(Handler handler) { + all_time.read_all([&handler](const void* data, std::size_t size) { + (void)size; + QTime time; + std::memcpy(&time, data, sizeof(time)); + handler(time); + }); + } + template + void read_all_tick(Handler handler) { + data.read_all([&handler](const void* data, std::size_t size) { + (void)size; + Time_Tick tick; + std::memcpy(&tick, data, sizeof(tick)); + handler(tick); + }); + } + void clear() override { + data.clear(); + all_time.clear(); + } + std::uint64_t get_pending_count() const override { + return data.get_pending_count() + all_time.get_pending_count(); + } + std::uint64_t get_dropped_count() const override { + return data.get_dropped_count() + all_time.get_dropped_count(); + } + std::uint64_t get_capacity_dropped_count() const override { + return data.get_capacity_dropped_count() + all_time.get_capacity_dropped_count(); + } + std::uint64_t rebuild_dropped_count() const override { + return data.get_rebuild_dropped_count() + all_time.get_rebuild_dropped_count(); + } + std::uint64_t consumer_dropped_count() const override { + return data.get_consumer_dropped_count() + all_time.get_consumer_dropped_count(); + } + std::uint64_t get_pushed_count() const override { + return data.get_pushed_count() + all_time.get_pushed_count(); + } +}; +struct Time_Axis_Render_State : Abs_Axis_Render_State, Time_Axis_Prop { + int tick_space = 4; + int get_tick_space_hint(SRC src = SRC::Edit) { + QFontMetrics fm(font); + double rate = (double)time_point_size / (double)pixel_size; + double ret = rate * (tick_pixel_space + (orientation == Qt::Horizontal ? fm.horizontalAdvance(time_format) : fm.height())); + return std::max(1, (int)ret); + } +}; +struct Time_Axis_Private : Typed_Render_Data_Base { + friend class Time_Axis; + Time_Ticker time_ticker{}; + int tick_pixel_space{}; + QFont font; + QString time_format; + Psc::StreamRingBuffer_ST buffer; + std::vector time_snapshot; + int time_data_count{}; + std::list data; + void resize_time_buffer(int count) { + buffer.init(sizeof(QTime) * count); + time_snapshot.resize(count); + time_data_count = 0; + } + void push_time(const QTime& time) { + if (time_data_count == time_ticker.time_point_size) { + QTime ignored; + std::size_t len = sizeof(QTime); + buffer.read(&ignored, len); + --time_data_count; + } + buffer.write(&time, sizeof(QTime)); + ++time_data_count; + } + void snapshot_time_buffer() { + buffer.peek_best_effort(time_snapshot.data(), sizeof(QTime) * time_data_count); + } + QTime time_by_offset(int offset) const { + int index = time_ticker.start_coord_to_end_coord ? time_data_count - 1 - offset : offset - (time_ticker.time_point_size - time_data_count); + if (index < 0 || index >= time_data_count) + return {}; + return time_snapshot[index]; + } + void prepare_data(const Plot_Render_Snapshot&) override { + sync_state_pipeline(); + auto d = render_input_data(); + auto s = render_state(); + Triple_Buffer_Lease input_lease = input_control.wait_mark_use_role(Input_Edit); + Triple_Buffer_Lease state_lease = state_control.wait_mark_use_role(State_Edit); + auto sc = reinterpret_cast(state_by_index(state_lease.index)); + bool refresh_space = false; + if (time_ticker.time_point_size != s->time_point_size) { + time_ticker.set_time_point_size(s->time_point_size); + resize_time_buffer(s->time_point_size); + data.clear(); + refresh_space = true; + } + if (tick_pixel_space != s->tick_pixel_space) { + tick_pixel_space = s->tick_pixel_space; + refresh_space = true; + } + if (font != s->font) { + font = s->font; + refresh_space = true; + } + if (time_format != s->time_format) { + time_format = s->time_format; + if (s->orientation == Qt::Horizontal) { + refresh_space = true; + } + } + if (refresh_space) { + s->tick_space = s->get_tick_space_hint(); + sc->tick_space = s->tick_space; + if (time_ticker.tick_space != s->tick_space) { + time_ticker.set_tick_space(s->tick_space); + data.resize(0); + } + } + s->coord_start = time_ticker.lower; + s->coord_length = time_ticker.time_point_size; + sc->coord_start = time_ticker.lower; + sc->coord_length = time_ticker.time_point_size; + int lower = time_ticker.lower; + int upper = time_ticker.upper(); + if (lower > upper) + std::swap(lower, upper); + d->read_all_time([this](const QTime& time) { + push_time(time); + }); + snapshot_time_buffer(); + d->read_all_tick([this](const Time_Tick& tick) { + data.push_front(tick); + }); + clear_render_input(); + while (!data.empty()) { + int tick = data.back().tick; + if (tick < lower || tick > upper) { + data.pop_back(); + } + else { + break; + } + } + int i = 0; + ticks.clear(); + labels.clear(); + for (Time_Tick& t : data) { + ticks.append(t.tick); + labels.append(t.time.toString(s->time_format)); + ++i; + } + state_control.unmark_use(state_lease); + input_control.unmark_use(input_lease); + } + QVector create_label_vector(const QVector& ticks, SRC src) override { + return labels; + } + QVector create_tick_vector(double tick_step, const Range& range) override { + return ticks; + } + QVector create_sub_tick_vector(int sub_tick_count, const QVector& ticks, const Range& range) override { + return {}; + } + // 最小值的范围 lower在这里面循环变化 + int lower = 0, lower_min = 0, lower_max{}; // 闭区间 + int tick_start = 0; + QVector labels; + QVector ticks; + void draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) override { + Abs_Axis_Private::draw(painter, snapshot); + } + QString get_tick_label(double tick, SRC src) override { + auto render_state = reinterpret_cast(state(src)); + return q()->tick_to_time((int)tick, src).toString(render_state->time_format); + } +}; +} // namespace renderive diff --git a/YSGraphic_Core/Axis/export.h b/Renderive/Axis/export.h similarity index 56% rename from YSGraphic_Core/Axis/export.h rename to Renderive/Axis/export.h index 59d0ee9..41617e8 100644 --- a/YSGraphic_Core/Axis/export.h +++ b/Renderive/Axis/export.h @@ -1,3 +1,3 @@ #pragma once -#include "Frequent_Axis.h" +#include "Frequency_Axis.h" #include "Time_Axis.h" diff --git a/YSGraphic_Core/Axis/global.h b/Renderive/Axis/global.h similarity index 100% rename from YSGraphic_Core/Axis/global.h rename to Renderive/Axis/global.h diff --git a/YSGraphic_Core/Generate_Mock_Data.cpp b/Renderive/Generate_Mock_Data.cpp similarity index 51% rename from YSGraphic_Core/Generate_Mock_Data.cpp rename to Renderive/Generate_Mock_Data.cpp index ba5c5cf..2ef324a 100644 --- a/YSGraphic_Core/Generate_Mock_Data.cpp +++ b/Renderive/Generate_Mock_Data.cpp @@ -1,24 +1,24 @@ #include "Generate_Mock_Data.h" #include -namespace YSG { +namespace renderive { std::random_device rd; std::default_random_engine eng(rd()); -QVector get_data(Range valueRange, int size) { - if (valueRange.origin > valueRange.target) { - std::swap(valueRange.origin, valueRange.target); +QVector get_data(Range value_range, int size) { + if (value_range.origin > value_range.target) { + std::swap(value_range.origin, value_range.target); } - std::uniform_real_distribution dist(valueRange.origin, valueRange.target); + std::uniform_real_distribution dist(value_range.origin, value_range.target); QVector ret(size); for (auto& value : ret) { value = dist(eng); } return ret; } -double get_data(Range valueRange) { - if (valueRange.origin > valueRange.target) { - std::swap(valueRange.origin, valueRange.target); +double get_data(Range value_range) { + if (value_range.origin > value_range.target) { + std::swap(value_range.origin, value_range.target); } - std::uniform_real_distribution dist(valueRange.origin, valueRange.target); + std::uniform_real_distribution dist(value_range.origin, value_range.target); return dist(eng); } QVector get_data(int value, int size) { @@ -35,4 +35,4 @@ QVector get_colored_data(int size) { } return ret; } -} // namespace YSG +} // namespace renderive diff --git a/Renderive/Generate_Mock_Data.h b/Renderive/Generate_Mock_Data.h new file mode 100644 index 0000000..cee6e58 --- /dev/null +++ b/Renderive/Generate_Mock_Data.h @@ -0,0 +1,8 @@ +#pragma once +#include "architecture/global.h" +namespace renderive { +QVector LIB_DECL get_data(Range value_range, int size); +double LIB_DECL get_data(Range value_range); +QVector LIB_DECL get_data(int value, int size); +QVector LIB_DECL get_colored_data(int size); +} // namespace renderive diff --git a/YSGraphic_Core/algorithm.hpp b/Renderive/algorithm.hpp similarity index 66% rename from YSGraphic_Core/algorithm.hpp rename to Renderive/algorithm.hpp index 3b55c0e..bfb7f5a 100644 --- a/YSGraphic_Core/algorithm.hpp +++ b/Renderive/algorithm.hpp @@ -4,43 +4,43 @@ namespace YSG { #define LOWER(offset) l_lower(spaces[offset]) #define UPPER(offset) l_upper(spaces[offset]) template -int binary_search(double value, T** spaces, int spaceSize, std::function& l_lower, std::function& l_upper) { - int startIndex = 0, endIndex = spaceSize - 1; - if (startIndex == endIndex) - return startIndex; - double min = LOWER(startIndex), max = UPPER(endIndex); +int binary_search(double value, T** spaces, int space_size, std::function& l_lower, std::function& l_upper) { + int start_index = 0, end_index = space_size - 1; + if (start_index == end_index) + return start_index; + double min = LOWER(start_index), max = UPPER(end_index); if (value < min) { // qDebug() << QString("warnning binary_search value:%1 < %2").arg(value).arg(min); - return startIndex; + return start_index; } if (value > max) { // qDebug() << QString("warnning binary_search value:%1 > %2").arg(value).arg(max); - return endIndex; + return end_index; } - while (startIndex != endIndex) { - if (startIndex + 1 == endIndex) { - double mid = (UPPER(startIndex) + LOWER(endIndex)) / 2.0; + while (start_index != end_index) { + if (start_index + 1 == end_index) { + double mid = (UPPER(start_index) + LOWER(end_index)) / 2.0; if (value < mid) - return startIndex; - return endIndex; + return start_index; + return end_index; } - int m = (startIndex + endIndex) / 2; + int m = (start_index + end_index) / 2; double lower = m != 0 ? (UPPER(m - 1) + LOWER(m)) / 2.0 : min; - double upper = m != spaceSize - 1 ? (UPPER(m) + LOWER(m + 1)) / 2.0 : max; + double upper = m != space_size - 1 ? (UPPER(m) + LOWER(m + 1)) / 2.0 : max; // qDebug() << " lower == " << lower << " upper == " << upper << "midIndex == " << m << " value == " << value; - // qDebug() << " startIndex == " << startIndex << " endIndex == " << endIndex; + // qDebug() << " start_index == " << start_index << " end_index == " << end_index; if (value < lower) { - endIndex = m; + end_index = m; } else if (value > upper) { - startIndex = m; + start_index = m; } else { return m; } } - qDebug() << QString("warnning startIndex:%1, endIndex:%2").arg(startIndex).arg(endIndex); - return startIndex; + qDebug() << QString("warnning start_index:%1, end_index:%2").arg(start_index).arg(end_index); + return start_index; } #undef LOWER #undef UPPER @@ -50,14 +50,14 @@ static int binary_search(double value, const QVector& data, bool& ok) { return -1; // 返回 -1 表示数组为空 } // 判断排序顺序 - bool ascendingOrder = data[0] < data[data.size() - 1]; + bool ascending_order = data[0] < data[data.size() - 1]; int left = 0; int right = data.size() - 1; // 二分查找 while (left <= right) { int mid = left + (right - left) / 2; if (mid < data.size() - 1) { - if (ascendingOrder) { + if (ascending_order) { if (data[mid] <= value && data[mid + 1] > value) { ok = true; return mid; diff --git a/Renderive/architecture/Bounded_Input_Buffer.h b/Renderive/architecture/Bounded_Input_Buffer.h new file mode 100644 index 0000000..662aa92 --- /dev/null +++ b/Renderive/architecture/Bounded_Input_Buffer.h @@ -0,0 +1,175 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "Core/Base/RingBuffer.hpp" +namespace renderive { +class Bounded_Input_Buffer { +public: + void push(const void* data, std::size_t size, std::size_t max_packet_count) { + configure(size, max_packet_count); + while (!buffer.write(data, size)) { + if (!buffer.skip_one()) + return; + dropped_count.fetch_add(1, std::memory_order_relaxed); + capacity_dropped_count.fetch_add(1, std::memory_order_relaxed); + decrement_pending(); + } + pending_count.fetch_add(1, std::memory_order_relaxed); + pushed_count.fetch_add(1, std::memory_order_relaxed); + } + template + void read_all(Handler handler) { + std::size_t packet_size{}; + while (buffer.peek_len(packet_size)) { + read_buffer.resize(packet_size); + std::size_t read_size = packet_size; + if (!buffer.read(read_buffer.data(), read_size)) + return; + decrement_pending(); + handler(read_buffer.data(), read_size); + } + } + void clear() { + while (buffer.skip_one()) {} + pending_count.store(0, std::memory_order_relaxed); + } + [[nodiscard]] std::uint64_t get_pending_count() const { + return pending_count.load(std::memory_order_relaxed); + } + [[nodiscard]] std::uint64_t get_dropped_count() const { + return dropped_count.load(std::memory_order_relaxed); + } + [[nodiscard]] std::uint64_t get_capacity_dropped_count() const { + return capacity_dropped_count.load(std::memory_order_relaxed); + } + [[nodiscard]] std::uint64_t get_rebuild_dropped_count() const { + return rebuild_dropped_count.load(std::memory_order_relaxed); + } + [[nodiscard]] std::uint64_t get_consumer_dropped_count() const { + return consumer_dropped_count.load(std::memory_order_relaxed); + } + [[nodiscard]] std::uint64_t get_pushed_count() const { + return pushed_count.load(std::memory_order_relaxed); + } + void record_consumer_dropped() { + dropped_count.fetch_add(1, std::memory_order_relaxed); + consumer_dropped_count.fetch_add(1, std::memory_order_relaxed); + } +private: + void configure(std::size_t max_packet_size, std::size_t max_packet_count) { + max_packet_count = std::max(1, max_packet_count); + max_packet_size = std::max(1, max_packet_size); + if (Initialized && max_packet_size <= this->max_packet_size && max_packet_count == this->max_packet_count) + return; + std::uint64_t pending = pending_count.load(std::memory_order_relaxed); + dropped_count.fetch_add(pending, std::memory_order_relaxed); + rebuild_dropped_count.fetch_add(pending, std::memory_order_relaxed); + this->max_packet_size = max_packet_size; + this->max_packet_count = max_packet_count; + pending_count.store(0, std::memory_order_relaxed); + buffer.init((Psc::RingBuffer_ST::HEADER_SIZE + max_packet_size) * max_packet_count); + Initialized = true; + } + void decrement_pending() { + std::uint64_t pending = pending_count.load(std::memory_order_relaxed); + while (pending && !pending_count.compare_exchange_weak(pending, pending - 1, std::memory_order_relaxed)) {} + } + bool Initialized = false; + std::size_t max_packet_size{}; + std::size_t max_packet_count{}; + std::atomic pending_count{}; + std::atomic dropped_count{}; + std::atomic capacity_dropped_count{}; + std::atomic rebuild_dropped_count{}; + std::atomic consumer_dropped_count{}; + std::atomic pushed_count{}; + Psc::RingBuffer_ST buffer; + std::vector read_buffer; +}; +class Bounded_Vector_Double_Input_Buffer { +public: + void push(const QVector& data, std::size_t max_packet_count) { + buffer.push(data.constData(), static_cast(data.size()) * sizeof(double), max_packet_count); + } + template + void read_all(Handler handler) { + buffer.read_all([this, &handler](const void* data, std::size_t size) { + vector_buffer.resize(static_cast(size / sizeof(double))); + std::memcpy(vector_buffer.data(), data, size); + handler(vector_buffer); + }); + } + void clear() { + buffer.clear(); + } + [[nodiscard]] std::uint64_t pending_count() const { + return buffer.get_pending_count(); + } + [[nodiscard]] std::uint64_t dropped_count() const { + return buffer.get_dropped_count(); + } + [[nodiscard]] std::uint64_t capacity_dropped_count() const { + return buffer.get_capacity_dropped_count(); + } + [[nodiscard]] std::uint64_t rebuild_dropped_count() const { + return buffer.get_rebuild_dropped_count(); + } + [[nodiscard]] std::uint64_t consumer_dropped_count() const { + return buffer.get_consumer_dropped_count(); + } + [[nodiscard]] std::uint64_t pushed_count() const { + return buffer.get_pushed_count(); + } + void record_consumer_dropped() { + buffer.record_consumer_dropped(); + } +private: + Bounded_Input_Buffer buffer; + QVector vector_buffer; +}; +class Bounded_Double_Input_Buffer { +public: + void push(double data, std::size_t max_packet_count) { + buffer.push(&data, sizeof(data), max_packet_count); + } + template + void read_all(Handler handler) { + buffer.read_all([this, &handler](const void* data, std::size_t size) { + (void)size; + std::memcpy(&value_buffer, data, sizeof(value_buffer)); + handler(value_buffer); + }); + } + void clear() { + buffer.clear(); + } + [[nodiscard]] std::uint64_t pending_count() const { + return buffer.get_pending_count(); + } + [[nodiscard]] std::uint64_t dropped_count() const { + return buffer.get_dropped_count(); + } + [[nodiscard]] std::uint64_t capacity_dropped_count() const { + return buffer.get_capacity_dropped_count(); + } + [[nodiscard]] std::uint64_t rebuild_dropped_count() const { + return buffer.get_rebuild_dropped_count(); + } + [[nodiscard]] std::uint64_t consumer_dropped_count() const { + return buffer.get_consumer_dropped_count(); + } + [[nodiscard]] std::uint64_t pushed_count() const { + return buffer.get_pushed_count(); + } + void record_consumer_dropped() { + buffer.record_consumer_dropped(); + } +private: + Bounded_Input_Buffer buffer; + double value_buffer{}; +}; +} diff --git a/Renderive/architecture/Plot.cpp b/Renderive/architecture/Plot.cpp new file mode 100644 index 0000000..aad0d1d --- /dev/null +++ b/Renderive/architecture/Plot.cpp @@ -0,0 +1,863 @@ +#include +#include +#include +#include "../base/global.h" +#include "../plottable/Performance_Shower_p.h" +#include "Plot_p.h" +namespace renderive { +static std::uint64_t steady_now_ns() { + return static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); +} +static double elapsed_ms(std::uint64_t start_ns, std::uint64_t end_ns) { + return static_cast(end_ns - start_ns) / 1000000.0; +} +static QString job_state_text(Renderable::Job_State state) { + switch (state) { + case Renderable::Job_State::Idle: + return "Idle"; + case Renderable::Job_State::Queued: + return "Queued"; + case Renderable::Job_State::Running: + return "Running"; + } + return {}; +} +static QString renderable_name(Renderable* able) { + if (!able->object_name.isEmpty()) + return able->object_name; + return QString::number(reinterpret_cast(able), 16); +} +static std::shared_ptr performance_shower_owner(Plot_Private* data) { + if (!data || !data->q) + return {}; + auto context = data->q->get_render_context(); + if (!context) + return {}; + std::lock_guard lock(context->mutex); + return context->performance_shower_value; +} +static QString acquire_mode_text(Plot_Buffer_Acquire_Mode mode) { + return mode == Plot_Buffer_Acquire_Mode::Wait ? "Wait" : "Try"; +} +static QString plot_schedule_mode_text(Plot_Render_Schedule_Mode mode) { + switch (mode) { + case Plot_Render_Schedule_Mode::Timer_Check: + return "Timer_Check"; + case Plot_Render_Schedule_Mode::Chase_Latest: + return "Chase_Latest"; + case Plot_Render_Schedule_Mode::Max_Fps: + return "Max_Fps"; + case Plot_Render_Schedule_Mode::Manual: + return "Manual"; + } + return {}; +} +static QString renderable_schedule_mode_text(Renderable_Render_Schedule_Mode mode) { + switch (mode) { + case Renderable_Render_Schedule_Mode::Inherit: + return "Inherit"; + case Renderable_Render_Schedule_Mode::Chase_Latest: + return "Chase_Latest"; + case Renderable_Render_Schedule_Mode::Max_Fps: + return "Max_Fps"; + case Renderable_Render_Schedule_Mode::On_Dirty: + return "On_Dirty"; + case Renderable_Render_Schedule_Mode::Manual: + return "Manual"; + } + return {}; +} +static QString renderable_cache_mode_text(Renderable_Cache_Mode mode) { + switch (mode) { + case Renderable_Cache_Mode::Direct: + return "Direct"; + case Renderable_Cache_Mode::Local_Pixel: + return "Local_Pixel"; + } + return {}; +} +static void publish_triple_buffer_stats(Performance_Shower* shower, const QString& name, const Triple_Buffer_Stats& stats) { + if (!shower || !shower->enabled()) + return; + shower->set_gauge("Buffer", name + ".markSuccess", static_cast(stats.mark_success.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".markBusy", static_cast(stats.mark_busy.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".markStateChanged", static_cast(stats.mark_state_changed.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".swapSuccess", static_cast(stats.swap_success.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".swapBusy", static_cast(stats.swap_busy.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".swapStateChanged", static_cast(stats.swap_state_changed.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".swapNoNeed", static_cast(stats.swap_condition_failed.load(std::memory_order_relaxed))); + shower->set_gauge("Buffer", name + ".wait", static_cast(stats.wait_count.load(std::memory_order_relaxed))); +} +static void publish_renderable_buffer_stats(Performance_Shower* shower, Renderable* able) { + if (!shower || !shower->enabled()) + return; + if (able == shower) + return; + QString name = renderable_name(able); + shower->set_state("Renderable", name + ".buffer_acquire_mode", acquire_mode_text(able->get_buffer_acquire_mode())); + shower->set_state("Renderable", name + ".render_schedule_mode", renderable_schedule_mode_text(able->get_render_schedule_mode())); + shower->set_state("Renderable", name + ".cache_mode", renderable_cache_mode_text(able->get_cache_mode())); + shower->set_gauge("Renderable", name + ".render_schedule_max_fps", able->get_render_schedule_max_fps()); + std::uint64_t input_pending = 0; + std::uint64_t input_dropped = 0; + std::uint64_t input_capacity_dropped = 0; + std::uint64_t input_rebuild_dropped = 0; + std::uint64_t input_consumer_dropped = 0; + std::uint64_t input_pushed = 0; + for (const Input_Buffer_Slot& slot : able->d_ptr->input_buffers) { + if (!slot.data) + continue; + input_pending += slot.data->get_pending_count(); + input_dropped += slot.data->get_dropped_count(); + input_capacity_dropped += slot.data->get_capacity_dropped_count(); + input_rebuild_dropped += slot.data->rebuild_dropped_count(); + input_consumer_dropped += slot.data->consumer_dropped_count(); + input_pushed += slot.data->get_pushed_count(); + } + shower->set_gauge("Renderable", name + ".input_pending", static_cast(input_pending)); + shower->set_gauge("Renderable", name + ".input_dropped", static_cast(input_dropped)); + shower->set_gauge("Renderable", name + ".input_capacity_dropped", static_cast(input_capacity_dropped)); + shower->set_gauge("Renderable", name + ".input_rebuild_dropped", static_cast(input_rebuild_dropped)); + shower->set_gauge("Renderable", name + ".input_consumer_dropped", static_cast(input_consumer_dropped)); + shower->set_gauge("Renderable", name + ".input_pushed", static_cast(input_pushed)); + shower->set_gauge("Renderable", name + ".pixel_cache_area", static_cast(able->cache_image_area())); + shower->set_gauge("Renderable", name + ".pixel_cache_bytes", static_cast(able->cache_image_bytes())); + publish_triple_buffer_stats(shower, name + ".State", able->d_ptr->state_buffer_stats); + publish_triple_buffer_stats(shower, name + ".Input", able->d_ptr->input_buffer_stats); +} +static void publish_pipeline_stats(Plot_Private* data) { + auto shower_owner = performance_shower_owner(data); + Performance_Shower* shower = shower_owner.get(); + if (!shower || !shower->enabled()) + return; + Renderable::Render_Pipeline& pipeline = data->pipeline; + shower->set_state("Pipeline", "jobState", job_state_text(pipeline.job_state)); + shower->set_state("Pipeline", "render_schedule_mode", plot_schedule_mode_text(data->render_schedule_mode.load(std::memory_order_acquire))); + shower->set_state("Pipeline", "paint_buffer_acquire_mode", acquire_mode_text(data->paint_buffer_acquire_mode.load(std::memory_order_acquire))); + shower->set_state("Pipeline", "renderable_buffer_acquire_mode", acquire_mode_text(data->renderable_buffer_acquire_mode.load(std::memory_order_acquire))); + shower->set_gauge("Pipeline", "refresh_times_pre_second", static_cast(data->refresh_times_pre_second)); + shower->set_gauge("Pipeline", "max_render_fps", data->max_render_fps.load(std::memory_order_acquire)); + shower->set_gauge("Pipeline", "active_render_tasks", data->active_render_tasks.load(std::memory_order_acquire)); + shower->set_gauge("Pipeline", "renderEnabled", data->render_enabled.load(std::memory_order_acquire) ? 1.0 : 0.0); + shower->set_gauge("Pipeline", "render_submit_pending", data->render_submit_pending.load(std::memory_order_acquire) ? 1.0 : 0.0); + shower->set_gauge("Pipeline", "paint_request_pending", pipeline.paint_request_pending.load(std::memory_order_acquire) ? 1.0 : 0.0); + shower->set_gauge("Pipeline", "edit_state_version", static_cast(pipeline.edit_state_version.load(std::memory_order_acquire))); + shower->set_gauge("Pipeline", "render_state_version", static_cast(pipeline.render_state_version)); + publish_triple_buffer_stats(shower, "color_buffer_stats", pipeline.color_buffer_stats); +} +static void notify_render_task_done(Plot_Private* data) { + if (data->active_render_tasks.fetch_sub(1, std::memory_order_acq_rel) == 1) + data->render_task_done.notify_all(); +} +void start_render_scheduler() { + Global::instance()->start_render_scheduler(); +} +Abs_Plot::Abs_Plot() { + d = new Plot_Private(this); + render_context = std::make_shared(); + { + std::lock_guard lock(render_context->mutex); + render_context->background_color = d->background; + render_context->refresh_times_per_second = d->refresh_times_pre_second; + render_context->plot = this; + } + setAttribute(Qt::WA_OpaquePaintEvent, true); + setMouseTracking(true); + setFocusPolicy(Qt::NoFocus); + Global::instance()->render_scheduler().register_plot(this); +} +void Abs_Plot::init() { + init_renderable_tree(); +} +void Abs_Plot::init_renderable_tree() { + root_renderable = std::make_shared(); + root_renderable->object_name = "Root_Renderable"; + root_renderable->init_root(this); +} +bool Abs_Plot::get_use_performance_shower() { + auto shower = performance_shower_owner(d); + return shower && shower->enabled(); +} +void Abs_Plot::remove_renderable(const std::shared_ptr& able) { + if (!able || able->plot != this) + return; + if (able == root_renderable) + return; + std::shared_ptr parent = able->parent_renderable.lock(); + if (parent) + parent->remove_child(able); + { + std::lock_guard lock(render_context->mutex); + if (render_context->performance_shower_value.get() == able.get()) + render_context->performance_shower_value.reset(); + } + mark_render_state_dirty(); +} +void Abs_Plot::set_use_performance_shower(bool use) { + auto shower = performance_shower_owner(d); + if (!shower && use) { + auto created_shower = std::make_shared(); + created_shower->init(root_renderable); + std::lock_guard lock(render_context->mutex); + render_context->performance_shower_value = created_shower; + } + shower = performance_shower_owner(d); + if (shower) + shower->setEnabled(use); +} +Abs_Plot::~Abs_Plot() { + { + std::lock_guard lock(render_context->mutex); + d->destroying.store(true, std::memory_order_release); + render_context->destroying.store(true, std::memory_order_release); + render_context->plot = nullptr; + } + d->render_enabled.store(false, std::memory_order_release); + Global::instance()->render_scheduler().remove_plot(this); + { + std::unique_lock lock(d->render_task_mutex); + d->render_task_done.wait(lock, [this]() { + return d->active_render_tasks.load(std::memory_order_acquire) == 0; + }); + } + { + std::lock_guard lock(renderable_mutex); + if (root_renderable) + root_renderable->detach_from_plot_tree(); + root_renderable.reset(); + } + { + std::lock_guard lock(render_context->mutex); + render_context->performance_shower_value.reset(); + } + render_context.reset(); + delete d; +} +std::shared_ptr Abs_Plot::get_render_context() const { + return render_context; +} +std::shared_ptr Abs_Plot::get_root_renderable() const { + return root_renderable; +} +std::shared_ptr Abs_Plot::create_renderable_node(const std::shared_ptr& parent, const QString& object_name) { + if (!parent || parent->plot != this) { + ASSERT(parent && parent->plot == this, "Abs_Plot create_renderable_node error! parent invalid"); + return {}; + } + auto able = std::make_shared(); + able->object_name = object_name; + able->init(parent); + return able; +} +Abs_Plot::Renderable_Snapshot Abs_Plot::renderable_snapshot() const { + std::lock_guard lock(renderable_mutex); + Renderable_Snapshot snapshot; + append_renderable_snapshot(snapshot, root_renderable); + return snapshot; +} +void Abs_Plot::append_renderable_snapshot(Renderable_Snapshot& snapshot, const std::shared_ptr& able) const { + if (!able) + return; + snapshot.append(able); + QVector> children = able->children_snapshot(); + for (const auto& child : children) + append_renderable_snapshot(snapshot, child); +} +std::shared_ptr Abs_Plot::render_snapshot() const { + auto snapshot = std::make_shared(); + snapshot->context = render_context; + if (!render_context) + return snapshot; + std::lock_guard lock(render_context->mutex); + snapshot->size = render_context->render_size; + snapshot->background_color = render_context->background_color; + snapshot->refresh_times_per_second = render_context->refresh_times_per_second; + snapshot->performance_shower = render_context->performance_shower_value; + return snapshot; +} +bool Abs_Plot::is_rendering() { + return d->render_enabled.load(std::memory_order_acquire); +} +void Abs_Plot::start_render(int refresh_times_per_second) { + set_render_check_fps(refresh_times_per_second); + start_render(); +} +void Abs_Plot::start_render() const { + if (d->destroying.load(std::memory_order_acquire)) + return; + d->render_enabled.store(true, std::memory_order_release); + Abs_Plot * self = const_cast(this); + Plot_Private* private_data = d; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + Global::instance()->render_scheduler().post([self, private_data]() { + Plot_Private* d = self->d; + if (!d->destroying.load(std::memory_order_acquire)) { + if (d->render_timer) { + d->render_timer->cancel(); + self->schedule_render_timer(); + } + self->on_render_request(Render_Request_Source::Dirty); + } + notify_render_task_done(private_data); + }); +} +void Abs_Plot::pause_render() const { + d->render_enabled.store(false, std::memory_order_release); + if (d->destroying.load(std::memory_order_acquire)) + return; + Abs_Plot * self = const_cast(this); + Plot_Private* private_data = d; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + Global::instance()->render_scheduler().post([self, private_data]() { + Plot_Private* d = self->d; + if (!d->destroying.load(std::memory_order_acquire)) { + if (d->render_timer) { + d->render_timer->cancel(); + } + if (d->submit_timer) { + d->submit_timer->cancel(); + d->submit_timer_target_ns = 0; + d->render_submit_pending.store(false, std::memory_order_release); + } + } + notify_render_task_done(private_data); + }); +} +void Abs_Plot::paintEvent(QPaintEvent* event) { + Q_UNUSED(event) + auto shower_owner = performance_shower_owner(d); + Performance_Shower* shower = shower_owner.get(); + Performance_Scope_Timer paint_data("Pipeline", "paintEvent", shower); + std::uint64_t paint_ns = steady_now_ns(); + std::uint64_t update_request_ns = d->last_update_request_ns.exchange(0, std::memory_order_acq_rel); + if (update_request_ns && shower) + shower->record_duration("Pipeline", "updateToPaint", elapsed_ms(update_request_ns, paint_ns)); + QPainter painter(this); + auto mode = to_triple_buffer_mode(d->paint_buffer_acquire_mode.load(std::memory_order_acquire)); + bool color_lease_acquired = false; + { + Performance_Scope_Timer consume_data("Buffer", "Color.consumeReady", shower); + auto color_lease = d->pipeline.consume_ready_color(mode); + color_lease_acquired = static_cast(color_lease); + Renderable::Color_Buffer* color = color_lease.buffer; + if (color && !color->image.isNull()) + painter.drawImage(QPoint(0, 0), color->image); + else + painter.fillRect(rect(), d->background); + } + painter.end(); + if (shower) { + if (color_lease_acquired) + shower->increment_counter("Buffer", "Color.frontLeaseSuccess"); + else + shower->increment_counter("Buffer", "Color.frontLeaseMiss"); + shower->increment_counter("Pipeline", "paint"); + publish_pipeline_stats(d); + } +} +void Abs_Plot::render() { + request_render(Render_Request_Source::Manual); +} +Plot_Buffer_Acquire_Mode Abs_Plot::get_paint_buffer_acquire_mode() const { + return d->paint_buffer_acquire_mode.load(std::memory_order_acquire); +} +void Abs_Plot::set_paint_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode) { + d->paint_buffer_acquire_mode.store(mode, std::memory_order_release); +} +Plot_Buffer_Acquire_Mode Abs_Plot::get_renderable_buffer_acquire_mode() const { + return d->renderable_buffer_acquire_mode.load(std::memory_order_acquire); +} +void Abs_Plot::set_renderable_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode) { + d->renderable_buffer_acquire_mode.store(mode, std::memory_order_release); +} +Plot_Render_Schedule_Mode Abs_Plot::get_render_schedule_mode() const { + return d->render_schedule_mode.load(std::memory_order_acquire); +} +void Abs_Plot::set_render_schedule_mode(Plot_Render_Schedule_Mode mode) { + d->render_schedule_mode.store(mode, std::memory_order_release); + if (mode == Plot_Render_Schedule_Mode::Max_Fps && d->max_render_fps.load(std::memory_order_acquire) <= 0.0) + d->max_render_fps.store(get_render_check_fps(), std::memory_order_release); + request_render(Render_Request_Source::Dirty); +} +double Abs_Plot::get_render_check_fps() const { + return static_cast(d->refresh_times_pre_second); +} +void Abs_Plot::set_render_check_fps(double fps) { + d->refresh_times_pre_second = qMax(1, qRound(fps)); + std::lock_guard lock(render_context->mutex); + render_context->refresh_times_per_second = d->refresh_times_pre_second; +} +double Abs_Plot::get_max_render_fps() const { + return d->max_render_fps.load(std::memory_order_acquire); +} +void Abs_Plot::set_max_render_fps(double fps) { + d->max_render_fps.store(fps, std::memory_order_release); +} +bool Abs_Plot::submit_render_once() { + Render_Scheduler& scheduler = Global::instance()->render_scheduler(); + if (!scheduler.is_scheduler_thread()) { + Plot_Private* private_data = d; + std::uint64_t post_ns = steady_now_ns(); + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + scheduler.post([this, private_data, post_ns]() { + auto shower = performance_shower_owner(private_data); + if (shower) + shower->record_duration("Pipeline", "schedulerQueueWait", elapsed_ms(post_ns, steady_now_ns())); + if (!private_data->destroying.load(std::memory_order_acquire)) + submit_render_once(); + notify_render_task_done(private_data); + }); + return false; + } + if (d->destroying.load(std::memory_order_acquire)) + return false; + std::uint64_t submit_ns = steady_now_ns(); + Render_Request_Source source = d->submit_source; + std::uint64_t request_ns = d->last_request_ns.exchange(0, std::memory_order_acq_rel); + { + auto shower = performance_shower_owner(d); + if (request_ns && shower) + shower->record_duration("Pipeline", "request_to_submit", elapsed_ms(request_ns, submit_ns)); + } + if (first_resize) + return false; + if (!d->render_enabled.load(std::memory_order_acquire)) + return false; + auto frame_snapshot = render_snapshot(); + if (frame_snapshot->destroying()) + return false; + QSize render_size = frame_snapshot->size; + if (render_size.width() <= 0 || render_size.height() <= 0) + return false; + Renderable::Render_Pipeline& pipeline = d->pipeline; + if (pipeline.job_state != Renderable::Job_State::Idle) + return false; + auto snapshot = renderable_snapshot(); + auto root = get_root_renderable(); + if (!root) + return false; + if (!first_prepare_data && !pipeline.has_new_state()) + return false; + pipeline.job_state = Renderable::Job_State::Queued; + pipeline.render_state_version = pipeline.edit_state_version.load(std::memory_order_acquire); + Performance_Shower* shower = frame_snapshot->performance_shower.get(); + if (shower) { + shower->increment_counter("Pipeline", "renderFrame"); + shower->set_info("interval", QString("渲染:%1, global:%2").arg(qRound(1000.0 / (double)frame_snapshot->refresh_times_per_second)).arg(Global::instance()->interval)); + publish_pipeline_stats(d); + } + { + Performance_Scope_Timer prepare_data("Pipeline", "prepare_data", shower); + for (const auto& cur : snapshot) { + if (!cur || cur->get_retiring() || !cur->visible || !cur->d_ptr) + continue; + if (!renderable_ready_for_submit(cur, source, submit_ns)) + continue; + if (!cur->prepared) { + { + Performance_Scope_Timer renderable_prepare("Renderable", renderable_name(cur.get()) + ".prepare_data", shower); + cur->prepare_data(*frame_snapshot); + } + mark_renderable_submitted(cur, submit_ns); + publish_renderable_buffer_stats(shower, cur.get()); + cur->prepared = true; + } + } + if (first_prepare_data) { + first_prepare_data = false; + render_context->first_prepare_data.store(false, std::memory_order_release); + } + } + for (const auto& able : snapshot) { + if (able) + able->prepared = false; + } + Renderable::Color_Buffer_Lease color_lease; + { + Performance_Scope_Timer wait_render_color("Buffer", "Color.waitRenderLease", shower); + color_lease = pipeline.wait_render_color(); + } + Renderable::Color_Buffer* color = color_lease.buffer; + auto color_lease_owner = std::make_shared(std::move(color_lease)); + std::uint64_t version = pipeline.render_state_version; + pipeline.job_state = Renderable::Job_State::Running; + if (shower) + publish_pipeline_stats(d); + Plot_Private* private_data = d; + std::uint64_t cpu_post_ns = steady_now_ns(); + auto renderable_snapshot_owner = std::make_shared(std::move(snapshot)); + Abs_Plot * plot = this; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + scheduler.post_cpu([private_data, color_lease_owner, color, version, cpu_post_ns, root, renderable_snapshot_owner, frame_snapshot, plot]() { + if (frame_snapshot->performance_shower) + frame_snapshot->performance_shower->record_duration("Pipeline", "cpuQueueWait", elapsed_ms(cpu_post_ns, steady_now_ns())); + if (private_data->destroying.load(std::memory_order_acquire)) { + color_lease_owner->reset(); + notify_render_task_done(private_data); + return; + } + Abs_Plot::render_color(color, version, root, *renderable_snapshot_owner, *frame_snapshot); + color_lease_owner->reset(); + if (private_data->destroying.load(std::memory_order_acquire)) { + notify_render_task_done(private_data); + return; + } + Global::instance()->render_scheduler().post([plot, private_data]() { + if (!private_data->destroying.load(std::memory_order_acquire)) + plot->finish_render(); + notify_render_task_done(private_data); + }); + }); + return true; +} +void Abs_Plot::on_render_request(Render_Request_Source source) { + if (d->destroying.load(std::memory_order_acquire)) + return; + Plot_Render_Schedule_Mode mode = d->render_schedule_mode.load(std::memory_order_acquire); + d->submit_source = source; + switch (mode) { + case Plot_Render_Schedule_Mode::Timer_Check: + if (source == Render_Request_Source::Timer) + submit_render_once(); + break; + case Plot_Render_Schedule_Mode::Chase_Latest: + submit_render_once(); + break; + case Plot_Render_Schedule_Mode::Max_Fps: + submit_render_with_fps_limit(); + break; + case Plot_Render_Schedule_Mode::Manual: + if (source == Render_Request_Source::Manual) + submit_render_once(); + break; + } + if (performance_shower_owner(d)) + publish_pipeline_stats(d); +} +bool Abs_Plot::submit_render_with_fps_limit() { + double fps = d->max_render_fps.load(std::memory_order_acquire); + if (fps <= 0.0) + return submit_render_once(); + std::uint64_t now = steady_now_ns(); + std::uint64_t interval_ns = static_cast(1000000000.0 / fps); + if (now < d->next_submit_ns) { + d->render_submit_pending.store(true, std::memory_order_release); + schedule_max_fps_submit(d->next_submit_ns); + return false; + } + bool submitted = submit_render_once(); + if (submitted) { + d->next_submit_ns = now + interval_ns; + d->render_submit_pending.store(false, std::memory_order_release); + } + else if (!d->pipeline.has_new_state()) { + d->render_submit_pending.store(false, std::memory_order_release); + } + return submitted; +} +void Abs_Plot::schedule_max_fps_submit(std::uint64_t target_ns) { + if (!d->submit_timer || !d->render_enabled.load(std::memory_order_acquire)) + return; + if (d->submit_timer_target_ns && d->submit_timer_target_ns <= target_ns) + return; + d->submit_timer_target_ns = target_ns; + std::uint64_t now = steady_now_ns(); + std::uint64_t delay_ns = target_ns > now ? target_ns - now : 0; + d->submit_timer->expires_after(std::chrono::nanoseconds(delay_ns)); + Plot_Private* private_data = d; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + d->submit_timer->async_wait([this, private_data, target_ns](const asio::error_code& error) { + if (!error && !private_data->destroying.load(std::memory_order_acquire) && private_data->submit_timer_target_ns == target_ns) { + private_data->submit_timer_target_ns = 0; + if (private_data->render_submit_pending.load(std::memory_order_acquire)) + on_render_request(private_data->submit_source); + } + notify_render_task_done(private_data); + }); +} +bool Abs_Plot::renderable_ready_for_submit(const std::shared_ptr& able, Render_Request_Source source, std::uint64_t now_ns) { + if (!able || able->get_retiring()) + return false; + Renderable_Render_Schedule_Mode mode = able->get_render_schedule_mode(); + if (mode == Renderable_Render_Schedule_Mode::Inherit) { + switch (d->render_schedule_mode.load(std::memory_order_acquire)) { + case Plot_Render_Schedule_Mode::Timer_Check: + return source == Render_Request_Source::Timer; + case Plot_Render_Schedule_Mode::Chase_Latest: + return true; + case Plot_Render_Schedule_Mode::Max_Fps: + return true; + case Plot_Render_Schedule_Mode::Manual: + return source == Render_Request_Source::Manual; + } + } + switch (mode) { + case Renderable_Render_Schedule_Mode::Inherit: + return true; + case Renderable_Render_Schedule_Mode::Chase_Latest: + return true; + case Renderable_Render_Schedule_Mode::Max_Fps: { + double fps = able->get_render_schedule_max_fps(); + if (fps <= 0.0) + return true; + std::uint64_t next_ns = able->d_ptr->next_render_submit_ns.load(std::memory_order_acquire); + if (now_ns >= next_ns) + return true; + d->render_submit_pending.store(true, std::memory_order_release); + schedule_max_fps_submit(next_ns); + return false; + } + case Renderable_Render_Schedule_Mode::On_Dirty: + return source == Render_Request_Source::Dirty || source == Render_Request_Source::Finish || source == Render_Request_Source::Manual; + case Renderable_Render_Schedule_Mode::Manual: + return source == Render_Request_Source::Manual; + } + return true; +} +void Abs_Plot::mark_renderable_submitted(const std::shared_ptr& able, std::uint64_t now_ns) { + if (able->get_render_schedule_mode() != Renderable_Render_Schedule_Mode::Max_Fps) + return; + double fps = able->get_render_schedule_max_fps(); + if (fps <= 0.0) + return; + able->d_ptr->next_render_submit_ns.store(now_ns + static_cast(1000000000.0 / fps), std::memory_order_release); +} +void Abs_Plot::finish_render() { + if (d->destroying.load(std::memory_order_acquire)) + return; + Renderable::Render_Pipeline& pipeline = d->pipeline; + QRegion update_region; + auto shower_owner = performance_shower_owner(d); + Performance_Shower* shower = shower_owner.get(); + { + Performance_Scope_Timer publish_data("Pipeline", "publish_render_color", shower); + update_region = pipeline.publish_render_color(); + } + pipeline.job_state = Renderable::Job_State::Idle; + if (shower) + publish_pipeline_stats(d); + if (!update_region.isEmpty()) + request_update(update_region); + on_render_request(Render_Request_Source::Finish); +} +void Abs_Plot::render_color(Renderable::Color_Buffer* color, std::uint64_t version, const std::shared_ptr& root, const Renderable_Snapshot& snapshot, const Plot_Render_Snapshot& render_snapshot_data) { + Performance_Scope_Timer render_data("Pipeline", "render_color", render_snapshot_data.performance_shower.get()); + QSize size = render_snapshot_data.size; + if (color->image.size() != size || color->image.format() != QImage::Format_ARGB32) { + color->image = QImage(size, QImage::Format_ARGB32); + } + color->image.detach(); + color->image.fill(render_snapshot_data.background_color); + QPainter painter(&color->image); + int renderable_count = 0; + int visible_renderable_count = 0; + int direct_draw_count = 0; + int local_cache_count = 0; + { + Performance_Scope_Timer draw_data("Pipeline", "draw", render_snapshot_data.performance_shower.get()); + for (const auto& cur : snapshot) { + ++renderable_count; + if (!cur || cur->get_retiring() || !cur->visible) + continue; + ++visible_renderable_count; + if (cur->get_cache_mode() == Renderable_Cache_Mode::Local_Pixel) + ++local_cache_count; + else + ++direct_draw_count; + } + if (root) { + Performance_Scope_Timer renderable_draw("Renderable", renderable_name(root.get()) + ".render", render_snapshot_data.performance_shower.get()); + root->render(&painter, render_snapshot_data); + } + } + painter.end(); + color->version.store(version, std::memory_order_release); + color->dirty_region = QRegion(QRect(QPoint(0, 0), size)); + if (render_snapshot_data.performance_shower) { + double area = static_cast(size.width()) * static_cast(size.height()); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_render_area", area); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_render_full_ratio", area > 0.0 ? 1.0 : 0.0); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_root_child_count", root ? static_cast(root->children_snapshot().size()) : 0.0); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_renderable_count", static_cast(renderable_count)); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_visible_renderable_count", static_cast(visible_renderable_count)); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_direct_draw_count", static_cast(direct_draw_count)); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_local_cache_count", static_cast(local_cache_count)); + render_snapshot_data.performance_shower->set_gauge("Pipeline", "main_state_lease_miss_count", 0.0); + } +} +void Abs_Plot::schedule_render_timer() { + if (d->destroying.load(std::memory_order_acquire) || !d->render_timer || !d->render_enabled.load(std::memory_order_acquire)) + return; + int interval = std::max(1, qRound(1000.0 / (double)d->refresh_times_pre_second)); + d->render_timer->expires_after(std::chrono::milliseconds(interval)); + Plot_Private* private_data = d; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + d->render_timer->async_wait([this, private_data](const asio::error_code& error) { + if (!error && !d->destroying.load(std::memory_order_acquire)) { + auto shower = performance_shower_owner(private_data); + if (shower) + shower->increment_counter("Pipeline", "timerTick"); + on_render_request(Render_Request_Source::Timer); + schedule_render_timer(); + } + notify_render_task_done(private_data); + }); +} +void Abs_Plot::mark_render_state_dirty() { + if (d->destroying.load(std::memory_order_acquire)) + return; + d->pipeline.mark_edit_state(); + request_render(); +} +void Abs_Plot::request_render(Render_Request_Source source) { + if (d->destroying.load(std::memory_order_acquire)) + return; + d->last_request_ns.store(steady_now_ns(), std::memory_order_release); + Plot_Private* private_data = d; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + Global::instance()->render_scheduler().post([this, private_data, source]() { + if (!d->destroying.load(std::memory_order_acquire)) + on_render_request(source); + notify_render_task_done(private_data); + }); +} +void Abs_Plot::request_update(const QRegion& region) { + d->last_update_request_ns.store(steady_now_ns(), std::memory_order_release); + QTimer::singleShot(0, this, [this, region]() { + if (d->destroying.load(std::memory_order_acquire)) + return; + if (region.isEmpty()) + update(); + else + update(region); + }); +} +QColor Abs_Plot::background_color() { + std::lock_guard lock(render_context->mutex); + return render_context->background_color; +} +void Abs_Plot::set_background_color(const QColor& color) const { + d->background = color; + std::lock_guard lock(render_context->mutex); + render_context->background_color = color; + const_cast(this)->mark_render_state_dirty(); +} +bool Abs_Plot::event(QEvent* event) { + bool ret = QWidget::event(event); + switch (event->type()) { + case QEvent::Resize: { + auto e = reinterpret_cast(event); + QSize render_size = e->size(); + d->pending_render_width.store(render_size.width(), std::memory_order_release); + d->pending_render_height.store(render_size.height(), std::memory_order_release); + Plot_Private* private_data = d; + private_data->active_render_tasks.fetch_add(1, std::memory_order_acq_rel); + Global::instance()->render_scheduler().post([this, private_data, render_size]() { + if (!private_data->destroying.load(std::memory_order_acquire)) { + private_data->render_size = render_size; + { + std::lock_guard lock(render_context->mutex); + render_context->render_size = render_size; + } + private_data->pipeline.mark_edit_state(); + on_render_request(Render_Request_Source::Dirty); + } + notify_render_task_done(private_data); + }); + if (first_resize) { + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->first_resize_event(e); + } + { + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->resizeEvent(e); + } + if (first_resize) + first_resize = false; + render_context->first_resize.store(false, std::memory_order_release); + mark_render_state_dirty(); + break; + } + case QEvent::Show: { + start_render(); + break; + } + case QEvent::Hide: { + pause_render(); + break; + } + case QEvent::Enter: { + break; + } + case QEvent::Leave: { + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->set_hover_state(QPoint(), false); + break; + } + case QEvent::Wheel: { + auto e = reinterpret_cast(event); + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->wheelEvent(e); + break; + } + case QEvent::MouseMove: { + auto e = reinterpret_cast(event); + auto snapshot = renderable_snapshot(); + auto root = get_root_renderable(); + auto hits = root ? root->hit_renderables(e->pos()) : Renderable_Snapshot{}; + for (const auto& able : snapshot) { + if (able) + able->set_hover_state(e->pos(), false); + } + for (const auto& able : hits) { + if (!able) + continue; + able->set_hover_state(e->pos(), true); + able->mouseMoveEvent(e); + } + break; + } + case QEvent::MouseButtonPress: { + auto e = reinterpret_cast(event); + auto root = get_root_renderable(); + auto hits = root ? root->hit_renderables(e->pos()) : Renderable_Snapshot{}; + for (const auto& able : hits) + able->mousePressEvent(e); + break; + } + case QEvent::MouseButtonRelease: { + auto e = reinterpret_cast(event); + auto root = get_root_renderable(); + auto hits = root ? root->hit_renderables(e->pos()) : Renderable_Snapshot{}; + for (const auto& able : hits) + able->mouseReleaseEvent(e); + break; + } + case QEvent::KeyPress: { + auto e = reinterpret_cast(event); + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->keyPressEvent(e); + break; + } + case QEvent::KeyRelease: { + auto e = reinterpret_cast(event); + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->keyReleaseEvent(e); + break; + } + default: + break; + } + auto snapshot = renderable_snapshot(); + for (const auto& able : snapshot) + able->plot_event(event); + return ret; +} +Plot::Plot() = default; +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Plot.h b/Renderive/architecture/Plot.h similarity index 66% rename from YSGraphic_Core/architecture/Plot.h rename to Renderive/architecture/Plot.h index 9c19f96..ace2a36 100644 --- a/YSGraphic_Core/architecture/Plot.h +++ b/Renderive/architecture/Plot.h @@ -5,7 +5,7 @@ #include #include "Plot_Render_Context.h" #include "Renderable.h" -namespace YSG { +namespace renderive { void LIB_DECL start_render_scheduler(); class Render_Scheduler; struct Plot_Private; @@ -15,7 +15,7 @@ class LIB_DECL Abs_Plot : public QWidget { Q_OBJECT public: /// 返回性能面板是否启用。 - bool use_performance_shower(); + bool get_use_performance_shower(); /// 启用或关闭性能面板。 void set_use_performance_shower(bool use); /// 初始化 Plot Renderable 根节点。 @@ -24,26 +24,26 @@ public: void render(); /// 返回背景颜色。 QColor background_color(); - std::shared_ptr render_context() const; - std::shared_ptr root_renderable() const; - std::shared_ptr create_renderable_node(const std::shared_ptr& parent, const QString& objectName = {}); + std::shared_ptr get_render_context() const; + std::shared_ptr get_root_renderable() const; + std::shared_ptr create_renderable_node(const std::shared_ptr& parent, const QString& object_name = {}); bool first_resize = true, first_prepare_data = true; /// 设置背景颜色。 void set_background_color(const QColor& color) const; /// paintEvent 消费颜色缓冲时的获取模式。 - Plot_Buffer_Acquire_Mode paint_buffer_acquire_mode() const; + Plot_Buffer_Acquire_Mode get_paint_buffer_acquire_mode() const; void set_paint_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode); /// Renderable 侧 State/Input 缓冲默认获取模式。 - Plot_Buffer_Acquire_Mode render_able_buffer_acquire_mode() const; - void set_render_able_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode); + Plot_Buffer_Acquire_Mode get_renderable_buffer_acquire_mode() const; + void set_renderable_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode); /// Plot 级渲染调度模式。 - Plot_Render_Schedule_Mode render_schedule_mode() const; + Plot_Render_Schedule_Mode get_render_schedule_mode() const; void set_render_schedule_mode(Plot_Render_Schedule_Mode mode); /// 调度检查定时器频率。 - double render_check_fps() const; + double get_render_check_fps() const; void set_render_check_fps(double fps); /// Plot 级最大提交帧率,0 表示不限速。 - double max_render_fps() const; + double get_max_render_fps() const; void set_max_render_fps(double fps); /// 标记 Plot 状态有新版本。 void mark_render_state_dirty(); @@ -57,7 +57,7 @@ public: /// 判断是否有 Plot 级 CPU 渲染任务运行。 bool is_rendering(); /// 启动渲染检查定时器。 - void start_render(int refreshTimesPreSecond); + void start_render(int refresh_times_per_second); /// 启动默认渲染检查定时器。 void start_render() const; /// 暂停自动渲染检查。 @@ -66,25 +66,25 @@ public: ~Abs_Plot() override; Plot_Private* d{}; private: - std::shared_ptr mRenderContext; - std::shared_ptr mRootRenderable; - mutable std::mutex mRenderableMutex; - using RenderableSnapshot = QVector>; + std::shared_ptr render_context; + std::shared_ptr root_renderable; + mutable std::mutex renderable_mutex; + using Renderable_Snapshot = QVector>; bool event(QEvent* event) final; void paintEvent(QPaintEvent* event) final; - RenderableSnapshot renderable_snapshot() const; - void append_renderable_snapshot(RenderableSnapshot& snapshot, const std::shared_ptr& able) const; + Renderable_Snapshot renderable_snapshot() const; + void append_renderable_snapshot(Renderable_Snapshot& snapshot, const std::shared_ptr& able) const; std::shared_ptr render_snapshot() const; void schedule_render_timer(); bool submit_render_once(); void on_render_request(Render_Request_Source source); bool submit_render_with_fps_limit(); - void schedule_max_fps_submit(std::uint64_t targetNs); - bool render_able_ready_for_submit(const std::shared_ptr& able, Render_Request_Source source, std::uint64_t nowNs); - void mark_render_able_submitted(const std::shared_ptr& able, std::uint64_t nowNs); + void schedule_max_fps_submit(std::uint64_t target_ns); + bool renderable_ready_for_submit(const std::shared_ptr& able, Render_Request_Source source, std::uint64_t now_ns); + void mark_renderable_submitted(const std::shared_ptr& able, std::uint64_t now_ns); void finish_render(); void request_update(const QRegion& region); - static void render_color(Renderable::Color_Buffer* color, std::uint64_t version, const std::shared_ptr& root, const RenderableSnapshot& snapshot, const Plot_Render_Snapshot& renderSnapshot); + static void render_color(Renderable::Color_Buffer* color, std::uint64_t version, const std::shared_ptr& root, const Renderable_Snapshot& snapshot, const Plot_Render_Snapshot& render_snapshot_data); friend class Render_Scheduler; friend struct Renderable; }; @@ -93,4 +93,4 @@ public: Plot(); ~Plot() override = default; }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Plot_Render_Context.h b/Renderive/architecture/Plot_Render_Context.h similarity index 52% rename from YSGraphic_Core/architecture/Plot_Render_Context.h rename to Renderive/architecture/Plot_Render_Context.h index a999251..1b00079 100644 --- a/YSGraphic_Core/architecture/Plot_Render_Context.h +++ b/Renderive/architecture/Plot_Render_Context.h @@ -4,28 +4,28 @@ #include #include #include -namespace YSG { +namespace renderive { class Abs_Plot; class Performance_Shower; struct Plot_Render_Context { std::atomic_bool destroying{false}; - std::atomic_bool firstResize{true}; - std::atomic_bool firstPrepareData{true}; + std::atomic_bool first_resize{true}; + std::atomic_bool first_prepare_data{true}; mutable std::mutex mutex; - QSize renderSize; - QColor backgroundColor = Qt::black; - int refreshTimesPerSecond = 30; - std::shared_ptr performanceShower; + QSize render_size; + QColor background_color = Qt::black; + int refresh_times_per_second = 30; + std::shared_ptr performance_shower_value; Abs_Plot* plot{}; }; struct Plot_Render_Snapshot { std::shared_ptr context; QSize size; - QColor backgroundColor = Qt::black; - int refreshTimesPerSecond = 30; - std::shared_ptr performanceShower; + QColor background_color = Qt::black; + int refresh_times_per_second = 30; + std::shared_ptr performance_shower; bool destroying() const { return !context || context->destroying.load(std::memory_order_acquire); } }; -} // namespace YSG +} // namespace renderive diff --git a/Renderive/architecture/Plot_p.h b/Renderive/architecture/Plot_p.h new file mode 100644 index 0000000..66ae7ff --- /dev/null +++ b/Renderive/architecture/Plot_p.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include +#include +#include +#include "Plot.h" +#include "asio.hpp" +namespace renderive { +struct Plot_Private { + explicit Plot_Private(Abs_Plot* plot) : q(plot) {}; + Abs_Plot* q{}; + int refresh_times_pre_second = 30; + std::unique_ptr render_timer; + std::unique_ptr submit_timer; + std::atomic_bool render_enabled{false}; + std::atomic_bool destroying{false}; + std::atomic render_schedule_mode{Plot_Render_Schedule_Mode::Chase_Latest}; + std::atomic max_render_fps{0.0}; + std::atomic_bool render_submit_pending{false}; + std::uint64_t next_submit_ns = 0; + std::uint64_t submit_timer_target_ns = 0; + Render_Request_Source submit_source = Render_Request_Source::Dirty; + std::atomic_int active_render_tasks{0}; + std::condition_variable render_task_done; + std::mutex render_task_mutex; + std::atomic_int pending_render_width{0}; + std::atomic_int pending_render_height{0}; + std::atomic last_request_ns{0}; + std::atomic last_update_request_ns{0}; + QSize render_size; + Renderable::Render_Pipeline pipeline; + std::atomic paint_buffer_acquire_mode{Plot_Buffer_Acquire_Mode::Try}; + std::atomic renderable_buffer_acquire_mode{Plot_Buffer_Acquire_Mode::Wait}; + QColor background = Qt::black; +}; +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Render_Config.h b/Renderive/architecture/Render_Config.h similarity index 96% rename from YSGraphic_Core/architecture/Render_Config.h rename to Renderive/architecture/Render_Config.h index c23de07..9e1fea8 100644 --- a/YSGraphic_Core/architecture/Render_Config.h +++ b/Renderive/architecture/Render_Config.h @@ -1,7 +1,7 @@ #pragma once #include #include "Triple_Buffer.h" -namespace YSG { +namespace renderive { /// 绘制或渲染线程获取三缓冲物理块时的策略。 enum class Plot_Buffer_Acquire_Mode : std::uint8_t { /// 缓冲被占用时立即放弃本次获取。 @@ -21,7 +21,7 @@ enum class Plot_Render_Schedule_Mode : std::uint8_t { Manual }; /// Renderable 级调度策略。 -enum class RenderAble_Render_Schedule_Mode : std::uint8_t { +enum class Renderable_Render_Schedule_Mode : std::uint8_t { /// 使用父 Plot 的调度策略。 Inherit, /// 本对象有新状态时尽快追到最新帧。 @@ -87,4 +87,4 @@ enum Color_Role : std::uint8_t { inline bool buffer_version_newer(std::uint64_t a, std::uint64_t b) { return static_cast(a - b) > 0; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Render_Data.cpp b/Renderive/architecture/Render_Data.cpp similarity index 55% rename from YSGraphic_Core/architecture/Render_Data.cpp rename to Renderive/architecture/Render_Data.cpp index 882df2f..5486215 100644 --- a/YSGraphic_Core/architecture/Render_Data.cpp +++ b/Renderive/architecture/Render_Data.cpp @@ -1,41 +1,39 @@ #include "Renderable_Core.h" -namespace YSG { +namespace renderive { QDebug operator<<(QDebug debug, const Range& range) { QDebugStateSaver saver(debug); debug.nospace() << "Range(" << range.origin << ", " << range.target << ")"; return debug; } -Render_Edit_Guard::Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease) : mData(data), mLease(lease) { -} +Render_Edit_Guard::Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease) : data(data), lease(lease) {} Render_Edit_Guard::~Render_Edit_Guard() { - if (!mData) + if (!data) return; - ++mData->state_by_index(mLease.index)->version; - if (mData->qPtr) - mData->qPtr->mark_render_dirty(); - mData->unmark_state(mLease); -} -Render_Input_Guard::Render_Input_Guard(Render_Data* data, Triple_Buffer_Lease lease) : mData(data), mLease(lease) { + ++data->state_by_index(lease.index)->version; + if (data->q_ptr) + data->q_ptr->mark_render_dirty(); + data->unmark_state(lease); } +Render_Input_Guard::Render_Input_Guard(Render_Data* data, Triple_Buffer_Lease lease) : data(data), lease(lease) {} Render_Input_Guard::~Render_Input_Guard() { - if (!mData) + if (!data) return; - mData->mark_input_dirty(mLease); - mData->mInputControl.unmark_use(mLease); + data->mark_input_dirty(lease); + data->input_control.unmark_use(lease); } -void Render_Data::mark_input_dirty(Triple_Buffer_Lease lease, bool notifyRender) { +void Render_Data::mark_input_dirty(Triple_Buffer_Lease lease, bool notify_render) { Input_Buffer_Slot& slot = input_slot_by_index(lease.index); - slot.version = ++mInputVersion; + slot.version = ++input_version; slot.pending = true; - if (notifyRender && qPtr) - qPtr->mark_render_dirty(); + if (notify_render && q_ptr) + q_ptr->mark_render_dirty(); } SRC Render_State::src() { - auto view = dPtr->mStateControl.read_view(); + auto view = d_ptr->state_control.read_view(); for (std::uint8_t role = State_Edit; role <= State_Render; ++role) { - if (dPtr->mStateBuffers[view[role]] == this) + if (d_ptr->state_buffers[view[role]] == this) return static_cast(role); } return SRC::Edit; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Render_Data.h b/Renderive/architecture/Render_Data.h similarity index 56% rename from YSGraphic_Core/architecture/Render_Data.h rename to Renderive/architecture/Render_Data.h index bbd6950..6f7ca65 100644 --- a/YSGraphic_Core/architecture/Render_Data.h +++ b/Renderive/architecture/Render_Data.h @@ -15,20 +15,19 @@ class QPainter; class QPointF; class QResizeEvent; class QWheelEvent; -namespace YSG { +namespace renderive { struct Render_Data; struct Renderable; struct Input_Data { virtual ~Input_Data() = default; - virtual void clear() { - } - virtual std::uint64_t pending_count() const { + virtual void clear() {} + virtual std::uint64_t get_pending_count() const { return 0; } - virtual std::uint64_t dropped_count() const { + virtual std::uint64_t get_dropped_count() const { return 0; } - virtual std::uint64_t capacity_dropped_count() const { + virtual std::uint64_t get_capacity_dropped_count() const { return 0; } virtual std::uint64_t rebuild_dropped_count() const { @@ -37,14 +36,14 @@ struct Input_Data { virtual std::uint64_t consumer_dropped_count() const { return 0; } - virtual std::uint64_t pushed_count() const { + virtual std::uint64_t get_pushed_count() const { return 0; } }; struct Render_State { virtual ~Render_State() = default; std::uint64_t version = 0; - Render_Data* dPtr{}; + Render_Data* d_ptr{}; SRC src(); }; struct Input_Buffer_Slot { @@ -54,102 +53,102 @@ struct Input_Buffer_Slot { }; struct Render_Data { Render_Data() { - mStateControl.set_stats(&mStateBufferStats); - mInputControl.set_stats(&mInputBufferStats); + state_control.set_stats(&state_buffer_stats); + input_control.set_stats(&input_buffer_stats); } - Renderable* qPtr{}; - bool mRenderStart = false; - Triple_Role_Buffer_Control mStateControl; - Triple_Buffer_Stats mStateBufferStats; - std::array mStateBuffers{}; - Triple_Role_Buffer_Control mInputControl; - Triple_Buffer_Stats mInputBufferStats; - std::array mInputBuffers{}; - std::uint64_t mInputVersion = 0; - std::atomic mBufferAcquireMode{Plot_Buffer_Acquire_Mode::Wait}; - std::atomic mRenderScheduleMode{RenderAble_Render_Schedule_Mode::Inherit}; - std::atomic mRenderScheduleMaxFps{0.0}; - std::atomic mNextRenderSubmitNs{0}; + Renderable* q_ptr{}; + bool render_start = false; + Triple_Role_Buffer_Control state_control; + Triple_Buffer_Stats state_buffer_stats; + std::array state_buffers{}; + Triple_Role_Buffer_Control input_control; + Triple_Buffer_Stats input_buffer_stats; + std::array input_buffers{}; + std::uint64_t input_version = 0; + std::atomic buffer_acquire_mode{Plot_Buffer_Acquire_Mode::Wait}; + std::atomic render_schedule_mode{Renderable_Render_Schedule_Mode::Inherit}; + std::atomic render_schedule_max_fps{0.0}; + std::atomic next_render_submit_ns{0}; Render_State* state(std::uint8_t role) const { - return state_by_index(mStateControl.read_view()[role]); + return state_by_index(state_control.read_view()[role]); } Render_State* state(SRC src) const { return state(static_cast(src)); } Render_State* state_by_index(std::uint8_t index) const { - return mStateBuffers[index]; + return state_buffers[index]; } - Plot_Buffer_Acquire_Mode buffer_acquire_mode() const { - return mBufferAcquireMode.load(std::memory_order_acquire); + Plot_Buffer_Acquire_Mode get_buffer_acquire_mode() const { + return buffer_acquire_mode.load(std::memory_order_acquire); } void set_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode) { - mBufferAcquireMode.store(mode, std::memory_order_release); + buffer_acquire_mode.store(mode, std::memory_order_release); } - RenderAble_Render_Schedule_Mode render_schedule_mode() const { - return mRenderScheduleMode.load(std::memory_order_acquire); + Renderable_Render_Schedule_Mode get_render_schedule_mode() const { + return render_schedule_mode.load(std::memory_order_acquire); } - void set_render_schedule_mode(RenderAble_Render_Schedule_Mode mode) { - mRenderScheduleMode.store(mode, std::memory_order_release); + void set_render_schedule_mode(Renderable_Render_Schedule_Mode mode) { + render_schedule_mode.store(mode, std::memory_order_release); } - double render_schedule_max_fps() const { - return mRenderScheduleMaxFps.load(std::memory_order_acquire); + double get_render_schedule_max_fps() const { + return render_schedule_max_fps.load(std::memory_order_acquire); } void set_render_schedule_max_fps(double fps) { - mRenderScheduleMaxFps.store(fps, std::memory_order_release); + render_schedule_max_fps.store(fps, std::memory_order_release); } Triple_Buffer_Lease mark_state_role(std::uint8_t role) { - if (buffer_acquire_mode() == Plot_Buffer_Acquire_Mode::Wait) { - return mStateControl.wait_mark_use_role(role); + if (get_buffer_acquire_mode() == Plot_Buffer_Acquire_Mode::Wait) { + return state_control.wait_mark_use_role(role); } - auto record = mStateControl.try_mark_use_role(role); + auto record = state_control.try_mark_use_role(role); if (record.result != Triple_Buffer_Result::Success) { return {}; } return record.lease; } void unmark_state(Triple_Buffer_Lease lease) { - mStateControl.unmark_use(lease); + state_control.unmark_use(lease); } void clear_state_buffers() { - for (Render_State*& state : mStateBuffers) { + for (Render_State*& state : state_buffers) { delete state; state = nullptr; } - mStateControl.reset(); + state_control.reset(); } Input_Data* input_data(std::uint8_t role) const { return input_slot(role).data; } Input_Data* input_data_by_index(std::uint8_t index) const { - return mInputBuffers[index].data; + return input_buffers[index].data; } Input_Buffer_Slot& input_slot(std::uint8_t role) { - return input_slot_by_index(mInputControl.read_view()[role]); + return input_slot_by_index(input_control.read_view()[role]); } const Input_Buffer_Slot& input_slot(std::uint8_t role) const { - return input_slot_by_index(mInputControl.read_view()[role]); + return input_slot_by_index(input_control.read_view()[role]); } Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) { - return mInputBuffers[index]; + return input_buffers[index]; } const Input_Buffer_Slot& input_slot_by_index(std::uint8_t index) const { - return mInputBuffers[index]; + return input_buffers[index]; } bool has_pending_state() const { - auto view = mStateControl.read_view(); - return buffer_version_newer(mStateBuffers[view[State_Edit]]->version, mStateBuffers[view[State_Render]]->version); + auto view = state_control.read_view(); + return buffer_version_newer(state_buffers[view[State_Edit]]->version, state_buffers[view[State_Render]]->version); } bool has_pending_input() const { - auto view = mInputControl.read_view(); - const Input_Buffer_Slot& edit = mInputBuffers[view[Input_Edit]]; - const Input_Buffer_Slot& ready = mInputBuffers[view[Input_Ready]]; - const Input_Buffer_Slot& render = mInputBuffers[view[Input_Render]]; + auto view = input_control.read_view(); + const Input_Buffer_Slot& edit = input_buffers[view[Input_Edit]]; + const Input_Buffer_Slot& ready = input_buffers[view[Input_Ready]]; + const Input_Buffer_Slot& render = input_buffers[view[Input_Render]]; return (edit.pending && buffer_version_newer(edit.version, render.version)) || (ready.pending && buffer_version_newer(ready.version, render.version)); } bool has_pending_render_data() const { return has_pending_state() || has_pending_input(); } - void mark_input_dirty(Triple_Buffer_Lease lease, bool notifyRender = true); + void mark_input_dirty(Triple_Buffer_Lease lease, bool notify_render = true); void clear_input_role(std::uint8_t role) { Input_Buffer_Slot& slot = input_slot(role); slot.data->clear(); @@ -159,14 +158,14 @@ struct Render_Data { clear_input_role(Input_Render); } void clear_input_buffers() { - for (Input_Buffer_Slot& slot : mInputBuffers) { + for (Input_Buffer_Slot& slot : input_buffers) { delete slot.data; slot.data = nullptr; slot.version = 0; slot.pending = false; } - mInputVersion = 0; - mInputControl.reset(); + input_version = 0; + input_control.reset(); } public: /// 同步 State/Input 的 ready 角色到 render 角色。 @@ -186,39 +185,28 @@ public: clear_input_buffers(); } /// 绘制当前已准备好的数据。 - virtual void draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) { - } + virtual void draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) {} /// 准备当前帧数据,默认只同步三缓冲管线。 virtual void prepare_data(const Plot_Render_Snapshot& snapshot) { sync_state_pipeline(); } - virtual QRect pixel_bounds(const QSize& plotSize) { - return QRect(QPoint(0, 0), plotSize); + virtual QRect pixel_bounds(const QSize& plot_size) { + return QRect(QPoint(0, 0), plot_size); } /// 判断指定坐标是否命中对象。 virtual bool select_test(const QPointF& pos) { return false; } - virtual void plot_event(QEvent* event) { - } - virtual void mousePressEvent(QMouseEvent* event) { - } - virtual void mouseMoveEvent(QMouseEvent* event) { - } - virtual void mouseReleaseEvent(QMouseEvent* event) { - } - virtual void set_hover_state(const QPoint& pos, bool active) { - } - virtual void keyPressEvent(QKeyEvent* event) { - } - virtual void keyReleaseEvent(QKeyEvent* event) { - } - virtual void first_resize_event(QResizeEvent* event) { - } - virtual void resizeEvent(QResizeEvent* event) { - } - virtual void wheelEvent(QWheelEvent* event) { - } + virtual void plot_event(QEvent* event) {} + virtual void mousePressEvent(QMouseEvent* event) {} + virtual void mouseMoveEvent(QMouseEvent* event) {} + virtual void mouseReleaseEvent(QMouseEvent* event) {} + virtual void set_hover_state(const QPoint& pos, bool active) {} + virtual void keyPressEvent(QKeyEvent* event) {} + virtual void keyReleaseEvent(QKeyEvent* event) {} + virtual void first_resize_event(QResizeEvent* event) {} + virtual void resizeEvent(QResizeEvent* event) {} + virtual void wheelEvent(QWheelEvent* event) {} }; struct Base_Render_Data : Render_Data { Render_State* render_state() override { @@ -236,20 +224,19 @@ struct Base_Render_Data : Render_Data { Input_Data* edit_input_data() override { return nullptr; } - void sync_state_pipeline() override { - } + void sync_state_pipeline() override {} }; class Abs_Plot; struct LIB_DECL Render_Edit_Guard { Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease); ~Render_Edit_Guard(); - Render_Data* mData{}; - Triple_Buffer_Lease mLease{}; + Render_Data* data{}; + Triple_Buffer_Lease lease{}; }; struct LIB_DECL Render_Input_Guard { Render_Input_Guard(Render_Data* data, Triple_Buffer_Lease lease); ~Render_Input_Guard(); - Render_Data* mData{}; - Triple_Buffer_Lease mLease{}; + Render_Data* data{}; + Triple_Buffer_Lease lease{}; }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Render_Lease.h b/Renderive/architecture/Render_Lease.h similarity index 74% rename from YSGraphic_Core/architecture/Render_Lease.h rename to Renderive/architecture/Render_Lease.h index 63d7db7..00e626a 100644 --- a/YSGraphic_Core/architecture/Render_Lease.h +++ b/Renderive/architecture/Render_Lease.h @@ -3,7 +3,7 @@ #include #include #include "Renderable_Core.h" -namespace YSG { +namespace renderive { template concept Render_State_Type = std::derived_from && std::is_copy_assignable_v; template @@ -13,7 +13,7 @@ concept Render_Data_Type = std::derived_from; template struct Typed_Render_Data_Base : Base { Owner* q() { - return reinterpret_cast(this->qPtr); + return reinterpret_cast(this->q_ptr); } State* render_state() override { return reinterpret_cast(this->state(State_Render)); @@ -39,43 +39,45 @@ struct Typed_Render_Data_Base : Base { Input* input_data_by_index(std::uint8_t index) { return reinterpret_cast(Base::input_data_by_index(index)); } - template - Field state_value(Field State::* field, SRC src) { + template + requires std::derived_from + Field state_value(Field Source_State::* field, SRC src) { return state_data(src)->*field; } - template - void set_state_value(Field State::* field, Field value) { - auto lease = this->mStateControl.wait_mark_use_role(State_Edit); + template + requires std::derived_from + void set_state_value(Field Source_State::* field, Field value) { + auto lease = this->state_control.wait_mark_use_role(State_Edit); auto state = state_data_by_index(lease.index); Render_Edit_Guard guard(this, lease); state->*field = std::move(value); } void sync_state_pipeline() override { - Triple_Buffer_Lease editLease = this->mStateControl.wait_mark_use_role(State_Edit); - Triple_Buffer_Lease readyLease = this->mStateControl.wait_mark_use_role(State_Ready); - auto ready = reinterpret_cast(this->state_by_index(readyLease.index)); - auto edit = reinterpret_cast(this->state_by_index(editLease.index)); + Triple_Buffer_Lease edit_lease = this->state_control.wait_mark_use_role(State_Edit); + Triple_Buffer_Lease ready_lease = this->state_control.wait_mark_use_role(State_Ready); + auto ready = reinterpret_cast(this->state_by_index(ready_lease.index)); + auto edit = reinterpret_cast(this->state_by_index(edit_lease.index)); if (buffer_version_newer(edit->version, ready->version)) *ready = *edit; - this->mStateControl.unmark_use(readyLease); - this->mStateControl.unmark_use(editLease); - this->mStateControl.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { + this->state_control.unmark_use(ready_lease); + this->state_control.unmark_use(edit_lease); + this->state_control.wait_swap_role(State_Ready, State_Render, [this](const Triple_Buffer_View& view) { auto ready = reinterpret_cast(this->state_by_index(view[State_Ready])); auto render = reinterpret_cast(this->state_by_index(view[State_Render])); return buffer_version_newer(ready->version, render->version); }); - this->mInputControl.wait_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) { + this->input_control.wait_swap_role(Input_Edit, Input_Ready, [this](const Triple_Buffer_View& view) { const Input_Buffer_Slot& edit = this->input_slot_by_index(view[Input_Edit]); const Input_Buffer_Slot& ready = this->input_slot_by_index(view[Input_Ready]); return edit.pending && buffer_version_newer(edit.version, ready.version); }); - this->mInputControl.wait_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) { + this->input_control.wait_swap_role(Input_Ready, Input_Render, [this](const Triple_Buffer_View& view) { const Input_Buffer_Slot& ready = this->input_slot_by_index(view[Input_Ready]); const Input_Buffer_Slot& render = this->input_slot_by_index(view[Input_Render]); return ready.pending && buffer_version_newer(ready.version, render.version); }); - if (!this->mRenderStart) - this->mRenderStart = true; + if (!this->render_start) + this->render_start = true; } }; template @@ -83,11 +85,11 @@ using Typed_Render_Data = Typed_Render_Data_Base struct Renderable_Binding { static void init(Owner* owner, const char* name) { - owner->dPtr = new Data; - owner->mObjectName = name; + owner->d_ptr = new Data; + owner->object_name = name; } static Data* d(Owner* owner) { - return reinterpret_cast(owner->dPtr); + return reinterpret_cast(owner->d_ptr); } static Render_Data* create_render_data() { return new Data; @@ -101,8 +103,7 @@ struct Renderable_Binding { }; template struct Render_State_Lease { - explicit Render_State_Lease(Data* data) : data(data), lease(data->mStateControl.wait_mark_use_role(State_Edit)), state(reinterpret_cast(data->state_by_index(lease.index))) { - } + explicit Render_State_Lease(Data* data) : data(data), lease(data->state_control.wait_mark_use_role(State_Edit)), state(reinterpret_cast(data->state_by_index(lease.index))) {} Render_State_Lease(const Render_State_Lease&) = delete; Render_State_Lease& operator=(const Render_State_Lease&) = delete; ~Render_State_Lease() { @@ -120,14 +121,13 @@ struct Render_State_Lease { }; template struct Render_Edit_Lease { - explicit Render_Edit_Lease(Data* data) : data(data), lease(data->mStateControl.wait_mark_use_role(State_Edit)), state(reinterpret_cast(data->state_by_index(lease.index))) { - } + explicit Render_Edit_Lease(Data* data) : data(data), lease(data->state_control.wait_mark_use_role(State_Edit)), state(reinterpret_cast(data->state_by_index(lease.index))) {} Render_Edit_Lease(const Render_Edit_Lease&) = delete; Render_Edit_Lease& operator=(const Render_Edit_Lease&) = delete; ~Render_Edit_Lease() { ++data->state_by_index(lease.index)->version; - if (data->qPtr) - data->qPtr->mark_render_dirty(); + if (data->q_ptr) + data->q_ptr->mark_render_dirty(); data->unmark_state(lease); } State* operator->() { @@ -142,13 +142,12 @@ struct Render_Edit_Lease { }; template struct Render_Input_Lease { - explicit Render_Input_Lease(Data* data, bool notify_render = true) : data(data), notify_render(notify_render), lease(data->mInputControl.wait_mark_use_role(Input_Edit)), input(reinterpret_cast(data->input_data_by_index(lease.index))) { - } + explicit Render_Input_Lease(Data* data, bool notify_render = true) : data(data), notify_render(notify_render), lease(data->input_control.wait_mark_use_role(Input_Edit)), input(reinterpret_cast(data->input_data_by_index(lease.index))) {} Render_Input_Lease(const Render_Input_Lease&) = delete; Render_Input_Lease& operator=(const Render_Input_Lease&) = delete; ~Render_Input_Lease() { data->mark_input_dirty(lease, notify_render); - data->mInputControl.unmark_use(lease); + data->input_control.unmark_use(lease); } Input* operator->() { return input; @@ -161,4 +160,4 @@ struct Render_Input_Lease { Triple_Buffer_Lease lease{}; Input* input{}; }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Render_Pipeline.cpp b/Renderive/architecture/Render_Pipeline.cpp similarity index 58% rename from YSGraphic_Core/architecture/Render_Pipeline.cpp rename to Renderive/architecture/Render_Pipeline.cpp index 7b0895f..24bf5c1 100644 --- a/YSGraphic_Core/architecture/Render_Pipeline.cpp +++ b/Renderive/architecture/Render_Pipeline.cpp @@ -1,66 +1,66 @@ #include "Renderable_Core.h" -namespace YSG { +namespace renderive { Renderable::Render_Pipeline::Render_Pipeline() { - colorControl.set_stats(&colorBufferStats); - colorControl.reset(); + color_control.set_stats(&color_buffer_stats); + color_control.reset(); } void Renderable::Render_Pipeline::mark_edit_state() { - editStateVersion.fetch_add(1, std::memory_order_release); + edit_state_version.fetch_add(1, std::memory_order_release); } bool Renderable::Render_Pipeline::has_new_state() const { - return Renderable::version_newer(editStateVersion.load(std::memory_order_acquire), renderStateVersion); + return Renderable::version_newer(edit_state_version.load(std::memory_order_acquire), render_state_version); } Renderable::Color_Buffer* Renderable::Render_Pipeline::color_by_index(std::uint8_t index) { - return &colorBuffers[index]; + return &color_buffers[index]; } Renderable::Color_Buffer* Renderable::Render_Pipeline::color_by_role(std::uint8_t role) { - return color_by_index(colorControl.read_view()[role]); + return color_by_index(color_control.read_view()[role]); } Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::wait_render_color() { - auto lease = colorControl.wait_mark_use_role(Color_Render); - return {color_by_index(lease.index), &colorControl, lease}; + auto lease = color_control.wait_mark_use_role(Color_Render); + return {color_by_index(lease.index), &color_control, lease}; } Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::wait_front_color() { - auto lease = colorControl.wait_mark_use_role(Color_Front); - return {color_by_index(lease.index), &colorControl, lease}; + auto lease = color_control.wait_mark_use_role(Color_Front); + return {color_by_index(lease.index), &color_control, lease}; } Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::try_front_color() { - auto record = colorControl.try_mark_use_role(Color_Front); + auto record = color_control.try_mark_use_role(Color_Front); if (record.result != Triple_Buffer_Result::Success) { return {}; } - return {color_by_index(record.lease.index), &colorControl, record.lease}; + return {color_by_index(record.lease.index), &color_control, record.lease}; } QRegion Renderable::Render_Pipeline::publish_render_color() { - colorControl.wait_swap_role(Color_Ready, Color_Render, [this](const Triple_Buffer_View& view) { + color_control.wait_swap_role(Color_Ready, Color_Render, [this](const Triple_Buffer_View& view) { auto render = color_by_index(view[Color_Render]); auto ready = color_by_index(view[Color_Ready]); return Renderable::version_newer(render->version.load(std::memory_order_acquire), ready->version.load(std::memory_order_acquire)); }); - auto view = colorControl.read_view(); + auto view = color_control.read_view(); auto ready = color_by_index(view[Color_Ready]); auto front = color_by_index(view[Color_Front]); - if (Renderable::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire)) && !paintRequestPending.exchange(true, std::memory_order_acq_rel)) { - return ready->dirtyRegion; + if (Renderable::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire)) && !paint_request_pending.exchange(true, std::memory_order_acq_rel)) { + return ready->dirty_region; } return {}; } Renderable::Color_Buffer_Lease Renderable::Render_Pipeline::consume_ready_color(Triple_Buffer_Mode mode) { - auto canSwap = [this](const Triple_Buffer_View& view) { + auto can_swap = [this](const Triple_Buffer_View& view) { auto ready = color_by_index(view[Color_Ready]); auto front = color_by_index(view[Color_Front]); return Renderable::version_newer(ready->version.load(std::memory_order_acquire), front->version.load(std::memory_order_acquire)); }; if (mode == Triple_Buffer_Mode::Wait) { - colorControl.wait_swap_role(Color_Front, Color_Ready, canSwap); + color_control.wait_swap_role(Color_Front, Color_Ready, can_swap); } else { - colorControl.try_swap_role(Color_Front, Color_Ready, canSwap); + color_control.try_swap_role(Color_Front, Color_Ready, can_swap); } - paintRequestPending.store(false, std::memory_order_release); + paint_request_pending.store(false, std::memory_order_release); if (mode == Triple_Buffer_Mode::Wait) { return wait_front_color(); } return try_front_color(); } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Render_Utils.cpp b/Renderive/architecture/Render_Utils.cpp similarity index 68% rename from YSGraphic_Core/architecture/Render_Utils.cpp rename to Renderive/architecture/Render_Utils.cpp index e596b95..ced931e 100644 --- a/YSGraphic_Core/architecture/Render_Utils.cpp +++ b/Renderive/architecture/Render_Utils.cpp @@ -3,29 +3,29 @@ #include "Renderable_Core.h" #include "psc_global_include/Fail_Fast.h" #include "psc_global_include/export.h" -namespace YSG { +namespace renderive { QVector get_turbo_color_gradient() { QVector colors; - QFile file(":/turbo.colorMap"); + QFile file(":/turbo.color_map"); if (!file.open(QIODevice::ReadOnly)) { std::ostringstream oss; oss << file.errorString().toStdString() << " getTurboColorGradient2: Failed to open file" << LOG_POS_SIMPLE << std::endl; Psc::fail_fast(oss.str()); return colors; } - QByteArray fileData = file.readAll(); + QByteArray file_data = file.readAll(); file.close(); - if (fileData.size() != 768) { - qDebug() << "getTurboColorGradient2: File size is not as expected (768 bytes), got" << fileData.size(); + if (file_data.size() != 768) { + qDebug() << "getTurboColorGradient2: File size is not as expected (768 bytes), got" << file_data.size(); return colors; } colors.reserve(256); for (int i = 0; i < 256; ++i) { - uchar r = fileData[i * 3]; - uchar g = fileData[i * 3 + 1]; - uchar b = fileData[i * 3 + 2]; + uchar r = file_data[i * 3]; + uchar g = file_data[i * 3 + 1]; + uchar b = file_data[i * 3 + 2]; colors.push_back(qRgb(r, g, b)); } return colors; } -} // namespace YSG +} // namespace renderive diff --git a/Renderive/architecture/Renderable.cpp b/Renderive/architecture/Renderable.cpp new file mode 100644 index 0000000..d19208c --- /dev/null +++ b/Renderive/architecture/Renderable.cpp @@ -0,0 +1,395 @@ +#include +#include +#include "../base/global.h" +#include "Plot.h" +#include "Renderable_Core.h" +namespace renderive { +Renderable::Color_Buffer_Lease::Color_Buffer_Lease(Color_Buffer* buffer, Triple_Role_Buffer_Control* control, Triple_Buffer_Lease lease) : buffer(buffer), control(control), lease(lease) {} +Renderable::Color_Buffer_Lease::Color_Buffer_Lease(Color_Buffer_Lease&& other) noexcept : buffer(std::exchange(other.buffer, nullptr)), control(std::exchange(other.control, nullptr)), lease(std::exchange(other.lease, Triple_Buffer_Lease{})) {} +Renderable::Color_Buffer_Lease& Renderable::Color_Buffer_Lease::operator=(Color_Buffer_Lease&& other) noexcept { + if (this == &other) + return *this; + reset(); + buffer = std::exchange(other.buffer, nullptr); + control = std::exchange(other.control, nullptr); + lease = std::exchange(other.lease, Triple_Buffer_Lease{}); + return *this; +} +Renderable::Color_Buffer_Lease::~Color_Buffer_Lease() { + reset(); +} +void Renderable::Color_Buffer_Lease::reset() { + if (!control) + return; + control->unmark_use(lease); + buffer = nullptr; + control = nullptr; + lease = {}; +} +Plot_Buffer_Acquire_Mode Renderable::get_buffer_acquire_mode() const { + return d_ptr->get_buffer_acquire_mode(); +} +void Renderable::set_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode) { + d_ptr->set_buffer_acquire_mode(mode); +} +Renderable_Render_Schedule_Mode Renderable::get_render_schedule_mode() const { + return d_ptr->get_render_schedule_mode(); +} +void Renderable::set_render_schedule_mode(Renderable_Render_Schedule_Mode mode) { + d_ptr->set_render_schedule_mode(mode); +} +double Renderable::get_render_schedule_max_fps() const { + return d_ptr->get_render_schedule_max_fps(); +} +void Renderable::set_render_schedule_max_fps(double fps) { + d_ptr->set_render_schedule_max_fps(fps); +} +Renderable_Cache_Mode Renderable::get_cache_mode() const { + return cache_mode.load(std::memory_order_acquire); +} +void Renderable::set_cache_mode(Renderable_Cache_Mode mode) { + cache_mode.store(mode, std::memory_order_release); + cache_dirty.store(true, std::memory_order_release); + mark_render_dirty(); +} +Renderable_Child_Render_Order Renderable::get_child_render_order() const { + return child_render_order.load(std::memory_order_acquire); +} +void Renderable::set_child_render_order(Renderable_Child_Render_Order order) { + child_render_order.store(order, std::memory_order_release); + mark_render_dirty(); +} +std::uint64_t Renderable::cache_image_bytes() const { + std::lock_guard lock(cache_mutex); + return cache_image.isNull() ? 0 : static_cast(cache_image.sizeInBytes()); +} +std::uint64_t Renderable::cache_image_area() const { + std::lock_guard lock(cache_mutex); + return static_cast(cache_bounds.width()) * static_cast(cache_bounds.height()); +} +void Renderable::init_root(Abs_Plot* plot) { + if (!plot) { + ASSERT(plot, "Renderable root init error! plot == nullptr"); + return; + } + bool initialized = this->initialized.exchange(true, std::memory_order_acq_rel); + if (initialized) { + ASSERT(!initialized, "Renderable root init error! Renderable already initialized"); + return; + } + init_common(plot); +} +void Renderable::init(const std::shared_ptr& parent) { + if (!parent || !parent->plot) { + ASSERT(parent && parent->plot, "Renderable init error! parent invalid"); + return; + } + bool initialized = this->initialized.exchange(true, std::memory_order_acq_rel); + if (initialized) { + ASSERT(!initialized, "Renderable init error! Renderable already initialized"); + return; + } + init_common(parent->plot); + parent->add_child(shared_from_this()); +} +void Renderable::init_common(Abs_Plot* plot) { + this->plot = plot; + plot_context = plot->get_render_context(); + retiring.store(false, std::memory_order_release); + if (!d_ptr) + d_ptr = create_render_data(); + d_ptr->set_buffer_acquire_mode(plot->get_renderable_buffer_acquire_mode()); + d_ptr->clear_state_buffers(); + d_ptr->clear_input_buffers(); + d_ptr->state_buffers[State_Edit] = create_render_state(); + d_ptr->state_buffers[State_Ready] = create_render_state(); + d_ptr->state_buffers[State_Render] = create_render_state(); + d_ptr->input_buffers[Input_Edit].data = create_input_data(); + d_ptr->input_buffers[Input_Ready].data = create_input_data(); + d_ptr->input_buffers[Input_Render].data = create_input_data(); + for (Render_State* state : d_ptr->state_buffers) { + state->d_ptr = d_ptr; + } + d_ptr->q_ptr = this; + d_ptr->state_buffers[State_Edit]->version = 1; + plot->mark_render_state_dirty(); +} +void Renderable::add_child(const std::shared_ptr& child) { + if (!child || child.get() == this || child->plot != plot || !child->parent_renderable.expired()) { + ASSERT(child && child.get() != this && child->plot == plot && child->parent_renderable.expired(), "Renderable add_child error! invalid child"); + return; + } + std::lock_guard lock(children_mutex); + if (children.contains(child)) + return; + child->parent_renderable = shared_from_this(); + children.append(child); + mark_render_dirty(); +} +void Renderable::remove_child(const std::shared_ptr& child) { + if (!child || child->parent_renderable.lock().get() != this) + return; + { + std::lock_guard lock(children_mutex); + children.erase(std::remove(children.begin(), children.end(), child), children.end()); + } + child->detach_from_plot_tree(); + mark_render_dirty(); +} +QVector> Renderable::children_snapshot() const { + std::lock_guard lock(children_mutex); + return children; +} +QVector> Renderable::hit_renderables(const QPointF& pos) { + QVector> hits; + append_hit_renderables(hits, pos); + return hits; +} +void Renderable::append_hit_renderables(QVector>& hits, const QPointF& pos) { + if (get_retiring() || !visible) + return; + if (get_child_render_order() == Renderable_Child_Render_Order::Children_Before_Self && select_test(pos)) + hits.append(shared_from_this()); + QVector> children = children_snapshot(); + for (int i = children.size() - 1; i >= 0; --i) { + const auto& child = children.at(i); + if (child) + child->append_hit_renderables(hits, pos); + } + if (get_child_render_order() == Renderable_Child_Render_Order::Self_Before_Children && select_test(pos)) + hits.append(shared_from_this()); +} +void Renderable::render(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + if (get_retiring() || !visible) + return; + if (get_cache_mode() == Renderable_Cache_Mode::Local_Pixel) + render_cached(painter, snapshot); + else + render_direct(painter, snapshot); +} +void Renderable::render_direct(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + if (get_child_render_order() == Renderable_Child_Render_Order::Children_Before_Self) { + render_children(painter, snapshot); + render_self(painter, snapshot); + } + else { + render_self(painter, snapshot); + render_children(painter, snapshot); + } +} +void Renderable::render_children(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + QVector> children = children_snapshot(); + for (const auto& child : children) { + if (child) + child->render(painter, snapshot); + } +} +void Renderable::render_cached(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + QSize size = snapshot.size; + QRect bounds = d_ptr ? d_ptr->pixel_bounds(size).intersected(QRect(QPoint(0, 0), size)) : QRect(QPoint(0, 0), size); + if (bounds.isEmpty()) + return; + std::uint64_t edit_version = cache_edit_version.load(std::memory_order_acquire); + { + std::lock_guard lock(cache_mutex); + bool ready = !cache_dirty.load(std::memory_order_acquire) && cache_ready_version.load(std::memory_order_acquire) == edit_version && cache_image.size() == bounds.size() && cache_image.format() == QImage::Format_ARGB32 && cache_bounds == bounds; + if (ready) { + painter->drawImage(bounds.topLeft(), cache_image); + return; + } + if (!cache_image.isNull() && cache_bounds == bounds) { + schedule_cache_render(bounds, snapshot, edit_version); + painter->drawImage(bounds.topLeft(), cache_image); + return; + } + } + render_cache_image(bounds, snapshot, edit_version); + std::lock_guard lock(cache_mutex); + if (!cache_image.isNull()) + painter->drawImage(bounds.topLeft(), cache_image); +} +void Renderable::render_cache_image(const QRect& bounds, const Plot_Render_Snapshot& snapshot, std::uint64_t version) { + if (get_retiring()) + return; + QImage cache_image(bounds.size(), QImage::Format_ARGB32); + cache_image.fill(Qt::transparent); + { + QPainter cache_painter(&cache_image); + cache_painter.translate(-bounds.topLeft()); + render_direct(&cache_painter, snapshot); + cache_painter.end(); + } + { + std::lock_guard lock(cache_mutex); + cache_bounds = bounds; + cache_image = cache_image; + cache_ready_version.store(version, std::memory_order_release); + bool dirty = cache_edit_version.load(std::memory_order_acquire) != version; + cache_dirty.store(dirty, std::memory_order_release); + } +} +void Renderable::schedule_cache_render(const QRect& bounds, const Plot_Render_Snapshot& snapshot, std::uint64_t version) { + if (cache_render_queued.exchange(true, std::memory_order_acq_rel)) + return; + auto self = shared_from_this(); + auto snapshot_owner = std::make_shared(snapshot); + Global::instance()->render_scheduler().post_cpu([self, snapshot_owner, bounds, version]() { + if (self->get_retiring() || !snapshot_owner || snapshot_owner->destroying()) { + self->cache_render_queued.store(false, std::memory_order_release); + return; + } + self->render_cache_image(bounds, *snapshot_owner, version); + self->cache_render_queued.store(false, std::memory_order_release); + if (!self->get_retiring()) + self->notify_parent_render_dirty(); + }); +} +void Renderable::notify_parent_render_dirty() { + if (get_retiring()) + return; + auto context = plot_context.lock(); + if (!context || context->destroying.load(std::memory_order_acquire)) + return; + if (auto parent = parent_renderable.lock()) { + parent->mark_render_dirty(); + return; + } + std::lock_guard lock(context->mutex); + if (!context->destroying.load(std::memory_order_acquire) && context->plot) + context->plot->mark_render_state_dirty(); +} +void Renderable::render_self(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + if (!d_ptr) + return; + auto lease = d_ptr->mark_state_role(State_Render); + if (!lease) + return; + draw(painter, snapshot); + d_ptr->unmark_state(lease); +} +void Renderable::draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + if (get_retiring()) + return; + d_ptr->draw(painter, snapshot); +} +void Renderable::prepare_data(const Plot_Render_Snapshot& snapshot) { + if (get_retiring()) + return; + d_ptr->prepare_data(snapshot); +} +bool Renderable::select_test(const QPointF& pos) { + if (get_retiring()) + return false; + return d_ptr->select_test(pos); +} +void Renderable::plot_event(QEvent* event) { + if (get_retiring()) + return; + d_ptr->plot_event(event); +} +void Renderable::mousePressEvent(QMouseEvent* event) { + if (get_retiring()) + return; + d_ptr->mousePressEvent(event); +} +void Renderable::mouseMoveEvent(QMouseEvent* event) { + if (get_retiring()) + return; + d_ptr->mouseMoveEvent(event); +} +void Renderable::mouseReleaseEvent(QMouseEvent* event) { + if (get_retiring()) + return; + d_ptr->mouseReleaseEvent(event); +} +void Renderable::set_hover_state(const QPoint& pos, bool active) { + if (get_retiring()) + return; + d_ptr->set_hover_state(pos, active); +} +void Renderable::keyPressEvent(QKeyEvent* event) { + if (get_retiring()) + return; + d_ptr->keyPressEvent(event); +} +void Renderable::keyReleaseEvent(QKeyEvent* event) { + if (get_retiring()) + return; + d_ptr->keyReleaseEvent(event); +} +void Renderable::first_resize_event(QResizeEvent* event) { + if (get_retiring()) + return; + d_ptr->first_resize_event(event); +} +void Renderable::resizeEvent(QResizeEvent* event) { + if (get_retiring()) + return; + d_ptr->resizeEvent(event); +} +void Renderable::wheelEvent(QWheelEvent* event) { + if (get_retiring()) + return; + d_ptr->wheelEvent(event); +} +bool Renderable::version_newer(std::uint64_t a, std::uint64_t b) { + return buffer_version_newer(a, b); +} +void Renderable::mark_state_dirty() { + if (get_retiring()) + return; + if (d_ptr) { + auto lease = d_ptr->state_control.wait_mark_use_role(State_Edit); + ++d_ptr->state_by_index(lease.index)->version; + d_ptr->state_control.unmark_use(lease); + } + mark_render_dirty(); +} +void Renderable::mark_render_dirty() { + if (get_retiring()) + return; + auto context = plot_context.lock(); + if (!context || context->destroying.load(std::memory_order_acquire)) + return; + cache_dirty.store(true, std::memory_order_release); + cache_edit_version.fetch_add(1, std::memory_order_acq_rel); + if (auto parent = parent_renderable.lock()) { + parent->mark_render_dirty(); + return; + } + std::lock_guard lock(context->mutex); + if (!context->destroying.load(std::memory_order_acquire) && context->plot) + context->plot->mark_render_state_dirty(); +} +bool Renderable::ok() const { + auto context = plot_context.lock(); + return d_ptr && d_ptr->render_start && !get_retiring() && context && !context->destroying.load(std::memory_order_acquire) && !context->first_resize.load(std::memory_order_acquire) && !context->first_prepare_data.load(std::memory_order_acquire); +} +bool Renderable::get_retiring() const { + return retiring.load(std::memory_order_acquire); +} +void Renderable::detach_from_plot_tree() { + retiring.store(true, std::memory_order_release); + QVector> children = children_snapshot(); + { + std::lock_guard lock(children_mutex); + children.clear(); + } + for (const auto& child : children) { + if (child) + child->detach_from_plot_tree(); + } + plot = nullptr; + cache_render_queued.store(false, std::memory_order_release); + { + std::lock_guard lock(cache_mutex); + cache_image = QImage(); + cache_bounds = {}; + } +} +Renderable::~Renderable() { + detach_from_plot_tree(); + delete d_ptr; + d_ptr = nullptr; +} +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Renderable.h b/Renderive/architecture/Renderable.h similarity index 100% rename from YSGraphic_Core/architecture/Renderable.h rename to Renderive/architecture/Renderable.h diff --git a/YSGraphic_Core/architecture/Renderable_Core.h b/Renderive/architecture/Renderable_Core.h similarity index 77% rename from YSGraphic_Core/architecture/Renderable_Core.h rename to Renderive/architecture/Renderable_Core.h index cfafbba..ffe104f 100644 --- a/YSGraphic_Core/architecture/Renderable_Core.h +++ b/Renderive/architecture/Renderable_Core.h @@ -7,11 +7,11 @@ #include #include #include "Render_Data.h" -namespace YSG { +namespace renderive { /// 可渲染对象的基础接口和每对象渲染管线。 struct Renderable : std::enable_shared_from_this { /// 后台渲染任务状态。 - enum class JobState { + enum class Job_State { /// 没有任务运行或排队。 Idle, /// 已经进入调度队列。 @@ -23,7 +23,7 @@ struct Renderable : std::enable_shared_from_this { struct Color_Buffer { std::atomic version{0}; QImage image; - QRegion dirtyRegion; + QRegion dirty_region; }; /// 颜色缓冲占用租约,析构时自动释放底层 busy 标记。 struct Color_Buffer_Lease { @@ -46,13 +46,13 @@ struct Renderable : std::enable_shared_from_this { }; /// 单个 Plot 的颜色三缓冲管线。 struct Render_Pipeline { - Triple_Role_Buffer_Control colorControl; - Triple_Buffer_Stats colorBufferStats; - std::array colorBuffers; - std::atomic editStateVersion{1}; - std::uint64_t renderStateVersion = 0; - JobState jobState = JobState::Idle; - std::atomic_bool paintRequestPending{false}; + Triple_Role_Buffer_Control color_control; + Triple_Buffer_Stats color_buffer_stats; + std::array color_buffers; + std::atomic edit_state_version{1}; + std::uint64_t render_state_version = 0; + Job_State job_state = Job_State::Idle; + std::atomic_bool paint_request_pending{false}; Render_Pipeline(); /// 标记 GUI/edit 状态已经变化。 void mark_edit_state(); @@ -107,18 +107,18 @@ struct Renderable : std::enable_shared_from_this { /// 按三缓冲版本号环绕语义判断 a 是否比 b 新。 static bool version_newer(std::uint64_t a, std::uint64_t b); /// 当前对象三缓冲获取模式。 - Plot_Buffer_Acquire_Mode buffer_acquire_mode() const; + Plot_Buffer_Acquire_Mode get_buffer_acquire_mode() const; void set_buffer_acquire_mode(Plot_Buffer_Acquire_Mode mode); /// 当前对象渲染调度策略。 - RenderAble_Render_Schedule_Mode render_schedule_mode() const; - void set_render_schedule_mode(RenderAble_Render_Schedule_Mode mode); + Renderable_Render_Schedule_Mode get_render_schedule_mode() const; + void set_render_schedule_mode(Renderable_Render_Schedule_Mode mode); /// 当前对象自身最大提交帧率,0 表示继承或不限速。 - double render_schedule_max_fps() const; + double get_render_schedule_max_fps() const; void set_render_schedule_max_fps(double fps); /// 当前 Renderable 输出缓存策略。 - Renderable_Cache_Mode cache_mode() const; + Renderable_Cache_Mode get_cache_mode() const; void set_cache_mode(Renderable_Cache_Mode mode); - Renderable_Child_Render_Order child_render_order() const; + Renderable_Child_Render_Order get_child_render_order() const; void set_child_render_order(Renderable_Child_Render_Order order); std::uint64_t cache_image_bytes() const; std::uint64_t cache_image_area() const; @@ -126,33 +126,32 @@ struct Renderable : std::enable_shared_from_this { void mark_state_dirty(); /// 请求父 Plot 调度一次渲染。 void mark_render_dirty(); - QString mObjectName; - Render_Data* dPtr{}; - Abs_Plot* mPlot{}; - std::weak_ptr mParentRenderable; + QString object_name; + Render_Data* d_ptr{}; + Abs_Plot* plot{}; + std::weak_ptr parent_renderable; [[nodiscard]] bool ok() const; - [[nodiscard]] bool retiring() const; - bool mPrepared = false; + [[nodiscard]] bool get_retiring() const; + bool prepared = false; virtual ~Renderable(); virtual bool select(QPointF pos) { return false; } - bool mVisable = true; - QVector> mChildren; - mutable std::mutex mChildrenMutex; - std::weak_ptr mPlotContext; - std::atomic mCacheMode{Renderable_Cache_Mode::Direct}; - std::atomic mChildRenderOrder{Renderable_Child_Render_Order::Self_Before_Children}; - std::atomic_bool mCacheDirty{true}; - std::atomic_bool mCacheRenderQueued{false}; - std::atomic mCacheEditVersion{1}; - std::atomic mCacheReadyVersion{0}; - mutable std::mutex mCacheMutex; - QImage mCacheImage; - QRect mCacheBounds; - std::atomic_bool mRetiring{true}; - std::atomic_bool mInitialized{false}; -protected: + bool visible = true; + QVector> children; + mutable std::mutex children_mutex; + std::weak_ptr plot_context; + std::atomic cache_mode{Renderable_Cache_Mode::Direct}; + std::atomic child_render_order{Renderable_Child_Render_Order::Self_Before_Children}; + std::atomic_bool cache_dirty{true}; + std::atomic_bool cache_render_queued{false}; + std::atomic cache_edit_version{1}; + std::atomic cache_ready_version{0}; + mutable std::mutex cache_mutex; + QImage cache_image; + QRect cache_bounds; + std::atomic_bool retiring{true}; + std::atomic_bool initialized{false}; friend class Abs_Plot; void init_common(Abs_Plot* plot); void render_direct(QPainter* painter, const Plot_Render_Snapshot& snapshot); @@ -165,4 +164,4 @@ protected: void append_hit_renderables(QVector>& hits, const QPointF& pos); void detach_from_plot_tree(); }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/Triple_Buffer.cpp b/Renderive/architecture/Triple_Buffer.cpp similarity index 100% rename from YSGraphic_Core/architecture/Triple_Buffer.cpp rename to Renderive/architecture/Triple_Buffer.cpp diff --git a/YSGraphic_Core/architecture/Triple_Buffer.h b/Renderive/architecture/Triple_Buffer.h similarity index 99% rename from YSGraphic_Core/architecture/Triple_Buffer.h rename to Renderive/architecture/Triple_Buffer.h index 8caaf48..fec00e3 100644 --- a/YSGraphic_Core/architecture/Triple_Buffer.h +++ b/Renderive/architecture/Triple_Buffer.h @@ -2,7 +2,7 @@ #include #include #include -namespace YSG { +namespace renderive { static constexpr std::uint8_t triple_buffer_invalid_index = 255; /// 三缓冲操作结果。 enum class Triple_Buffer_Result : std::uint8_t { @@ -316,4 +316,4 @@ private: return {Triple_Buffer_Result::Success, old_view, new_view, triple_buffer_invalid_index}; } }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/architecture/export.h b/Renderive/architecture/export.h similarity index 100% rename from YSGraphic_Core/architecture/export.h rename to Renderive/architecture/export.h diff --git a/YSGraphic_Core/architecture/global.h b/Renderive/architecture/global.h similarity index 96% rename from YSGraphic_Core/architecture/global.h rename to Renderive/architecture/global.h index abce02b..e855d04 100644 --- a/YSGraphic_Core/architecture/global.h +++ b/Renderive/architecture/global.h @@ -28,16 +28,16 @@ } \ while (0) #endif -#if defined(buildLib) +#if defined(build_lib) #define LIB_DECL -#elif defined(buildDll) +#elif defined(build_dll) #define LIB_DECL Q_DECL_EXPORT -#elif defined(buildExe) +#elif defined(build_exe) #define LIB_DECL #else #define LIB_DECL #endif -namespace YSG { +namespace renderive { QVector get_turbo_color_gradient(); class Abs_Axis; class Axis; @@ -82,7 +82,7 @@ enum class LIB_DECL SRC : std::uint8_t { Ready, Render }; -} // namespace YSG +} // namespace renderive #define PROP(Type, Name) \ Type Name(SRC src = SRC::Edit); \ void set_##Name(Type); @@ -131,14 +131,14 @@ public: \ return *static_cast(this); \ } #define SETTER(TYPE, FIELD, DEFAULT) \ -protected: \ + \ TYPE FIELD = DEFAULT; \ public: \ Builder& set_##FIELD(TYPE value) { \ this->FIELD = std::move(value); \ return *this; \ } -namespace YSG { +namespace renderive { template constexpr const T& clamp(const T& v, const T& lo, const T& hi) { return (v < lo) @@ -147,6 +147,6 @@ constexpr const T& clamp(const T& v, const T& lo, const T& hi) { ? hi : v; } -} // namespace YSG +} // namespace renderive #undef min #undef max diff --git a/Renderive/base/Tool.h b/Renderive/base/Tool.h new file mode 100644 index 0000000..8f6d80f --- /dev/null +++ b/Renderive/base/Tool.h @@ -0,0 +1,783 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../Axis/export.h" +#include "../Generate_Mock_Data.h" +#include "../architecture/export.h" +#include "../../Widget/base/export.h" +#include "../plottable/export.h" +namespace renderive { +static QColor get_color(int lowest, int highest) { + int r = QRandomGenerator::global()->bounded(lowest, highest); + int g = QRandomGenerator::global()->bounded(lowest, highest); + int b = QRandomGenerator::global()->bounded(lowest, highest); + return {r, g, b}; +} +static QString get_background_style_sheet() { + QString color = QString("background-color: %1;").arg(get_color(176, 256).name()); + return color; +} +static QString get_button_style_sheet() { + QString color = QString("background-color: %1; color: #000000;").arg(get_color(200, 256).name()); + return color; +} +template +QString get_init_value(const T& value) { + return QString::number(value); +} +template <> +inline QString get_init_value(const QString& value) { + return value; +} +template +T get_value_from_string(const QString& value) { + return value.toDouble(); +} +template <> +inline QString get_value_from_string(const QString& value) { + return value; +} +template +static QWidget* create_edit_widget_list(const QString& button_text, + const std::function &)>& click, const QVector& init_values) { + auto container = new QWidget; + auto layout = new QHBoxLayout(container); + layout->setAlignment(Qt::AlignLeft); + layout->setContentsMargins(0, 0, 0, 0); + auto confirm = new QPushButton(button_text); + // QApplication* app = (QApplication*)QApplication::instance(); + // qDebug() << "Global StyleSheet:" << app->styleSheet(); + confirm->setStyleSheet(get_button_style_sheet()); + // 清除 QSS + QFont font; + font.setFamily("Segoe UI"); + confirm->setFont(font); + confirm->setMinimumWidth(QFontMetrics(confirm->font()).horizontalAdvance(button_text) + 8); + confirm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + layout->addWidget(confirm); + QVector lineEditList; + for (const T& init_value : init_values) { + QString init_value_str = get_init_value(init_value); + auto cur_edit = new QLineEdit(init_value_str); + cur_edit->setStyleSheet(get_button_style_sheet()); + // cur_edit->setMaximumWidth(50); + auto fm = QFontMetrics(QFont()); + int width = fm.horizontalAdvance(init_value_str); + // cur_edit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + cur_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + int w = qMax((int)((double)width * 1.4) + 16, 50); + cur_edit->setMinimumWidth(w); + lineEditList.append(cur_edit); + layout->addWidget(cur_edit); + } + QObject::connect(confirm, &QPushButton::clicked, [lineEditList, click]() { + QVector values; + for (QLineEdit* line_edit : lineEditList) { + values.append(get_value_from_string(line_edit->text())); + } + click(values); + }); + return container; +} +template +static QWidget* create_edit_widget(const QString& button_text, + const std::function& click, const T& init_values) { + return create_edit_widget_list(button_text, [click](const QVector& data) { + click(data.first()); + }, QVector{init_values}); +} +static QWidget* create_range(Axis* axis, const QString& text = "更改轴范围") { + return create_edit_widget_list(text, [axis](const QVector& values) { + axis->set_coord_range(Range{values[0], values[1]}); + }, + {axis->coord_range().origin, axis->coord_range().target}); +} +static QMenu* find_parent_menu(QWidget* widget) { + // 从当前窗口开始,逐步检查父窗口 + QWidget* parent = widget->parentWidget(); + while (parent) { + if (QMenu* menu = qobject_cast(parent)) { + return menu; // 找到第一个 QMenu 类型的父窗口 + } + parent = parent->parentWidget(); + } + return nullptr; // 如果没有找到 QMenu 类型的父窗口 +} +static QWidget* create_select_color(const QString& text, const std::function& click, const QColor& color = QColor()) { + auto ret = new QWidget; + auto l = new QHBoxLayout(ret); + l->setContentsMargins(0, 0, 0, 0); + // l->setSpacing(0); + QString bs = get_button_style_sheet(); + auto show_color = new QWidget; + show_color->setStyleSheet(QString("background-color: %1; border: 2px solid #000000;").arg(color.name(QColor::HexArgb))); + show_color->setFixedWidth(30); + static QPushButton* btn = nullptr; + // static auto dialog = new CustomColorDialog(Qt::white, QApplication::activeWindow()); + static auto dialog = new Select_Color_Dialog; + dialog->resize(800, 600); + // dialog->adjustSize(); + auto label = new QLineEdit(color.isValid() ? color.name(QColor::HexArgb) : "无效"); + label->setAlignment(Qt::AlignCenter); + label->setStyleSheet("background-color: #ffffff; color: #000000;"); + // label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + auto button = new QPushButton(text); + button->setStyleSheet(bs); + QObject::connect(button, &QPushButton::clicked, [button, label]() { + btn = button; + dialog->set_current_color(QColor(label->text())); + dialog->show(); + }); + QObject::connect(dialog, &QDialog::finished, [ret, button, click, label, show_color](int result) { + if (btn != button) + return; + if (result == QDialog::Accepted) { + QColor select_color = dialog->current_color(); + click(select_color); + label->setText(select_color.name(QColor::HexArgb)); + show_color->setStyleSheet(QString("background-color: %1; border: 2px solid #000000;") + .arg(select_color.name(QColor::HexArgb))); + } + else if (result == -1) { + click(QColor()); + label->setText("无颜色"); + show_color->setStyleSheet(QString("background-color: rgba(255, 255, 255, 0); border: 2px solid #000000;")); + } + QMenu* menu = find_parent_menu(ret); + if (menu) { + menu->show(); + } + }); + l->addWidget(button); + l->addWidget(label); + l->addWidget(show_color); + return ret; +} +static QPushButton* create_button(const QString& text, const std::function& click) { + auto button = new QPushButton(text); + button->setStyleSheet(get_button_style_sheet()); + QObject::connect(button, &QPushButton::clicked, [click]() { + click(); + }); + return button; +} +static QPushButton* create_toggle_button(const QString& text, const QString& text2, const std::function& click, bool first_state) { + auto button = new QPushButton(first_state ? text : text2); + button->setStyleSheet(get_button_style_sheet()); + QObject::connect(button, &QPushButton::clicked, [button, click, text, text2]() { + click(); + if (button->text() == text2) { + button->setText(text); + } + else { + button->setText(text2); + } + }); + return button; +} +static QLabel* create_label(const QString& text, int h = 50, const QColor& color = Qt::black) { + auto l = new QLabel(text); + QFont font; + font.setFamily("Segoe UI"); + font.setBold(true); + l->setFont(font); + l->setFixedHeight(h); + l->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); + l->setStyleSheet(QString("color: %1;").arg(color.name(QColor::HexArgb))); + return l; +} +} // namespace renderive +static QVector bw(const QVector& widgets, const QString& name) { + if (widgets.empty()) + return {}; + auto ret = new QWidget; + ret->setStyleSheet(renderive::get_background_style_sheet()); + auto l = new QVBoxLayout(ret); + auto label = new QLabel(name); + label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + QFontMetrics fm(label->font()); + label->setFixedSize(fm.horizontalAdvance(name) + 16, fm.height() + 8); + label->setStyleSheet(QString("color: %1; background-color: %2; padding: 0px; margin: 0px;") + .arg( + QColor(Qt::white).name(QColor::HexArgb), + QColor(Qt::black).name(QColor::HexArgb))); + l->addWidget(label, 0, Qt::AlignHCenter | Qt::AlignBottom); + for (QWidget* w : widgets) { + l->addWidget(w); + } + return {ret}; +} +static QWidget* create_plot_render_schedule_combo(renderive::Abs_Plot* plot) { + auto container = new QWidget; + auto layout = new QHBoxLayout(container); + layout->setAlignment(Qt::AlignLeft); + layout->setContentsMargins(0, 0, 0, 0); + auto label = new QLabel("渲染策略"); + auto combo = new QComboBox; + label->setStyleSheet(renderive::get_button_style_sheet()); + combo->setStyleSheet(renderive::get_button_style_sheet()); + combo->addItem("Timer_Check", static_cast(renderive::Plot_Render_Schedule_Mode::Timer_Check)); + combo->addItem("Chase_Latest", static_cast(renderive::Plot_Render_Schedule_Mode::Chase_Latest)); + combo->addItem("Max_Fps", static_cast(renderive::Plot_Render_Schedule_Mode::Max_Fps)); + combo->addItem("Manual", static_cast(renderive::Plot_Render_Schedule_Mode::Manual)); + int index = combo->findData(static_cast(plot->get_render_schedule_mode())); + combo->setCurrentIndex(index >= 0 ? index : 0); + QObject::connect(combo, QOverload::of(&QComboBox::currentIndexChanged), [plot, combo](int index) { + plot->set_render_schedule_mode(static_cast(combo->itemData(index).toInt())); + }); + layout->addWidget(label); + layout->addWidget(combo); + return container; +} +template +static QWidget* create_line_interpolation_combo(T* renderable) { + auto container = new QWidget; + auto layout = new QHBoxLayout(container); + layout->setContentsMargins(0, 0, 0, 0); + auto label = new QLabel("线图插值"); + auto combo = new QComboBox; + label->setStyleSheet(renderive::get_button_style_sheet()); + combo->setStyleSheet(renderive::get_button_style_sheet()); + combo->addItem("Nearest_Bin", static_cast(renderive::Line_Interpolation_Mode::Nearest_Bin)); + combo->addItem("Linear_Display", static_cast(renderive::Line_Interpolation_Mode::Linear_Display)); + combo->addItem("Linear_Power", static_cast(renderive::Line_Interpolation_Mode::Linear_Power)); + combo->addItem("Step_Left", static_cast(renderive::Line_Interpolation_Mode::Step_Left)); + combo->addItem("Step_Right", static_cast(renderive::Line_Interpolation_Mode::Step_Right)); + combo->addItem("Cubic_Display", static_cast(renderive::Line_Interpolation_Mode::Cubic_Display)); + combo->setCurrentIndex(combo->findData(static_cast(renderable->interpolation_mode()))); + QObject::connect(combo, QOverload::of(&QComboBox::currentIndexChanged), [renderable, combo](int index) { + renderable->set_interpolation_mode(static_cast(combo->itemData(index).toInt())); + }); + layout->addWidget(label); + layout->addWidget(combo); + return container; +} +static QWidget* create_image_interpolation_combo(renderive::Waterfall* waterfall) { + auto container = new QWidget; + auto layout = new QHBoxLayout(container); + layout->setContentsMargins(0, 0, 0, 0); + auto label = new QLabel("二维插值"); + auto combo = new QComboBox; + label->setStyleSheet(renderive::get_button_style_sheet()); + combo->setStyleSheet(renderive::get_button_style_sheet()); + combo->addItem("Nearest", static_cast(renderive::Image_Interpolation_Mode::Nearest)); + combo->addItem("Bilinear", static_cast(renderive::Image_Interpolation_Mode::Bilinear)); + combo->addItem("Bicubic", static_cast(renderive::Image_Interpolation_Mode::Bicubic)); + combo->setCurrentIndex(combo->findData(static_cast(waterfall->interpolation_mode()))); + QObject::connect(combo, QOverload::of(&QComboBox::currentIndexChanged), [waterfall, combo](int index) { + waterfall->set_interpolation_mode(static_cast(combo->itemData(index).toInt())); + }); + layout->addWidget(label); + layout->addWidget(combo); + return container; +} +static QWidget* create_control(renderive::Abs_Plot* plot, const QVector& widgets = {}) { + auto control = new QWidget; + auto l = new QVBoxLayout(control); + l->setAlignment(Qt::AlignTop); + l->setContentsMargins({0, 0, 0, 0}); + l->setSpacing(0); + QVector ws = { + renderive::create_toggle_button("暂停渲染", "开始渲染", [plot]() { + plot->is_rendering() ? plot->pause_render() : plot->start_render(); + }, plot->is_rendering()), + renderive::create_toggle_button("停止性能测试", "启动性能测试", [plot]() { + plot->set_use_performance_shower(plot->get_use_performance_shower() ? false : true); + }, plot->get_use_performance_shower()), + renderive::create_select_color("更改背景色", [plot](const QColor& color) { + plot->set_background_color(color); + }, plot->background_color()), + create_plot_render_schedule_combo(plot), + renderive::create_edit_widget_list("渲染检查FPS", [plot](QVector data) { + if (data[0] < 0) { + plot->pause_render(); + } + else { + plot->start_render(data[0]); + } + }, {30}), + renderive::create_edit_widget_list("最大渲染FPS", [plot](QVector data) { + plot->set_max_render_fps(data[0]); + }, {plot->get_max_render_fps() > 0.0 ? plot->get_max_render_fps() : plot->get_render_check_fps()}), + }; + for (QWidget* cur : bw(ws, "plot基础") + widgets) { + l->addWidget(cur); + } + return control; +} +static QVector cw(renderive::Abs_Axis* it) { + if (it == nullptr) + return {}; + auto t = QVector{ + renderive::create_button("反转轴整体方向", [it]() { + it->set_orientation(it->orientation() == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal); + }), + renderive::create_edit_widget_list("主刻度值", [it](const QVector& values) { + it->set_tick_length(values[0]); + }, + {it->tick_length()}), + renderive::create_edit_widget_list("子刻度值", [it](const QVector& values) { + it->set_sub_tick_length(values[0]); + }, + {it->sub_tick_length()}), + renderive::create_select_color("更改轴颜色", [it](const QColor& color) { + it->set_color(color); + }, it->color()), + renderive::create_edit_widget_list("设置单位", [it](const QVector& values) { + it->set_unit_text(values[0]); + }, {it->unit_text()}), + renderive::create_select_color("更改UnitText颜色", [it](const QColor& color) { + it->set_unit_text_pen(QPen(color)); + }, it->color()), + renderive::create_select_color("更改UnitText背景色", [it](const QColor& color) { + it->set_unit_text_background_brush(QBrush(color)); + }, it->color()), + renderive::create_edit_widget_list("更改刻度斜度", [it](const QVector& values) { + it->set_rotate(values[0]); + }, {it->rotate()}), + }; + return t; +} +static QVector cw(renderive::Axis* it) { + if (it == nullptr) + return {}; + auto t = QVector{ + renderive::create_range(it), + }; + return cw(dynamic_cast(it)) + t; +} +static QVector cw(renderive::Frequency_Axis* it) { + if (it == nullptr) + return {}; + auto t = QVector{}; + return cw(dynamic_cast(it)) + t; +} +static QVector cw(renderive::Time_Axis* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + auto t = QVector{ + renderive::create_edit_widget_list("时间格式", [it](QVector data) { + it->set_time_format(data[0]); + }, + {it->time_format()}), + renderive::create_edit_widget_list("单位间隔pixel", [it](QVector data) { + it->set_tick_pixel_space(data[0]); + }, + {it->tick_pixel_space()}), + }; + auto timer = new QTimer(it->plot); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + QObject::connect(timer, &QTimer::timeout, [it]() { + it->give_data(QTime::currentTime()); + }); + t.append(renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, + {timer->interval() > 0 ? 1000.0 / timer->interval() : -1})); + return t + cw(dynamic_cast(it)); +} +static QVector cw(renderive::Multi_Select_Rect* it) { + if (it == nullptr) + return {}; + auto t = QVector{ + renderive::create_select_color("更改填充色", [it](const QColor& color) { + it->set_rect_brush(QBrush(color)); + }, it->rect_brush().color()), + renderive::create_select_color("更改边框色", [it](const QColor& color) { + qDebug() << " color.isValid() == " << color.isValid(); + QPen pen(color); + pen.setStyle(Qt::DashLine); + it->set_border_pen(pen); + qDebug() << " color.isValid() == " << pen.color().isValid(); + }, it->border_pen().color()), + renderive::create_select_color("更改字色", [it](const QColor& color) { + it->set_font_pen(QPen(color)); + }, it->font_pen().color()) + }; + return t; +} +template +static QVector cw(renderive::Hover_Info_Renderable* it) { + if (it == nullptr) + return {}; + auto t = QVector{ + renderive::create_label("悬浮信息"), + renderive::create_toggle_button("启动悬浮信息", "停止悬浮信息", [it]() { + it->set_use_hover_info(!it->use_hover_info()); + }, !it->use_hover_info()), + renderive::create_select_color("设置文字颜色", [it](const QColor& c) { + QPen pen = it->hover_info_pen(); + pen.setColor(c); + it->set_hover_info_pen(pen); + }, it->hover_info_pen().color()), + renderive::create_select_color("设置背景颜色", [it](const QColor& c) { + QBrush brush = it->hover_info_background_brush(); + brush.setColor(c); + it->set_hover_info_background_brush(brush); + }, it->hover_info_background_brush().color()) + }; + return t; +} +static QVector cw(renderive::Waterfall* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + auto timer = new QTimer(it->plot); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + QObject::connect(timer, &QTimer::timeout, [it]() { + QVector d = renderive::get_data(it->power_range(), it->frequency_point_size()); + int tick = it->time_axis()->give_data(QTime::currentTime()); + it->give_data(tick, d); + }); + auto t = QVector{ + renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() { + it->set_visible_range_only(!it->visible_range_only()); + }, it->visible_range_only()), + create_image_interpolation_combo(it), + renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), + }; + return t + cw(static_cast*>(it)); +} +static QVector cw(renderive::Audio_Frequency* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + auto timer = new QTimer(it->plot); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + QObject::connect(timer, &QTimer::timeout, [it]() { + int tick = it->time_axis()->give_data(QTime::currentTime()); + it->give_data(tick, renderive::get_data({0, 20})); + }); + auto t = QVector{ + renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, + {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), + }; + return t; +} +static QVector cw(renderive::Planisphere* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + auto timer = new QTimer(it->plot); + QObject::connect(timer, &QTimer::timeout, [it]() { + for (int i = 0; i < 10; ++i) { + double x = renderive::get_data(it->i_range()); + double y = renderive::get_data(it->q_range()); + it->give_data({x, y}); + } + }); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + auto t = QVector{ + renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, + {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), + renderive::create_edit_widget_list("设置持续时间(ms)", [it](QVector data) { + it->set_continue_millisecond(data[0]); + }, + {it->continue_millisecond()}), + renderive::create_select_color("更改IQ点颜色", [it](const QColor& color) { + it->set_point_color(color); + }, it->point_color()), + renderive::create_select_color("更改锚点颜色", [it](const QColor& color) { + it->set_anchor_color(color); + }, it->anchor_color()), + renderive::create_edit_widget_list("I范围", [it](QVector data) { + it->set_i_range({data[0], data[1]}); + }, {it->i_range().origin, it->i_range().target}), + renderive::create_edit_widget_list("Q范围", [it](QVector data) { + it->set_q_range({data[0], data[1]}); + }, {it->q_range().origin, it->q_range().target}), + renderive::create_button("设置到轴中心", [it]() { + it->set_to_axis_center(); + }), + }; + return t; +} +static QVector cw(renderive::Afterglow* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + static auto create_base_data = [it]() { + renderive::Range r = it->power_range(); + QVector ret(it->frequency_point_size()); + ret[0] = get_data(r); + for (int i = 1; i < it->frequency_point_size(); ++i) { + double rate; + if (i % 20 == 0) { + double that = qAbs(ret[i - 1] - r.origin) / r.size() - 0.5; + rate = (1.0 - that) * renderive::get_data({0.8, 1.2}); + } + else { + rate = renderive::get_data({0.8, 1.2}); + } + ret[i] = renderive::clamp(ret[i - 1] * rate, r.origin, r.target); + } + return ret; + }; + static QVector base_data = create_base_data(); + auto timer = new QTimer(it->plot); + QObject::connect(timer, &QTimer::timeout, [it]() { + renderive::Range r = it->power_range(); + int n = base_data.size(); + QVector cur_data(n); + for (int i = 0; i < n; ++i) { + double rate = renderive::get_data({0.8, 1.2}); + cur_data[i] = renderive::clamp(base_data[i] * rate, r.origin, r.target); + } + it->give_data(cur_data); + }); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + auto t = QVector{ + renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, + {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), + renderive::create_edit_widget_list("频率范围", [it](QVector data) { + it->set_frequency_range({data[0], data[1]}); + }, + {it->frequency_range().origin, it->frequency_range().target}), + renderive::create_edit_widget_list("功率概率范围", [it](QVector data) { + it->set_power_range({data[0], data[1]}); + }, + {it->power_range().origin, it->power_range().target}), + renderive::create_button("更改基础线", []() { + base_data = create_base_data(); + }), + }; + return t; +} +static QVector cw(renderive::Spectrum* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + auto timer = new QTimer(it->plot); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + QObject::connect(timer, &QTimer::timeout, [it]() { + it->give_data(renderive::get_data(it->power_axis()->coord_range(), it->frequency_point_size())); + }); + auto t = QVector{ + renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() { + it->set_visible_range_only(!it->visible_range_only()); + }, it->visible_range_only()), + create_line_interpolation_combo(it), + renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), + renderive::create_edit_widget_list("频率范围", [it](QVector data) { + it->set_frequency_range({data[0], data[1]}); + }, {it->frequency_range().origin, it->frequency_range().target}), + renderive::create_edit_widget_list("设置频率点数", [it](QVector data) { + it->set_frequency_point_size(data[0]); + }, {it->frequency_point_size()}), + renderive::create_label("sweepRect"), + renderive::create_toggle_button("停止sweepRect", "启动sweepRect", [it]() { + it->set_use_sweep_frequency_rect(!it->use_sweep_frequency_rect()); + }, it->use_sweep_frequency_rect()), + renderive::create_edit_widget_list("sweepRect 范围", [it](QVector data) { + if (!it->use_sweep_frequency_rect()) it->set_use_sweep_frequency_rect(true); + it->set_sweep_frequency_range({data[0], data[1]}); + }, {it->sweep_frequency_range().origin, it->sweep_frequency_range().target}), + renderive::create_edit_widget_list("中频", [it](QVector data) { + if (!it->use_sweep_frequency_rect()) it->set_use_sweep_frequency_rect(true); + it->set_middle_sweep_frequency(data[0]); + }, {it->middle_sweep_frequency()}), + renderive::create_select_color("扫频矩形", [it](const QColor& c) { + it->set_sweep_rect_brush(QBrush(c)); + }), + renderive::create_select_color("中频", [it](const QColor& c) { + if (!c.isValid()) { + it->set_middle_frequency_pen(Qt::NoPen); + } + it->set_middle_frequency_pen(QPen(c)); + }, it->middle_frequency_pen().color()), + renderive::create_label("marker"), + renderive::create_toggle_button("停止最大值marker", "启动最大值marker", [it]() { + it->set_use_max_marker(!it->use_max_marker()); + }, it->use_max_marker()), + renderive::create_toggle_button("停止最小值marker", "启动最小值marker", [it]() { + it->set_use_min_marker(!it->use_min_marker()); + }, it->use_min_marker()), + renderive::create_edit_widget_list("添加自定义marker", [it](QVector data) { + it->add_custom_marker(data[0]); + }, {0}), + renderive::create_edit_widget_list("添加自定义Linemarker", [it](QVector data) { + it->add_custom_line_marker(data[0]); + }, {0}), + renderive::create_edit_widget_list("删除marker", [it](QVector data) { + it->remove_custom_marker(data[0]); + }, {0}), + renderive::create_edit_widget_list("清楚所有marker", [it](QVector data) { + it->clear_all_custom_marker(); + }, {}), + renderive::create_edit_widget_list("选择当前marker", [it](QVector data) { + it->set_selected_line_marker(data[0]); + }, {0}), + renderive::create_edit_widget_list("选择下一个marker", [it](QVector data) { + it->select_next(); + }, {}), + renderive::create_edit_widget_list("选择上一个marker", [it](QVector data) { + it->select_previous(); + }, {}), + renderive::create_label("当前线"), + renderive::create_select_color("当前线色", [it](const QColor& c) { + if (!c.isValid()) { + it->set_cur_pen(Qt::NoPen); + return; + } + it->set_cur_pen(c); + }, it->cur_pen().color()), + renderive::create_select_color("当前线填充色", [it](const QColor& c) { + it->set_cur_brush(c); + }, it->cur_brush().color()), + renderive::create_label("最大值线"), + renderive::create_toggle_button("停止最大值线", "启动最大值线", [it]() { + it->set_use_max_line(!it->use_max_line()); + }, it->use_max_line()), + renderive::create_select_color("最大值线色", [it](const QColor& c) { + if (c.isValid()) { + it->set_max_pen(Qt::NoPen); + return; + } + it->set_max_pen(c); + }, it->max_pen().color()), + renderive::create_select_color("最大值线填充色", [it](const QColor& c) { + it->set_max_brush(c); + }, it->max_brush().color()), + renderive::create_label("最小值线"), + renderive::create_toggle_button("停止最小值线", "启动最小值线", [it]() { + it->set_use_min_line(!it->use_min_line()); + }, it->use_min_line()), + renderive::create_select_color("最小值线色", [it](const QColor& c) { + it->set_min_pen(c); + }, it->min_pen().color()), + renderive::create_select_color("最小值线填充色", [it](const QColor& c) { + it->set_min_brush(c); + }, it->min_brush().color()), + }; + return cw(static_cast*>(it)) + t; +} +static QVector cw(renderive::Sweep_Frequency* it, int num_pre_second = -1) { + if (it == nullptr) + return {}; + auto timer = new QTimer(it->plot); + if (num_pre_second > 0) + timer->start(static_cast(1000.0 / static_cast(num_pre_second))); + QObject::connect(timer, &QTimer::timeout, [it]() { + it->give_data(renderive::get_data(it->power_axis()->coord_range(), it->block_frequency_point_size())); + }); + auto t = QVector{ + renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() { + it->set_visible_range_only(!it->visible_range_only()); + }, it->visible_range_only()), + create_line_interpolation_combo(it), renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](QVector data) { + if (data[0] < 0) { + timer->stop(); + } + else { + timer->start((int)(1000.0 / data[0])); + } + }, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), + renderive::create_select_color("线颜色", [it](const QColor& color) { + it->set_pen(QPen(color)); + }, it->pen().color()), + renderive::create_select_color("扫频线颜色", [it](const QColor& color) { + QPen p = it->cur_frequency_pen(); + p.setColor(color); + it->set_cur_frequency_pen(p); + }, it->cur_frequency_pen().color()), + renderive::create_edit_widget_list("频率范围", [it](const QVector& data) { + it->set_frequency_range({data[0], data[1]}); + }, {it->frequency_range().origin, it->frequency_range().target}) + }; + return t; +} +static QMenu* create_menu(renderive::Abs_Plot* plot, const QVector& widgets) { + auto menu = new QMenu(plot); + menu->setObjectName("memu"); + // menu->setStyle(nullptr); + menu->hide(); + menu->setContentsMargins(0, 0, 0, 0); + auto container = create_control(plot, widgets); + auto scroll_area = new QScrollArea; + scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroll_area->setContentsMargins(0, 0, 0, 0); + scroll_area->setWidget(container); + scroll_area->setWidgetResizable(true); + scroll_area->setObjectName("scroll_area"); + auto scrollAction = new QWidgetAction(menu); + scrollAction->setDefaultWidget(scroll_area); + menu->addAction(scrollAction); + return menu; +} +static QMenu* create_menu_normal(QWidget* w, const QVector& widgets) { + auto menu = new QMenu(w); + menu->setObjectName("memu_normal"); + // menu->setStyle(nullptr); + menu->hide(); + menu->setContentsMargins(0, 0, 0, 0); + auto container = new QWidget; + auto l = new QVBoxLayout(container); + l->setAlignment(Qt::AlignTop); + l->setContentsMargins({0, 0, 0, 0}); + l->setSpacing(4); + for (auto widget : widgets) { + l->addWidget(widget); + } + auto scroll_area = new QScrollArea; + scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + scroll_area->setContentsMargins(0, 0, 0, 0); + scroll_area->setWidget(container); + scroll_area->setWidgetResizable(true); + scroll_area->setObjectName("scrollArea2"); + auto scrollAction = new QWidgetAction(menu); + scrollAction->setDefaultWidget(scroll_area); + menu->addAction(scrollAction); + return menu; +} diff --git a/Renderive/base/global.cpp b/Renderive/base/global.cpp new file mode 100644 index 0000000..d32277d --- /dev/null +++ b/Renderive/base/global.cpp @@ -0,0 +1,185 @@ +#include "global.h" +#include +#include +#include "../architecture/Plot_p.h" +#include "asio.hpp" +namespace renderive { +struct Render_Scheduler_Private { + asio::io_context io_context; + std::unique_ptr> work_guard; + std::unique_ptr cpu_pool; + std::thread scheduler_thread; + std::thread::id scheduler_thread_id; + QList plots; + std::atomic_bool running{false}; + std::atomic_bool cpu_joined{true}; +}; +Render_Scheduler::Render_Scheduler() : d(std::make_unique()) { + QObject::connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() { + shutdown(); + }); +} +Render_Scheduler::~Render_Scheduler() { + shutdown(); +} +void Render_Scheduler::start() { + if (d->running.exchange(true, std::memory_order_acq_rel)) + return; + d->io_context.restart(); + d->work_guard = std::make_unique>(d->io_context.get_executor()); + unsigned cpu_count = std::max(1u, std::thread::hardware_concurrency() > 1 ? std::thread::hardware_concurrency() - 1 : 1u); + d->cpu_pool = std::make_unique(cpu_count); + d->cpu_joined.store(false, std::memory_order_release); + d->scheduler_thread = std::thread([this]() { + d->scheduler_thread_id = std::this_thread::get_id(); + for (Abs_Plot* plot : d->plots) { + initialize_plot_on_scheduler(plot); + } + d->io_context.run(); + d->running.store(false, std::memory_order_release); + }); +} +void Render_Scheduler::shutdown() { + if (!d->running.load(std::memory_order_acquire)) { + join_cpu_pool(); + if (d->scheduler_thread.joinable() && d->scheduler_thread.get_id() != std::this_thread::get_id()) + d->scheduler_thread.join(); + d->cpu_pool.reset(); + d->work_guard.reset(); + return; + } + if (is_scheduler_thread()) { + shutdown_on_scheduler(); + d->work_guard.reset(); + join_cpu_pool(); + return; + } + post_and_wait([this]() { + shutdown_on_scheduler(); + }); + join_cpu_pool(); + post([this]() { + d->work_guard.reset(); + }); + if (d->scheduler_thread.joinable()) + d->scheduler_thread.join(); + d->cpu_pool.reset(); +} +void Render_Scheduler::post(std::function task) { + asio::post(d->io_context, std::move(task)); +} +void Render_Scheduler::post_cpu(std::function task) { + if (d->cpu_pool) { + asio::post(*d->cpu_pool, std::move(task)); + } + else { + post(std::move(task)); + } +} +void Render_Scheduler::register_plot(Abs_Plot* plot) { + if (d->running.load(std::memory_order_acquire) && !is_scheduler_thread()) { + post_and_wait([this, plot]() { + register_plot_on_scheduler(plot); + }); + return; + } + register_plot_on_scheduler(plot); +} +void Render_Scheduler::remove_plot(Abs_Plot* plot) { + if (d->running.load(std::memory_order_acquire) && !is_scheduler_thread()) { + post_and_wait([this, plot]() { + remove_plot_on_scheduler(plot); + }); + return; + } + remove_plot_on_scheduler(plot); +} +bool Render_Scheduler::is_scheduler_thread() const { + return std::this_thread::get_id() == d->scheduler_thread_id; +} +bool Render_Scheduler::is_running() const { + return d->running.load(std::memory_order_acquire); +} +asio::io_context& Render_Scheduler::io_context() { + return d->io_context; +} +void Render_Scheduler::join_cpu_pool() { + if (d->cpu_pool && !d->cpu_joined.exchange(true, std::memory_order_acq_rel)) + d->cpu_pool->join(); +} +void Render_Scheduler::post_and_wait(std::function task) { + if (is_scheduler_thread() || !d->running.load(std::memory_order_acquire)) { + task(); + return; + } + std::mutex mutex; + std::condition_variable cv; + bool done = false; + post([&task, &mutex, &cv, &done]() { + task(); + { + std::lock_guard lock(mutex); + done = true; + } + cv.notify_one(); + }); + std::unique_lock lock(mutex); + cv.wait(lock, [&done]() { + return done; + }); +} +void Render_Scheduler::register_plot_on_scheduler(Abs_Plot* plot) { + if (!d->plots.contains(plot)) + d->plots.append(plot); + if (d->running.load(std::memory_order_acquire)) + initialize_plot_on_scheduler(plot); +} +void Render_Scheduler::remove_plot_on_scheduler(Abs_Plot* plot) { + d->plots.removeAll(plot); + Plot_Private* data = plot->d; + data->render_enabled.store(false, std::memory_order_release); + if (data->render_timer) { + data->render_timer->cancel(); + data->render_timer.reset(); + } + if (data->submit_timer) { + data->submit_timer->cancel(); + data->submit_timer.reset(); + } +} +void Render_Scheduler::shutdown_on_scheduler() { + for (Abs_Plot* plot : d->plots) { + Plot_Private* data = plot->d; + data->destroying.store(true, std::memory_order_release); + data->render_enabled.store(false, std::memory_order_release); + if (data->render_timer) { + data->render_timer->cancel(); + data->render_timer.reset(); + } + if (data->submit_timer) { + data->submit_timer->cancel(); + data->submit_timer.reset(); + } + } + d->plots.clear(); +} +void Render_Scheduler::initialize_plot_on_scheduler(Abs_Plot* plot) { + Plot_Private* data = plot->d; + if (!data->render_timer) + data->render_timer = std::make_unique(d->io_context); + if (!data->submit_timer) + data->submit_timer = std::make_unique(d->io_context); + data->render_size = QSize(data->pending_render_width.load(std::memory_order_acquire), data->pending_render_height.load(std::memory_order_acquire)); + if (plot->isVisible()) + data->render_enabled.store(true, std::memory_order_release); + if (data->render_enabled.load(std::memory_order_acquire)) + plot->schedule_render_timer(); + plot->on_render_request(Render_Request_Source::Dirty); +} +Render_Scheduler& Global::render_scheduler() { + return render_scheduler_value; +} +void Global::start_render_scheduler() { + render_scheduler_value.start(); +} +} // namespace renderive diff --git a/YSGraphic_Core/base/global.h b/Renderive/base/global.h similarity index 87% rename from YSGraphic_Core/base/global.h rename to Renderive/base/global.h index 9d0904c..f1ba9a6 100644 --- a/YSGraphic_Core/base/global.h +++ b/Renderive/base/global.h @@ -1,12 +1,11 @@ #pragma once -#include "YSGraphic_Core/architecture/global.h" +#include "Renderive/architecture/global.h" #include "psc_global_include/Singleton.hpp" extern int qInitResources_resource(); -extern int qInitResources_dict(); namespace asio { class io_context; } -namespace YSG { +namespace renderive { class Abs_Plot; struct Render_Scheduler_Private; class LIB_DECL Render_Scheduler { @@ -23,7 +22,7 @@ public: [[nodiscard]] bool is_running() const; asio::io_context& io_context(); private: - void join_cpu_Pool(); + void join_cpu_pool(); void post_and_wait(std::function task); void register_plot_on_scheduler(Abs_Plot* plot); void remove_plot_on_scheduler(Abs_Plot* plot); @@ -34,22 +33,21 @@ private: class LIB_DECL Global : public QObject, public Psc::Singleton { public: int r = qInitResources_resource(); - int dictResource = qInitResources_dict(); - int mInterval = 10; - Render_Scheduler& renderScheduler(); + int interval = 10; + Render_Scheduler& render_scheduler(); void start_render_scheduler(); - QVector mColorMap = get_turbo_color_gradient(); + QVector color_map = get_turbo_color_gradient(); private: - Render_Scheduler mRenderScheduler; + Render_Scheduler render_scheduler_value; }; -} // namespace YSG +} // namespace renderive #define QLOG_POS QString(__func__) + QString(" ") + __FILE__ + QString(":") + QString::number(__LINE__) template struct has_qdebug_stream : std::false_type {}; template struct has_qdebug_stream() << std::declval())>> : std::true_type {}; + decltype(std::declval() << std::declval())>> : std::true_type {}; template QString to_qstring(const T& value) { using C = std::decay_t; diff --git a/YSGraphic_Core/export.cpp b/Renderive/export.cpp similarity index 56% rename from YSGraphic_Core/export.cpp rename to Renderive/export.cpp index 480f30f..2991100 100644 --- a/YSGraphic_Core/export.cpp +++ b/Renderive/export.cpp @@ -1,29 +1,29 @@ #include "export.h" #include #include -ScreenInfo get_screen_info() { - ScreenInfo info; +Screen_Info get_screen_info() { + Screen_Info info; #if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) // Qt5.3+ / Qt6 QScreen* screen = QGuiApplication::primaryScreen(); if (!screen) return info; - info.fullSize = screen->geometry().size(); - info.availableSize = screen->availableGeometry().size(); + info.full_size = screen->geometry().size(); + info.available_size = screen->availableGeometry().size(); #elif QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) // Qt5 早期版本 QDesktopWidget* desktop = QApplication::desktop(); if (!desktop) return info; - info.fullSize = desktop->screenGeometry().size(); - info.availableSize = desktop->availableGeometry().size(); + info.full_size = desktop->screenGeometry().size(); + info.available_size = desktop->availableGeometry().size(); #else // Qt4 QDesktopWidget* desktop = QApplication::desktop(); if (!desktop) return info; - info.fullSize = desktop->screenGeometry().size(); - info.availableSize = desktop->availableGeometry().size(); + info.full_size = desktop->screenGeometry().size(); + info.available_size = desktop->availableGeometry().size(); #endif return info; } diff --git a/Renderive/export.h b/Renderive/export.h new file mode 100644 index 0000000..ce5c0e2 --- /dev/null +++ b/Renderive/export.h @@ -0,0 +1,11 @@ +#pragma once +#include "Axis/export.h" +#include "Generate_Mock_Data.h" +#include "architecture/export.h" +#include "plottable/export.h" +#include "primitive/export.h" +struct Screen_Info { + QSize full_size; + QSize available_size; +}; +Screen_Info get_screen_info(); diff --git a/YSGraphic_Core/main.cpp b/Renderive/main.cpp similarity index 79% rename from YSGraphic_Core/main.cpp rename to Renderive/main.cpp index 38e6ba4..61fc3fa 100644 --- a/YSGraphic_Core/main.cpp +++ b/Renderive/main.cpp @@ -8,7 +8,7 @@ #include #include #include -#include "Demo_Gallery/export.h" +#include "../Demo_Gallery/export.h" #include "Generate_Mock_Data.h" #include "base/Graphic.h" #include "base/Select_Color_Dialog/Select_Color_Dialog.h" @@ -28,13 +28,11 @@ public: image.load("D:/wyc/projects/CLionProjects/plantSunCat/mainProjects/YSGraphic/src/img.png"); } QImage image; -protected: +public: void paintEvent(QPaintEvent* event) override { QPainter painter(this); double w = width(); double h = height(); - // painter.scale(-1.5, 1); - // painter.drawImage(QRectF(-100, 100, 100, 100), image); painter.scale(1.5, 1); painter.drawImage(QRectF(100, 100, 100, 100), image); painter.end(); @@ -47,19 +45,9 @@ int main(int argc, char* argv[]) { #ifdef _WINDOWS SetConsoleOutputCP(CP_UTF8); system("chcp 65001"); -// setbuf(stdout, 0); #endif Button btn; btn.show(); - // WaveWidget w; - // w.resize(400, 400); - // w.show(); return QApplication::exec(); } -int main2(int argc, char* argv[]) { - QApplication a(argc, argv); - WaveWidget w; - w.show(); - return a.exec(); -} #endif diff --git a/YSGraphic_Core/plottable/Afterglow.cpp b/Renderive/plottable/Afterglow.cpp similarity index 50% rename from YSGraphic_Core/plottable/Afterglow.cpp rename to Renderive/plottable/Afterglow.cpp index 2cbc341..113de51 100644 --- a/YSGraphic_Core/plottable/Afterglow.cpp +++ b/Renderive/plottable/Afterglow.cpp @@ -1,6 +1,6 @@ #include #include "Afterglow_p.h" -namespace YSG { +namespace renderive { using Afterglow_Binding = Renderable_Binding; Afterglow::Afterglow() { Afterglow_Binding::init(this, "Afterglow"); @@ -17,12 +17,12 @@ Render_State* Afterglow::create_render_state() { Input_Data* Afterglow::create_input_data() { return Afterglow_Binding::create_input_data(); } -std::shared_ptr Afterglow::frequent_axis(SRC src) { - return d()->state_value(&Afterglow_Render_State::frequent_axis, src).lock(); +std::shared_ptr Afterglow::frequency_axis(SRC src) { + return d()->state_value(&Afterglow_Render_State::frequency_axis, src).lock(); } -void Afterglow::set_frequent_axis(std::shared_ptr value) { - d()->set_state_value(&Afterglow_Render_State::frequent_axis, std::weak_ptr(value)); - if (auto image = mImageItem.lock()) +void Afterglow::set_frequency_axis(std::shared_ptr value) { + d()->set_state_value(&Afterglow_Render_State::frequency_axis, std::weak_ptr(value)); + if (auto image = image_item.lock()) image->set_x_axis(value); } std::shared_ptr Afterglow::power_axis(SRC src) { @@ -30,18 +30,18 @@ std::shared_ptr Afterglow::power_axis(SRC src) { } void Afterglow::set_power_axis(std::shared_ptr value) { d()->set_state_value(&Afterglow_Render_State::power_axis, std::weak_ptr(value)); - if (auto image = mImageItem.lock()) + if (auto image = image_item.lock()) image->set_y_axis(value); } -Range Afterglow::frequent_range(SRC src) { - return d()->state_value(&Afterglow_Render_State::frequent_range, src); +Range Afterglow::frequency_range(SRC src) { + return d()->state_value(&Afterglow_Render_State::frequency_range, src); } -void Afterglow::set_frequent_range(Range value) { +void Afterglow::set_frequency_range(Range value) { if (value.length() == 0.0) return; - d()->set_state_value(&Afterglow_Render_State::frequent_range, std::move(value)); - if (auto image = mImageItem.lock()) - image->set_x_range(frequent_range()); + d()->set_state_value(&Afterglow_Render_State::frequency_range, std::move(value)); + if (auto image = image_item.lock()) + image->set_x_range(frequency_range()); } Range Afterglow::power_range(SRC src) { return d()->state_value(&Afterglow_Render_State::power_range, src); @@ -50,14 +50,14 @@ void Afterglow::set_power_range(Range value) { if (value.size() == 0.0) return; d()->set_state_value(&Afterglow_Render_State::power_range, std::move(value)); - if (auto image = mImageItem.lock()) + if (auto image = image_item.lock()) image->set_y_range(power_range()); - auto bar = mColorBar.lock(); + auto bar = color_bar_item.lock(); if (bar) bar->set_range(power_range()); } -int Afterglow::frequent_point_size(SRC src) { - return d()->state_value(&Afterglow_Render_State::frequent_point_size, src); +int Afterglow::frequency_point_size(SRC src) { + return d()->state_value(&Afterglow_Render_State::frequency_point_size, src); } int Afterglow::power_point_size(SRC src) { return d()->state_value(&Afterglow_Render_State::power_point_size, src); @@ -90,106 +90,106 @@ Color_Map Afterglow::color_map(SRC src) { return d()->state_value(&Afterglow_Render_State::color_map, src); } void Afterglow::set_color_map(Color_Map value) { - auto bar = mColorBar.lock(); + auto bar = color_bar_item.lock(); if (bar) bar->set_color_map(value); d()->set_state_value(&Afterglow_Render_State::color_map, std::move(value)); } std::shared_ptr Afterglow::color_bar() const { - return mColorBar.lock(); + return color_bar_item.lock(); } -void Afterglow::set_frequent_point_size(int t) { +void Afterglow::set_frequency_point_size(int t) { Afterglow_Private* pd = d(); Render_Edit_Lease edit(pd); - edit->frequent_point_size = qMax(1, t); + edit->frequency_point_size = qMax(1, t); edit->power_point_size = qMax(1, edit->power_point_size); - edit->buffer_size = edit->frequent_point_size * edit->power_point_size; + edit->buffer_size = edit->frequency_point_size * edit->power_point_size; } void Afterglow::set_power_point_size(int t) { Afterglow_Private* pd = d(); Render_Edit_Lease edit(pd); - edit->frequent_point_size = qMax(1, edit->frequent_point_size); + edit->frequency_point_size = qMax(1, edit->frequency_point_size); edit->power_point_size = qMax(1, t); - edit->buffer_size = edit->frequent_point_size * edit->power_point_size; + edit->buffer_size = edit->frequency_point_size * edit->power_point_size; } -Afterglow::Builder::Builder(std::shared_ptr parent, std::shared_ptr frequent_axis, std::shared_ptr power_axis) { - init(parent, frequent_axis, power_axis); +Afterglow::Builder::Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis) { + init(parent, frequency_axis, power_axis); } std::shared_ptr Afterglow::Builder::build() { - std::shared_ptr ret(new Afterglow()); + std::shared_ptr < Afterglow > ret(new Afterglow()); set(ret.get()); return ret; } -void Afterglow::give_data(const QVector& powerRangeData) { +void Afterglow::give_data(const QVector& power_range_data) { if (!ok()) return; Afterglow_Private* pd = d(); Render_State_Lease state(pd); - int frequent_point_size = state->frequent_point_size; - if (powerRangeData.size() != frequent_point_size) + int frequency_point_size = state->frequency_point_size; + if (power_range_data.size() != frequency_point_size) return; Render_Input_Lease input(pd); - input->mDataList.push(powerRangeData, Afterglow_Input_Data::Max_Pending_Frame_Count); + input->data_list.push(power_range_data, Afterglow_Input_Data::Max_Pending_Frame_Count); } -void Afterglow_Private::push_data(const QVector& powerRangeData, const Afterglow_Render_State* s) { - if (powerRangeData.size() != s->frequent_point_size || +void Afterglow_Private::push_data(const QVector& power_range_data, const Afterglow_Render_State* s) { + if (power_range_data.size() != s->frequency_point_size || s->init_strong_value <= 0 || s->power_range.size() == 0.0 || - s->frequent_point_size <= 0 || + s->frequency_point_size <= 0 || s->power_point_size <= 0) return; - QVector indexList(s->frequent_point_size); + QVector index_list(s->frequency_point_size); double rate = (double)s->power_point_size / s->power_range.size(); - for (int i = 0; i < s->frequent_point_size; ++i) { - int lineIndex = (int)((powerRangeData[i] - s->power_range.origin) * rate); - if (lineIndex < 0) - lineIndex = 0; - if (lineIndex > s->power_point_size - 1) - lineIndex = s->power_point_size - 1; - indexList[i] = lineIndex; + for (int i = 0; i < s->frequency_point_size; ++i) { + int line_index = (int)((power_range_data[i] - s->power_range.origin) * rate); + if (line_index < 0) + line_index = 0; + if (line_index > s->power_point_size - 1) + line_index = s->power_point_size - 1; + index_list[i] = line_index; } if (!s->interpolate) { - for (int i = 0; i < s->frequent_point_size; ++i) { - int index = indexList[i] * s->frequent_point_size + i; - cachedPowerData[index]++; + for (int i = 0; i < s->frequency_point_size; ++i) { + int index = index_list[i] * s->frequency_point_size + i; + cached_power_data[index]++; } } else { - int lastLower = -1, lastUpper = -1; - for (int i = 0; i < s->frequent_point_size; ++i) { - int y = indexList[i]; - cachedPowerData[y * s->frequent_point_size + i]++; - if (y - lastUpper >= 2) { - for (int curY = lastUpper + 1; curY < y; ++curY) { - cachedPowerData[curY * s->frequent_point_size + i]++; + int last_lower = -1, last_upper = -1; + for (int i = 0; i < s->frequency_point_size; ++i) { + int y = index_list[i]; + cached_power_data[y * s->frequency_point_size + i]++; + if (y - last_upper >= 2) { + for (int cur_y = last_upper + 1; cur_y < y; ++cur_y) { + cached_power_data[cur_y * s->frequency_point_size + i]++; } - lastUpper = y; - lastLower = lastLower + 1; + last_upper = y; + last_lower = last_lower + 1; continue; } - if (lastLower - y >= 2) { - for (int curY = y + 1; curY < lastLower; ++curY) { - cachedPowerData[curY * s->frequent_point_size + i]++; + if (last_lower - y >= 2) { + for (int cur_y = y + 1; cur_y < last_lower; ++cur_y) { + cached_power_data[cur_y * s->frequency_point_size + i]++; } - lastUpper = lastLower - 1; - lastLower = y; + last_upper = last_lower - 1; + last_lower = y; continue; } - lastUpper = y; - lastLower = y; + last_upper = y; + last_lower = y; } } - curIndex++; - if (curIndex < s->init_strong_value) + cur_index++; + if (cur_index < s->init_strong_value) return; - curIndex = 0; - double oldRemain = s->attenuation_rate == 1.0 ? 1.0 : 1.0 - s->attenuation_rate; - double cacheRemain = s->attenuation_rate / (double)s->init_strong_value; - for (int i = 0; i < cacheBufferSize; ++i) { - mergedPowerData[i] = oldRemain * oldCachePowerData[i] + cacheRemain * cachedPowerData[i]; - cachedPowerData[i] = 0; + cur_index = 0; + double old_remain = s->attenuation_rate == 1.0 ? 1.0 : 1.0 - s->attenuation_rate; + double cache_remain = s->attenuation_rate / (double)s->init_strong_value; + for (int i = 0; i < cache_buffer_buffer_size; ++i) { + merged_power_data[i] = old_remain * old_cache_power_data[i] + cache_remain * cached_power_data[i]; + cached_power_data[i] = 0; } - oldCachePowerData = mergedPowerData; - cacheImageDirty = true; + old_cache_power_data = merged_power_data; + cache_image_dirty = true; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Afterglow.h b/Renderive/plottable/Afterglow.h similarity index 62% rename from YSGraphic_Core/plottable/Afterglow.h rename to Renderive/plottable/Afterglow.h index 1c93b4d..8797bc6 100644 --- a/YSGraphic_Core/plottable/Afterglow.h +++ b/Renderive/plottable/Afterglow.h @@ -3,8 +3,8 @@ #include "../primitive/Color_Bar.h" #include "../primitive/Color_Map.h" #include "../primitive/Raster_Image.h" -namespace YSG { -class Frequent_Axis; +namespace renderive { +class Frequency_Axis; class Afterglow_Plot; struct Afterglow_Private; /// 残影频谱图元,按强度衰减显示历史能量。 @@ -15,14 +15,12 @@ public: Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: Afterglow(); -public: - PROP(std::shared_ptr, frequent_axis) + PROP(std::shared_ptr, frequency_axis) PROP(std::shared_ptr, power_axis) - PROP(Range, frequent_range) + PROP(Range, frequency_range) PROP(Range, power_range) - PROP(int, frequent_point_size) + PROP(int, frequency_point_size) PROP(int, power_point_size) PROP(int, buffer_size) PROP(bool, interpolate) @@ -31,19 +29,19 @@ public: PROP(Color_Map, color_map) std::shared_ptr color_bar() const; /// 写入一帧功率数据。 - void give_data(const QVector& powerRangeData); + void give_data(const QVector& power_range_data); template - struct BuilderT; + struct Builder_T; struct Builder; - std::weak_ptr mColorBar; - std::weak_ptr mImageItem; + std::weak_ptr color_bar_item; + std::weak_ptr image_item; }; struct Afterglow_Prop { - std::weak_ptr frequent_axis{}; + std::weak_ptr frequency_axis{}; std::weak_ptr power_axis{}; - Range frequent_range{0, 10}; + Range frequency_range{0, 10}; Range power_range{0, 10}; - int frequent_point_size{}; + int frequency_point_size{}; int power_point_size{}; int buffer_size{}; bool interpolate = true; // 线性插值 @@ -53,12 +51,12 @@ struct Afterglow_Prop { bool color_bar_enabled = false; }; template -struct Afterglow::BuilderT { - PROP_BT(std::shared_ptr, frequent_axis) +struct Afterglow::Builder_T { + PROP_BT(std::shared_ptr, frequency_axis) PROP_BT(std::shared_ptr, power_axis) - PROP_BT(Range, frequent_range) + PROP_BT(Range, frequency_range) PROP_BT(Range, power_range) - PROP_BT(int, frequent_point_size) + PROP_BT(int, frequency_point_size) PROP_BT(int, power_point_size) PROP_BT(int, buffer_size) PROP_BT(bool, interpolate) @@ -67,16 +65,20 @@ struct Afterglow::BuilderT { PROP_BT(Color_Map, color_map) PROP_BT(bool, color_bar_enabled) /// 初始化残影构造器。 - void init(std::shared_ptr parent, std::shared_ptr frequent_axis, std::shared_ptr power_axis); + void init(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis); /// 把构造参数写入目标对象。 void set(Afterglow* t); -protected: std::shared_ptr parent{}; }; -struct LIB_DECL Afterglow::Builder : Afterglow::BuilderT, Afterglow_Prop { - /// 构建并返回残影对象。 +struct LIB_DECL Afterglow::Builder : Afterglow::Builder_T, Afterglow_Prop{ + /// 构建并返回残影对象。 std::shared_ptr build(); - /// 创建残影构造器。 - Builder(std::shared_ptr parent, std::shared_ptr frequent_axis, std::shared_ptr power_axis); -}; -} // namespace YSG + /// 创建残影构造器。 + Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis); + + + + + + }; +} // namespace renderive diff --git a/Renderive/plottable/Afterglow_p.h b/Renderive/plottable/Afterglow_p.h new file mode 100644 index 0000000..61e4777 --- /dev/null +++ b/Renderive/plottable/Afterglow_p.h @@ -0,0 +1,159 @@ +#pragma once +#include +#include +#include "../Axis/Frequency_Axis.h" +#include "../Axis/Frequency_Axis_p.h" +#include "../architecture/Bounded_Input_Buffer.h" +#include "../architecture/Plot_p.h" +#include "../base/global.h" +#include "../primitive/Raster_Image.h" +#include "Afterglow.h" +#include "Performance_Shower_p.h" +namespace renderive { +struct Afterglow_Render_State : Render_State, Afterglow_Prop {}; +struct Afterglow_Input_Data : Input_Data { + static constexpr std::size_t Max_Pending_Frame_Count = 4; + Bounded_Vector_Double_Input_Buffer data_list; + void clear() override { + data_list.clear(); + } + std::uint64_t get_pending_count() const override { + return data_list.pending_count(); + } + std::uint64_t get_dropped_count() const override { + return data_list.dropped_count(); + } + std::uint64_t get_capacity_dropped_count() const override { + return data_list.capacity_dropped_count(); + } + std::uint64_t rebuild_dropped_count() const override { + return data_list.rebuild_dropped_count(); + } + std::uint64_t consumer_dropped_count() const override { + return data_list.consumer_dropped_count(); + } + std::uint64_t get_pushed_count() const override { + return data_list.pushed_count(); + } +}; +struct Afterglow_Private : Typed_Render_Data { + friend class Afterglow; + Raster_Image_Buffer image; + bool cache_image_dirty = false; + int cur_index = 0; + int cache_frequency_point_size{}; + int cache_power_point_point_size{}; + int cache_buffer_buffer_size{}; + std::uint64_t cache_color_map_hash{}; + QVector cached_power_data; + QVector old_cache_power_data; + QVector merged_power_data; + [[nodiscard]] int strength_value(const Afterglow_Render_State* s) const { + if (s->attenuation_rate == 1.0) + return std::numeric_limits::max(); + return (int)((double)s->init_strong_value / (1.0 - s->attenuation_rate)); + } + void update_cache_size(int frequency_point_size, int power_point_size) { + cache_frequency_point_size = frequency_point_size; + cache_power_point_point_size = power_point_size; + cache_buffer_buffer_size = frequency_point_size * power_point_size; + cached_power_data.resize(cache_buffer_buffer_size); + cached_power_data.fill(0); + old_cache_power_data.resize(cache_buffer_buffer_size); + old_cache_power_data.fill(0); + merged_power_data.resize(cache_buffer_buffer_size); + merged_power_data.fill(0); + cur_index = 0; + } + void push_data(const QVector& power_range_data, const Afterglow_Render_State* s); + void draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) override { + Q_UNUSED(painter) + Afterglow_Render_State* s = render_state(); + Performance_Shower* shower = snapshot.performance_shower.get(); + if (shower) { + shower->set_performance_line("col_count, row_count", Performance_Line(QString("col_count:%1, row_count:%2").arg(s->frequency_point_size).arg(s->power_point_size))); + } + } + void prepare_data(const Plot_Render_Snapshot& snapshot) override { + sync_state_pipeline(); + Afterglow_Render_State* s = render_state(); + if (s->frequency_point_size <= 0 || s->power_point_size <= 0) + return; + if (cache_frequency_point_size != s->frequency_point_size || cache_power_point_point_size != s->power_point_size) { + update_cache_size(s->frequency_point_size, s->power_point_size); + } + bool image_size_changed = image.width() != s->frequency_point_size || image.height() != s->power_point_size; + std::uint64_t color_map_hash = s->color_map.hash(); + if (cache_color_map_hash != color_map_hash) { + cache_color_map_hash = color_map_hash; + cache_image_dirty = true; + } + if (image_size_changed) { + image.resize(s->frequency_point_size, s->power_point_size); + image.fill(Qt::transparent); + cache_image_dirty = true; + } + Afterglow_Input_Data* input = render_input_data(); + input->data_list.read_all([this, s, input](const QVector& data) { + if (data.size() != s->frequency_point_size) { + input->data_list.record_consumer_dropped(); + return; + } + push_data(data, s); + }); + if (cache_image_dirty) { + Performance_Scope_Timer c("Afterglow set_time:%1 SRTT:%2 RTTVAR:%3", snapshot.performance_shower.get()); + image.write_normalized_grid(old_cache_power_data.data(), s->frequency_point_size, s->power_point_size, s->color_map); + cache_image_dirty = false; + if (auto image_item = q()->image_item.lock()) + image_item->give_image(image.image(), false); + } + clear_render_input(); + } +}; +template +void Afterglow::Builder_T::init(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis) { + ASSERT(parent && parent->plot, "Afterglow build error! parent invalid"); + ASSERT(frequency_axis && power_axis, "Afterglow build error! axis == nullptr"); + ASSERT(frequency_axis->plot != nullptr, "Afterglow build error! frequency_axis->plot == nullptr"); + ASSERT(frequency_axis->plot == power_axis->plot, "Afterglow build error! frequency_axis->plot != power_axis->plot"); + ASSERT(parent->plot == frequency_axis->plot, "Afterglow build error! parent->plot != frequency_axis->plot"); + this->parent = parent; + static_cast(this)->frequency_axis = frequency_axis; + static_cast(this)->power_axis = power_axis; +} +template +void Afterglow::Builder_T::set(Afterglow* ret) { + ret->init(parent); + std::shared_ptr owner = ret->shared_from_this(); + Afterglow_Private* pd = ret->d(); + Afterglow_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); + PROP_RT(std::weak_ptr, frequency_axis) + PROP_RT(std::weak_ptr, power_axis) + PROP_RT(Range, frequency_range) + PROP_RT(Range, power_range) + PROP_RT(int, frequency_point_size) + PROP_RT(int, power_point_size) + PROP_RT(int, buffer_size) + PROP_RT(bool, interpolate) + PROP_RT(double, attenuation_rate) + PROP_RT(int, init_strong_value) + PROP_RT(Color_Map, color_map) + sc->frequency_point_size = qMax(1, sc->frequency_point_size); + sc->power_point_size = qMax(1, sc->power_point_size); + sc->buffer_size = qMax(1, sc->frequency_point_size * sc->power_point_size); + sc->attenuation_rate = std::clamp(sc->attenuation_rate, 0.0, 1.0); + sc->init_strong_value = qMax(1, sc->init_strong_value); + auto frequency_axis = static_cast(this)->frequency_axis.lock(); + auto power_axis = static_cast(this)->power_axis.lock(); + if (frequency_axis && power_axis) { + auto image = Raster_Image::Builder(owner, frequency_axis, power_axis).set_x_range(sc->frequency_range).set_y_range(sc->power_range).build(); + image->object_name = "AfterglowRasterImage"; + ret->image_item = image; + } + if (static_cast(this)->color_bar_enabled) { + auto bar = Color_Bar::Builder(owner).set_color_map(sc->color_map).set_range(sc->power_range).set_name("Afterglow").build(); + ret->color_bar_item = bar; + } +} +} // namespace renderive diff --git a/Renderive/plottable/Audio_Frequency.cpp b/Renderive/plottable/Audio_Frequency.cpp new file mode 100644 index 0000000..63f5393 --- /dev/null +++ b/Renderive/plottable/Audio_Frequency.cpp @@ -0,0 +1,102 @@ +#include "../Axis/Time_Axis.h" +#include "Audio_Frequency_p.h" +namespace renderive { +using Audio_Frequency_Binding = Renderable_Binding; +Audio_Frequency::Audio_Frequency() { + Audio_Frequency_Binding::init(this, "Audio_Frequency"); +} +Audio_Frequency_Private* Audio_Frequency::d() { + return Audio_Frequency_Binding::d(this); +} +Render_Data* Audio_Frequency::create_render_data() { + return Audio_Frequency_Binding::create_render_data(); +} +Render_State* Audio_Frequency::create_render_state() { + return Audio_Frequency_Binding::create_render_state(); +} +Input_Data* Audio_Frequency::create_input_data() { + return Audio_Frequency_Binding::create_input_data(); +} +int Audio_Frequency::time_point_size(SRC src) { + return d()->state_value(&Audio_Frequency_Render_State::time_point_size, src); +} +void Audio_Frequency::set_time_point_size(int value) { + d()->set_state_value(&Audio_Frequency_Render_State::time_point_size, qMax(1, value)); +} +std::shared_ptr Audio_Frequency::time_axis(SRC src) { + return d()->state_value(&Audio_Frequency_Render_State::time_axis, src).lock(); +} +void Audio_Frequency::set_time_axis(std::shared_ptr value) { + d()->set_state_value(&Audio_Frequency_Render_State::time_axis, std::weak_ptr(value)); + if (auto curve = curve_item.lock()) + curve->set_x_axis(value); +} +std::shared_ptr Audio_Frequency::value_axis(SRC src) { + return d()->state_value(&Audio_Frequency_Render_State::value_axis, src).lock(); +} +void Audio_Frequency::set_value_axis(std::shared_ptr value) { + d()->set_state_value(&Audio_Frequency_Render_State::value_axis, std::weak_ptr(value)); + if (auto curve = curve_item.lock()) + curve->set_y_axis(value); +} +Range Audio_Frequency::key_range(SRC src) { + return d()->state_value(&Audio_Frequency_Render_State::key_range, src); +} +void Audio_Frequency::set_key_range(Range value) { + if (value.length() == 0.0) + return; + d()->set_state_value(&Audio_Frequency_Render_State::key_range, std::move(value)); +} +QColor Audio_Frequency::color(SRC src) { + return d()->state_value(&Audio_Frequency_Render_State::color, src); +} +void Audio_Frequency::set_color(QColor value) { + if (auto curve = curve_item.lock()) { + QPen pen(value); + pen.setWidth(0); + curve->set_pen(pen); + } + d()->set_state_value(&Audio_Frequency_Render_State::color, std::move(value)); +} +Audio_Frequency::Builder::Builder(std::shared_ptr parent, std::shared_ptr time_axis, std::shared_ptr value_axis) { + ASSERT(parent && parent->plot, "Audio_Frequency build error! parent invalid"); + ASSERT(time_axis && value_axis, "Audio_Frequency build error! axis == nullptr"); + ASSERT(time_axis->plot != nullptr, "Audio_Frequency build error! time_axis->plot == nullptr"); + ASSERT(time_axis->plot == value_axis->plot, "Audio_Frequency build error! time_axis->plot != value_axis->plot"); + ASSERT(parent->plot == time_axis->plot, "Audio_Frequency build error! parent->plot != time_axis->plot"); + this->parent = parent; + this->time_axis = time_axis; + this->value_axis = value_axis; +} +std::shared_ptr Audio_Frequency::Builder::build() { + std::shared_ptr < Audio_Frequency > ret(new Audio_Frequency()); + ret->init(parent); + Audio_Frequency_Private* pd = ret->d(); + Audio_Frequency_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); + PROP_R(int, time_point_size) + PROP_R(std::weak_ptr, time_axis) + PROP_R(std::weak_ptr, value_axis) + PROP_R(Range, key_range) + PROP_R(QColor, color) + sc->time_point_size = qMax(1, sc->time_point_size); + if (sc->key_range.length() == 0.0) + sc->key_range = {0.0, 1.0}; + auto time_axis = this->time_axis.lock(); + auto value_axis = this->value_axis.lock(); + if (time_axis && value_axis) { + QPen pen(sc->color); + pen.setWidth(0); + auto curve = Curve::Builder(ret, time_axis, value_axis).set_pen(pen).build(); + curve->object_name = "Audio_Frequency_Curve"; + ret->curve_item = curve; + } + return ret; +} +void Audio_Frequency::give_data(int tick, double data) { + Q_UNUSED(tick) + if (!ok()) + return; + Render_Input_Lease input(d()); + input->data_list.push(data, Audio_Frequency_Input_Data::Max_Pending_Value_Count); +} +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Audio_Frequent.h b/Renderive/plottable/Audio_Frequency.h similarity index 74% rename from YSGraphic_Core/plottable/Audio_Frequent.h rename to Renderive/plottable/Audio_Frequency.h index ab0172e..55b6f08 100644 --- a/YSGraphic_Core/plottable/Audio_Frequent.h +++ b/Renderive/plottable/Audio_Frequency.h @@ -1,20 +1,18 @@ #pragma once #include "global.h" #include "../primitive/Curve.h" -namespace YSG { +namespace renderive { class Time_Axis; -struct Audio_Frequent_Private; +struct Audio_Frequency_Private; /// 音频频率随时间变化的折线图元。 -class LIB_DECL Audio_Frequent : public Renderable { +class LIB_DECL Audio_Frequency : public Renderable { public: /// 返回私有渲染数据。 - Audio_Frequent_Private* d(); + Audio_Frequency_Private* d(); Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: - Audio_Frequent(); -public: + Audio_Frequency(); /// 写入一个 tick 和对应数值。 void give_data(int tick, double data); PROP(int, time_point_size) @@ -23,18 +21,17 @@ public: PROP(Range, key_range) PROP(QColor, color) struct Builder; -protected: - friend struct Audio_Frequent_Private; - std::weak_ptr mCurve; + friend struct Audio_Frequency_Private; + std::weak_ptr curve_item; }; -struct AudioFrequent_Prop { +struct Audio_Frequency_Prop { int time_point_size = 100; std::weak_ptr time_axis; std::weak_ptr value_axis{}; Range key_range = {0, 20}; QColor color = Qt::yellow; }; -struct LIB_DECL Audio_Frequent::Builder : AudioFrequent_Prop { +struct LIB_DECL Audio_Frequency::Builder : Audio_Frequency_Prop{ PROP_B(int, time_point_size) PROP_B(std::shared_ptr, time_axis) PROP_B(std::shared_ptr, value_axis) @@ -43,8 +40,9 @@ struct LIB_DECL Audio_Frequent::Builder : AudioFrequent_Prop { /// 创建音频频率构造器。 Builder(std::shared_ptr parent, std::shared_ptr time_axis, std::shared_ptr value_axis); /// 构建并返回音频频率对象。 - std::shared_ptr build(); -protected: + std::shared_ptr build(); std::shared_ptr parent{}; + + }; -} // namespace YSG +} // namespace renderive diff --git a/Renderive/plottable/Audio_Frequency_p.h b/Renderive/plottable/Audio_Frequency_p.h new file mode 100644 index 0000000..57f30c6 --- /dev/null +++ b/Renderive/plottable/Audio_Frequency_p.h @@ -0,0 +1,103 @@ +#pragma once +#include "../Axis/Axis_p.h" +#include "../Axis/Time_Axis_p.h" +#include "../architecture/Bounded_Input_Buffer.h" +#include "../architecture/Plot_p.h" +#include "../architecture/Renderable.h" +#include "../primitive/Curve.h" +#include "Audio_Frequency.h" +#include "Performance_Shower_p.h" +namespace renderive { +struct Audio_Frequency_Input_Data : Input_Data { + static constexpr std::size_t Max_Pending_Value_Count = 16; + Bounded_Double_Input_Buffer data_list; + void clear() override { + data_list.clear(); + } + std::uint64_t get_pending_count() const override { + return data_list.pending_count(); + } + std::uint64_t get_dropped_count() const override { + return data_list.dropped_count(); + } + std::uint64_t get_capacity_dropped_count() const override { + return data_list.capacity_dropped_count(); + } + std::uint64_t rebuild_dropped_count() const override { + return data_list.rebuild_dropped_count(); + } + std::uint64_t consumer_dropped_count() const override { + return data_list.consumer_dropped_count(); + } + std::uint64_t get_pushed_count() const override { + return data_list.pushed_count(); + } +}; +struct Audio_Frequency_Render_State : Render_State, Audio_Frequency_Prop {}; +struct Audio_Frequency_Private : Typed_Render_Data { + friend class Audio_Frequency; + Psc::StreamRingBuffer_ST buffer; + std::vector power_snapshot; + int data_count{}; + int point_count{}; + void resize_power_buffer(int count) { + point_count = count; + data_count = 0; + power_snapshot.resize(count); + buffer.init(sizeof(double) * count); + } + void push_power(double power) { + if (data_count == point_count) { + double ignored; + std::size_t len = sizeof(double); + buffer.read(&ignored, len); + --data_count; + } + buffer.write(&power, sizeof(double)); + ++data_count; + } + void snapshot_power_buffer() { + buffer.peek_best_effort(power_snapshot.data(), sizeof(double) * data_count); + } + void prepare_data(const Plot_Render_Snapshot& snapshot) override { + sync_state_pipeline(); + Audio_Frequency_Render_State* s = render_state(); + Audio_Frequency_Input_Data* d = render_input_data(); + if (point_count != s->time_point_size) { + resize_power_buffer(s->time_point_size); + Performance_Shower* shower = snapshot.performance_shower.get(); + if (shower) { + shower->set_performance_line("TimePointSize", Performance_Line(QString("time_point_size:%1").arg(s->time_point_size))); + } + } + d->data_list.read_all([this](double power) { + push_power(power); + }); + snapshot_power_buffer(); + auto time_axis = s->time_axis.lock(); + auto value_axis = s->value_axis.lock(); + if (time_axis && value_axis) { + int start = (int)time_axis->start_coord(); + QVector points = Curve_Utils::create_points(data_count, [this, time_axis, start](int i) { + double* power = power_snapshot.data() + data_count - 1 - i; + int index = time_axis->d()->time_ticker.start_coord_to_end_coord ? start + i : start + time_axis->d()->time_ticker.time_point_size - i; + return QPointF(index, *power); + }); + if (auto curve = q()->curve_item.lock()) + curve->give_points(points, false); + } + clear_render_input(); + } + void draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) override { + Q_UNUSED(painter) + Audio_Frequency_Render_State* s = render_state(); + auto time_axis = s->time_axis.lock(); + if (!time_axis) + return; + Performance_Shower* shower = snapshot.performance_shower.get(); + if (shower) { + shower->set_performance_line("time_point_size", Performance_Line(QString("time_point_size:%1").arg(time_axis->time_point_size()))); + } + } +}; +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Hover_Info.cpp b/Renderive/plottable/Hover_Info.cpp similarity index 67% rename from YSGraphic_Core/plottable/Hover_Info.cpp rename to Renderive/plottable/Hover_Info.cpp index 6e4712b..86a28ce 100644 --- a/YSGraphic_Core/plottable/Hover_Info.cpp +++ b/Renderive/plottable/Hover_Info.cpp @@ -1,12 +1,12 @@ #include "Hover_Info.h" -namespace YSG { +namespace renderive { void Hover_Info_Render_State::draw_hover(QPainter* painter, Abs_Axis* h, Abs_Axis* v) { QPoint pos = hover_info_pos; - if (!renderAble) { + if (!renderable) { auto that = dynamic_cast(this); - renderAble = dynamic_cast(that->dPtr->qPtr); + renderable = dynamic_cast(that->d_ptr->q_ptr); } - QVector lines = renderAble->create_hover_string(h, v, pos); + QVector lines = renderable->create_hover_string(h, v, pos); QFontMetrics fm(hover_info_font); int width = std::numeric_limits::min(); for (QString& s : lines) @@ -16,21 +16,21 @@ void Hover_Info_Render_State::draw_hover(QPainter* painter, Abs_Axis* h, Abs_Axi painter->fillRect(r, hover_info_brush); painter->setPen(hover_info_pen); painter->setFont(hover_info_font); - int lineHeight = fm.height(); + int line_height = fm.height(); for (int i = 0; i < lines.size(); ++i) { - QRect lineRect(r.left(), r.top() + i * lineHeight, r.width(), lineHeight); - painter->drawText(lineRect, Qt::AlignCenter, lines[i]); + QRect line_rect(r.left(), r.top() + i * line_height, r.width(), line_height); + painter->drawText(line_rect, Qt::AlignCenter, lines[i]); } } bool Hover_Info_Render_State::hover_ok(Renderable* able) const { - auto tmp = dynamic_cast(able); + auto tmp = dynamic_cast(able); return use_hover_info && hover_info_active && tmp->hover_test(hover_info_pos); } -QVector Hover_Info_Render_Able_InterFace::create_hover_string(Abs_Axis* h, Abs_Axis* v, QPoint pos) { +QVector Hover_Info_Renderable_Interface::create_hover_string(Abs_Axis* h, Abs_Axis* v, QPoint pos) { double tick1 = h->pixel_to_coord(pos.x(), SRC::Render); double tick2 = v->pixel_to_coord(pos.y(), SRC::Render); QString line1 = h->get_tick_label(tick1, SRC::Render) + h->unit_text(); QString line2 = v->get_tick_label(tick2, SRC::Render) + v->unit_text(); return {line1, line2}; } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Hover_Info.h b/Renderive/plottable/Hover_Info.h similarity index 79% rename from YSGraphic_Core/plottable/Hover_Info.h rename to Renderive/plottable/Hover_Info.h index 05c9732..7e4f1bb 100644 --- a/YSGraphic_Core/plottable/Hover_Info.h +++ b/Renderive/plottable/Hover_Info.h @@ -1,9 +1,9 @@ #pragma once #include "../Axis/export.h" #include "../architecture/export.h" -namespace YSG { +namespace renderive { struct Hover_Info_Render_State; -struct Hover_Info_Render_Able_InterFace; +struct Hover_Info_Renderable_Interface; struct LIB_DECL Hover_Info_Render_State { virtual ~Hover_Info_Render_State() = default; Hover_Info_Render_State() { @@ -16,13 +16,13 @@ struct LIB_DECL Hover_Info_Render_State { bool use_hover_info = true; bool hover_info_active = false; QPoint hover_info_pos; - Hover_Info_Render_Able_InterFace* renderAble{}; + Hover_Info_Renderable_Interface* renderable{}; void draw_hover(QPainter* painter, Abs_Axis* h, Abs_Axis* v); bool hover_ok(Renderable* able) const; }; -struct LIB_DECL Hover_Info_Render_Able_InterFace { +struct LIB_DECL Hover_Info_Renderable_Interface { virtual QVector create_hover_string(Abs_Axis* h, Abs_Axis* v, QPoint pos); - virtual ~Hover_Info_Render_Able_InterFace() = default; + virtual ~Hover_Info_Renderable_Interface() = default; virtual void draw_hover(QPainter* painter, Abs_Axis* h, Abs_Axis* v) { return hover_state(SRC::Render)->draw_hover(painter, h, v); } @@ -79,12 +79,11 @@ struct LIB_DECL Hover_Info_Render_Able_InterFace { sc->hover_info_bottom = bottom; finish_hover_edit(); } -protected: virtual Hover_Info_Render_State* hover_state(SRC src) = 0; virtual Hover_Info_Render_State* begin_hover_edit() = 0; virtual void finish_hover_edit() = 0; }; -struct LIB_DECL Hover_Info_Independ_Render_Able : Hover_Info_Render_Able_InterFace { +struct LIB_DECL Hover_Info_Independent_Renderable : Hover_Info_Renderable_Interface { private: Hover_Info_Render_State s, sc; Hover_Info_Render_State* hover_state(SRC src) override { @@ -96,38 +95,37 @@ private: Hover_Info_Render_State* begin_hover_edit() override { return ≻ } - void finish_hover_edit() override { - } + void finish_hover_edit() override {} public: void draw_hover(QPainter* painter, Abs_Axis* h, Abs_Axis* v) override { - s.renderAble = this; - sc.renderAble = this; + s.renderable = this; + sc.renderable = this; s = sc; - Hover_Info_Render_Able_InterFace::draw_hover(painter, h, v); + Hover_Info_Renderable_Interface::draw_hover(painter, h, v); } }; template -struct LIB_DECL Hover_Info_Render_Able : Hover_Info_Render_Able_InterFace { +struct LIB_DECL Hover_Info_Renderable : Hover_Info_Renderable_Interface { private: That* that() { return static_cast(this); } - Triple_Buffer_Lease mHoverLease{}; + Triple_Buffer_Lease hover_lease{}; Hover_Info_Render_State* hover_state(SRC src) override { auto t = that(); - return dynamic_cast(t->dPtr->state(src)); + return dynamic_cast(t->d_ptr->state(src)); } Hover_Info_Render_State* begin_hover_edit() override { auto t = that(); - mHoverLease = t->dPtr->mStateControl.wait_mark_use_role(State_Edit); - return dynamic_cast(t->dPtr->state_by_index(mHoverLease.index)); + hover_lease = t->d_ptr->state_control.wait_mark_use_role(State_Edit); + return dynamic_cast(t->d_ptr->state_by_index(hover_lease.index)); } void finish_hover_edit() override { auto t = that(); - ++t->dPtr->state_by_index(mHoverLease.index)->version; + ++t->d_ptr->state_by_index(hover_lease.index)->version; t->mark_render_dirty(); - t->dPtr->mStateControl.unmark_use(mHoverLease); - mHoverLease = {}; + t->d_ptr->state_control.unmark_use(hover_lease); + hover_lease = {}; } }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Interpolation.h b/Renderive/plottable/Interpolation.h similarity index 94% rename from YSGraphic_Core/plottable/Interpolation.h rename to Renderive/plottable/Interpolation.h index e80117f..085a7d1 100644 --- a/YSGraphic_Core/plottable/Interpolation.h +++ b/Renderive/plottable/Interpolation.h @@ -1,6 +1,6 @@ #pragma once #include -namespace YSG { +namespace renderive { /// 频谱线从输入采样点生成屏幕曲线时使用的插值方式。 enum class Line_Interpolation_Mode : std::uint8_t { /// 使用最近的频点值,不做连续插值。 @@ -25,4 +25,4 @@ enum class Image_Interpolation_Mode : std::uint8_t { /// 双三次插值。 Bicubic }; -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Interpolation_p.h b/Renderive/plottable/Interpolation_p.h similarity index 99% rename from YSGraphic_Core/plottable/Interpolation_p.h rename to Renderive/plottable/Interpolation_p.h index effcd08..a8f52bc 100644 --- a/YSGraphic_Core/plottable/Interpolation_p.h +++ b/Renderive/plottable/Interpolation_p.h @@ -6,7 +6,7 @@ #include #include "../Axis/Abs_Axis.h" #include "Interpolation.h" -namespace YSG { +namespace renderive { struct Line_Sample_Window { double first_index{}; double last_index{}; @@ -142,4 +142,4 @@ inline QImage bicubic_scale(const QImage& source, const QRectF& source_rect, con } return target; } -} // namespace YSG +} // namespace renderive diff --git a/Renderive/plottable/Multi_Select_Rect.cpp b/Renderive/plottable/Multi_Select_Rect.cpp new file mode 100644 index 0000000..cad9e0c --- /dev/null +++ b/Renderive/plottable/Multi_Select_Rect.cpp @@ -0,0 +1,78 @@ +#include "Multi_Select_Rect_p.h" +namespace renderive { +using Multi_Select_Rect_Binding = Renderable_Binding; +Multi_Select_Rect::Multi_Select_Rect() { + Multi_Select_Rect_Binding::init(this, "Multi_Select_Rect"); +} +Multi_Select_Rect_Private* Multi_Select_Rect::d() { + return Multi_Select_Rect_Binding::d(this); +} +Render_Data* Multi_Select_Rect::create_render_data() { + return Multi_Select_Rect_Binding::create_render_data(); +} +Render_State* Multi_Select_Rect::create_render_state() { + return Multi_Select_Rect_Binding::create_render_state(); +} +Input_Data* Multi_Select_Rect::create_input_data() { + return Multi_Select_Rect_Binding::create_input_data(); +} +Multi_Select_Rect::Builder::Builder(std::shared_ptr parent, std::shared_ptr key_axis, std::shared_ptr value_axis) { + ASSERT(parent && parent->plot, "Multi_Select_Rect build error! parent invalid"); + ASSERT(key_axis && value_axis, "Multi_Select_Rect build error! axis == nullptr"); + ASSERT(key_axis->plot != nullptr, "Multi_Select_Rect build error! key_axis->plot == nullptr"); + ASSERT(key_axis->plot == value_axis->plot, "Multi_Select_Rect build error! key_axis->plot != value_axis->plot"); + ASSERT(parent->plot == key_axis->plot, "Multi_Select_Rect build error! parent->plot != key_axis->plot"); + this->parent = parent; + this->key_axis = key_axis; + this->value_axis = value_axis; +} +std::shared_ptr Multi_Select_Rect::Builder::build() { + std::shared_ptr < Multi_Select_Rect > ret(new Multi_Select_Rect()); + ret->init(parent); + Multi_Select_Rect_Private* pd = ret->d(); + Multi_Select_Rect_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); + sc->horizontal_axis = key_axis; + sc->vertical_axis = value_axis; + sc->font = font; + sc->font_pen = font_pen; + sc->rect_brush = rect_brush; + sc->border_pen = border_pen; + return ret; +} +void Multi_Select_Rect::set_horizontal_axis(std::shared_ptr axis) { + Render_Edit_Lease edit(d()); + edit->horizontal_axis = std::weak_ptr(axis); +} +void Multi_Select_Rect::set_vertical_axis(std::shared_ptr axis) { + Render_Edit_Lease edit(d()); + edit->vertical_axis = std::weak_ptr(axis); +} +QFont Multi_Select_Rect::font(SRC src) { + return d()->state_data(src)->font; +} +QPen Multi_Select_Rect::font_pen(SRC src) { + return d()->state_data(src)->font_pen; +} +QBrush Multi_Select_Rect::rect_brush(SRC src) { + return d()->state_data(src)->rect_brush; +} +QPen Multi_Select_Rect::border_pen(SRC src) { + return d()->state_data(src)->border_pen; +} +void Multi_Select_Rect::set_font(const QFont& font) { + Render_Edit_Lease edit(d()); + edit->font = font; +} +void Multi_Select_Rect::set_font_pen(const QPen& pen) { + Render_Edit_Lease edit(d()); + edit->font_pen = pen.color().isValid() ? pen : Qt::NoPen; +} +void Multi_Select_Rect::set_rect_brush(const QBrush& brush) { + Render_Edit_Lease edit(d()); + edit->rect_brush = brush.color().isValid() ? brush : Qt::NoBrush; +} +void Multi_Select_Rect::set_border_pen(const QPen& pen) { + Render_Edit_Lease edit(d()); + edit->border_pen = pen.color().isValid() ? pen : Qt::NoPen; +} +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Muti_Select_Rect.h b/Renderive/plottable/Multi_Select_Rect.h similarity index 79% rename from YSGraphic_Core/plottable/Muti_Select_Rect.h rename to Renderive/plottable/Multi_Select_Rect.h index 14c94c6..92dc329 100644 --- a/YSGraphic_Core/plottable/Muti_Select_Rect.h +++ b/Renderive/plottable/Multi_Select_Rect.h @@ -1,17 +1,16 @@ #pragma once #include "global.h" -namespace YSG { -struct Muti_Select_Rect_Private; +namespace renderive { +struct Multi_Select_Rect_Private; /// 多区域框选图元。 -class LIB_DECL Muti_Select_Rect : public Renderable { +class LIB_DECL Multi_Select_Rect : public Renderable { public: /// 返回私有渲染数据。 - Muti_Select_Rect_Private* d(); + Multi_Select_Rect_Private* d(); Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: - Muti_Select_Rect(); + Multi_Select_Rect(); public: /// 设置水平坐标轴。 void set_horizontal_axis(std::shared_ptr axis); @@ -35,7 +34,7 @@ public: void set_border_pen(const QPen& pen); struct Builder; }; -struct LIB_DECL Muti_Select_Rect::Builder { +struct LIB_DECL Multi_Select_Rect::Builder { SETTER(QFont, font, QFont()) SETTER(QPen, font_pen, QPen(Qt::white)) SETTER(QBrush, rect_brush, QColor(0, 0, 255, 50)) @@ -45,12 +44,11 @@ struct LIB_DECL Muti_Select_Rect::Builder { return pen; }()) /// 创建多区域框选构造器。 - Builder(std::shared_ptr parent, std::shared_ptr keyAxis, std::shared_ptr value_axis); + Builder(std::shared_ptr parent, std::shared_ptr key_axis, std::shared_ptr value_axis); /// 构建并返回多区域框选对象。 - std::shared_ptr build(); -protected: - std::weak_ptr keyAxis; + std::shared_ptr build(); + std::weak_ptr key_axis; std::weak_ptr value_axis{}; std::shared_ptr parent{}; }; -} // namespace YSG +} // namespace renderive diff --git a/Renderive/plottable/Multi_Select_Rect_p.h b/Renderive/plottable/Multi_Select_Rect_p.h new file mode 100644 index 0000000..10807a9 --- /dev/null +++ b/Renderive/plottable/Multi_Select_Rect_p.h @@ -0,0 +1,128 @@ +#pragma once +#include +#include "../Axis/Abs_Axis.h" +#include "Multi_Select_Rect.h" +namespace renderive { +struct Multi_Select_Rect_Render_State : renderive::Render_State { + QVector rects; + QFont font; + QPen border_pen, font_pen = QPen(Qt::white); + QBrush rect_brush = QColor(0, 0, 255, 50); + std::weak_ptr horizontal_axis{}, vertical_axis{}; + Multi_Select_Rect_Render_State() { + border_pen.setStyle(Qt::DashLine); + border_pen.setColor(Qt::white); + } +}; +struct Multi_Select_Rect_Input_Data : renderive::Input_Data {}; +struct Multi_Select_Rect_Private : renderive::Typed_Render_Data { + friend class Multi_Select_Rect; + bool active = false; + bool select_test(const QPointF& pos) override { + return true; + } + void mousePressEvent(QMouseEvent* event) override { + if (event->button() != Qt::LeftButton) + return; + Render_Edit_Lease edit(this); + auto horizontal_axis = edit->horizontal_axis.lock(); + auto vertical_axis = edit->vertical_axis.lock(); + if (!horizontal_axis || !vertical_axis) + return; + QVector& rect_list = edit->rects; + if (!(QApplication::keyboardModifiers() & Qt::ControlModifier)) { + rect_list.clear(); + } + else { + int n = rect_list.size(); + for (int i = n - 1; i >= 0; i--) { + auto& rect = rect_list[i]; + if (qFuzzyCompare(rect.width(), 0.0) || qFuzzyCompare(rect.height(), 0.0)) { + rect_list.removeAt(i); + } + } + } + double x = horizontal_axis->pixel_to_coord(event->pos().x(), SRC::Render); + double y = vertical_axis->pixel_to_coord(event->pos().y(), SRC::Render); + rect_list.append(QRectF(QPointF(x, y), QPointF(x, y))); + active = true; + } + void mouseMoveEvent(QMouseEvent* event) override { + if (!active) + return; + if (!(event->buttons() & Qt::LeftButton)) + return; + Render_Edit_Lease edit(this); + auto horizontal_axis = edit->horizontal_axis.lock(); + auto vertical_axis = edit->vertical_axis.lock(); + if (!horizontal_axis || !vertical_axis) + return; + QVector& rect_list = edit->rects; + if (rect_list.empty()) + return; + rect_list.last().setBottomRight(event->pos()); + QRectF& r = rect_list.last(); + r.setRight(horizontal_axis->pixel_to_coord(r.right(), SRC::Render)); + r.setBottom(vertical_axis->pixel_to_coord(r.bottom(), SRC::Render)); + } + void mouseReleaseEvent(QMouseEvent* event) override {} + void keyPressEvent(QKeyEvent* event) override { + if (event->key() != Qt::Key_Escape || !active) + return; + Render_Edit_Lease edit(this); + active = false; + QVector& rect_list = edit->rects; + if (rect_list.empty()) + return; + rect_list.removeLast(); + } + void keyReleaseEvent(QKeyEvent* event) override {} + void draw(QPainter* painter, const Plot_Render_Snapshot&) override { + if (!active) + return; + Multi_Select_Rect_Render_State* s = render_state(); + auto horizontal_axis = s->horizontal_axis.lock(); + auto vertical_axis = s->vertical_axis.lock(); + if (!horizontal_axis || !vertical_axis) + return; + QList draw_rect_list; + for (QRectF r : s->rects) { + if (qFuzzyCompare(r.width(), 0.0) || qFuzzyCompare(r.height(), 0.0)) + continue; + r.setX(horizontal_axis->coord_to_pixel(r.x(), SRC::Render)); + r.setY(vertical_axis->coord_to_pixel(r.y(), SRC::Render)); + r.setRight(horizontal_axis->coord_to_pixel(r.right(), SRC::Render)); + r.setBottom(vertical_axis->coord_to_pixel(r.bottom(), SRC::Render)); + draw_rect_list.append(r); + } + painter->save(); + QFontMetrics xfm(horizontal_axis->unit_text_font()); + QFontMetrics yfm(vertical_axis->unit_text_font()); + painter->setPen(s->border_pen); + painter->setBrush(s->rect_brush); + for (auto& rect : draw_rect_list) { + painter->drawRect(rect); + } + painter->setPen(s->font_pen); + painter->setFont(s->font); + int n = draw_rect_list.size(); + for (int i = 0; i < n; ++i) { + QRectF& rect = draw_rect_list[i]; + QRectF& coord_rect = s->rects[i]; + double offset_x = coord_rect.right() - coord_rect.left(); + double offset_y = coord_rect.bottom() - coord_rect.top(); + QString text1 = "offset_x == " + QString::number(offset_x) + horizontal_axis->unit_text(); + QString text2 = "offset_y == " + QString::number(offset_y) + vertical_axis->unit_text(); + double width1 = xfm.horizontalAdvance(text1) + 32; + double width2 = yfm.horizontalAdvance(text2) + 32; + double rect1_x = rect.x() + rect.width() / 2 - width1 / 2; + double rect2_x = rect.x() + rect.width() / 2 - width2 / 2; + QRectF rect1 = QRectF(rect1_x, rect.y(), width1, xfm.lineSpacing()); + QRectF rect2 = QRectF(rect2_x, rect1.bottom(), width2, yfm.lineSpacing()); + painter->drawText(rect1, Qt::AlignCenter, text1); + painter->drawText(rect2, Qt::AlignCenter, text2); + } + painter->restore(); + } +}; +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Performance_Shower.cpp b/Renderive/plottable/Performance_Shower.cpp similarity index 72% rename from YSGraphic_Core/plottable/Performance_Shower.cpp rename to Renderive/plottable/Performance_Shower.cpp index 4d911b5..15b094d 100644 --- a/YSGraphic_Core/plottable/Performance_Shower.cpp +++ b/Renderive/plottable/Performance_Shower.cpp @@ -1,36 +1,36 @@ #include "../plottable/Performance_Shower_p.h" -namespace YSG { -using PerformanceShower_Binding = Renderable_Binding; +namespace renderive { +using Performance_Shower_Binding = Renderable_Binding; Performance_Shower::Performance_Shower() { - PerformanceShower_Binding::init(this, "PerformanceShower"); + Performance_Shower_Binding::init(this, "Performance_Shower"); } Performance_Shower_Private* Performance_Shower::d() { - return PerformanceShower_Binding::d(this); + return Performance_Shower_Binding::d(this); } Render_Data* Performance_Shower::create_render_data() { - return PerformanceShower_Binding::create_render_data(); + return Performance_Shower_Binding::create_render_data(); } Render_State* Performance_Shower::create_render_state() { - return PerformanceShower_Binding::create_render_state(); + return Performance_Shower_Binding::create_render_state(); } Input_Data* Performance_Shower::create_input_data() { - return PerformanceShower_Binding::create_input_data(); + return Performance_Shower_Binding::create_input_data(); } void Performance_Shower::setEnabled(bool enabled) { - mEnabled.store(enabled, std::memory_order_release); + enabled_value.store(enabled, std::memory_order_release); if (enabled) { append_event({Performance_Event_Type::Clear}); } mark_render_dirty(); } bool Performance_Shower::enabled() const { - return mEnabled.load(std::memory_order_acquire); + return enabled_value.load(std::memory_order_acquire); } void Performance_Shower::refresh_counter() { append_event({Performance_Event_Type::Clear}); } -void Performance_Shower::counter_increase(const QString& counterName) { - increment_counter("General", counterName); +void Performance_Shower::counter_increase(const QString& counter_name) { + increment_counter("General", counter_name); } void Performance_Shower::increment_counter(const QString& scope, const QString& name) { Performance_Event event; @@ -82,14 +82,14 @@ void Performance_Shower::set_view_filter(const QString& name) { } void Performance_Shower::set_view_filter(const QString& group, const QString& name) { Performance_Event event; - event.type = Performance_Event_Type::SelectView; + event.type = Performance_Event_Type::Select_View; event.scope = group; event.key = name; append_event(event); } void Performance_Shower::scroll_view(int lines) { Performance_Event event; - event.type = Performance_Event_Type::ScrollView; + event.type = Performance_Event_Type::Scroll_View; event.number = lines; append_event(event); } @@ -97,21 +97,21 @@ void Performance_Shower::append_event(const Performance_Event& event) { if (!enabled() && event.type != Performance_Event_Type::Clear) return; auto pd = d(); - Render_Input_Lease input(pd, false); + Render_Input_Lease input(pd, false); input->events.append(event); - notify_observed_update(event.type == Performance_Event_Type::Clear || event.type == Performance_Event_Type::SelectView || event.type == Performance_Event_Type::ScrollView); + notify_observed_update(event.type == Performance_Event_Type::Clear || event.type == Performance_Event_Type::Select_View || event.type == Performance_Event_Type::Scroll_View); } void Performance_Shower::notify_observed_update(bool force) { std::uint64_t now = static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); - std::uint64_t last = mLastNotifyNs.load(std::memory_order_acquire); + std::uint64_t last = last_notify_ns.load(std::memory_order_acquire); if (!force && now - last < 100000000) return; if (force) { - mLastNotifyNs.store(now, std::memory_order_release); + last_notify_ns.store(now, std::memory_order_release); mark_render_dirty(); return; } - if (force || mLastNotifyNs.compare_exchange_strong(last, now, std::memory_order_acq_rel, std::memory_order_acquire)) + if (force || last_notify_ns.compare_exchange_strong(last, now, std::memory_order_acq_rel, std::memory_order_acquire)) mark_render_dirty(); } -} // namespace YSG +} // namespace renderive diff --git a/Renderive/plottable/Performance_Shower_p.h b/Renderive/plottable/Performance_Shower_p.h new file mode 100644 index 0000000..ff1cdf8 --- /dev/null +++ b/Renderive/plottable/Performance_Shower_p.h @@ -0,0 +1,551 @@ +#pragma once +#include +#include +#include +#include +#include "../architecture/Renderable.h" +#include "Core/Statistics/Statistics.h" +namespace renderive { +inline QString performance_align_text(const QString& text, int& width) { + width = qMax(width, static_cast(text.size())); + return QString("%1").arg(text, width); +} +inline QString performance_number(double value, int& width, int precision = 2) { + return performance_align_text(QString::number(value, 'f', precision), width); +} +template +inline QString performance_count(T value, int& width) { + return performance_align_text(QString::number(static_cast(value)), width); +} +struct Performance_Line { + Performance_Line() = default; + explicit Performance_Line(const QString& data) { + this->data = data; + int arg_index = 1; + while (data.contains("%" + QString::number(arg_index))) { + arg_index++; + } + place_holder_num = arg_index - 1; + values.resize(place_holder_num); + value_widths.resize(place_holder_num); + } + QString data; + int place_holder_num{}; + QVector values; + QVector value_widths; + Psc::Value_Statistics statistics; + void update(double value) { + statistics.update(value); + if (values.size() > 0) + values[0] = statistics.instant; + if (values.size() > 1) + values[1] = statistics.smooth; + if (values.size() > 2) + values[2] = statistics.variation; + } + int& width_at(int index) { + if (value_widths.size() <= index) + value_widths.resize(index + 1); + return value_widths[index]; + } + QString to_string() { + QString ret = data; + int arg_index = 1; + for (const double& value : values) { + ret = ret.replace("%" + QString::number(arg_index), performance_number(value, width_at(arg_index - 1))); + arg_index++; + } + return ret; + } +}; +enum class Performance_Metric_Type : std::uint8_t { + Duration, + Counter, + Gauge, + State, + Line +}; +enum class Performance_Event_Type : std::uint8_t { + Clear, + Duration, + Counter, + Line, + Gauge, + State, + Select_View, + Scroll_View +}; +struct Performance_Event { + Performance_Event_Type type = Performance_Event_Type::Clear; + QString scope; + QString key; + QString value; + Performance_Line line; + double number{}; +}; +struct Performance_Metric { + Performance_Metric_Type type = Performance_Metric_Type::State; + Psc::Value_Statistics value; + Psc::Speed_Statistics speed; + Performance_Line line; + QString text; + double gauge{}; + std::uint64_t count{}; + QVector widths; + int& width_at(int index) { + if (widths.size() <= index) + widths.resize(index + 1); + return widths[index]; + } + [[nodiscard]] QString to_string(const QString& name) { + switch (type) { + case Performance_Metric_Type::Duration: + if (name.contains("%1")) { + QString ret = name; + ret = ret.replace("%1", performance_number(value.instant, width_at(0))); + ret = ret.replace("%2", performance_number(value.smooth, width_at(1))); + ret = ret.replace("%3", performance_number(value.variation, width_at(2))); + ret = ret.replace("%4", performance_number(value.p95, width_at(3))); + return ret; + } + return QString("%1 last:%2ms srtt:%3ms rttvar:%4ms min:%5ms max:%6ms p95:%7ms count:%8") + .arg(name, performance_number(value.instant, width_at(0)), performance_number(value.smooth, width_at(1)), performance_number(value.variation, width_at(2)), performance_number(value.min, width_at(3)), performance_number(value.max, width_at(4)), performance_number(value.p95, width_at(5)), performance_count(value.times, width_at(6))); + case Performance_Metric_Type::Counter: + return QString("%1 speed:%2/s avg:%3/s count:%4") + .arg(name, performance_number(speed.instant_speed, width_at(0)), performance_number(speed.average_speed, width_at(1)), performance_count(speed.times, width_at(2))); + case Performance_Metric_Type::Gauge: + return QString("%1: %2").arg(name, performance_number(gauge, width_at(0))); + case Performance_Metric_Type::State: + return QString("%1: %2").arg(name, text); + case Performance_Metric_Type::Line: + return line.to_string(); + } + return {}; + } +}; +struct Performance_Shower_Render_State : Render_State { + QFont font; + int top_margin = 4; + int left_margin = 4; + int right_margin = 28; + int bottom_margin = 8; + int column_gap = 12; + int group_sidebar_width = 92; + int target_sidebar_width = 170; + QColor background = Qt::white; + QColor foreground = Qt::black; + QColor sidebar_background = QColor(235, 235, 235); + QColor selected_background = QColor(210, 225, 245); + QColor scrollbar_background = QColor(210, 210, 210); + QColor scrollbar_handle = QColor(120, 120, 120); +}; +struct Performance_Shower_Input_Data : Input_Data { + QVector events; + void clear() override { + events.clear(); + } +}; +struct Performance_Shower_Private; +class Performance_Shower : public Renderable { +public: + Performance_Shower(); + Performance_Shower_Private* d(); + Render_Data* create_render_data() override; + Render_State* create_render_state() override; + Input_Data* create_input_data() override; + void setEnabled(bool enabled); + bool enabled() const; + void refresh_counter(); + void counter_increase(const QString& counter_name); + void increment_counter(const QString& scope, const QString& name); + void set_performance_line(const QString& key, const Performance_Line& line); + void set_info(const QString& key, const QString& value); + void set_state(const QString& scope, const QString& name, const QString& value); + void set_gauge(const QString& scope, const QString& name, double value); + void record_cost(const QString& key, double value); + void record_duration(const QString& scope, const QString& name, double value); + void set_view_filter(const QString& name); + void set_view_filter(const QString& group, const QString& name); + void scroll_view(int lines); +private: + void append_event(const Performance_Event& event); + void notify_observed_update(bool force); + std::atomic_bool enabled_value{false}; + std::atomic last_notify_ns{0}; +}; +struct Performance_Shower_Private : Typed_Render_Data { + friend class Performance_Shower; + QMap> scopes; + QVector all_info; + QVector group_items; + QVector target_items; + QVector group_rects; + QVector target_rects; + QRect panel_rect; + int group_sidebar_width{}; + int target_sidebar_width{}; + int content_width{}; + int scroll_line{}; + int max_scroll_line{}; + bool sidebar_width_dirty = true; + bool content_width_dirty = true; + QString selected_group = "Plot"; + QString selected_target = "Overview"; + void prepare_data(const Plot_Render_Snapshot&) override { + sync_state_pipeline(); + auto input = render_input_data(); + for (const Performance_Event& event : input->events) { + apply_event(event); + } + clear_render_input(); + rebuild_lines(); + } + bool select_test(const QPointF& pos) override { + return q()->enabled() && panel_rect.contains(pos.toPoint()); + } + void mousePressEvent(QMouseEvent* event) override { + for (int i = 0; i < group_rects.size(); ++i) { + if (group_rects[i].contains(event->pos())) { + q()->set_view_filter(group_items[i], {}); + return; + } + } + for (int i = 0; i < target_rects.size(); ++i) { + if (target_rects[i].contains(event->pos())) { + q()->set_view_filter(selected_group, target_items[i]); + return; + } + } + } + void wheelEvent(QWheelEvent* event) override { + if (!panel_rect.contains(event->pos())) + return; + int steps = event->angleDelta().y() > 0 ? -3 : 3; + q()->scroll_view(steps); + } + void draw(QPainter* painter, const Plot_Render_Snapshot&) override { + if (!q()->enabled() || group_items.isEmpty()) + return; + auto s = render_state(); + painter->save(); + painter->setFont(s->font); + QFontMetrics fm(s->font); + if (sidebar_width_dirty) + update_sidebar_width(fm, s); + if (content_width_dirty) + update_content_width(fm, s); + int side_line_count = qMax(group_items.size(), target_items.size()); + int line_count = qMax(all_info.size(), side_line_count); + int max_height = painter->device()->height(); + int sidebar_width = group_sidebar_width + target_sidebar_width; + int content_x = sidebar_width + s->column_gap; + int width = sidebar_width + s->column_gap + content_width; + int full_height = fm.lineSpacing() * line_count + s->top_margin + s->bottom_margin; + int height = qMin(full_height, max_height); + int visible_lines = qMax(1, (height - s->top_margin - s->bottom_margin) / fm.lineSpacing()); + max_scroll_line = qMax(0, all_info.size() - visible_lines); + scroll_line = qBound(0, scroll_line, max_scroll_line); + QRect rect(0, 0, width, height); + QRect group_rect(0, 0, group_sidebar_width, height); + QRect target_rect(group_rect.right() + 1, 0, target_sidebar_width, height); + panel_rect = rect; + group_rects.clear(); + target_rects.clear(); + painter->fillRect(rect, s->background); + painter->fillRect(group_rect, s->sidebar_background); + painter->fillRect(target_rect, s->sidebar_background); + painter->setPen(s->foreground); + for (int i = 0; i < visible_lines && i + scroll_line < all_info.size(); ++i) { + painter->drawText(QPointF(content_x + s->left_margin, s->top_margin + i * fm.lineSpacing() + fm.lineSpacing()), all_info[i + scroll_line]); + } + for (int i = 0; i < group_items.size() && i < visible_lines; ++i) { + QRect item_rect(group_rect.left(), s->top_margin + i * fm.lineSpacing(), group_sidebar_width, fm.lineSpacing()); + group_rects.append(item_rect); + if (group_items[i] == selected_group) + painter->fillRect(item_rect, s->selected_background); + painter->drawText(QPointF(item_rect.left() + s->left_margin, item_rect.top() + fm.lineSpacing()), group_items[i]); + } + for (int i = 0; i < target_items.size() && i < visible_lines; ++i) { + QRect item_rect(target_rect.left(), s->top_margin + i * fm.lineSpacing(), target_sidebar_width, fm.lineSpacing()); + target_rects.append(item_rect); + if (target_items[i] == selected_target) + painter->fillRect(item_rect, s->selected_background); + painter->drawText(QPointF(item_rect.left() + s->left_margin, item_rect.top() + fm.lineSpacing()), target_items[i]); + } + if (max_scroll_line > 0) + draw_scrollbar(painter, s, QRect(width - 8, 0, 8, height), visible_lines); + painter->restore(); + } + QRect pixel_bounds(const QSize& plot_size) override { + if (!q()->enabled() || group_items.isEmpty()) + return {}; + auto s = render_state(); + QFontMetrics fm(s->font); + if (sidebar_width_dirty) + update_sidebar_width(fm, s); + if (content_width_dirty) + update_content_width(fm, s); + int side_line_count = qMax(group_items.size(), target_items.size()); + int line_count = qMax(all_info.size(), side_line_count); + int sidebar_width = group_sidebar_width + target_sidebar_width; + int width = sidebar_width + s->column_gap + content_width; + int full_height = fm.lineSpacing() * line_count + s->top_margin + s->bottom_margin; + int height = qMin(full_height, plot_size.height()); + return QRect(0, 0, width, height); + } + void draw_scrollbar(QPainter* painter, Performance_Shower_Render_State* state, const QRect& rect, int visible_lines) { + painter->fillRect(rect, state->scrollbar_background); + double ratio = static_cast(visible_lines) / static_cast(all_info.size()); + int handle_height = qMax(16, qRound(rect.height() * ratio)); + int travel = qMax(1, rect.height() - handle_height); + int top = qRound(static_cast(travel) * static_cast(scroll_line) / static_cast(max_scroll_line)); + painter->fillRect(QRect(rect.left(), rect.top() + top, rect.width(), handle_height), state->scrollbar_handle); + } + void update_sidebar_width(const QFontMetrics& fm, Performance_Shower_Render_State* state) { + int group_width = 0; + int target_width = 0; + for (const QString& item : group_items) + group_width = qMax(group_width, fm.horizontalAdvance(item)); + for (const QString& item : target_items) + target_width = qMax(target_width, fm.horizontalAdvance(item)); + group_sidebar_width = qMax(state->group_sidebar_width, group_width + state->left_margin + state->right_margin); + target_sidebar_width = qMax(state->target_sidebar_width, target_width + state->left_margin + state->right_margin); + sidebar_width_dirty = false; + } + void update_content_width(const QFontMetrics& fm, Performance_Shower_Render_State* state) { + int max_width = 0; + for (const QString& line : all_info) + max_width = qMax(max_width, fm.horizontalAdvance(line)); + content_width = max_width + state->left_margin + state->right_margin; + content_width_dirty = false; + } + void apply_event(const Performance_Event& event) { + switch (event.type) { + case Performance_Event_Type::Clear: + scopes.clear(); + all_info.clear(); + content_width = 0; + content_width_dirty = true; + break; + case Performance_Event_Type::Duration: { + Performance_Metric& metric = scopes[event.scope][event.key]; + metric.type = Performance_Metric_Type::Duration; + metric.value.update(event.number); + ++metric.count; + break; + } + case Performance_Event_Type::Counter: + scopes[event.scope][event.key].type = Performance_Metric_Type::Counter; + scopes[event.scope][event.key].speed.update(1); + ++scopes[event.scope][event.key].count; + break; + case Performance_Event_Type::Line: + scopes[event.scope][event.key].type = Performance_Metric_Type::Line; + scopes[event.scope][event.key].line = event.line; + break; + case Performance_Event_Type::Gauge: + scopes[event.scope][event.key].type = Performance_Metric_Type::Gauge; + scopes[event.scope][event.key].gauge = event.number; + ++scopes[event.scope][event.key].count; + break; + case Performance_Event_Type::State: + scopes[event.scope][event.key].type = Performance_Metric_Type::State; + scopes[event.scope][event.key].text = event.value; + break; + case Performance_Event_Type::Select_View: + selected_group = event.scope.isEmpty() ? "Plot" : event.scope; + selected_target = event.key; + scroll_line = 0; + content_width = 0; + content_width_dirty = true; + break; + case Performance_Event_Type::Scroll_View: + scroll_line += static_cast(event.number); + scroll_line = qBound(0, scroll_line, max_scroll_line); + break; + } + } + static QString object_name_from_metric(const QString& key) { + int state_index = key.indexOf(".State."); + if (state_index > 0) + return key.left(state_index); + int input_index = key.indexOf(".Input."); + if (input_index > 0) + return key.left(input_index); + int pixel_index = key.indexOf(".Pixel."); + if (pixel_index > 0) + return key.left(pixel_index); + int prepare_index = key.indexOf(".prepare_data"); + if (prepare_index > 0) + return key.left(prepare_index); + int draw_index = key.indexOf(".draw"); + if (draw_index > 0) + return key.left(draw_index); + int lease_index = key.indexOf(".stateLeaseMiss"); + if (lease_index > 0) + return key.left(lease_index); + int mode_index = key.indexOf(".buffer_acquire_mode"); + if (mode_index > 0) + return key.left(mode_index); + int schedule_mode_index = key.indexOf(".render_schedule_mode"); + if (schedule_mode_index > 0) + return key.left(schedule_mode_index); + int schedule_max_fps_index = key.indexOf(".render_schedule_max_fps"); + if (schedule_max_fps_index > 0) + return key.left(schedule_max_fps_index); + return {}; + } + void rebuild_views() { + QSet object_items; + QVector old_group_items = group_items; + QVector old_target_items = target_items; + QString old_selected_target = selected_target; + auto renderable_scope = scopes.constFind("Renderable"); + if (renderable_scope != scopes.cend()) { + for (auto metric_it = renderable_scope.value().cbegin(); metric_it != renderable_scope.value().cend(); ++metric_it) { + QString object_name = object_name_from_metric(metric_it.key()); + if (!object_name.isEmpty()) + object_items.insert(object_name); + } + } + auto buffer_scope = scopes.constFind("Buffer"); + if (buffer_scope != scopes.cend()) { + for (auto metric_it = buffer_scope.value().cbegin(); metric_it != buffer_scope.value().cend(); ++metric_it) { + if (!metric_it.key().startsWith("Color.")) { + QString object_name = object_name_from_metric(metric_it.key()); + if (!object_name.isEmpty()) + object_items.insert(object_name); + } + } + } + group_items.clear(); + group_items.append("Plot"); + QVector object_names = object_items.values().toVector(); + std::sort(object_names.begin(), object_names.end()); + for (const QString& item : object_names) + group_items.append(item); + if (!group_items.contains(selected_group)) + selected_group = "Plot"; + if (selected_group == "Plot") { + target_items.clear(); + if (scopes.contains("Pipeline")) + target_items.append("Pipeline"); + if (scopes.contains("General")) + target_items.append("General"); + if (has_color_buffer_metrics()) + target_items.append("Color"); + } + else { + target_items.clear(); + if (has_renderable_metrics(selected_group)) + target_items.append("Renderable"); + if (has_object_buffer_metrics(selected_group, "State")) + target_items.append("State"); + if (has_object_buffer_metrics(selected_group, "Input")) + target_items.append("Input"); + if (has_object_buffer_metrics(selected_group, "Pixel")) + target_items.append("Pixel"); + } + if (target_items.isEmpty()) + target_items.append("None"); + if (selected_target.isEmpty() || !target_items.contains(selected_target)) + selected_target = target_items.front(); + if (old_selected_target != selected_target) { + scroll_line = 0; + content_width = 0; + content_width_dirty = true; + } + if (old_group_items != group_items || old_target_items != target_items) + sidebar_width_dirty = true; + } + bool has_color_buffer_metrics() const { + auto buffer_scope = scopes.constFind("Buffer"); + if (buffer_scope == scopes.cend()) + return false; + for (auto metric_it = buffer_scope.value().cbegin(); metric_it != buffer_scope.value().cend(); ++metric_it) { + if (metric_it.key().startsWith("Color.")) + return true; + } + return false; + } + bool has_renderable_metrics(const QString& object_name) const { + auto renderable_scope = scopes.constFind("Renderable"); + if (renderable_scope == scopes.cend()) + return false; + for (auto metric_it = renderable_scope.value().cbegin(); metric_it != renderable_scope.value().cend(); ++metric_it) { + if (object_name_from_metric(metric_it.key()) == object_name) + return true; + } + return false; + } + bool has_object_buffer_metrics(const QString& object_name, const QString& buffer_name) const { + auto buffer_scope = scopes.constFind("Buffer"); + if (buffer_scope == scopes.cend()) + return false; + QString prefix = object_name + "." + buffer_name + "."; + for (auto metric_it = buffer_scope.value().cbegin(); metric_it != buffer_scope.value().cend(); ++metric_it) { + if (metric_it.key().startsWith(prefix)) + return true; + } + return false; + } + bool metric_visible(const QString& scope, const QString& key) const { + if (selected_group == "Plot") { + if (selected_target == "Pipeline") + return scope == "Pipeline"; + if (selected_target == "General") + return scope == "General"; + return selected_target == "Color" && scope == "Buffer" && key.startsWith("Color."); + } + if (selected_target == "Renderable") + return scope == "Renderable" && object_name_from_metric(key) == selected_group; + return scope == "Buffer" && key.startsWith(selected_group + "." + selected_target + "."); + } + QString display_metric_name(const QString& key) const { + if (selected_group == "Plot" && selected_target == "Color") + return key.mid(QString("Color.").size()); + if (selected_group != "Plot" && selected_target == "Renderable") + return key.mid(selected_group.size() + 1); + if (selected_group != "Plot") + return key.mid((selected_group + "." + selected_target + ".").size()); + return key; + } + void rebuild_lines() { + rebuild_views(); + QVector lines; + for (auto scope_it = scopes.begin(); scope_it != scopes.end(); ++scope_it) { + for (auto metric_it = scope_it.value().begin(); metric_it != scope_it.value().end(); ++metric_it) { + if (metric_visible(scope_it.key(), metric_it.key())) { + lines.append(metric_it.value().to_string(display_metric_name(metric_it.key()))); + } + } + } + if (all_info != lines) { + all_info = lines; + content_width_dirty = true; + } + } +}; +class Performance_Scope_Timer { +public: + std::chrono::steady_clock::time_point start; + QString scope; + QString name; + Performance_Shower* performance_shower{}; + Performance_Scope_Timer(const QString& name, Performance_Shower* performance_shower_value) : Performance_Scope_Timer("General", name, performance_shower_value) {} + Performance_Scope_Timer(const QString& scope, const QString& name, Performance_Shower* performance_shower) { + if (!performance_shower || !performance_shower->enabled()) + return; + start = std::chrono::steady_clock::now(); + this->scope = scope; + this->name = name; + this->performance_shower = performance_shower; + } + ~Performance_Scope_Timer() { + if (!performance_shower || !performance_shower->enabled()) + return; + double use_time = std::chrono::duration(std::chrono::steady_clock::now() - start).count() * 1000; + performance_shower->record_duration(scope, name, use_time); + } +}; +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Planisphere.cpp b/Renderive/plottable/Planisphere.cpp similarity index 67% rename from YSGraphic_Core/plottable/Planisphere.cpp rename to Renderive/plottable/Planisphere.cpp index 505a03e..83f154a 100644 --- a/YSGraphic_Core/plottable/Planisphere.cpp +++ b/Renderive/plottable/Planisphere.cpp @@ -2,7 +2,7 @@ #include "../Axis/Abs_Axis_p.h" #include "../primitive/Grid.h" #include "Planisphere_p.h" -namespace YSG { +namespace renderive { using Planisphere_Binding = Renderable_Binding; Planisphere::Planisphere() { Planisphere_Binding::init(this, "Planisphere"); @@ -24,11 +24,11 @@ std::shared_ptr Planisphere::i_axis(SRC src) { } void Planisphere::set_i_axis(std::shared_ptr value) { d()->set_state_value(&Planisphere_Render_State::i_axis, std::weak_ptr(value)); - if (auto points = mPointSet.lock()) + if (auto points = point_set.lock()) points->set_x_axis(value); - if (auto anchors = mAnchorSet.lock()) + if (auto anchors = anchor_set.lock()) anchors->set_x_axis(value); - if (auto grid = mGrid.lock()) + if (auto grid = this->grid.lock()) grid->set_x_axis(value); } std::shared_ptr Planisphere::q_axis(SRC src) { @@ -36,11 +36,11 @@ std::shared_ptr Planisphere::q_axis(SRC src) { } void Planisphere::set_q_axis(std::shared_ptr value) { d()->set_state_value(&Planisphere_Render_State::q_axis, std::weak_ptr(value)); - if (auto points = mPointSet.lock()) + if (auto points = point_set.lock()) points->set_y_axis(value); - if (auto anchors = mAnchorSet.lock()) + if (auto anchors = anchor_set.lock()) anchors->set_y_axis(value); - if (auto grid = mGrid.lock()) + if (auto grid = this->grid.lock()) grid->set_y_axis(value); } Range Planisphere::i_range(SRC src) { @@ -49,7 +49,7 @@ Range Planisphere::i_range(SRC src) { void Planisphere::set_i_range(Range value) { if (value.length() == 0.0) return; - if (auto grid = mGrid.lock()) + if (auto grid = this->grid.lock()) grid->set_x_range(value); d()->set_state_value(&Planisphere_Render_State::i_range, std::move(value)); } @@ -59,7 +59,7 @@ Range Planisphere::q_range(SRC src) { void Planisphere::set_q_range(Range value) { if (value.length() == 0.0) return; - if (auto grid = mGrid.lock()) + if (auto grid = this->grid.lock()) grid->set_y_range(value); d()->set_state_value(&Planisphere_Render_State::q_range, std::move(value)); } @@ -67,7 +67,7 @@ QColor Planisphere::point_color(SRC src) { return d()->state_value(&Planisphere_Render_State::point_color, src); } void Planisphere::set_point_color(QColor value) { - if (auto points = mPointSet.lock()) + if (auto points = point_set.lock()) points->set_brush(QBrush(value)); d()->set_state_value(&Planisphere_Render_State::point_color, std::move(value)); } @@ -75,7 +75,7 @@ QColor Planisphere::anchor_color(SRC src) { return d()->state_value(&Planisphere_Render_State::anchor_color, src); } void Planisphere::set_anchor_color(QColor value) { - if (auto anchors = mAnchorSet.lock()) + if (auto anchors = anchor_set.lock()) anchors->set_pen(QPen(value, 2)); d()->set_state_value(&Planisphere_Render_State::anchor_color, std::move(value)); } @@ -100,15 +100,15 @@ void Planisphere::give_data(QPointF pos) { Planisphere::Builder::Builder(std::shared_ptr parent, std::shared_ptr i_axis, std::shared_ptr q_axis) { ASSERT(parent, "Planisphere build error! parent == nullptr"); ASSERT(i_axis && q_axis, "Planisphere build error! axis == nullptr"); - ASSERT(i_axis->mPlot != nullptr, "Planisphere build error! i_axis->mPlot == nullptr"); - ASSERT(i_axis->mPlot == q_axis->mPlot, "Planisphere build error! i_axis->mPlot != q_axis->mPlot"); - ASSERT(parent->mPlot == i_axis->mPlot, "Planisphere build error! parent->mPlot != axis->mPlot"); + ASSERT(i_axis->plot != nullptr, "Planisphere build error! i_axis->plot == nullptr"); + ASSERT(i_axis->plot == q_axis->plot, "Planisphere build error! i_axis->plot != q_axis->plot"); + ASSERT(parent->plot == i_axis->plot, "Planisphere build error! parent->plot != axis->plot"); this->parent = parent; this->i_axis = i_axis; this->q_axis = q_axis; } std::shared_ptr Planisphere::Builder::build() { - std::shared_ptr ret(new Planisphere()); + std::shared_ptr < Planisphere > ret(new Planisphere()); ret->init(parent); Planisphere_Private* pd = ret->d(); Planisphere_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); @@ -125,35 +125,35 @@ std::shared_ptr Planisphere::Builder::build() { if (sc->q_range.length() == 0.0) sc->q_range = {0.0, 1.0}; sc->continue_millisecond = qMax(1, sc->continue_millisecond); - auto iAxis = this->i_axis.lock(); - auto qAxis = this->q_axis.lock(); - if (iAxis && qAxis) { - auto grid = Grid::Builder(ret, iAxis, qAxis).set_line_mode(Grid_Line_Mode::Range_Division).set_x_range(sc->i_range).set_y_range(sc->q_range).set_x_divisions(4).set_y_divisions(4).set_x_pen(QPen(Qt::white, 1, Qt::DotLine)).set_y_pen(QPen(Qt::white, 1, Qt::DotLine)).build(); - auto points = Point_Set::Builder(ret, iAxis, qAxis).set_size(4.0).set_pen(QPen(Qt::NoPen)).set_brush(QBrush(sc->point_color)).set_shape(Point_Set_Shape::Circle).set_antialias(true).build(); - auto anchors = Point_Set::Builder(ret, iAxis, qAxis).set_size(12.0).set_pen(QPen(sc->anchor_color, 2)).set_brush(QBrush(Qt::NoBrush)).set_shape(Point_Set_Shape::Cross).set_antialias(true).build(); - grid->mObjectName = "PlanisphereGrid"; - points->mObjectName = "PlanispherePoints"; - anchors->mObjectName = "PlanisphereAnchors"; - ret->mGrid = grid; - ret->mPointSet = points; - ret->mAnchorSet = anchors; + auto i_axis = this->i_axis.lock(); + auto q_axis = this->q_axis.lock(); + if (i_axis && q_axis) { + auto grid = Grid::Builder(ret, i_axis, q_axis).set_line_mode(Grid_Line_Mode::Range_Division).set_x_range(sc->i_range).set_y_range(sc->q_range).set_x_divisions(4).set_y_divisions(4).set_x_pen(QPen(Qt::white, 1, Qt::DotLine)).set_y_pen(QPen(Qt::white, 1, Qt::DotLine)).build(); + auto points = Point_Set::Builder(ret, i_axis, q_axis).set_size(4.0).set_pen(QPen(Qt::NoPen)).set_brush(QBrush(sc->point_color)).set_shape(Point_Set_Shape::Circle).set_antialias(true).build(); + auto anchors = Point_Set::Builder(ret, i_axis, q_axis).set_size(12.0).set_pen(QPen(sc->anchor_color, 2)).set_brush(QBrush(Qt::NoBrush)).set_shape(Point_Set_Shape::Cross).set_antialias(true).build(); + grid->object_name = "PlanisphereGrid"; + points->object_name = "PlanispherePoints"; + anchors->object_name = "PlanisphereAnchors"; + ret->grid = grid; + ret->point_set = points; + ret->anchor_set = anchors; } return ret; } void Planisphere::set_to_axis_center() { Planisphere_Render_State* s = reinterpret_cast(d()->state(State_Edit)); - auto iAxis = s->i_axis.lock(); - auto qAxis = s->q_axis.lock(); - if (!iAxis || !qAxis) + auto i_axis = s->i_axis.lock(); + auto q_axis = s->q_axis.lock(); + if (!i_axis || !q_axis) return; - double w = iAxis->pixel_size(), h = qAxis->pixel_size(); + double w = i_axis->pixel_size(), h = q_axis->pixel_size(); if (w <= 0.0 || h <= 0.0) return; double l = w < h ? w : h; - double iL = iAxis->coord_range().size() / w * l / 2; - double qL = qAxis->coord_range().size() / h * l / 2; - double im = iAxis->coord_range().middle(), qm = qAxis->coord_range().middle(); - set_i_range({im - iL, im + iL}); - set_q_range({qm - qL, qm + qL}); + double i_l = i_axis->coord_range().size() / w * l / 2; + double q_l = q_axis->coord_range().size() / h * l / 2; + double im = i_axis->coord_range().middle(), qm = q_axis->coord_range().middle(); + set_i_range({im - i_l, im + i_l}); + set_q_range({qm - q_l, qm + q_l}); } -} // namespace YSG +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Planisphere.h b/Renderive/plottable/Planisphere.h similarity index 86% rename from YSGraphic_Core/plottable/Planisphere.h rename to Renderive/plottable/Planisphere.h index f4da612..53ecde2 100644 --- a/YSGraphic_Core/plottable/Planisphere.h +++ b/Renderive/plottable/Planisphere.h @@ -1,7 +1,7 @@ #pragma once #include "global.h" #include "../primitive/Point_Set.h" -namespace YSG { +namespace renderive { /// 星座图调制类型。 enum class Planisphere_Type { /// 8PSK 星座图。 @@ -17,9 +17,7 @@ public: Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: Planisphere(); -public: /// 写入一个 I/Q 点。 void give_data(QPointF pos); PROP(std::shared_ptr, i_axis) @@ -33,11 +31,9 @@ public: /// 设置坐标轴到星座图中心范围。 void set_to_axis_center(); struct Builder; -protected: - friend struct Planisphere_Private; - std::weak_ptr mGrid; - std::weak_ptr mPointSet; - std::weak_ptr mAnchorSet; + std::weak_ptr grid; + std::weak_ptr point_set; + std::weak_ptr anchor_set; }; struct Planisphere_Prop { std::weak_ptr i_axis{}; @@ -49,7 +45,7 @@ struct Planisphere_Prop { int continue_millisecond = 1000; Planisphere_Type type = Planisphere_Type::Psk8; }; -struct LIB_DECL Planisphere::Builder : Planisphere_Prop { +struct LIB_DECL Planisphere::Builder : Planisphere_Prop{ PROP_B(std::shared_ptr, parent) PROP_B(std::shared_ptr, i_axis) PROP_B(std::shared_ptr, q_axis) @@ -63,7 +59,7 @@ struct LIB_DECL Planisphere::Builder : Planisphere_Prop { Builder(std::shared_ptr parent, std::shared_ptr i_axis, std::shared_ptr q_axis); /// 构建并返回星座图对象。 std::shared_ptr build(); -protected: std::shared_ptr parent{}; + }; -} // namespace YSG +} // namespace renderive diff --git a/Renderive/plottable/Planisphere_p.h b/Renderive/plottable/Planisphere_p.h new file mode 100644 index 0000000..3a29d82 --- /dev/null +++ b/Renderive/plottable/Planisphere_p.h @@ -0,0 +1,125 @@ +#pragma once +#include +#include +#include "../Axis/Axis.h" +#include "../architecture/Bounded_Input_Buffer.h" +#include "../architecture/Plot_p.h" +#include "Planisphere.h" +namespace renderive { +struct Planisphere_Data { + QPointF pos; + int remain_times{}; + int max_total_times{}; +}; +struct Planisphere_Input_Data : Input_Data { + static constexpr std::size_t Max_Pending_Point_Count = 128; + struct Packet { + double x{}; + double y{}; + }; + Bounded_Input_Buffer data_list; + void push(QPointF pos) { + Packet packet{pos.x(), pos.y()}; + data_list.push(&packet, sizeof(packet), Max_Pending_Point_Count); + } + template + void read_all(Handler handler) { + data_list.read_all([&handler](const void* data, std::size_t size) { + (void)size; + Packet packet; + std::memcpy(&packet, data, sizeof(packet)); + handler(QPointF(packet.x, packet.y)); + }); + } + void clear() override { + data_list.clear(); + } + std::uint64_t get_pending_count() const override { + return data_list.get_pending_count(); + } + std::uint64_t get_dropped_count() const override { + return data_list.get_dropped_count(); + } + std::uint64_t get_capacity_dropped_count() const override { + return data_list.get_capacity_dropped_count(); + } + std::uint64_t rebuild_dropped_count() const override { + return data_list.get_rebuild_dropped_count(); + } + std::uint64_t consumer_dropped_count() const override { + return data_list.get_consumer_dropped_count(); + } + std::uint64_t get_pushed_count() const override { + return data_list.get_pushed_count(); + } +}; +struct Planisphere_Render_State : Render_State, Planisphere_Prop {}; +struct Planisphere_Private : Typed_Render_Data { + friend class Planisphere; + std::list data_list; + QVector anchor_points(const Planisphere_Render_State* s) const { + QVector points; + if (s->type == Planisphere_Type::Psk8) { + double x_space = s->i_range.length() / 6.0; + double y_space = s->q_range.length() / 6.0; + double x_s = s->i_range.origin; + double y_s = s->q_range.origin; + points.reserve(8); + points.push_back({x_s + 2 * x_space, y_s + 1 * y_space}); + points.push_back({x_s + 1 * x_space, y_s + 2 * y_space}); + points.push_back({x_s + 1 * x_space, y_s + 4 * y_space}); + points.push_back({x_s + 2 * x_space, y_s + 5 * y_space}); + points.push_back({x_s + 4 * x_space, y_s + 5 * y_space}); + points.push_back({x_s + 5 * x_space, y_s + 4 * y_space}); + points.push_back({x_s + 5 * x_space, y_s + 2 * y_space}); + points.push_back({x_s + 4 * x_space, y_s + 1 * y_space}); + } + return points; + } + void refresh() { + for (auto it = data_list.begin(); it != data_list.end();) { + if (--it->remain_times == 0) + data_list.erase(it++); + else + ++it; + } + } + void prepare_data(const Plot_Render_Snapshot& snapshot) override { + sync_state_pipeline(); + Planisphere_Input_Data* d = render_input_data(); + Planisphere_Render_State* s = render_state(); + int times = qMax(5, (s->continue_millisecond * snapshot.refresh_times_per_second) / 1000); + d->read_all([this, times](const QPointF& pos) { + Planisphere_Data data; + data.pos = pos; + data.max_total_times = times; + data.remain_times = times; + data_list.push_back(data); + }); + clear_render_input(); + refresh(); + QVector points; + QVector colors; + points.reserve(static_cast(data_list.size())); + colors.reserve(static_cast(data_list.size())); + for (const Planisphere_Data& data : data_list) { + QColor color = s->point_color; + color.setAlphaF(color.alphaF() * data.remain_times / data.max_total_times); + points.append(data.pos); + colors.append(color); + } + if (auto point_set = q()->point_set.lock()) + point_set->give_colored_points(points, colors, false); + if (auto anchor_set = q()->anchor_set.lock()) + anchor_set->give_points(anchor_points(s), false); + } + void draw(QPainter* painter, const Plot_Render_Snapshot&) override { + Q_UNUSED(painter) + } + void plot_event(QEvent* event) override { + if (event->type() == QEvent::Resize) { + auto e = reinterpret_cast(event); + } + } +}; +} // namespace renderive diff --git a/Renderive/plottable/Spectrum.cpp b/Renderive/plottable/Spectrum.cpp new file mode 100644 index 0000000..2171f5d --- /dev/null +++ b/Renderive/plottable/Spectrum.cpp @@ -0,0 +1,556 @@ +#include +#include +#include "../primitive/Curve.h" +#include "../primitive/Label.h" +#include "../primitive/Marker.h" +#include "Spectrum_p.h" +namespace renderive { +static Curve_Sample_Mode spectrum_curve_sample_mode(Spectrum_Sample_Mode mode) { + switch (mode) { + case Spectrum_Sample_Mode::Source: + return Curve_Sample_Mode::Source; + case Spectrum_Sample_Mode::Pixel_Peak_Bucket: + return Curve_Sample_Mode::Pixel_Peak_Bucket; + } + return Curve_Sample_Mode::Source; +} +using Spectrum_Binding = Renderable_Binding; +Spectrum::Spectrum() { + Spectrum_Binding::init(this, "Spectrum"); +} +Spectrum_Private* Spectrum::d() { + return Spectrum_Binding::d(this); +} +Render_Data* Spectrum::create_render_data() { + return Spectrum_Binding::create_render_data(); +} +Render_State* Spectrum::create_render_state() { + return Spectrum_Binding::create_render_state(); +} +Input_Data* Spectrum::create_input_data() { + return Spectrum_Binding::create_input_data(); +} +std::shared_ptr Spectrum::frequency_axis(SRC src) { + return d()->state_value(&Spectrum_Render_State::frequency_axis, src).lock(); +} +void Spectrum::set_frequency_axis(std::shared_ptr value) { + d()->set_state_value(&Spectrum_Render_State::frequency_axis, std::weak_ptr(value)); + if (auto curve = cur_curve.lock()) + curve->set_x_axis(value); + if (auto curve = max_curve.lock()) + curve->set_x_axis(value); + if (auto curve = min_curve.lock()) + curve->set_x_axis(value); + if (auto item = marker_item.lock()) + item->set_x_axis(value); + if (auto item = label_item.lock()) + item->set_x_axis(value); +} +std::shared_ptr Spectrum::power_axis(SRC src) { + return d()->state_value(&Spectrum_Render_State::power_axis, src).lock(); +} +void Spectrum::set_power_axis(std::shared_ptr value) { + d()->set_state_value(&Spectrum_Render_State::power_axis, std::weak_ptr(value)); + if (auto curve = cur_curve.lock()) + curve->set_y_axis(value); + if (auto curve = max_curve.lock()) + curve->set_y_axis(value); + if (auto curve = min_curve.lock()) + curve->set_y_axis(value); + if (auto item = marker_item.lock()) + item->set_y_axis(value); + if (auto item = label_item.lock()) + item->set_y_axis(value); +} +int Spectrum::frequency_point_size(SRC src) { + return d()->state_value(&Spectrum_Render_State::frequency_point_size, src); +} +Range Spectrum::frequency_range(SRC src) { + return d()->state_value(&Spectrum_Render_State::frequency_range, src); +} +double Spectrum::middle_sweep_frequency(SRC src) { + return d()->state_value(&Spectrum_Render_State::middle_sweep_frequency, src); +} +void Spectrum::set_middle_sweep_frequency(double value) { + d()->set_state_value(&Spectrum_Render_State::middle_sweep_frequency, value); +} +Range Spectrum::sweep_frequency_range(SRC src) { + return d()->state_value(&Spectrum_Render_State::sweep_frequency_range, src); +} +void Spectrum::set_sweep_frequency_range(Range value) { + if (value.length() == 0.0) + return; + d()->set_state_value(&Spectrum_Render_State::sweep_frequency_range, std::move(value)); +} +bool Spectrum::use_max_line(SRC src) { + return d()->state_value(&Spectrum_Render_State::use_max_line, src); +} +void Spectrum::set_use_max_line(bool value) { + d()->set_state_value(&Spectrum_Render_State::use_max_line, value); + if (auto curve = max_curve.lock()) + curve->visible = value; +} +bool Spectrum::use_min_line(SRC src) { + return d()->state_value(&Spectrum_Render_State::use_min_line, src); +} +void Spectrum::set_use_min_line(bool value) { + d()->set_state_value(&Spectrum_Render_State::use_min_line, value); + if (auto curve = min_curve.lock()) + curve->visible = value; +} +bool Spectrum::use_max_marker(SRC src) { + return d()->state_value(&Spectrum_Render_State::use_max_marker, src); +} +void Spectrum::set_use_max_marker(bool value) { + d()->set_state_value(&Spectrum_Render_State::use_max_marker, value); +} +bool Spectrum::use_min_marker(SRC src) { + return d()->state_value(&Spectrum_Render_State::use_min_marker, src); +} +void Spectrum::set_use_min_marker(bool value) { + d()->set_state_value(&Spectrum_Render_State::use_min_marker, value); +} +bool Spectrum::use_sweep_frequency_rect(SRC src) { + return d()->state_value(&Spectrum_Render_State::use_sweep_frequency_rect, src); +} +void Spectrum::set_use_sweep_frequency_rect(bool value) { + d()->set_state_value(&Spectrum_Render_State::use_sweep_frequency_rect, value); +} +bool Spectrum::visible_range_only(SRC src) { + return d()->state_value(&Spectrum_Render_State::visible_range_only, src); +} +void Spectrum::set_visible_range_only(bool value) { + d()->set_state_value(&Spectrum_Render_State::visible_range_only, value); + if (auto curve = cur_curve.lock()) + curve->set_visible_range_only(value); + if (auto curve = max_curve.lock()) + curve->set_visible_range_only(value); + if (auto curve = min_curve.lock()) + curve->set_visible_range_only(value); +} +Line_Interpolation_Mode Spectrum::interpolation_mode(SRC src) { + return d()->state_value(&Spectrum_Render_State::interpolation_mode, src); +} +void Spectrum::set_interpolation_mode(Line_Interpolation_Mode value) { + d()->set_state_value(&Spectrum_Render_State::interpolation_mode, value); + if (auto curve = cur_curve.lock()) + curve->set_interpolation_mode(value); + if (auto curve = max_curve.lock()) + curve->set_interpolation_mode(value); + if (auto curve = min_curve.lock()) + curve->set_interpolation_mode(value); +} +Spectrum_Sample_Mode Spectrum::sample_mode(SRC src) { + return d()->state_value(&Spectrum_Render_State::sample_mode, src); +} +void Spectrum::set_sample_mode(Spectrum_Sample_Mode value) { + d()->set_state_value(&Spectrum_Render_State::sample_mode, value); + Curve_Sample_Mode curve_mode = spectrum_curve_sample_mode(value); + if (auto curve = cur_curve.lock()) + curve->set_sample_mode(curve_mode); + if (auto curve = max_curve.lock()) + curve->set_sample_mode(curve_mode); + if (auto curve = min_curve.lock()) + curve->set_sample_mode(curve_mode); +} +QBrush Spectrum::max_brush(SRC src) { + return d()->state_value(&Spectrum_Render_State::max_brush, src); +} +void Spectrum::set_max_brush(QBrush value) { + if (auto curve = max_curve.lock()) + curve->set_fill_brush(value); + d()->set_state_value(&Spectrum_Render_State::max_brush, std::move(value)); +} +QBrush Spectrum::cur_brush(SRC src) { + return d()->state_value(&Spectrum_Render_State::cur_brush, src); +} +void Spectrum::set_cur_brush(QBrush value) { + if (auto curve = cur_curve.lock()) + curve->set_fill_brush(value); + d()->set_state_value(&Spectrum_Render_State::cur_brush, std::move(value)); +} +QBrush Spectrum::min_brush(SRC src) { + return d()->state_value(&Spectrum_Render_State::min_brush, src); +} +void Spectrum::set_min_brush(QBrush value) { + if (auto curve = min_curve.lock()) + curve->set_fill_brush(value); + d()->set_state_value(&Spectrum_Render_State::min_brush, std::move(value)); +} +QPen Spectrum::max_pen(SRC src) { + return d()->state_value(&Spectrum_Render_State::max_pen, src); +} +void Spectrum::set_max_pen(QPen value) { + if (auto curve = max_curve.lock()) + curve->set_pen(value); + d()->set_state_value(&Spectrum_Render_State::max_pen, std::move(value)); +} +QPen Spectrum::cur_pen(SRC src) { + return d()->state_value(&Spectrum_Render_State::cur_pen, src); +} +void Spectrum::set_cur_pen(QPen value) { + if (auto curve = cur_curve.lock()) + curve->set_pen(value); + d()->set_state_value(&Spectrum_Render_State::cur_pen, std::move(value)); +} +QPen Spectrum::min_pen(SRC src) { + return d()->state_value(&Spectrum_Render_State::min_pen, src); +} +void Spectrum::set_min_pen(QPen value) { + if (auto curve = min_curve.lock()) + curve->set_pen(value); + d()->set_state_value(&Spectrum_Render_State::min_pen, std::move(value)); +} +QPen Spectrum::select_marker_pen(SRC src) { + return d()->state_value(&Spectrum_Render_State::select_marker_pen, src); +} +void Spectrum::set_select_marker_pen(QPen value) { + d()->set_state_value(&Spectrum_Render_State::select_marker_pen, std::move(value)); +} +QPen Spectrum::marker_pen(SRC src) { + return d()->state_value(&Spectrum_Render_State::marker_pen, src); +} +void Spectrum::set_marker_pen(QPen value) { + d()->set_state_value(&Spectrum_Render_State::marker_pen, std::move(value)); +} +QPen Spectrum::middle_frequency_pen(SRC src) { + return d()->state_value(&Spectrum_Render_State::middle_frequency_pen, src); +} +void Spectrum::set_middle_frequency_pen(QPen value) { + d()->set_state_value(&Spectrum_Render_State::middle_frequency_pen, std::move(value)); +} +QBrush Spectrum::sweep_rect_brush(SRC src) { + return d()->state_value(&Spectrum_Render_State::sweep_rect_brush, src); +} +void Spectrum::set_sweep_rect_brush(QBrush value) { + d()->set_state_value(&Spectrum_Render_State::sweep_rect_brush, std::move(value)); +} +void Spectrum::set_frequency_point_size(int frequency_point_size) { + Render_Edit_Lease edit(d()); + edit->frequency_point_size = qMax(1, frequency_point_size); +} +void Spectrum::set_frequency_range(Range frequency_range) { + if (frequency_range.length() == 0.0) + return; + Render_Edit_Lease edit(d()); + edit->frequency_range = frequency_range; + if (auto curve = cur_curve.lock()) + curve->set_data_range(frequency_range); + if (auto curve = max_curve.lock()) + curve->set_data_range(frequency_range); + if (auto curve = min_curve.lock()) + curve->set_data_range(frequency_range); +} +Spectrum::Builder::Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis) { + ASSERT(parent, "Spectrum build error! parent == nullptr"); + ASSERT(frequency_axis && power_axis, "Spectrum build error! axis == nullptr"); + ASSERT(frequency_axis->plot != nullptr, "Spectrum build error! frequency_axis->plot == nullptr"); + ASSERT(frequency_axis->plot == power_axis->plot, "Spectrum build error! frequency_axis->plot != power_axis->plot"); + ASSERT(parent->plot == frequency_axis->plot, "Spectrum build error! parent->plot != axis->plot"); + this->parent = parent; + this->frequency_axis = frequency_axis; + this->power_axis = power_axis; +} +std::shared_ptr Spectrum::Builder::build() { + std::shared_ptr < Spectrum > ret(new Spectrum); + ret->init(parent); + Spectrum_Private* pd = ret->d(); + Spectrum_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); + PROP_R(std::weak_ptr, frequency_axis) + PROP_R(std::weak_ptr, power_axis); + PROP_R(int, frequency_point_size); + PROP_R(Range, frequency_range); + PROP_R(double, middle_sweep_frequency); + PROP_R(Range, sweep_frequency_range); + PROP_R(bool, use_max_line); + PROP_R(bool, use_min_line); + PROP_R(bool, use_max_marker); + PROP_R(bool, use_min_marker); + PROP_R(bool, use_sweep_frequency_rect); + PROP_R(bool, visible_range_only); + PROP_R(Line_Interpolation_Mode, interpolation_mode); + PROP_R(Spectrum_Sample_Mode, sample_mode); + PROP_R(QBrush, max_brush); + PROP_R(QBrush, cur_brush); + PROP_R(QBrush, min_brush); + PROP_R(QPen, max_pen); + PROP_R(QPen, cur_pen); + PROP_R(QPen, min_pen); + PROP_R(QPen, select_marker_pen); + PROP_R(QPen, marker_pen); + PROP_R(QPen, middle_frequency_pen); + PROP_R(QBrush, sweep_rect_brush); + sc->frequency_point_size = qMax(1, sc->frequency_point_size); + if (sc->frequency_range.length() == 0.0) + sc->frequency_range = {0.0, 1.0}; + if (sc->sweep_frequency_range.length() == 0.0) + sc->sweep_frequency_range = {0.0, 1.0}; + ret->set_child_render_order(Renderable_Child_Render_Order::Children_Before_Self); + auto frequency_axis = this->frequency_axis.lock(); + auto power_axis = this->power_axis.lock(); + if (frequency_axis && power_axis) { + Curve_Sample_Mode curve_sample_mode = spectrum_curve_sample_mode(sc->sample_mode); + auto max_curve = Curve::Builder(ret, frequency_axis, power_axis).set_data_range(sc->frequency_range).set_pen(sc->max_pen).set_fill_brush(sc->max_brush).set_visible_range_only(sc->visible_range_only).set_interpolation_mode(sc->interpolation_mode).set_sample_mode(curve_sample_mode).build(); + auto cur_curve = Curve::Builder(ret, frequency_axis, power_axis).set_data_range(sc->frequency_range).set_pen(sc->cur_pen).set_fill_brush(sc->cur_brush).set_visible_range_only(sc->visible_range_only).set_interpolation_mode(sc->interpolation_mode).set_sample_mode(curve_sample_mode).build(); + auto min_curve = Curve::Builder(ret, frequency_axis, power_axis).set_data_range(sc->frequency_range).set_pen(sc->min_pen).set_fill_brush(sc->min_brush).set_visible_range_only(sc->visible_range_only).set_interpolation_mode(sc->interpolation_mode).set_sample_mode(curve_sample_mode).build(); + auto marker_item = Marker::Builder(ret, frequency_axis, power_axis).build(); + auto label_item = Label::Builder(ret, frequency_axis, power_axis).build(); + max_curve->object_name = "SpectrumMaxCurve"; + cur_curve->object_name = "SpectrumCurCurve"; + min_curve->object_name = "SpectrumMinCurve"; + marker_item->object_name = "SpectrumMarker"; + label_item->object_name = "SpectrumLabel"; + max_curve->visible = sc->use_max_line; + min_curve->visible = sc->use_min_line; + ret->max_curve = max_curve; + ret->cur_curve = cur_curve; + ret->min_curve = min_curve; + ret->marker_item = marker_item; + ret->label_item = label_item; + } + return ret; +} +void Spectrum_Private::update_frequency_point_size(int frequency_point_size, Range frequency_range) { + if (frequency_point_size <= 0) { + cache_frequency_point_size = frequency_point_size; + cache_frequency_range = frequency_range; + has_power_data = false; + max_powers.clear(); + cur_powers.clear(); + min_powers.clear(); + frequency.clear(); + return; + } + cache_frequency_point_size = frequency_point_size; + cache_frequency_range = frequency_range; + has_power_data = false; + max_powers.resize(frequency_point_size); + cur_powers.resize(frequency_point_size); + min_powers.resize(frequency_point_size); + frequency.resize(frequency_point_size); + if (frequency_point_size == 1) { + frequency[0] = frequency_range.origin; + return; + } + double cur = frequency_range.origin; + double step = frequency_range.length() / (frequency_point_size - 1); + frequency[0] = frequency_range.origin; + for (int i = 1; i < frequency_point_size; ++i) { + cur += step; + frequency[i] = cur; + } +} +void Spectrum_Private::set_frequency_data(const QVector& line_data, const QVector* max_data, const QVector* min_data, const Spectrum_Render_State* s) { + if (s->frequency_point_size <= 0) + return; + if (line_data.size() != s->frequency_point_size) + return; + if ((max_data && max_data->size() != s->frequency_point_size) || (min_data && min_data->size() != s->frequency_point_size)) + return; + cur_powers = line_data; + cur_powers.detach(); + if (!has_power_data) { + max_powers = line_data; + max_powers.detach(); + min_powers = line_data; + min_powers.detach(); + has_power_data = true; + } + double min = std::numeric_limits::max(); + double max = std::numeric_limits::lowest(); + int min_index = 0, max_index = 0; + for (int i = 0; i < s->frequency_point_size; ++i) { + double& cur_data = cur_powers[i]; + if (s->use_max_line) { + double hold_max = max_data ? max_data->at(i) : cur_data; + if (hold_max > max_powers.at(i)) + max_powers[i] = hold_max; + } + if (s->use_min_line) { + double hold_min = min_data ? min_data->at(i) : cur_data; + if (hold_min < min_powers.at(i)) + min_powers[i] = hold_min; + } + if (s->use_max_marker && cur_data > max) { + max = cur_data; + max_index = i; + } + if (s->use_min_marker && cur_data < min) { + min = cur_data; + min_index = i; + } + } + max_marker_key = frequency[max_index]; + max_marker_value = cur_powers[max_index]; + min_marker_key = frequency[min_index]; + min_marker_value = cur_powers[min_index]; +} +double Spectrum_Private::get_y(double x, bool& ok, Line_Interpolation_Mode mode) { + if (cur_powers.size() < 2 || cache_frequency_range.length() == 0.0 || !cache_frequency_range.contain(x)) { + ok = false; + return -1; + } + double index = coord_to_source_index(cache_frequency_range, cur_powers.size(), x); + ok = true; + return interpolate_line_value(index, cur_powers.size(), mode, [this](int i) { + return cur_powers.at(i); + }); +} +void Spectrum_Private::update_marker_items(const Spectrum_Render_State* s) { + auto frequency_axis = s->frequency_axis.lock(); + auto power_axis = s->power_axis.lock(); + QVector marker_items; + QVector label_items; + if (!frequency_axis || !power_axis) { + if (auto marker_item = q()->marker_item.lock()) + marker_item->give_items(marker_items, false); + if (auto label_item = q()->label_item.lock()) + label_item->give_items(label_items, false); + return; + } + auto append_marker = [&](double frequency, double power, bool drawLine, bool selected) { + QPen pen = selected ? s->select_marker_pen : s->marker_pen; + Marker_Item marker; + marker.position = QPointF(frequency, power); + marker.radius = 2.0; + marker.pen = pen; + marker.mode = drawLine ? Marker_Mode::Vertical_Line : Marker_Mode::Point; + marker_items.append(marker); + QString frequency_text = QString::number(frequency, 'f', 2) + frequency_axis->unit_text(); + QString power_text = QString::number(power, 'f', 2) + power_axis->unit_text(); + Label_Item frequency_label; + frequency_label.position = marker.position; + frequency_label.offset = QPointF(0.0, -28.0); + frequency_label.text = frequency_text; + frequency_label.alignment = Qt::AlignHCenter | Qt::AlignBottom; + frequency_label.text_pen = pen; + label_items.append(frequency_label); + Label_Item power_label = frequency_label; + power_label.offset = QPointF(0.0, -14.0); + power_label.text = power_text; + label_items.append(power_label); + }; + if (s->use_max_marker) + append_marker(max_marker_key, max_marker_value, false, false); + if (s->use_min_marker) + append_marker(min_marker_key, min_marker_value, false, false); + for (int i = 0; i < s->marker_list.size(); ++i) { + const Spectrum_Marker& custom_marker = s->marker_list.at(i); + bool ok; + double value = get_y(custom_marker.frequency, ok, s->interpolation_mode); + if (ok) + append_marker(custom_marker.frequency, value, custom_marker.draw_line, i == s->cur_select_index); + } + if (auto marker_item = q()->marker_item.lock()) + marker_item->give_items(marker_items, false); + if (auto label_item = q()->label_item.lock()) + label_item->give_items(label_items, false); +} +void Spectrum_Private::draw_spectrum(QPainter* painter, Spectrum_Render_State* s) { + if (s->use_sweep_frequency_rect) { + s->draw_axis_rect(painter, s->sweep_frequency_range, s->middle_sweep_frequency); + } +} +void Spectrum_Private::draw(QPainter* painter, const Plot_Render_Snapshot& snapshot) { + auto s = render_state(); + Performance_Shower* shower = snapshot.performance_shower.get(); + if (shower) { + shower->set_performance_line("frequency_point_size", Performance_Line(QString("frequency_point_size:%1").arg(s->frequency_point_size))); + } + draw_spectrum(painter, s); + if (q()->hover_ok(q())) { + auto frequency_axis = s->frequency_axis.lock(); + auto power_axis = s->power_axis.lock(); + if (frequency_axis && power_axis) + q()->draw_hover(painter, frequency_axis.get(), power_axis.get()); + } +} +void Spectrum::give_data(const QVector& line_data) { + if (!ok()) + return; + Spectrum_Private* pd = d(); + Render_State_Lease state(pd); + int frequency_point_size = state->frequency_point_size; + if (line_data.size() != frequency_point_size) + return; + Render_Input_Lease input(pd); + input->push(line_data, state->use_max_line, state->use_min_line); +} +void Spectrum::add_custom_marker(double frequency) { + Render_Edit_Lease edit(d()); + edit->marker_list.append(Spectrum_Marker{frequency, false}); +} +void Spectrum::add_custom_line_marker(double frequency) { + Render_Edit_Lease edit(d()); + edit->marker_list.append(Spectrum_Marker{frequency, true}); +} +void Spectrum::remove_custom_marker(double frequency) { + Render_Edit_Lease edit(d()); + for (Spectrum_Marker& marker : edit->marker_list) { + if (qFuzzyCompare(marker.frequency, frequency)) { + edit->marker_list.removeOne(marker); + break; + } + } +} +void Spectrum::remove_current_marker(SRC src) { + Q_UNUSED(src) + Render_Edit_Lease edit(d()); + if (edit->cur_select_index < 0 || edit->cur_select_index >= edit->marker_list.size()) + return; + edit->marker_list.removeAt(edit->cur_select_index); + edit->cur_select_index = -1; +} +void Spectrum::clear_all_custom_marker(SRC src) { + Q_UNUSED(src) + Render_Edit_Lease edit(d()); + edit->marker_list.clear(); +} +double Spectrum::get_mark_frequency(int mark_index, SRC src) { + auto render_state = d()->state_data(src); + if (mark_index < 0 || mark_index >= render_state->marker_list.size()) + return -1; + return render_state->marker_list[mark_index].frequency; +} +void Spectrum::set_marker_frequency(int marker_index, double frequency) { + Render_Edit_Lease edit(d()); + QVector& markers = edit->marker_list; + if (marker_index < 0 || marker_index >= markers.size()) + return; + markers[marker_index].frequency = frequency; +} +void Spectrum::set_current_marker_frequency(double frequency) { + Render_Edit_Lease edit(d()); + edit->set_cur_frequency(frequency); +} +int Spectrum::select_line_marker_size(SRC src) { + auto render_state = d()->state_data(src); + return render_state->marker_list.size(); +} +int Spectrum::cur_select_marker_index(SRC src) { + auto render_state = d()->state_data(src); + return render_state->cur_select_index; +} +void Spectrum::set_selected_line_marker(int marker_index) { + Render_Edit_Lease edit(d()); + edit->set_select_index(marker_index); +} +void Spectrum::select_next(SRC src) { + Q_UNUSED(src) + Render_Edit_Lease edit(d()); + edit->select_next_marker(); +} +void Spectrum::select_previous(SRC src) { + Q_UNUSED(src) + Render_Edit_Lease edit(d()); + edit->select_prev_marker(); +} +void Spectrum::un_select_marker(SRC src) { + Q_UNUSED(src) + Render_Edit_Lease edit(d()); + edit->un_select(); +} +double Spectrum::get_power(double frequency, bool& ok, SRC src) { + return d()->get_y(frequency, ok, interpolation_mode(src)); +} +} // namespace renderive diff --git a/YSGraphic_Core/plottable/Spectrum.h b/Renderive/plottable/Spectrum.h similarity index 68% rename from YSGraphic_Core/plottable/Spectrum.h rename to Renderive/plottable/Spectrum.h index d4ce1ab..2fea2c0 100644 --- a/YSGraphic_Core/plottable/Spectrum.h +++ b/Renderive/plottable/Spectrum.h @@ -2,7 +2,7 @@ #include "Hover_Info.h" #include "Interpolation.h" #include "../primitive/Curve.h" -namespace YSG { +namespace renderive { struct Spectrum_Private; class Label; class Marker; @@ -11,27 +11,25 @@ enum class Spectrum_Sample_Mode { Pixel_Peak_Bucket }; /// 单条频谱线图元,支持可见范围裁剪和多种线插值策略。 -class LIB_DECL Spectrum : public Renderable, public Hover_Info_Render_Able { +class LIB_DECL Spectrum : public Renderable, public Hover_Info_Renderable { public: /// 返回私有渲染数据。 Spectrum_Private* d(); Render_Data* create_render_data() override; Render_State* create_render_state() override; Input_Data* create_input_data() override; -protected: Spectrum(); -public: - PROP(std::shared_ptr, frequent_axis) + PROP(std::shared_ptr, frequency_axis) PROP(std::shared_ptr, power_axis); - PROP(int, frequent_point_size); - PROP(Range, frequent_range); - PROP(double, middle_sweep_frequent); - PROP(Range, sweep_frequent_range); + PROP(int, frequency_point_size); + PROP(Range, frequency_range); + PROP(double, middle_sweep_frequency); + PROP(Range, sweep_frequency_range); PROP(bool, use_max_line); PROP(bool, use_min_line); PROP(bool, use_max_marker); PROP(bool, use_min_marker); - PROP(bool, use_sweep_frequent_rect); + PROP(bool, use_sweep_frequency_rect); PROP(bool, visible_range_only); PROP(Line_Interpolation_Mode, interpolation_mode); PROP(Spectrum_Sample_Mode, sample_mode); @@ -43,18 +41,18 @@ public: PROP(QPen, min_pen); PROP(QPen, select_marker_pen); PROP(QPen, marker_pen); - PROP(QPen, middle_frequent_pen); + PROP(QPen, middle_frequency_pen); PROP(QBrush, sweep_rect_brush); /// 写入一帧频谱线数据。 - void give_data(const QVector& lineData); + void give_data(const QVector& line_data); /// 查询指定频率位置的功率值。 - double get_power(double frequent, bool& ok, SRC = SRC::Edit); + double get_power(double frequency, bool& ok, SRC = SRC::Edit); /// 添加自定义频率标记。 - void add_custom_marker(double frequent); + void add_custom_marker(double frequency); /// 添加自定义线标记。 - void add_custom_line_marker(double frequent); + void add_custom_line_marker(double frequency); /// 删除指定频率附近的自定义标记。 - void remove_custom_marker(double frequent); + void remove_custom_marker(double frequency); /// 删除当前选中的标记。 void remove_current_marker(SRC = SRC::Edit); /// 清空所有自定义标记。 @@ -64,7 +62,7 @@ public: /// 返回当前选中线标记索引。 int cur_select_marker_index(SRC = SRC::Edit); /// 设置当前选中线标记索引。 - void set_selected_line_marker(int markerIndex); + void set_selected_line_marker(int marker_index); /// 选择下一个线标记。 void select_next(SRC = SRC::Edit); /// 取消当前线标记选择。 @@ -72,32 +70,30 @@ public: /// 选择上一个线标记。 void select_previous(SRC = SRC::Edit); /// 返回指定标记索引对应频率。 - double get_mark_frequent(int markIndex, SRC = SRC::Edit); + double get_mark_frequency(int mark_index, SRC = SRC::Edit); /// 设置指定标记频率。 - void set_marker_frequent(int markerIndex, double frequent); + void set_marker_frequency(int marker_index, double frequency); /// 设置当前选中标记频率。 - void set_current_marker_frequent(double frequent); + void set_current_marker_frequency(double frequency); struct Builder; -protected: - friend struct Spectrum_Private; - std::weak_ptr mCurCurve; - std::weak_ptr mMaxCurve; - std::weak_ptr mMinCurve; - std::weak_ptr mMarkerItem; - std::weak_ptr