BsGUIGraphTicks.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsEditorPrerequisites.h"
  5. #include "Math/BsMath.h"
  6. namespace bs
  7. {
  8. /** @addtogroup GUI-Editor
  9. * @{
  10. */
  11. /** Determines how should ticks reported by <see cref="GUIGraphTicks"/> be distributed. */
  12. enum class BS_SCRIPT_EXPORT(m:GUIEditor,api:bed) GUITickStepType
  13. {
  14. /** Ticks represent time values (Multiples of 60). */
  15. Time,
  16. /** Ticks represent generic values (Multiples of 10). */
  17. Generic
  18. };
  19. /**
  20. * Generates a set of locations that can be used for rendering ticks on a graph. As input the class takes valid range,
  21. * size of the area the ticks will be displayed on, type of ticks and minimum/maximum spacing and outputs a set of
  22. * coordinates along which ticks should be positioned. Ticks are reported as multiple separate levels with different
  23. * strengths, depending on how close their distribution is to the upper valid range.
  24. */
  25. class BS_SCRIPT_EXPORT(m:GUIEditor,api:bed) GUIGraphTicks
  26. {
  27. public:
  28. /**
  29. * Contructs a new tick generating object.
  30. *
  31. * @param[in] stepType Determines how will ticks be distributed.
  32. */
  33. BS_SCRIPT_EXPORT()
  34. GUIGraphTicks(GUITickStepType stepType = GUITickStepType::Generic)
  35. {
  36. if(stepType == GUITickStepType::Generic)
  37. setGenericSteps();
  38. else
  39. setTimeSteps();
  40. rebuild();
  41. }
  42. /** Number of tick levels that will be generated. */
  43. BS_SCRIPT_EXPORT(pr:getter,n:NumLevels)
  44. UINT32 getNumLevels() const
  45. {
  46. return mNumLevels;
  47. }
  48. /**
  49. * Sets the range which ticks are to be displayed for, and the range along which the ticks will be displayed.
  50. *
  51. * @param[in] valueRangeStart Start of the range the ticks are to display.
  52. * @param[in] valueRangeEnd End of the range the ticks are to display.
  53. * @param[in] pixelRange Width or height on which the ticks will be rendered. In pixels.
  54. */
  55. BS_SCRIPT_EXPORT()
  56. void setRange(float valueRangeStart, float valueRangeEnd, UINT32 pixelRange)
  57. {
  58. this->mValueRangeStart = valueRangeStart;
  59. this->mValueRangeEnd = valueRangeEnd;
  60. this->mPixelRange = pixelRange;
  61. rebuild();
  62. }
  63. /**
  64. * Sets valid spacing between two ticks. Tick strength will be determined by how far away are they from either
  65. * end of this range.
  66. *
  67. * @param[in] minPx Minimum spacing between two ticks, in pixels.
  68. * @param[in] maxPx Maximum spacing between two ticks, in pixels.
  69. */
  70. BS_SCRIPT_EXPORT()
  71. void setTickSpacing(int minPx, int maxPx)
  72. {
  73. mMinTickSpacingPx = minPx;
  74. mMaxTickSpacingPx = maxPx;
  75. rebuild();
  76. }
  77. /**
  78. * Returns the strength of a particular tick level. Levels are ordered in descending order of strength (level 0 is
  79. * the strongest).
  80. *
  81. * @param[in] level Level for which to retrieve the strength. Must not be larger than getNumLevels() - 1.
  82. * @return Strength of the ticks at this level, in range [0, 1].
  83. */
  84. BS_SCRIPT_EXPORT()
  85. float getLevelStrength(UINT32 level)
  86. {
  87. if (level >= mNumLevels)
  88. return 0.0f;
  89. return Math::clamp01(mLevelStrengths[mMaxLevel + level]);
  90. }
  91. /**
  92. * Returns positions of all ticks of the provided level. The ticks will be within the range provided to setRange().
  93. *
  94. * @param[in] level Level for which to retrieve the positions. Must not be larger than getNumLevels() - 1.
  95. * @return Positions of all ticks of the provided level.
  96. */
  97. BS_SCRIPT_EXPORT()
  98. Vector<float> getTicks(UINT32 level)
  99. {
  100. if (level < 0 || level >= mNumLevels)
  101. return { };
  102. const float step = mValidSteps[mMaxLevel + level];
  103. // Round up and down so we get one extra tick on either side (outside of value range)
  104. // (Useful when rendering text above the ticks, so the text doesn't just pop-in when the tick appears, instead
  105. // it is slowly clipped-in.)
  106. const INT32 startTick = Math::ceilToInt(mValueRangeStart / step);
  107. const INT32 endTick = Math::floorToInt(mValueRangeEnd / step);
  108. const INT32 numTicks = endTick - startTick + 1;
  109. Vector<float> ticks(numTicks);
  110. for (INT32 i = startTick; i <= endTick; i++)
  111. ticks[i - startTick] = i*step;
  112. return ticks;
  113. }
  114. protected:
  115. /** Rebuilds the tick positions and strengths after some relevant parameter changes. */
  116. void rebuild()
  117. {
  118. mLevelStrengths = Vector<float>(mValidSteps.size());
  119. mMaxLevel = 0;
  120. const float valueRange = mValueRangeEnd - mValueRangeStart;
  121. const INT32 tickSpacing = (INT32)mMaxTickSpacingPx - (INT32)mMinTickSpacingPx;
  122. UINT32 i = 0;
  123. for (; i < (UINT32)mValidSteps.size(); i++)
  124. {
  125. const float tickSpacingPx = (mValidSteps[i]/valueRange) * mPixelRange;
  126. mLevelStrengths[i] = (tickSpacingPx - mMinTickSpacingPx)/tickSpacing;
  127. if (mLevelStrengths[i] > 1.0f)
  128. mMaxLevel = i;
  129. else if (mLevelStrengths[i] < 0.0f)
  130. break;
  131. }
  132. if (i > 0)
  133. mNumLevels = i - mMaxLevel;
  134. else
  135. mNumLevels = 0;
  136. }
  137. /**
  138. * Sets tick steps corresponding to time values. This will split the ticks into intervals relevant for displaying
  139. * times.
  140. */
  141. void setTimeSteps()
  142. {
  143. mValidSteps =
  144. {
  145. 3600.0f, 1800.0f, 600.0f, 300.0f,
  146. 60.0f, 30.0f, 10.0f, 5.0f,
  147. 1.0f, 0.5f, 0.25f, 0.1f, 0.05f, 0.01f
  148. };
  149. }
  150. /** Sets tick steps corresponding to generic values (as opposed to displaying time values). */
  151. void setGenericSteps()
  152. {
  153. constexpr UINT32 numSteps = 15;
  154. float minStep = 0.0000001f;
  155. mValidSteps = Vector<float>(numSteps * 2);
  156. for (int i = numSteps - 1; i >= 0; i--)
  157. {
  158. mValidSteps[i * 2 + 1] = minStep;
  159. mValidSteps[i * 2 + 0] = minStep * 5;
  160. minStep *= 10.0f;
  161. }
  162. }
  163. UINT32 mPixelRange = 100;
  164. float mValueRangeStart = 0.0f;
  165. float mValueRangeEnd = 1.0f;
  166. UINT32 mMinTickSpacingPx = 5;
  167. UINT32 mMaxTickSpacingPx = 30;
  168. Vector<float> mValidSteps = { 1.0f };
  169. Vector<float> mLevelStrengths = { 1.0f };
  170. UINT32 mNumLevels = 1;
  171. UINT32 mMaxLevel = 0;
  172. };
  173. /** @} */
  174. }