Materials: Default units (#20909)
Improves handling and assignment of default units When creating a material without specifying units, no units are currently assigned. This commit will assign the default units when none are given, or throw an error when incompatible units are given. In the latter case, the units are set to the property defaults. This commit also incidentally fixed an issue when saving the material that resulted in accessing an uninitialized pointer.
This commit is contained in:
@@ -246,8 +246,24 @@ void MaterialYamlEntry::addToTree(
|
||||
propertyValue = propertyValue.remove(
|
||||
QRegularExpression(QStringLiteral("[\r\n]")));
|
||||
}
|
||||
finalModel->setPhysicalValue(QString::fromStdString(propertyName),
|
||||
propertyValue);
|
||||
try {
|
||||
finalModel->setPhysicalValue(QString::fromStdString(propertyName),
|
||||
propertyValue);
|
||||
}
|
||||
catch (const Base::ValueError& e) {
|
||||
// Units mismatch
|
||||
Base::Console().Log("Units mismatch in material '%s':'%s' = '%s', "
|
||||
"setting to default property units '%s'\n",
|
||||
name.toStdString().c_str(),
|
||||
propertyName,
|
||||
propertyValue.toStdString().c_str(),
|
||||
prop->getUnits().toStdString().c_str());
|
||||
auto quantity = Base::Quantity::parse(propertyValue.toStdString());
|
||||
finalModel->setPhysicalValue(
|
||||
QString::fromStdString(propertyName),
|
||||
Base::Quantity(quantity.getValue(),
|
||||
prop->getUnits().toStdString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const YAML::BadConversion& e) {
|
||||
|
||||
@@ -283,7 +283,20 @@ QVariant MaterialProperty::getColumnNull(int column) const
|
||||
|
||||
void MaterialProperty::setValue(const QVariant& value)
|
||||
{
|
||||
_valuePtr->setValue(value);
|
||||
if (_valuePtr->getType() == MaterialValue::Quantity && value.canConvert<Base::Quantity>()) {
|
||||
// Ensure the units are set correctly
|
||||
auto quantity = value.value<Base::Quantity>();
|
||||
if (quantity.isValid()) {
|
||||
setQuantity(quantity);
|
||||
}
|
||||
else {
|
||||
// Set a default value with default units
|
||||
setValue(QStringLiteral("0"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
_valuePtr->setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialProperty::setValue(const QString& value)
|
||||
@@ -386,6 +399,20 @@ void MaterialProperty::setFloat(const QString& value)
|
||||
void MaterialProperty::setQuantity(const Base::Quantity& value)
|
||||
{
|
||||
auto quantity = value;
|
||||
if (quantity.isDimensionless()) {
|
||||
// Assign the default units when none are provided.
|
||||
//
|
||||
// This needs to be parsed rather than just setting units. Otherwise we get mm->m conversion
|
||||
// errors, etc
|
||||
quantity = Base::Quantity::parse(quantity.getUserString() + getUnits().toStdString());
|
||||
}
|
||||
else {
|
||||
auto propertyUnit = Base::Quantity::parse(getUnits().toStdString()).getUnit();
|
||||
auto units = quantity.getUnit();
|
||||
if (propertyUnit != units) {
|
||||
throw Base::ValueError("Incompatible material units");
|
||||
}
|
||||
}
|
||||
quantity.setFormat(MaterialValue::getQuantityFormat());
|
||||
_valuePtr->setValue(QVariant(QVariant::fromValue(quantity)));
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QDesktopServices>
|
||||
#include <QIODevice>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
@@ -143,7 +144,32 @@ void MaterialDelegate::setValue(QAbstractItemModel* model,
|
||||
auto propertyName = group->child(row, 0)->data().toString();
|
||||
std::string _name = propertyName.toStdString();
|
||||
auto property = material->getProperty(propertyName);
|
||||
property->setValue(value);
|
||||
|
||||
try {
|
||||
property->setValue(value);
|
||||
}
|
||||
catch (const Base::ValueError& e) {
|
||||
// Units mismatch
|
||||
auto quantity = value.value<Base::Quantity>();
|
||||
Base::Console().Log("Units mismatch '%s' = '%s', "
|
||||
"setting to default property units '%s'\n",
|
||||
propertyName.toStdString().c_str(),
|
||||
quantity.getUserString().c_str(),
|
||||
property->getUnits().toStdString().c_str());
|
||||
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle(QStringLiteral("Property units mismatch"));
|
||||
msgBox.setText(QStringLiteral("Units mismatch '%1' = '%2', "
|
||||
"setting to default property units '%3'\n")
|
||||
.arg(propertyName)
|
||||
.arg(QString::fromStdString(quantity.getUserString()))
|
||||
.arg(property->getUnits()));
|
||||
msgBox.exec();
|
||||
|
||||
property->setQuantity(
|
||||
Base::Quantity(quantity.getValue(), property->getUnits().toStdString()));
|
||||
}
|
||||
|
||||
group->child(row, 1)->setText(property->getString());
|
||||
}
|
||||
|
||||
|
||||
@@ -291,12 +291,10 @@ void MaterialSave::setLibraries()
|
||||
auto libraries = Materials::MaterialManager::getManager().getLibraries();
|
||||
for (auto& library : *libraries) {
|
||||
if (library->isLocal()) {
|
||||
auto materialLibrary =
|
||||
reinterpret_cast<const std::shared_ptr<Materials::MaterialLibraryLocal>&>(library);
|
||||
if (!materialLibrary->isReadOnly()) {
|
||||
if (!library->isReadOnly()) {
|
||||
QVariant libraryVariant;
|
||||
libraryVariant.setValue(materialLibrary);
|
||||
ui->comboLibrary->addItem(materialLibrary->getName(), libraryVariant);
|
||||
libraryVariant.setValue(library);
|
||||
ui->comboLibrary->addItem(library->getName(), libraryVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -333,8 +331,7 @@ void MaterialSave::addMaterials(
|
||||
for (auto& mat : *modelTree) {
|
||||
std::shared_ptr<Materials::MaterialTreeNode> nodePtr = mat.second;
|
||||
if (nodePtr->getType() == Materials::MaterialTreeNode::NodeType::DataNode) {
|
||||
std::shared_ptr<Materials::Material> material = nodePtr->getData();
|
||||
QString uuid = material->getUUID();
|
||||
QString uuid = nodePtr->getUUID();
|
||||
|
||||
auto card = new QStandardItem(icon, mat.first);
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
|
||||
@@ -240,8 +240,12 @@ void ModelSelect::addModels(
|
||||
for (auto& mod : *modelTree) {
|
||||
std::shared_ptr<Materials::ModelTreeNode> nodePtr = mod.second;
|
||||
if (nodePtr->getType() == Materials::ModelTreeNode::NodeType::DataNode) {
|
||||
QString uuid = nodePtr->getUUID();
|
||||
auto model = nodePtr->getData();
|
||||
QString uuid = model->getUUID();
|
||||
if (!model) {
|
||||
model = Materials::ModelManager::getManager().getModel(uuid);
|
||||
nodePtr->setData(model);
|
||||
}
|
||||
|
||||
auto card = new QStandardItem(icon, model->getName());
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
|
||||
@@ -130,6 +130,14 @@ class MaterialCreationTestCases(unittest.TestCase):
|
||||
self.assertTrue(material.hasPhysicalModel(self.uuids.Density))
|
||||
|
||||
# Quantity properties require units
|
||||
with self.assertRaises(ValueError):
|
||||
# Units of mass not density
|
||||
material.setPhysicalValue("Density", "99.9 kg")
|
||||
|
||||
material.setPhysicalValue("Density", "99.9")
|
||||
self.assertEqual(material.getPhysicalValue("Density").Format["NumberFormat"], "g")
|
||||
self.assertEqual(material.getPhysicalValue("Density").UserString, self.getQuantity("99.90 kg/m^3").UserString)
|
||||
|
||||
material.setPhysicalValue("Density", "99.9 kg/m^3")
|
||||
self.assertEqual(material.getPhysicalValue("Density").Format["NumberFormat"], "g")
|
||||
self.assertEqual(material.getPhysicalValue("Density").UserString, self.getQuantity("99.90 kg/m^3").UserString)
|
||||
|
||||
Reference in New Issue
Block a user