| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <cstdlib>
|
| |
|
| | #include <Base/Exception.h>
|
| |
|
| | #include "ColorModel.h"
|
| |
|
| |
|
| | using namespace App;
|
| |
|
| |
|
| | ColorModelPack ColorModelPack::createRedGreenBlue()
|
| | {
|
| | ColorModelPack pack {ColorModelBlueGreenRed(),
|
| | ColorModelGreenYellowRed(),
|
| | ColorModelBlueCyanGreen(),
|
| | "Red-Yellow-Green-Cyan-Blue"};
|
| | return pack;
|
| | }
|
| |
|
| | ColorModelPack ColorModelPack::createBlueGreenRed()
|
| | {
|
| | ColorModelPack pack {ColorModelRedGreenBlue(),
|
| | ColorModelGreenCyanBlue(),
|
| | ColorModelRedYellowGreen(),
|
| | "Blue-Cyan-Green-Yellow-Red"};
|
| | return pack;
|
| | }
|
| |
|
| | ColorModelPack ColorModelPack::createWhiteBlack()
|
| | {
|
| | ColorModelPack pack {ColorModelBlackWhite(),
|
| | ColorModelGrayWhite(),
|
| | ColorModelBlackGray(),
|
| | "White-Black"};
|
| | return pack;
|
| | }
|
| |
|
| | ColorModelPack ColorModelPack::createBlackWhite()
|
| | {
|
| | ColorModelPack pack {ColorModelWhiteBlack(),
|
| | ColorModelGrayBlack(),
|
| | ColorModelWhiteGray(),
|
| | "Black-White"};
|
| | return pack;
|
| | }
|
| |
|
| | ColorModelPack ColorModelPack::createRedWhiteBlue()
|
| | {
|
| | ColorModelPack pack {ColorModelBlueWhiteRed(),
|
| | ColorModelWhiteRed(),
|
| | ColorModelBlueWhite(),
|
| | "Red-White-Blue"};
|
| | return pack;
|
| | }
|
| |
|
| | ColorField::ColorField()
|
| | {
|
| | set(ColorModelBlueGreenRed(), -1.0f, 1.0f, 13);
|
| | }
|
| |
|
| | ColorField::ColorField(const ColorModel& rclModel, float fMin, float fMax, std::size_t usCt)
|
| | {
|
| | set(rclModel, fMin, fMax, usCt);
|
| | }
|
| |
|
| | ColorField& ColorField::operator=(const ColorField& rclCF)
|
| | {
|
| | colorField = rclCF.colorField;
|
| | return *this;
|
| | }
|
| |
|
| | void ColorField::set(const ColorModel& rclModel, float fMin, float fMax, std::size_t usCt)
|
| | {
|
| | auto bounds = std::minmax(fMin, fMax);
|
| | if (bounds.second <= bounds.first) {
|
| | throw Base::ValueError("Maximum must be higher than minimum");
|
| | }
|
| |
|
| | this->fMin = bounds.first;
|
| | this->fMax = bounds.second;
|
| | colorModel = rclModel;
|
| | ctColors = std::max<std::size_t>(usCt, colorModel.getCountColors());
|
| | rebuild();
|
| | }
|
| |
|
| | void ColorField::setColorModel(const ColorModel& rclModel)
|
| | {
|
| | colorModel = rclModel;
|
| | rebuild();
|
| | }
|
| |
|
| | void ColorField::rebuild()
|
| | {
|
| | colorField.resize(ctColors);
|
| |
|
| | std::size_t usStep =
|
| | std::min<std::size_t>(ctColors / (colorModel.getCountColors() - 1), ctColors - 1);
|
| | std::size_t usInd1 = 0;
|
| | std::size_t usInd2 = usStep;
|
| | for (std::size_t i = 0; i < (colorModel.getCountColors() - 1); i++) {
|
| | interpolate(colorModel.colors[i], usInd1, colorModel.colors[i + 1], usInd2);
|
| | usInd1 = usInd2;
|
| | if ((i + 1) == (colorModel.getCountColors() - 2)) {
|
| | usInd2 = ctColors - 1;
|
| | }
|
| | else {
|
| | usInd2 += usStep;
|
| | }
|
| | }
|
| |
|
| | fAscent = float(ctColors) / (fMax - fMin);
|
| | fConstant = -fAscent * fMin;
|
| | }
|
| |
|
| |
|
| | void ColorField::interpolate(Base::Color clCol1, std::size_t usInd1, Base::Color clCol2, std::size_t usInd2)
|
| | {
|
| | float fStep = 1.0f, fLen = float(usInd2 - usInd1);
|
| |
|
| | colorField[usInd1] = clCol1;
|
| | colorField[usInd2] = clCol2;
|
| |
|
| | float fR = (float(clCol2.r) - float(clCol1.r)) / fLen;
|
| | float fG = (float(clCol2.g) - float(clCol1.g)) / fLen;
|
| | float fB = (float(clCol2.b) - float(clCol1.b)) / fLen;
|
| |
|
| | for (std::size_t i = (usInd1 + 1); i < usInd2; i++) {
|
| | float ucR = clCol1.r + fR * fStep;
|
| | float ucG = clCol1.g + fG * fStep;
|
| | float ucB = clCol1.b + fB * fStep;
|
| | colorField[i] = Base::Color(ucR, ucG, ucB);
|
| | fStep += 1.0f;
|
| | }
|
| | }
|
| |
|
| |
|
| | ColorGradientProfile::ColorGradientProfile() = default;
|
| |
|
| | bool ColorGradientProfile::isEqual(const ColorGradientProfile& cg) const
|
| | {
|
| | if (tStyle != cg.tStyle) {
|
| | return false;
|
| | }
|
| | if (fMin != cg.fMin) {
|
| | return false;
|
| | }
|
| | if (fMax != cg.fMax) {
|
| | return false;
|
| | }
|
| | if (!visibility.isEqual(cg.visibility)) {
|
| | return false;
|
| | }
|
| | if (tColorModel != cg.tColorModel) {
|
| | return false;
|
| | }
|
| | return true;
|
| | }
|
| |
|
| |
|
| | ColorGradient::ColorGradient()
|
| | {
|
| | createStandardPacks();
|
| | setColorModel();
|
| | set(-1.0f, 1.0f, 13, ColorBarStyle::ZERO_BASED, Visibility::Default);
|
| | }
|
| |
|
| | ColorGradient::ColorGradient(float fMin,
|
| | float fMax,
|
| | std::size_t usCtColors,
|
| | ColorBarStyle tS,
|
| | VisibilityFlags flags)
|
| | {
|
| | createStandardPacks();
|
| | setColorModel();
|
| | set(fMin, fMax, usCtColors, tS, flags);
|
| | }
|
| |
|
| | void ColorGradient::createStandardPacks()
|
| | {
|
| | modelPacks.push_back(ColorModelPack::createRedGreenBlue());
|
| | modelPacks.push_back(ColorModelPack::createBlueGreenRed());
|
| | modelPacks.push_back(ColorModelPack::createRedWhiteBlue());
|
| | modelPacks.push_back(ColorModelPack::createWhiteBlack());
|
| | modelPacks.push_back(ColorModelPack::createBlackWhite());
|
| | }
|
| |
|
| | std::vector<std::string> ColorGradient::getColorModelNames() const
|
| | {
|
| | std::vector<std::string> names;
|
| | names.reserve(modelPacks.size());
|
| | for (const auto& it : modelPacks) {
|
| | names.push_back(it.description);
|
| | }
|
| | return names;
|
| | }
|
| |
|
| | void ColorGradient::setProfile(const ColorGradientProfile& pro)
|
| | {
|
| | profile = pro;
|
| | setColorModel();
|
| | rebuild();
|
| | }
|
| |
|
| | void ColorGradient::set(float fMin,
|
| | float fMax,
|
| | std::size_t usCt,
|
| | ColorBarStyle tS,
|
| | VisibilityFlags flags)
|
| | {
|
| | auto bounds = std::minmax(fMin, fMax);
|
| | if (bounds.second <= bounds.first) {
|
| | throw Base::ValueError("Maximum must be higher than minimum");
|
| | }
|
| |
|
| | profile.fMin = bounds.first;
|
| | profile.fMax = bounds.second;
|
| | profile.ctColors = std::max<std::size_t>(usCt, getMinColors());
|
| | profile.tStyle = tS;
|
| | profile.visibility = flags;
|
| | rebuild();
|
| | }
|
| |
|
| | void ColorGradient::rebuild()
|
| | {
|
| | switch (profile.tStyle) {
|
| | case ColorBarStyle::FLOW: {
|
| | colorField1.set(currentModelPack.totalModel,
|
| | profile.fMin,
|
| | profile.fMax,
|
| | profile.ctColors);
|
| | break;
|
| | }
|
| | case ColorBarStyle::ZERO_BASED: {
|
| | if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f)) {
|
| | colorField1.set(currentModelPack.bottomModel,
|
| | profile.fMin,
|
| | 0.0f,
|
| | profile.ctColors / 2);
|
| | colorField2.set(currentModelPack.topModel,
|
| | 0.0f,
|
| | profile.fMax,
|
| | profile.ctColors / 2);
|
| | }
|
| | else if (profile.fMin >= 0.0f) {
|
| | colorField1.set(currentModelPack.topModel, 0.0f, profile.fMax, profile.ctColors);
|
| | }
|
| | else {
|
| | colorField1.set(currentModelPack.bottomModel, profile.fMin, 0.0f, profile.ctColors);
|
| | }
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| | std::size_t ColorGradient::getMinColors() const
|
| | {
|
| | switch (profile.tStyle) {
|
| | case ColorBarStyle::FLOW:
|
| | return colorField1.getMinColors();
|
| | case ColorBarStyle::ZERO_BASED: {
|
| | if ((profile.fMin < 0.0f) && (profile.fMax > 0.0f)) {
|
| | return colorField1.getMinColors() + colorField2.getMinColors();
|
| | }
|
| | else {
|
| | return colorField1.getMinColors();
|
| | }
|
| | }
|
| | }
|
| | return 2;
|
| | }
|
| |
|
| | void ColorGradient::setColorModel(std::size_t tModel)
|
| | {
|
| | profile.tColorModel = tModel;
|
| | setColorModel();
|
| | rebuild();
|
| | }
|
| |
|
| | void ColorGradient::setColorModel()
|
| | {
|
| | if (profile.tColorModel < modelPacks.size()) {
|
| | currentModelPack = modelPacks[profile.tColorModel];
|
| | }
|
| |
|
| | switch (profile.tStyle) {
|
| | case ColorBarStyle::FLOW: {
|
| | colorField1.setColorModel(currentModelPack.totalModel);
|
| | colorField2.setColorModel(currentModelPack.bottomModel);
|
| | break;
|
| | }
|
| | case ColorBarStyle::ZERO_BASED: {
|
| | colorField1.setColorModel(currentModelPack.topModel);
|
| | colorField2.setColorModel(currentModelPack.bottomModel);
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| | ColorLegend::ColorLegend()
|
| | {
|
| |
|
| | colorFields.emplace_back(0, 0, 1);
|
| | colorFields.emplace_back(0, 1, 0);
|
| | colorFields.emplace_back(1, 0, 0);
|
| |
|
| | names.emplace_back("Min");
|
| | names.emplace_back("Mid");
|
| | names.emplace_back("Max");
|
| |
|
| | values.push_back(-1.0f);
|
| | values.push_back(-0.333f);
|
| | values.push_back(0.333f);
|
| | values.push_back(1.0f);
|
| | }
|
| |
|
| | bool ColorLegend::operator==(const ColorLegend& rclCL) const
|
| | {
|
| | return (colorFields.size() == rclCL.colorFields.size()) && (names.size() == rclCL.names.size())
|
| | && (values.size() == rclCL.values.size())
|
| | && std::equal(colorFields.begin(), colorFields.end(), rclCL.colorFields.begin())
|
| | && std::equal(names.begin(), names.end(), rclCL.names.begin())
|
| | && std::equal(values.begin(), values.end(), rclCL.values.begin())
|
| | && outsideGrayed == rclCL.outsideGrayed;
|
| | }
|
| |
|
| | float ColorLegend::getValue(std::size_t ulPos) const
|
| | {
|
| | if (ulPos < values.size()) {
|
| | return values[ulPos];
|
| | }
|
| | else {
|
| | return 0.0f;
|
| | }
|
| | }
|
| |
|
| | bool ColorLegend::setValue(std::size_t ulPos, float fVal)
|
| | {
|
| | if (ulPos < values.size()) {
|
| | values[ulPos] = fVal;
|
| | return true;
|
| | }
|
| | else {
|
| | return false;
|
| | }
|
| | }
|
| |
|
| | Base::Color ColorLegend::getColor(std::size_t ulPos) const
|
| | {
|
| | if (ulPos < colorFields.size()) {
|
| | return colorFields[ulPos];
|
| | }
|
| | else {
|
| | return Base::Color();
|
| | }
|
| | }
|
| |
|
| |
|
| | uint32_t ColorLegend::getPackedColor(std::size_t ulPos) const
|
| | {
|
| | Base::Color clRGB = getColor(ulPos);
|
| | return clRGB.getPackedValue();
|
| | }
|
| |
|
| | std::string ColorLegend::getText(std::size_t ulPos) const
|
| | {
|
| | if (ulPos < names.size()) {
|
| | return names[ulPos];
|
| | }
|
| | else {
|
| | return "";
|
| | }
|
| | }
|
| |
|
| | std::size_t ColorLegend::addMin(const std::string& rclName)
|
| | {
|
| | names.push_front(rclName);
|
| | values.push_front(values.front() - 1.0f);
|
| |
|
| | Base::Color clNewRGB;
|
| | clNewRGB.r = ((float)rand() / (float)RAND_MAX);
|
| | clNewRGB.g = ((float)rand() / (float)RAND_MAX);
|
| | clNewRGB.b = ((float)rand() / (float)RAND_MAX);
|
| |
|
| | colorFields.push_front(clNewRGB);
|
| |
|
| | return colorFields.size() - 1;
|
| | }
|
| |
|
| | std::size_t ColorLegend::addMax(const std::string& rclName)
|
| | {
|
| | names.push_back(rclName);
|
| | values.push_back(values.back() + 1.0f);
|
| |
|
| | Base::Color clNewRGB;
|
| | clNewRGB.r = ((float)rand() / (float)RAND_MAX);
|
| | clNewRGB.g = ((float)rand() / (float)RAND_MAX);
|
| | clNewRGB.b = ((float)rand() / (float)RAND_MAX);
|
| |
|
| | colorFields.push_back(clNewRGB);
|
| |
|
| | return colorFields.size() - 1;
|
| | }
|
| |
|
| | bool ColorLegend::remove(std::size_t ulPos)
|
| | {
|
| | if (ulPos < colorFields.size()) {
|
| | colorFields.erase(colorFields.begin() + ulPos);
|
| | names.erase(names.begin() + ulPos);
|
| | values.erase(values.begin() + ulPos);
|
| |
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | void ColorLegend::removeFirst()
|
| | {
|
| | if (!colorFields.empty()) {
|
| | colorFields.erase(colorFields.begin());
|
| | names.erase(names.begin());
|
| | values.erase(values.begin());
|
| | }
|
| | }
|
| |
|
| | void ColorLegend::removeLast()
|
| | {
|
| | if (!colorFields.empty()) {
|
| | colorFields.erase(colorFields.end() - 1);
|
| | names.erase(names.end() - 1);
|
| | values.erase(values.end() - 1);
|
| | }
|
| | }
|
| |
|
| | void ColorLegend::resize(std::size_t ulCt)
|
| | {
|
| | if ((ulCt < 2) || (ulCt == colorFields.size())) {
|
| | return;
|
| | }
|
| |
|
| | if (ulCt > colorFields.size()) {
|
| | int k = ulCt - colorFields.size();
|
| | for (int i = 0; i < k; i++) {
|
| | addMin("new");
|
| | }
|
| | }
|
| | else {
|
| | int k = colorFields.size() - ulCt;
|
| | for (int i = 0; i < k; i++) {
|
| | removeLast();
|
| | }
|
| | }
|
| | }
|
| |
|
| | bool ColorLegend::setColor(std::size_t ulPos, float ucRed, float ucGreen, float ucBlue)
|
| | {
|
| | if (ulPos < names.size()) {
|
| | colorFields[ulPos] = Base::Color(ucRed, ucGreen, ucBlue);
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| |
|
| | bool ColorLegend::setColor(std::size_t ulPos, unsigned long ulColor)
|
| | {
|
| | unsigned char ucRed = (unsigned char)((ulColor & 0x00ff0000) >> 16);
|
| | unsigned char ucGreen = (unsigned char)((ulColor & 0x0000ff00) >> 8);
|
| | unsigned char ucBlue = (unsigned char)(ulColor & 0x000000ff);
|
| | return setColor(ulPos, ucRed, ucGreen, ucBlue);
|
| | }
|
| |
|
| | bool ColorLegend::setText(std::size_t ulPos, const std::string& rclName)
|
| | {
|
| | if (ulPos < names.size()) {
|
| | names[ulPos] = rclName;
|
| | return true;
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|