diff --git a/src/Gui/SoFCColorGradient.cpp b/src/Gui/SoFCColorGradient.cpp index f6aef42012..92f551b6a7 100644 --- a/src/Gui/SoFCColorGradient.cpp +++ b/src/Gui/SoFCColorGradient.cpp @@ -47,12 +47,26 @@ using namespace Gui; +constexpr const float xMin = 5.0F; +constexpr const float xMax = 5.5F; +constexpr const float yMin = -4.0F; +constexpr const float yMax = 4.0F; +constexpr const float spaceX = 0.1F; +constexpr const float spaceY = 0.05F; +constexpr const int defaultNumLabels = 13; +constexpr const unsigned long defaultColor = 0xffffffff; +constexpr const float defaultMin = -0.5F; +constexpr const float defaultMax = 0.5F; +constexpr const float upperLimit = 10000.0F; + + SO_NODE_SOURCE(SoFCColorGradient) /*! Constructor. */ -SoFCColorGradient::SoFCColorGradient() : _bbox(5.0f, -4.0f, 5.5f, 4.0f) +SoFCColorGradient::SoFCColorGradient() + : _bbox(xMin, yMin, xMax, yMax) { SO_NODE_CONSTRUCTOR(SoFCColorGradient); coords = new SoCoordinate3; @@ -62,7 +76,7 @@ SoFCColorGradient::SoFCColorGradient() : _bbox(5.0f, -4.0f, 5.5f, 4.0f) _cColGrad.setStyle(App::ColorBarStyle::FLOW); setColorModel(0); - setRange(-0.5f, 0.5f, 1); + SoFCColorGradient::setRange(defaultMin, defaultMax, 1); } /*! @@ -103,15 +117,15 @@ void SoFCColorGradient::setMarkerLabel(const SoMFString& label) auto trans = new SoTransform; ParameterGrp::handle hGrp = Gui::WindowParameter::getDefaultParameter()->GetGroup("View"); - auto LabelTextSize = hGrp->GetInt("CbLabelTextSize", 13); + auto LabelTextSize = hGrp->GetInt("CbLabelTextSize", defaultNumLabels); auto LabelTextColor = - App::Color((uint32_t)hGrp->GetUnsigned("CbLabelColor", 0xffffffff)); + App::Color((uint32_t)hGrp->GetUnsigned("CbLabelColor", defaultColor)); auto textFont = new SoFont; auto color = new SoBaseColor; textFont->name.setValue("Helvetica,Arial,Times New Roman"); - textFont->size.setValue(LabelTextSize); - trans->translation.setValue(maxPt[0] + 0.1f, maxPt[1] - 0.05f + fStep, 0.0f); - color->rgb.setValue(LabelTextColor.r,LabelTextColor.g,LabelTextColor.b); + textFont->size.setValue(static_cast(LabelTextSize)); + trans->translation.setValue(maxPt[0] + spaceX, maxPt[1] - spaceY + fStep, 0.0F); + color->rgb.setValue(LabelTextColor.r, LabelTextColor.g, LabelTextColor.b); labels->addChild(trans); labels->addChild(color); labels->addChild(textFont); @@ -131,14 +145,18 @@ void SoFCColorGradient::setMarkerLabel(const SoMFString& label) void SoFCColorGradient::setViewportSize(const SbVec2s& size) { - float fMinX, fMinY, fMaxX, fMaxY; + float fMinX {}; + float fMinY {}; + float fMaxX {}; + float fMaxY {}; float boxWidth = getBounds(size, fMinX, fMinY, fMaxX, fMaxY); // search for the labels int num = 0; for (int i = 0; i < labels->getNumChildren(); i++) { - if (labels->getChild(i)->getTypeId() == SoTransform::getClassTypeId()) + if (labels->getChild(i)->getTypeId() == SoTransform::getClassTypeId()) { num++; + } } if (num > 2) { @@ -147,13 +165,15 @@ void SoFCColorGradient::setViewportSize(const SbVec2s& size) for (int j = 0; j < labels->getNumChildren(); j++) { if (labels->getChild(j)->getTypeId() == SoTransform::getClassTypeId()) { + auto transform = static_cast(labels->getChild(j)); // NOLINT if (first) { first = false; - // set the labels with a small space of 0.1f besides the bar - static_cast(labels->getChild(j))->translation.setValue(fMaxX + 0.1f - boxWidth, fMaxY - 0.05f + fStep, 0.0f); + transform->translation.setValue(fMaxX + spaceX - boxWidth, + fMaxY - spaceY + fStep, + 0.0F); } else { - static_cast(labels->getChild(j))->translation.setValue(0, -fStep, 0.0f); + transform->translation.setValue(0, -fStep, 0.0F); } } } @@ -164,53 +184,81 @@ void SoFCColorGradient::setViewportSize(const SbVec2s& size) modifyPoints(_bbox); } +namespace +{ + bool isScientific(float fMin, float fMax, int prec, int numColors) + { + const float base10 = 10.0F; + float eps = std::pow(base10, static_cast(-prec)); + float value_min = std::min(fabs(fMin), fabs(fMax)); + float value_max = std::max(fabs(fMin), fabs(fMax)); + + if (value_min < eps && value_min > 0.0F) { + return true; + } + + if ((value_max - value_min) < eps * static_cast(numColors -1)) { + return true; + } + + return value_max > upperLimit; + } + + std::ios::fmtflags getFormatFlags(float fMin, float fMax, int prec, int numColors) + { + bool scientific = isScientific(fMin, fMax, prec, numColors); + std::ios::fmtflags flags = scientific ? (std::ios::scientific | std::ios::showpoint | std::ios::showpos) + : (std::ios::fixed | std::ios::showpoint | std::ios::showpos); + return flags; + } + + std::string getLabelText(float value, int prec, std::ios::fmtflags flags) + { + std::stringstream str; + str.precision(prec); + str.setf(flags); + str << value; + return str.str(); + } +} + void SoFCColorGradient::setRange(float fMin, float fMax, int prec) { _cColGrad.setRange(fMin, fMax); + int numColors = static_cast(_cColGrad.getCountColors()); SoMFString label; - float eps = std::pow(10.0f, static_cast(-prec)); - float value_min = std::min(fabs(fMin), fabs(fMax)); - float value_max = std::max(fabs(fMin), fabs(fMax)); - - // format the label the following way: - // if Min is smaller than 1e-, - // or Max greater than 1e+4, - // or (Max - Min) < 1e- * number of labels - 1 (assures every label shows different number) - // -> output in scientific notation - // otherwise output "normal" (fixed notation) - bool scientific = (value_min < eps && value_min > 0.0f) - || (value_max - value_min) < eps * (_cColGrad.getCountColors() - 1) - || value_max > 1e4; - std::ios::fmtflags flags = scientific ? (std::ios::scientific | std::ios::showpoint | std::ios::showpos) - : (std::ios::fixed | std::ios::showpoint | std::ios::showpos); + std::ios::fmtflags flags = getFormatFlags(fMin, fMax, prec, numColors); // write the labels int i = 0; - std::vector marks = getMarkerValues(fMin, fMax, _cColGrad.getCountColors()); - for (const auto& it : marks) { - std::stringstream s; - s.precision(prec); - s.setf(flags); - s << it; - label.set1Value(i++, s.str().c_str()); + std::vector marks = getMarkerValues(fMin, fMax, numColors); + for (auto it : marks) { + std::string text = getLabelText(it, prec, flags); + label.set1Value(i++, text.c_str()); } setMarkerLabel(label); } +bool SoFCColorGradient::isZeroBased(float fMin, float fMax) const +{ + return (fMin < 0.0F && fMax > 0.0F && _cColGrad.getStyle() == App::ColorBarStyle::ZERO_BASED); +} + std::vector SoFCColorGradient::getMarkerValues(float fMin, float fMax, int count) const { std::vector labels; // the middle of the bar is zero - if (fMin < 0.0f && fMax > 0.0f && _cColGrad.getStyle() == App::ColorBarStyle::ZERO_BASED) { - if (count % 2 == 0) + if (isZeroBased(fMin, fMax)) { + if (count % 2 == 0) { count++; + } int half = count / 2; for (int j = 0; j < half + 1; j++) { float w = (float)j / ((float)half); - float fValue = (1.0f - w) * fMax; + float fValue = (1.0F - w) * fMax; labels.push_back(fValue); } for (int k = half + 1; k < count; k++) { @@ -221,8 +269,8 @@ std::vector SoFCColorGradient::getMarkerValues(float fMin, float fMax, in } else { // either not zero based or 0 is not in between [fMin,fMax] for (int j = 0; j < count; j++) { - float w = (float)j / ((float)count - 1.0f); - float fValue = (1.0f - w) * fMax + w * fMin; + float w = (float)j / ((float)count - 1.0F); + float fValue = (1.0F - w) * fMax + w * fMin; labels.push_back(fValue); } } @@ -240,10 +288,10 @@ void SoFCColorGradient::modifyPoints(const SbBox2f& box) // set the vertices spanning the faces for the color gradient int intFields = coords->point.getNum() / 2; for (int i = 0; i < intFields; i++) { - float w = static_cast(i) / (intFields - 1); - float fPosY = (1.0f - w) * fMaxY + w * fMinY; - coords->point.set1Value(2 * i, fMinX, fPosY, 0.0f); - coords->point.set1Value(2 * i + 1, fMaxX, fPosY, 0.0f); + float w = static_cast(i) / static_cast(intFields - 1); + float fPosY = (1.0F - w) * fMaxY + w * fMinY; + coords->point.set1Value(2 * i, fMinX, fPosY, 0.0F); + coords->point.set1Value(2 * i + 1, fMaxX, fPosY, 0.0F); } } @@ -259,19 +307,14 @@ void SoFCColorGradient::setColorStyle(App::ColorBarStyle tStyle) rebuildGradient(); } -void SoFCColorGradient::rebuildGradient() +SoIndexedFaceSet* SoFCColorGradient::createFaceSet(int numFaces) const { - App::ColorModel model = _cColGrad.getColorModel(); - int uCtColors = static_cast(model.getCountColors()); - - coords->point.setNum(2 * uCtColors); - modifyPoints(_bbox); - - // for uCtColors colors we need 2*(uCtColors-1) facets and therefore an array with - // 8*(uCtColors-1) face indices + // NOLINTBEGIN + // for numFaces colors we need 2*(numFaces-1) faces and therefore an array with + // 8*(numFaces-1) face indices auto faceset = new SoIndexedFaceSet; - faceset->coordIndex.setNum(8 * (uCtColors - 1)); - for (int j = 0; j < uCtColors - 1; j++) { + faceset->coordIndex.setNum(8 * (numFaces - 1)); + for (int j = 0; j < numFaces - 1; j++) { faceset->coordIndex.set1Value(8 * j, 2 * j); faceset->coordIndex.set1Value(8 * j + 1, 2 * j + 3); faceset->coordIndex.set1Value(8 * j + 2, 2 * j + 1); @@ -281,25 +324,69 @@ void SoFCColorGradient::rebuildGradient() faceset->coordIndex.set1Value(8 * j + 6, 2 * j + 3); faceset->coordIndex.set1Value(8 * j + 7, SO_END_FACE_INDEX); } + // NOLINTEND - // set an own transparency type for this color bar only + return faceset; +} + +SoTransparencyType* SoFCColorGradient::createTransparencyType() const +{ auto ttype = new SoTransparencyType; ttype->value = SoGLRenderAction::DELAYED_BLEND; + return ttype; +} + +SoMaterial* SoFCColorGradient::createMaterial() const +{ + App::ColorModel model = _cColGrad.getColorModel(); + int numColors = static_cast(model.getCountColors()); + auto mat = new SoMaterial; - //mat->transparency = 0.3f; - mat->diffuseColor.setNum(2 * uCtColors); - for (int k = 0; k < uCtColors; k++) { - App::Color col = model.colors[uCtColors - k - 1]; + mat->diffuseColor.setNum(2 * numColors); + for (int k = 0; k < numColors; k++) { + App::Color col = model.colors[numColors - k - 1]; mat->diffuseColor.set1Value(2 * k, col.r, col.g, col.b); mat->diffuseColor.set1Value(2 * k + 1, col.r, col.g, col.b); } + return mat; +} + +SoMaterialBinding* SoFCColorGradient::createMaterialBinding() const +{ auto matBinding = new SoMaterialBinding; matBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED; + return matBinding; +} + +int SoFCColorGradient::getNumColors() const +{ + App::ColorModel model = _cColGrad.getColorModel(); + return static_cast(model.getCountColors()); +} + +void SoFCColorGradient::setCoordSize(int numPoints) +{ + coords->point.setNum(numPoints); +} + +void SoFCColorGradient::rebuildGradient() +{ + int numColors = getNumColors(); + + setCoordSize(2 * numColors); + modifyPoints(_bbox); + + auto faceset = createFaceSet(numColors); + auto ttype = createTransparencyType(); + auto mat = createMaterial(); + auto matBinding = createMaterialBinding(); // first clear the children - if (getNumChildren() > 0) + if (getNumChildren() > 0) { coinRemoveAllChildren(this); + } + addChild(ttype); addChild(labels); addChild(coords); @@ -325,7 +412,7 @@ void SoFCColorGradient::customize(SoFCColorBarBase* parentNode) dlg.setNumberOfDecimals(_precision, profile.fMin, profile.fMax); QPoint pos(QCursor::pos()); - pos += QPoint(int(-1.1 * dlg.width()), int(-0.1 * dlg.height())); + pos += QPoint(int(-1.1 * dlg.width()), int(-0.1 * dlg.height())); // NOLINT dlg.move(pos); auto applyProfile = [&](const App::ColorGradientProfile& pro, int precision) { @@ -347,8 +434,9 @@ void SoFCColorGradient::customize(SoFCColorBarBase* parentNode) if (dlg.exec() != QDialog::Accepted) { int decimals = dlg.numberOfDecimals(); - if (!profile.isEqual(dlg.getProfile()) || decimals != _precision) + if (!profile.isEqual(dlg.getProfile()) || decimals != _precision) { applyProfile(profile, _precision); + } } else { _precision = dlg.numberOfDecimals(); diff --git a/src/Gui/SoFCColorGradient.h b/src/Gui/SoFCColorGradient.h index 478668a326..d55daf11e2 100644 --- a/src/Gui/SoFCColorGradient.h +++ b/src/Gui/SoFCColorGradient.h @@ -31,7 +31,11 @@ class SoCoordinate3; +class SoIndexedFaceSet; +class SoMaterial; +class SoMaterialBinding; class SoMFString; +class SoTransparencyType; class SbVec2s; namespace Gui { @@ -95,9 +99,16 @@ protected: std::vector getMarkerValues(float fMin, float fMax, int count) const; private: + bool isZeroBased(float fMin, float fMax) const; /** Sets the new labels. */ + int getNumColors() const; void setMarkerLabel( const SoMFString& label ); void modifyPoints(const SbBox2f&); + void setCoordSize(int numPoints); + SoIndexedFaceSet* createFaceSet(int numFaces) const; + SoTransparencyType* createTransparencyType() const; + SoMaterial* createMaterial() const; + SoMaterialBinding* createMaterialBinding() const; private: SoCoordinate3* coords;