ccColorScale.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
  15. //# #
  16. //##########################################################################
  17. #ifndef CC_COLOR_SCALE_HEADER
  18. #define CC_COLOR_SCALE_HEADER
  19. //Local
  20. #include "ccColorTypes.h"
  21. #include "ccSerializableObject.h"
  22. //Qt
  23. #include <QList>
  24. #include <QSharedPointer>
  25. //System
  26. #include <set>
  27. //! Color scale element: one value + one color
  28. class ccColorScaleElement
  29. {
  30. public:
  31. //! Default constructor
  32. ccColorScaleElement() : m_relativePos(0.0), m_color(Qt::black) {}
  33. //! Constructor from a (relative) position and a color
  34. ccColorScaleElement(double relativePos, const QColor& color) : m_relativePos(relativePos), m_color(color) {}
  35. //! Sets associated value (relative to scale boundaries)
  36. /** \param pos relative position (always between 0.0 and 1.0!)
  37. **/
  38. inline void setRelativePos(double pos) { m_relativePos = pos; }
  39. //! Returns step position (relative to scale boundaries)
  40. /** \return relative position (always between 0.0 and 1.0!)
  41. **/
  42. inline double getRelativePos() const { return m_relativePos; }
  43. //! Sets color
  44. inline void setColor(const QColor& color) { m_color = color; }
  45. //! Returns color
  46. inline const QColor& getColor() const { return m_color; }
  47. //! Comparison operator between two color scale elements
  48. inline static bool IsSmaller(const ccColorScaleElement& e1, const ccColorScaleElement& e2)
  49. {
  50. return e1.getRelativePos() < e2.getRelativePos();
  51. }
  52. protected:
  53. //! Step (relative) position
  54. /** Must always be between 0.0 and 1.0!
  55. **/
  56. double m_relativePos;
  57. //! Color
  58. QColor m_color;
  59. };
  60. //! Color scale
  61. /** A color scale is defined by several 'steps' corresponding to given colors.
  62. The color between each step is linearly interpolated. A valid color scale
  63. must have at least 2 steps, one at relative position 0.0 (scale start) and
  64. one at relative position 1.0 (scale end). Steps can't be defined outside
  65. this interval.
  66. For faster access, an array of interpolated colors is maintained internally.
  67. Be sure that the 'refresh' method has been called after any modification
  68. of the scale steps (position or color).
  69. **/
  70. class QCC_DB_LIB_API ccColorScale : public ccSerializableObject
  71. {
  72. public:
  73. //! Shared pointer type
  74. using Shared = QSharedPointer<ccColorScale>;
  75. //! Creates a new color scale (with auto-generated unique id)
  76. /** Warning: color scale is relative by default.
  77. **/
  78. static ccColorScale::Shared Create(const QString& name);
  79. //! Default constructor
  80. /** \param name scale name
  81. \param uuid UUID (automatically generated if none is provided)
  82. Scale are 'relative' by default (can be changed afterwards, see setAbsolute).
  83. On construction they already have the two extreme steps defined (at position
  84. 0.0 and 1.0).
  85. **/
  86. ccColorScale(const QString& name, const QString& uuid = QString());
  87. //! Destructor
  88. ~ccColorScale() override = default;
  89. //! Creates a copy of this color scale (with a specified unique id)
  90. ccColorScale::Shared copy(const QString& uuid = QString()) const;
  91. //! Minimum number of steps
  92. static constexpr unsigned MIN_STEPS = 2;
  93. //! Default number of steps for display
  94. static constexpr unsigned DEFAULT_STEPS = 256;
  95. //! Maximum number of steps (internal representation)
  96. static constexpr unsigned MAX_STEPS = 1024;
  97. //! Returns name
  98. inline const QString& getName() const { return m_name; }
  99. //! Sets name
  100. void setName(const QString& name) { m_name = name; }
  101. //! Returns unique ID
  102. const QString &getUuid() const { return m_uuid; }
  103. //! Sets unique ID
  104. void setUuid(const QString& uuid) { m_uuid = uuid; }
  105. //! Generates a new unique ID
  106. void generateNewUuid();
  107. //! Returns whether scale is relative or absoute
  108. /** Relative means that internal 'values' are percentage.
  109. **/
  110. inline bool isRelative() const { return m_relative; }
  111. //! Sets scale as relative
  112. inline void setRelative() { m_relative = true; }
  113. //! Sets scale as absolute
  114. void setAbsolute(double minVal, double maxVal);
  115. //! Get absolute scale boundaries
  116. /** Warning: only valid with absolute scales!
  117. **/
  118. void getAbsoluteBoundaries(double& minVal, double& maxVal) const;
  119. //! Returns whether scale is locked or not
  120. inline bool isLocked() const { return m_locked; }
  121. //! Sets whether scale is locked or not
  122. inline void setLocked(bool state) { m_locked = state; }
  123. //! Color scale label (value + optional text)
  124. struct Label
  125. {
  126. Label(double v)
  127. : value(v)
  128. {}
  129. Label(double v, const QString& t)
  130. : value(v)
  131. , text(t)
  132. {}
  133. double value = 0.0;
  134. QString text;
  135. bool operator<(const Label& otherLabel) const
  136. {
  137. return value < otherLabel.value;
  138. }
  139. };
  140. //! Type of a list of custom labels
  141. using LabelSet = std::set<Label>;
  142. //! Returns the list of custom labels (if any)
  143. inline LabelSet& customLabels() { return m_customLabels; }
  144. //! Returns the list of custom labels (if any - const version)
  145. inline const LabelSet& customLabels() const { return m_customLabels; }
  146. //! Sets the list of custom labels (only if the scale is absolute)
  147. /** \warning May throw std::bad_alloc exception)
  148. **/
  149. inline void setCustomLabels(const LabelSet& labels) { m_customLabels = labels; }
  150. //! Returns the current number of steps
  151. /** A valid scale should always have at least 2 steps!
  152. **/
  153. inline int stepCount() const { return m_steps.size(); }
  154. //! Access to a given step
  155. inline ccColorScaleElement& step(int index) { return m_steps[index]; }
  156. //! Access to a given step (const)
  157. inline const ccColorScaleElement& step(int index) const { return m_steps[index]; }
  158. //! Adds a step
  159. /** Scale must not be locked.
  160. **/
  161. void insert(const ccColorScaleElement& step, bool autoUpdate = true);
  162. //! Deletes a given step
  163. /** The first and last index shouldn't be deleted!
  164. Scale must not be locked.
  165. **/
  166. void remove(int index, bool autoUpdate = true);
  167. //! Clears all steps
  168. /** There should be at least 2 steps for the scale to be valid!
  169. Scale must not be locked.
  170. **/
  171. void clear();
  172. //! Updates internal representation
  173. /** Must be called at least once after any modification
  174. (before using this scale).
  175. **/
  176. void update();
  177. //! Returns relative position of a given value (wrt to scale absolute min and max)
  178. /** Warning: only valid with absolute scales! Use 'getColorByRelativePos' otherwise.
  179. **/
  180. inline double getRelativePosition(double value) const
  181. {
  182. assert(m_updated && !m_relative);
  183. return (value - m_absoluteMinValue) / m_absoluteRange;
  184. }
  185. //! Returns color by value
  186. /** Warning: only valid with absolute scales!
  187. \param value value
  188. \param outOfRangeColor default color to return if relativePos if out of [0;1]
  189. \return corresponding color
  190. **/
  191. inline const ccColor::Rgb* getColorByValue(double value, const ccColor::Rgb* outOfRangeColor = nullptr) const
  192. {
  193. assert(m_updated && !m_relative);
  194. double relativePos = getRelativePosition(value);
  195. return (relativePos >= 0.0 && relativePos <= 1.0 ? getColorByRelativePos(relativePos) : outOfRangeColor);
  196. }
  197. //! Returns color by relative position in scale
  198. /** \param relativePos relative position (should be in [0;1])
  199. \param outOfRangeColor default color to return if relativePos if out of [0;1]
  200. \return corresponding color
  201. **/
  202. inline const ccColor::Rgb* getColorByRelativePos(double relativePos, const ccColor::Rgb* outOfRangeColor = nullptr) const
  203. {
  204. assert(m_updated);
  205. if (relativePos >= 0.0 && relativePos <= 1.0)
  206. return &getColorByIndex(static_cast<unsigned>(relativePos * (MAX_STEPS - 1)));
  207. else
  208. return outOfRangeColor;
  209. }
  210. //! Returns color by relative position in scale with a given 'resolution'
  211. /** \param relativePos relative position (must be between 0 and 1!)
  212. \param steps desired resolution (must be greater than 1 and smaller than MAX_STEPS)
  213. \param outOfRangeColor default color to return if relativePos if out of [0;1]
  214. \return corresponding color
  215. **/
  216. inline const ccColor::Rgb* getColorByRelativePos(double relativePos, unsigned steps, const ccColor::Rgb* outOfRangeColor = nullptr) const
  217. {
  218. assert(m_updated);
  219. if (relativePos >= 0.0 && relativePos <= 1.0)
  220. {
  221. //quantized (16 bits) version --> much faster than floor!
  222. unsigned index = (static_cast<unsigned>((relativePos*steps)*65535.0)) >> 16;
  223. return &getColorByIndex((index*(MAX_STEPS - 1)) / steps);
  224. }
  225. else
  226. {
  227. return outOfRangeColor;
  228. }
  229. }
  230. //! Returns color by index
  231. /** \param index color index in m_rgbaScale array (must be below MAX_STEPS)
  232. \return corresponding color
  233. **/
  234. inline const ccColor::Rgb& getColorByIndex(unsigned index) const
  235. {
  236. assert(m_updated && index < MAX_STEPS);
  237. return m_rgbaScale[index];
  238. }
  239. //! Saves this color scale as an XML file
  240. bool saveAsXML(const QString& filename) const;
  241. //! Loads a color scale from an XML file
  242. static Shared LoadFromXML(const QString& filename);
  243. //inherited from ccSerializableObject
  244. bool isSerializable() const override { return true; }
  245. bool toFile(QFile& out, short dataVersion) const override;
  246. bool fromFile(QFile& in, short dataVersion, int flags, LoadedIDMap& oldToNewIDMap) override;
  247. short minimumFileVersion() const override;
  248. protected:
  249. //! Sort elements
  250. void sort();
  251. //! Name
  252. QString m_name;
  253. //! Unique ID
  254. QString m_uuid;
  255. //! Elements
  256. QList<ccColorScaleElement> m_steps;
  257. //! Internal representation (RGB)
  258. ccColor::Rgb m_rgbaScale[MAX_STEPS];
  259. //! Internal representation validity
  260. bool m_updated;
  261. //! Whether scale is relative or not
  262. bool m_relative;
  263. //! Whether scale is locked or not
  264. bool m_locked;
  265. //! 'Absolute' minimum value
  266. /** Only used if scale is 'absolute' (i.e. not relative).
  267. 'Absolute' should not be taken in its mathematical meaning!
  268. **/
  269. double m_absoluteMinValue;
  270. //! 'Absolute' range
  271. /** Only used if scale is 'absolute' (i.e. not relative).
  272. 'Absolute' should not be taken in its mathematical meaning!
  273. **/
  274. double m_absoluteRange;
  275. //! List of custom labels
  276. LabelSet m_customLabels;
  277. };
  278. #endif //CC_COLOR_SCALE_HEADER