mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 14:15:02 +00:00
311 lines
8.7 KiB
C++
311 lines
8.7 KiB
C++
//
|
|
// Copyright Contributors to the MaterialX Project
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include <MaterialXCore/Unit.h>
|
|
|
|
MATERIALX_NAMESPACE_BEGIN
|
|
|
|
namespace
|
|
{
|
|
|
|
const string SCALE_ATTRIBUTE = "scale";
|
|
|
|
} // anonymous namespace
|
|
|
|
//
|
|
// LinearUnitConverter methods
|
|
//
|
|
|
|
LinearUnitConverter::LinearUnitConverter(UnitTypeDefPtr unitTypeDef)
|
|
{
|
|
if (!unitTypeDef)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Populate the unit scale and offset maps for each UnitDef.
|
|
unsigned int enumerant = 0;
|
|
for (UnitDefPtr unitdef : unitTypeDef->getUnitDefs())
|
|
{
|
|
for (UnitPtr unit : unitdef->getUnits())
|
|
{
|
|
const string& name = unit->getName();
|
|
if (!name.empty())
|
|
{
|
|
const string& scaleString = unit->getAttribute(SCALE_ATTRIBUTE);
|
|
if (!scaleString.empty())
|
|
{
|
|
ValuePtr scaleValue = Value::createValueFromStrings(scaleString, getTypeString<float>());
|
|
_unitScale[name] = scaleValue->asA<float>();
|
|
}
|
|
else
|
|
{
|
|
_unitScale[name] = 1.0f;
|
|
}
|
|
_unitEnumeration[name] = enumerant++;
|
|
}
|
|
}
|
|
}
|
|
|
|
_unitType = unitTypeDef->getName();
|
|
}
|
|
|
|
LinearUnitConverterPtr LinearUnitConverter::create(UnitTypeDefPtr unitTypeDef)
|
|
{
|
|
return std::shared_ptr<LinearUnitConverter>(new LinearUnitConverter(unitTypeDef));
|
|
}
|
|
|
|
void LinearUnitConverter::write(DocumentPtr doc) const
|
|
{
|
|
if (!doc->getUnitTypeDef(_unitType))
|
|
{
|
|
// Add a unittypedef
|
|
doc->addUnitTypeDef(_unitType);
|
|
|
|
// Add a unitdef definition
|
|
string unitdefName = "UD_stdlib_" + _unitType;
|
|
if (!doc->getUnitDef(unitdefName))
|
|
{
|
|
UnitDefPtr unitDef = doc->addUnitDef(unitdefName);
|
|
unitDef->setUnitType(_unitType);
|
|
|
|
// Add in units to the definition
|
|
for (const auto& unitScale : _unitScale)
|
|
{
|
|
const string& unitName = unitScale.first;
|
|
UnitPtr unitPtr = unitDef->addUnit(unitName);
|
|
unitPtr->setAttribute(SCALE_ATTRIBUTE, std::to_string(unitScale.second));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
float LinearUnitConverter::conversionRatio(const string& inputUnit, const string& outputUnit) const
|
|
{
|
|
auto it = _unitScale.find(inputUnit);
|
|
if (it == _unitScale.end())
|
|
{
|
|
throw ExceptionTypeError("Unrecognized source unit: " + inputUnit);
|
|
}
|
|
float fromScale = it->second;
|
|
|
|
it = _unitScale.find(outputUnit);
|
|
if (it == _unitScale.end())
|
|
{
|
|
throw ExceptionTypeError("Unrecognized destination unit: " + outputUnit);
|
|
}
|
|
float toScale = it->second;
|
|
|
|
return fromScale / toScale;
|
|
}
|
|
|
|
float LinearUnitConverter::convert(float input, const string& inputUnit, const string& outputUnit) const
|
|
{
|
|
if (inputUnit == outputUnit)
|
|
{
|
|
return input;
|
|
}
|
|
|
|
return input * conversionRatio(inputUnit, outputUnit);
|
|
}
|
|
|
|
Vector2 LinearUnitConverter::convert(const Vector2& input, const string& inputUnit, const string& outputUnit) const
|
|
{
|
|
if (inputUnit == outputUnit)
|
|
{
|
|
return input;
|
|
}
|
|
|
|
return input * conversionRatio(inputUnit, outputUnit);
|
|
}
|
|
|
|
Vector3 LinearUnitConverter::convert(const Vector3& input, const string& inputUnit, const string& outputUnit) const
|
|
{
|
|
if (inputUnit == outputUnit)
|
|
{
|
|
return input;
|
|
}
|
|
|
|
return input * conversionRatio(inputUnit, outputUnit);
|
|
}
|
|
|
|
Vector4 LinearUnitConverter::convert(const Vector4& input, const string& inputUnit, const string& outputUnit) const
|
|
{
|
|
if (inputUnit == outputUnit)
|
|
{
|
|
return input;
|
|
}
|
|
|
|
return input * conversionRatio(inputUnit, outputUnit);
|
|
}
|
|
|
|
int LinearUnitConverter::getUnitAsInteger(const string& unitName) const
|
|
{
|
|
const auto it = _unitEnumeration.find(unitName);
|
|
if (it != _unitEnumeration.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
string LinearUnitConverter::getUnitFromInteger(int index) const
|
|
{
|
|
auto it = std::find_if(_unitEnumeration.begin(), _unitEnumeration.end(),
|
|
[&index](const std::pair<string, int>& e) -> bool
|
|
{
|
|
return (e.second == index);
|
|
});
|
|
|
|
if (it != _unitEnumeration.end())
|
|
{
|
|
return it->first;
|
|
}
|
|
return EMPTY_STRING;
|
|
}
|
|
|
|
//
|
|
// UnitConverterRegistry methods
|
|
//
|
|
|
|
UnitConverterRegistryPtr UnitConverterRegistry::create()
|
|
{
|
|
static UnitConverterRegistryPtr registry(new UnitConverterRegistry());
|
|
return registry;
|
|
}
|
|
|
|
bool UnitConverterRegistry::addUnitConverter(UnitTypeDefPtr def, UnitConverterPtr converter)
|
|
{
|
|
if (def && _unitConverters.find(def->getName()) == _unitConverters.end())
|
|
{
|
|
_unitConverters[def->getName()] = converter;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool UnitConverterRegistry::removeUnitConverter(UnitTypeDefPtr def)
|
|
{
|
|
if (def)
|
|
{
|
|
auto it = _unitConverters.find(def->getName());
|
|
if (it != _unitConverters.end())
|
|
{
|
|
_unitConverters.erase(it);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
UnitConverterPtr UnitConverterRegistry::getUnitConverter(UnitTypeDefPtr def)
|
|
{
|
|
if (def)
|
|
{
|
|
auto it = _unitConverters.find(def->getName());
|
|
if (it != _unitConverters.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void UnitConverterRegistry::clearUnitConverters()
|
|
{
|
|
_unitConverters.clear();
|
|
}
|
|
|
|
int UnitConverterRegistry::getUnitAsInteger(const string& unitName) const
|
|
{
|
|
for (const auto& it : _unitConverters)
|
|
{
|
|
int value = it.second->getUnitAsInteger(unitName);
|
|
if (value >= 0)
|
|
return value;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void UnitConverterRegistry::write(DocumentPtr doc) const
|
|
{
|
|
for (const auto& it : _unitConverters)
|
|
{
|
|
it.second->write(doc);
|
|
}
|
|
}
|
|
|
|
bool UnitConverterRegistry::convertToUnit(DocumentPtr doc, const string& unitType, const string& targetUnit)
|
|
{
|
|
UnitTypeDefPtr unitTypeDef = doc->getUnitTypeDef(unitType);
|
|
UnitConverterPtr unitConverter = getUnitConverter(unitTypeDef);
|
|
|
|
if (!unitTypeDef || !unitConverter)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool convertedUnits = false;
|
|
for (ElementPtr elem : doc->traverseTree())
|
|
{
|
|
NodePtr pNode = elem->asA<Node>();
|
|
if (!pNode || !pNode->getInputCount())
|
|
{
|
|
continue;
|
|
}
|
|
for (InputPtr input : pNode->getInputs())
|
|
{
|
|
const std::string type = input->getType();
|
|
const ValuePtr value = input->getValue();
|
|
if (value && input->hasUnit() && (input->getUnitType() == unitType))
|
|
{
|
|
if (type == getTypeString<float>())
|
|
{
|
|
float originalval = value->asA<float>();
|
|
float convertedValue = unitConverter->convert(originalval, input->getUnit(), targetUnit);
|
|
input->setValue<float>(convertedValue);
|
|
input->removeAttribute(ValueElement::UNIT_ATTRIBUTE);
|
|
input->removeAttribute(ValueElement::UNITTYPE_ATTRIBUTE);
|
|
convertedUnits = true;
|
|
}
|
|
else if (type == getTypeString<Vector2>())
|
|
{
|
|
Vector2 originalval = value->asA<Vector2>();
|
|
Vector2 convertedValue = unitConverter->convert(originalval, input->getUnit(), targetUnit);
|
|
input->setValue<Vector2>(convertedValue);
|
|
input->removeAttribute(ValueElement::UNIT_ATTRIBUTE);
|
|
input->removeAttribute(ValueElement::UNITTYPE_ATTRIBUTE);
|
|
convertedUnits = true;
|
|
}
|
|
else if (type == getTypeString<Vector3>())
|
|
{
|
|
Vector3 originalval = value->asA<Vector3>();
|
|
Vector3 convertedValue = unitConverter->convert(originalval, input->getUnit(), targetUnit);
|
|
input->setValue<Vector3>(convertedValue);
|
|
input->removeAttribute(ValueElement::UNIT_ATTRIBUTE);
|
|
input->removeAttribute(ValueElement::UNITTYPE_ATTRIBUTE);
|
|
convertedUnits = true;
|
|
}
|
|
else if (type == getTypeString<Vector4>())
|
|
{
|
|
Vector4 originalval = value->asA<Vector4>();
|
|
Vector4 convertedValue = unitConverter->convert(originalval, input->getUnit(), targetUnit);
|
|
input->setValue<Vector4>(convertedValue);
|
|
input->removeAttribute(ValueElement::UNIT_ATTRIBUTE);
|
|
input->removeAttribute(ValueElement::UNITTYPE_ATTRIBUTE);
|
|
convertedUnits = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return convertedUnits;
|
|
}
|
|
|
|
MATERIALX_NAMESPACE_END
|