mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-24 07:16:53 -06:00
297 lines
9.4 KiB
C++
297 lines
9.4 KiB
C++
|
|
#include "cafCategoryMapper.h"
|
|
|
|
#include "cvfBase.h"
|
|
#include "cvfMath.h"
|
|
#include "cvfOverlayColorLegend.h"
|
|
#include "cvfTextureImage.h"
|
|
#include <cmath>
|
|
|
|
using namespace cvf;
|
|
|
|
namespace caf {
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
CategoryMapper::CategoryMapper()
|
|
: m_textureSize(2048),
|
|
m_maxTexCoord(1.0)
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CategoryMapper::setCategories(const std::vector<int>& categoryValues)
|
|
{
|
|
m_categoryValues = categoryValues;
|
|
|
|
ref<Color3ubArray> colorArr = ScalarMapper::colorTableArray(ColorTable::NORMAL);
|
|
|
|
setCycleColors(*(colorArr.p()));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CategoryMapper::setCategoriesWithNames(const std::vector<int>& categoryValues, const std::vector<cvf::String>& categoryNames)
|
|
{
|
|
m_categoryValues = categoryValues;
|
|
m_categoryNames = categoryNames;
|
|
|
|
ref<Color3ubArray> colorArr = ScalarMapper::colorTableArray(ColorTable::NORMAL);
|
|
|
|
setInterpolateColors(*(colorArr.p()));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CategoryMapper::setCycleColors(const Color3ubArray& colorArray)
|
|
{
|
|
m_colors.resize(m_categoryValues.size());
|
|
|
|
for (size_t i = 0; i < m_categoryValues.size(); i++)
|
|
{
|
|
size_t colIdx = i % colorArray.size();
|
|
m_colors[i] = colorArray[colIdx];
|
|
}
|
|
|
|
recomputeMaxTexCoord();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CategoryMapper::setInterpolateColors(const cvf::Color3ubArray& colorArray)
|
|
{
|
|
CVF_ASSERT(colorArray.size());
|
|
|
|
if (m_categoryValues.size() > 1 && colorArray.size() > 1)
|
|
{
|
|
m_colors = *interpolateColorArray(colorArray, static_cast<cvf::uint>(m_categoryValues.size()));
|
|
|
|
recomputeMaxTexCoord();
|
|
return;
|
|
}
|
|
|
|
// Either we are requesting one output color, or we have only one input color
|
|
|
|
m_colors.clear();
|
|
m_colors.reserve(m_categoryValues.size());
|
|
for (size_t cIdx = 0; cIdx < m_categoryValues.size(); ++cIdx)
|
|
{
|
|
m_colors.add(colorArray[0]);
|
|
}
|
|
|
|
recomputeMaxTexCoord();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
size_t CategoryMapper::categoryCount() const
|
|
{
|
|
return m_categoryValues.size();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const cvf::String CategoryMapper::textForCategoryIndex(size_t index) const
|
|
{
|
|
CVF_ASSERT(index < m_categoryValues.size());
|
|
if (index < m_categoryNames.size())
|
|
{
|
|
return m_categoryNames[index];
|
|
}
|
|
else
|
|
{
|
|
double tickValue = m_categoryValues[index];
|
|
return String::number(tickValue);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Vec2f CategoryMapper::mapToTextureCoord(double categoryValue) const
|
|
{
|
|
double normVal = normalizedValue(categoryValue);
|
|
|
|
double s = normVal*m_maxTexCoord;
|
|
|
|
// Clamp to the currently legal texture coord range
|
|
// Might need to add code to correct for float precision, but that is probably not the main enemy.
|
|
// Our real problem is the fact that in most cases the texture coords get treated with even less precision
|
|
// on the graphics hardware. What we would really like is to guess at the HW precision and then correct for that.
|
|
// Currently the workaround is done in updateTexture() which pads the upper end of the texture when we're not filling
|
|
// all the texture pixels.
|
|
s = Math::clamp(s, 0.0, m_maxTexCoord);
|
|
|
|
return Vec2f(static_cast<float>(s), 0.5f);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Color3ub CategoryMapper::mapToColor(double categoryValue) const
|
|
{
|
|
int catIndex = categoryIndexForCategory(categoryValue);
|
|
|
|
if (catIndex != -1)
|
|
{
|
|
uint colorCount = static_cast<uint>(m_colors.size());
|
|
CVF_ASSERT(colorCount > static_cast<uint>(catIndex));
|
|
|
|
return m_colors[catIndex];
|
|
}
|
|
else
|
|
{
|
|
return Color3::BLACK;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CategoryMapper::majorTickValues(std::vector<double>* domainValues) const
|
|
{
|
|
// Not intended to be supported
|
|
CVF_ASSERT(false);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double CategoryMapper::normalizedValue(double categoryValue) const
|
|
{
|
|
int catIndex = categoryIndexForCategory(categoryValue);
|
|
|
|
if (catIndex != -1)
|
|
{
|
|
double halfLevelHeight = 1.0 / (m_categoryValues.size() * 2);
|
|
|
|
double normVal = static_cast<double>(catIndex) / static_cast<double>(m_categoryValues.size());
|
|
|
|
return normVal + halfLevelHeight;
|
|
}
|
|
else
|
|
{
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
double CategoryMapper::domainValue(double normalizedValue) const
|
|
{
|
|
double clampedValue = cvf::Math::clamp(normalizedValue, 0.0, 1.0);
|
|
|
|
if (m_categoryValues.size() == 0)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
size_t catIndex = static_cast<size_t>(clampedValue * m_categoryValues.size());
|
|
return m_categoryValues[catIndex];
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
int CategoryMapper::categoryIndexForCategory(double domainValue) const
|
|
{
|
|
int catIndex = -1;
|
|
|
|
int intDomainValue = static_cast<int>(nearbyint(domainValue));
|
|
|
|
size_t i = 0;
|
|
while (i < m_categoryValues.size() && catIndex == -1)
|
|
{
|
|
if (m_categoryValues[i] == intDomainValue)
|
|
{
|
|
catIndex = static_cast<int>(i);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return catIndex;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void CategoryMapper::recomputeMaxTexCoord()
|
|
{
|
|
const uint numColors = static_cast<uint>(m_colors.size());
|
|
if (numColors == 0)
|
|
{
|
|
m_maxTexCoord = 1.0;
|
|
return;
|
|
}
|
|
|
|
const uint numPixelsPerColor = m_textureSize / numColors;
|
|
if (numPixelsPerColor == 0)
|
|
{
|
|
m_maxTexCoord = 1.0;
|
|
return;
|
|
}
|
|
|
|
uint texturePixelsInUse = numColors*numPixelsPerColor;
|
|
CVF_ASSERT(texturePixelsInUse <= m_textureSize);
|
|
|
|
m_maxTexCoord = static_cast<double>(texturePixelsInUse) / static_cast<double>(m_textureSize);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool CategoryMapper::updateTexture(TextureImage* image) const
|
|
{
|
|
CVF_ASSERT(image);
|
|
|
|
image->allocate(m_textureSize, 1);
|
|
|
|
// For now fill with white so we can see any errors more easily
|
|
image->fill(Color4ub(Color3::WHITE));
|
|
|
|
const uint numColors = static_cast<uint>(m_colors.size());
|
|
if (numColors < 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const uint numPixelsPerColor = m_textureSize / numColors;
|
|
CVF_ASSERT(numPixelsPerColor >= 1);
|
|
|
|
uint ic;
|
|
for (ic = 0; ic < numColors; ic++)
|
|
{
|
|
const Color4ub clr(m_colors[ic], 255);
|
|
|
|
uint ip;
|
|
for (ip = 0; ip < numPixelsPerColor; ip++)
|
|
{
|
|
image->setPixel(ic*numPixelsPerColor + ip, 0, clr);
|
|
}
|
|
}
|
|
|
|
// In cases where we're not using the entire texture we might get into problems with texture coordinate precision on the graphics hardware.
|
|
// Therefore we set one extra pixel with the 'highest' color in the color table
|
|
if (numColors*numPixelsPerColor < m_textureSize)
|
|
{
|
|
const Color4ub topClr(m_colors[numColors - 1], 255);
|
|
image->setPixel(numColors*numPixelsPerColor, 0, topClr);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace cvf
|
|
|