FreeCAD

Форк
0
/
Materials.cpp 
1706 строк · 43.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2023 David Carter <dcarter@david.carter.ca>             *
3
 *                                                                         *
4
 *   This file is part of FreeCAD.                                         *
5
 *                                                                         *
6
 *   FreeCAD is free software: you can redistribute it and/or modify it    *
7
 *   under the terms of the GNU Lesser General Public License as           *
8
 *   published by the Free Software Foundation, either version 2.1 of the  *
9
 *   License, or (at your option) any later version.                       *
10
 *                                                                         *
11
 *   FreeCAD is distributed in the hope that it will be useful, but        *
12
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
14
 *   Lesser General Public License for more details.                       *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Lesser General Public      *
17
 *   License along with FreeCAD. If not, see                               *
18
 *   <https://www.gnu.org/licenses/>.                                      *
19
 *                                                                         *
20
 **************************************************************************/
21

22
#include "PreCompiled.h"
23
#ifndef _PreComp_
24
#include <QMetaType>
25
#include <QUuid>
26
#endif
27

28

29
#include <App/Application.h>
30
#include <Gui/MetaTypes.h>
31

32
#include "Materials.h"
33

34
#include "MaterialLibrary.h"
35
#include "MaterialManager.h"
36
#include "ModelManager.h"
37
#include "ModelUuids.h"
38

39

40
using namespace Materials;
41

42
/* TRANSLATOR Material::Materials */
43

44
TYPESYSTEM_SOURCE(Materials::MaterialProperty, Materials::ModelProperty)
45

46
int const MaterialProperty::PRECISION = 6;
47

48
MaterialProperty::MaterialProperty()
49
{
50
    _valuePtr = std::make_shared<MaterialValue>(MaterialValue::None);
51
}
52

53
MaterialProperty::MaterialProperty(const ModelProperty& other, QString modelUUID)
54
    : ModelProperty(other)
55
    , _modelUUID(modelUUID)
56
    , _valuePtr(nullptr)
57
{
58
    setType(getPropertyType());
59
    auto columns = other.getColumns();
60
    for (auto& it : columns) {
61
        MaterialProperty prop(it, modelUUID);
62
        addColumn(prop);
63
    }
64
}
65

66
void MaterialProperty::copyValuePtr(const std::shared_ptr<MaterialValue>& value)
67
{
68
    if (value->getType() == MaterialValue::Array2D) {
69
        _valuePtr =
70
            std::make_shared<Material2DArray>(*(std::static_pointer_cast<Material2DArray>(value)));
71
    }
72
    else if (value->getType() == MaterialValue::Array3D) {
73
        _valuePtr =
74
            std::make_shared<Material3DArray>(*(std::static_pointer_cast<Material3DArray>(value)));
75
    }
76
    else {
77
        _valuePtr = std::make_shared<MaterialValue>(*value);
78
    }
79
}
80

81
MaterialProperty::MaterialProperty(const MaterialProperty& other)
82
    : ModelProperty(other)
83
    , _modelUUID(other._modelUUID)
84
{
85
    copyValuePtr(other._valuePtr);
86

87
    for (auto& it : other._columns) {
88
        _columns.push_back(it);
89
    }
90
}
91

92
MaterialProperty::MaterialProperty(const std::shared_ptr<MaterialProperty>& other)
93
    : MaterialProperty(*other)
94
{}
95

96
void MaterialProperty::setModelUUID(const QString& uuid)
97
{
98
    _modelUUID = uuid;
99
}
100

101
QVariant MaterialProperty::getValue()
102
{
103
    return _valuePtr->getValue();
104
}
105

106
QVariant MaterialProperty::getValue() const
107
{
108
    return _valuePtr->getValue();
109
}
110

111
std::shared_ptr<MaterialValue> MaterialProperty::getMaterialValue()
112
{
113
    return _valuePtr;
114
}
115

116
std::shared_ptr<MaterialValue> MaterialProperty::getMaterialValue() const
117
{
118
    return _valuePtr;
119
}
120

121
QString MaterialProperty::getString() const
122
{
123
    // This method produces a localized string. For a non-localized string use
124
    // getDictionaryString()
125
    if (isNull()) {
126
        return {};
127
    }
128
    if (getType() == MaterialValue::Quantity) {
129
        auto quantity = getValue().value<Base::Quantity>();
130
        return quantity.getUserString();
131
    }
132
    if (getType() == MaterialValue::Float) {
133
        auto value = getValue();
134
        if (value.isNull()) {
135
            return {};
136
        }
137
        return QString(QLatin1String("%L1")).arg(value.toFloat(), 0, 'g', PRECISION);
138
    }
139
    return getValue().toString();
140
}
141

142
QString MaterialProperty::getYAMLString() const
143
{
144
    return _valuePtr->getYAMLString();
145
}
146

147
App::Color MaterialProperty::getColor() const
148
{
149
    auto colorString = getValue().toString();
150
    std::stringstream stream(colorString.toStdString());
151

152
    char c;
153
    stream >> c;  // read "("
154
    float red;
155
    stream >> red;
156
    stream >> c;  // ","
157
    float green;
158
    stream >> green;
159
    stream >> c;  // ","
160
    float blue;
161
    stream >> blue;
162
    stream >> c;  // ","
163
    float alpha = 1.0;
164
    if (c == ',') {
165
        stream >> alpha;
166
    }
167

168
    App::Color color(red, green, blue, alpha);
169
    return color;
170
}
171

172

173
QString MaterialProperty::getDictionaryString() const
174
{
175
    // This method produces a non-localized string. For a localized string use
176
    // getString()
177
    if (isNull()) {
178
        return {};
179
    }
180
    if (getType() == MaterialValue::Quantity) {
181
        auto quantity = getValue().value<Base::Quantity>();
182
        auto string = QString(QLatin1String("%1 %2"))
183
                          .arg(quantity.getValue(), 0, 'g', PRECISION)
184
                          .arg(quantity.getUnit().getString());
185
        return string;
186
    }
187
    if (getType() == MaterialValue::Float) {
188
        auto value = getValue();
189
        if (value.isNull()) {
190
            return {};
191
        }
192
        return QString(QLatin1String("%1")).arg(value.toFloat(), 0, 'g', PRECISION);
193
    }
194
    return getValue().toString();
195
}
196

197
void MaterialProperty::setPropertyType(const QString& type)
198
{
199
    ModelProperty::setPropertyType(type);
200
    setType(type);
201
}
202

203
void MaterialProperty::setType(const QString& type)
204
{
205
    auto mappedType = MaterialValue::mapType(type);
206
    if (mappedType == MaterialValue::None) {
207
        throw UnknownValueType();
208
    }
209
    if (mappedType == MaterialValue::Array2D) {
210
        auto arrayPtr = std::make_shared<Material2DArray>();
211
        arrayPtr->setColumns(columns());
212
        _valuePtr = arrayPtr;
213
    }
214
    else if (mappedType == MaterialValue::Array3D) {
215
        auto arrayPtr = std::make_shared<Material3DArray>();
216
        // First column is third dimension
217
        arrayPtr->setColumns(columns() - 1);
218
        _valuePtr = arrayPtr;
219
    }
220
    else {
221
        _valuePtr = std::make_shared<MaterialValue>(mappedType);
222
    }
223
}
224

225
MaterialProperty& MaterialProperty::getColumn(int column)
226
{
227
    try {
228
        return _columns.at(column);
229
    }
230
    catch (std::out_of_range const&) {
231
        throw InvalidIndex();
232
    }
233
}
234

235
const MaterialProperty& MaterialProperty::getColumn(int column) const
236
{
237
    try {
238
        return _columns.at(column);
239
    }
240
    catch (std::out_of_range const&) {
241
        throw InvalidIndex();
242
    }
243
}
244

245
MaterialValue::ValueType MaterialProperty::getColumnType(int column) const
246
{
247
    try {
248
        return _columns.at(column).getType();
249
    }
250
    catch (std::out_of_range const&) {
251
        throw InvalidIndex();
252
    }
253
}
254

255
QString MaterialProperty::getColumnUnits(int column) const
256
{
257
    try {
258
        return _columns.at(column).getUnits();
259
    }
260
    catch (std::out_of_range const&) {
261
        throw InvalidIndex();
262
    }
263
}
264

265
QVariant MaterialProperty::getColumnNull(int column) const
266
{
267
    MaterialValue::ValueType valueType = getColumnType(column);
268

269
    switch (valueType) {
270
        case MaterialValue::Quantity: {
271
            Base::Quantity quant = Base::Quantity(0, getColumnUnits(column));
272
            return QVariant::fromValue(quant);
273
        }
274

275
        case MaterialValue::Float:
276
        case MaterialValue::Integer:
277
            return 0;
278

279
        default:
280
            break;
281
    }
282

283
    return QString();
284
}
285

286
void MaterialProperty::setValue(const QVariant& value)
287
{
288
    _valuePtr->setValue(value);
289
}
290

291
void MaterialProperty::setValue(const QString& value)
292
{
293
    if (_valuePtr->getType() == MaterialValue::Boolean) {
294
        setBoolean(value);
295
    }
296
    else if (_valuePtr->getType() == MaterialValue::Integer) {
297
        setInt(value);
298
    }
299
    else if (_valuePtr->getType() == MaterialValue::Float) {
300
        setFloat(value);
301
    }
302
    else if (_valuePtr->getType() == MaterialValue::URL) {
303
        setURL(value);
304
    }
305
    else if (_valuePtr->getType() == MaterialValue::Array2D
306
             || _valuePtr->getType() == MaterialValue::Array3D) {
307
        // This value can't be directly assigned
308
    }
309
    else if (_valuePtr->getType() == MaterialValue::Quantity) {
310
        try {
311
            setQuantity(Base::Quantity::parse(value));
312
        }
313
        catch (const Base::ParserError& e) {
314
            Base::Console().Log("MaterialProperty::setValue Error '%s' - '%s'\n",
315
                                e.what(),
316
                                value.toStdString().c_str());
317
            // Save as a string
318
            setString(value);
319
        }
320
    }
321
    else {
322
        setString(value);
323
    }
324
}
325

326
void MaterialProperty::setValue(const std::shared_ptr<MaterialValue>& value)
327
{
328
    _valuePtr = value;
329
}
330

331
void MaterialProperty::setString(const QString& value)
332
{
333
    _valuePtr->setValue(QVariant(value));
334
}
335

336
void MaterialProperty::setString(const std::string& value)
337
{
338
    _valuePtr->setValue(QVariant(QString::fromStdString(value)));
339
}
340

341
void MaterialProperty::setBoolean(bool value)
342
{
343
    _valuePtr->setValue(QVariant(value));
344
}
345

346
void MaterialProperty::setBoolean(int value)
347
{
348
    _valuePtr->setValue(QVariant(value != 0));
349
}
350

351
void MaterialProperty::setBoolean(const QString& value)
352
{
353
    bool boolean = false;
354
    std::string val = value.toStdString();
355
    if ((val == "true") || (val == "True")) {
356
        boolean = true;
357
    }
358
    else if ((val == "false") || (val == "False")) {
359
        boolean = false;
360
    }
361
    else {
362
        boolean = (std::stoi(val) != 0);
363
    }
364

365
    setBoolean(boolean);
366
}
367

368
void MaterialProperty::setInt(int value)
369
{
370
    _valuePtr->setValue(QVariant(value));
371
}
372

373
void MaterialProperty::setInt(const QString& value)
374
{
375
    _valuePtr->setValue(value.toInt());
376
}
377

378
void MaterialProperty::setFloat(double value)
379
{
380
    _valuePtr->setValue(QVariant(value));
381
}
382

383
void MaterialProperty::setFloat(const QString& value)
384
{
385
    _valuePtr->setValue(QVariant(value.toFloat()));
386
}
387

388
void MaterialProperty::setQuantity(const Base::Quantity& value)
389
{
390
    _valuePtr->setValue(QVariant(QVariant::fromValue(value)));
391
}
392

393
void MaterialProperty::setQuantity(double value, const QString& units)
394
{
395
    setQuantity(Base::Quantity(value, units));
396
}
397

398
void MaterialProperty::setQuantity(const QString& value)
399
{
400
    setQuantity(Base::Quantity::parse(value));
401
}
402

403
void MaterialProperty::setList(const QList<QVariant>& value)
404
{
405
    _valuePtr->setList(value);
406
}
407

408
void MaterialProperty::setURL(const QString& value)
409
{
410
    _valuePtr->setValue(QVariant(value));
411
}
412

413
void MaterialProperty::setColor(const App::Color& value)
414
{
415
    std::stringstream ss;
416
    ss << "(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")";
417
    _valuePtr->setValue(QVariant(QString::fromStdString(ss.str())));
418
}
419

420
MaterialProperty& MaterialProperty::operator=(const MaterialProperty& other)
421
{
422
    if (this == &other) {
423
        return *this;
424
    }
425

426
    ModelProperty::operator=(other);
427

428
    _modelUUID = other._modelUUID;
429
    copyValuePtr(other._valuePtr);
430

431
    _columns.clear();
432
    for (auto& it : other._columns) {
433
        _columns.push_back(it);
434
    }
435

436
    return *this;
437
}
438

439
bool MaterialProperty::operator==(const MaterialProperty& other) const
440
{
441
    if (this == &other) {
442
        return true;
443
    }
444

445
    if (ModelProperty::operator==(other)) {
446
        return (*_valuePtr == *other._valuePtr);
447
    }
448
    return false;
449
}
450

451
TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass)
452

453
Material::Material()
454
    : _dereferenced(false)
455
    , _oldFormat(false)
456
    , _editState(ModelEdit_None)
457
{
458
    // Create an initial UUID
459
    newUuid();
460
}
461

462
Material::Material(const std::shared_ptr<MaterialLibrary>& library,
463
                   const QString& directory,
464
                   const QString& uuid,
465
                   const QString& name)
466
    : _library(library)
467
    , _uuid(uuid)
468
    , _name(name)
469
    , _dereferenced(false)
470
    , _oldFormat(false)
471
    , _editState(ModelEdit_None)
472
{
473
    setDirectory(directory);
474
}
475

476
Material::Material(const Material& other)
477
    : _library(other._library)
478
    , _directory(other._directory)
479
    , _uuid(other._uuid)
480
    , _name(other._name)
481
    , _author(other._author)
482
    , _license(other._license)
483
    , _parentUuid(other._parentUuid)
484
    , _description(other._description)
485
    , _url(other._url)
486
    , _reference(other._reference)
487
    , _dereferenced(other._dereferenced)
488
    , _oldFormat(other._oldFormat)
489
    , _editState(other._editState)
490
{
491
    for (auto& it : other._tags) {
492
        _tags.insert(it);
493
    }
494
    for (auto& it : other._physicalUuids) {
495
        _physicalUuids.insert(it);
496
    }
497
    for (auto& it : other._appearanceUuids) {
498
        _appearanceUuids.insert(it);
499
    }
500
    for (auto& it : other._allUuids) {
501
        _allUuids.insert(it);
502
    }
503
    for (auto& it : other._physical) {
504
        MaterialProperty prop(it.second);
505
        _physical[it.first] = std::make_shared<MaterialProperty>(prop);
506
    }
507
    for (auto& it : other._appearance) {
508
        MaterialProperty prop(it.second);
509
        _appearance[it.first] = std::make_shared<MaterialProperty>(prop);
510
    }
511
    for (auto& it : other._legacy) {
512
        _legacy[it.first] = it.second;
513
    }
514
}
515

516
QString Material::getAuthorAndLicense() const
517
{
518
    QString authorAndLicense;
519

520
    // Combine the author and license field for backwards compatibility
521
    if (!_author.isNull()) {
522
        authorAndLicense = _author;
523
        if (!_license.isNull()) {
524
            authorAndLicense += QLatin1String(" ") + _license;
525
        }
526
    }
527
    else if (!_license.isNull()) {
528
        authorAndLicense = _license;
529
    }
530

531
    return _license;
532
}
533

534
void Material::addModel(const QString& uuid)
535
{
536
    for (const auto& modelUUID : std::as_const(_allUuids)) {
537
        if (modelUUID == uuid) {
538
            return;
539
        }
540
    }
541

542
    _allUuids << uuid;
543

544
    ModelManager manager;
545

546
    try {
547
        auto model = manager.getModel(uuid);
548
        auto inheritance = model->getInheritance();
549
        for (auto& inherits : inheritance) {
550
            addModel(inherits);
551
        }
552
    }
553
    catch (ModelNotFound const&) {
554
    }
555
}
556

557
void Material::clearModels()
558
{
559
    _physicalUuids.clear();
560
    _appearanceUuids.clear();
561
    _allUuids.clear();
562
    _physical.clear();
563
    _appearance.clear();
564
}
565

566
void Material::clearInherited()
567
{
568
    _allUuids.clear();
569

570
    // Rebuild the UUID lists without the inherited UUIDs
571
    for (auto& uuid : _physicalUuids) {
572
        _allUuids << uuid;
573
    }
574
    for (auto& uuid : _appearanceUuids) {
575
        _allUuids << uuid;
576
    }
577
}
578

579
void Material::setName(const QString& name)
580
{
581
    _name = name;
582
    setEditStateExtend();
583
}
584

585
void Material::setAuthor(const QString& author)
586
{
587
    _author = author;
588
    setEditStateExtend();
589
}
590

591
void Material::setLicense(const QString& license)
592
{
593
    _license = license;
594
    setEditStateExtend();
595
}
596

597
void Material::setParentUUID(const QString& uuid)
598
{
599
    _parentUuid = uuid;
600
    setEditStateExtend();
601
}
602

603
void Material::setDescription(const QString& description)
604
{
605
    _description = description;
606
    setEditStateExtend();
607
}
608

609
void Material::setURL(const QString& url)
610
{
611
    _url = url;
612
    setEditStateExtend();
613
}
614

615
void Material::setReference(const QString& reference)
616
{
617
    _reference = reference;
618
    setEditStateExtend();
619
}
620

621
void Material::setEditState(ModelEdit newState)
622
{
623
    if (newState == ModelEdit_Extend) {
624
        if (_editState != ModelEdit_Alter) {
625
            _editState = newState;
626
        }
627
    }
628
    else if (newState == ModelEdit_Alter) {
629
        _editState = newState;
630
    }
631
}
632

633
void Material::removeUUID(QSet<QString>& uuidList, const QString& uuid)
634
{
635
    uuidList.remove(uuid);
636
}
637

638
void Material::addPhysical(const QString& uuid)
639
{
640
    if (hasPhysicalModel(uuid)) {
641
        return;
642
    }
643

644
    ModelManager manager;
645

646
    try {
647
        auto model = manager.getModel(uuid);
648

649
        auto& inheritance = model->getInheritance();
650
        for (auto& it : inheritance) {
651
            // Inherited models may already have the properties, so just
652
            // remove the uuid
653
            removeUUID(_physicalUuids, it);
654
        }
655

656
        _physicalUuids.insert(uuid);
657
        addModel(uuid);
658
        setEditStateExtend();
659

660
        for (auto& it : *model) {
661
            QString propertyName = it.first;
662
            if (!hasPhysicalProperty(propertyName)) {
663
                ModelProperty property = static_cast<ModelProperty>(it.second);
664

665
                try {
666
                    _physical[propertyName] = std::make_shared<MaterialProperty>(property, uuid);
667
                }
668
                catch (const UnknownValueType&) {
669
                    Base::Console().Error("Property '%s' has unknown type '%s'. Ignoring\n",
670
                                          property.getName().toStdString().c_str(),
671
                                          property.getPropertyType().toStdString().c_str());
672
                }
673
            }
674
        }
675
    }
676
    catch (ModelNotFound const&) {
677
    }
678
}
679

680
void Material::removePhysical(const QString& uuid)
681
{
682
    if (!hasPhysicalModel(uuid)) {
683
        return;
684
    }
685

686
    // If it's an inherited model, do nothing
687
    if (isInherited(uuid)) {
688
        return;
689
    }
690

691
    ModelManager manager;
692

693
    try {
694
        auto model = manager.getModel(uuid);
695

696
        auto& inheritance = model->getInheritance();
697
        for (auto& it : inheritance) {
698
            removeUUID(_physicalUuids, it);
699
            removeUUID(_allUuids, it);
700
        }
701
        removeUUID(_physicalUuids, uuid);
702
        removeUUID(_allUuids, uuid);
703

704
        for (auto& it : *model) {
705
            _physical.erase(it.first);
706
        }
707

708
        setEditStateAlter();
709
    }
710
    catch (ModelNotFound const&) {
711
        Base::Console().Log("Physical model not found '%s'\n", uuid.toStdString().c_str());
712
    }
713
}
714

715
void Material::addAppearance(const QString& uuid)
716
{
717
    if (hasAppearanceModel(uuid)) {
718
        return;
719
    }
720

721
    ModelManager manager;
722

723
    try {
724
        auto model = manager.getModel(uuid);
725

726
        auto& inheritance = model->getInheritance();
727
        for (auto& it : inheritance) {
728
            // Inherited models may already have the properties, so just
729
            // remove the uuid
730
            removeUUID(_appearanceUuids, it);
731
        }
732

733
        _appearanceUuids.insert(uuid);
734
        addModel(uuid);
735
        setEditStateExtend();
736

737
        for (auto& it : *model) {
738
            QString propertyName = it.first;
739
            if (!hasAppearanceProperty(propertyName)) {
740
                ModelProperty property = static_cast<ModelProperty>(it.second);
741

742
                _appearance[propertyName] = std::make_shared<MaterialProperty>(property, uuid);
743
            }
744
        }
745
    }
746
    catch (ModelNotFound const&) {
747
        Base::Console().Log("Appearance model not found '%s'\n", uuid.toStdString().c_str());
748
    }
749
}
750

751
void Material::removeAppearance(const QString& uuid)
752
{
753
    if (!hasAppearanceModel(uuid)) {
754
        return;
755
    }
756

757
    // If it's an inherited model, do nothing
758
    if (isInherited(uuid)) {
759
        return;
760
    }
761

762
    ModelManager manager;
763

764
    try {
765
        auto model = manager.getModel(uuid);
766

767
        auto& inheritance = model->getInheritance();
768
        for (auto& it : inheritance) {
769
            removeUUID(_appearanceUuids, it);
770
            removeUUID(_allUuids, it);
771
        }
772
        removeUUID(_appearanceUuids, uuid);
773
        removeUUID(_allUuids, uuid);
774

775
        for (auto& it : *model) {
776
            _appearance.erase(it.first);
777
        }
778

779
        setEditStateAlter();
780
    }
781
    catch (ModelNotFound const&) {
782
    }
783
}
784

785
void Material::setPropertyEditState(const QString& name)
786
{
787
    try {
788
        if (hasPhysicalProperty(name)) {
789
            setPhysicalEditState(name);
790
        }
791
        else if (hasAppearanceProperty(name)) {
792
            setAppearanceEditState(name);
793
        }
794
    }
795
    catch (const PropertyNotFound&) {
796
    }
797
}
798

799
void Material::setPhysicalEditState(const QString& name)
800
{
801
    if (getPhysicalProperty(name)->isNull()) {
802
        setEditStateExtend();
803
    }
804
    else {
805
        setEditStateAlter();
806
    }
807
}
808

809
void Material::setAppearanceEditState(const QString& name)
810
{
811
    try {
812
        if (getAppearanceProperty(name)->isNull()) {
813
            setEditStateExtend();
814
        }
815
        else {
816
            setEditStateAlter();
817
        }
818
    }
819
    catch (const PropertyNotFound&) {
820
    }
821
}
822

823
void Material::setPhysicalValue(const QString& name, const QString& value)
824
{
825
    setPhysicalEditState(name);
826

827
    if (hasPhysicalProperty(name)) {
828
        _physical[name]->setValue(value);  // may not be a string type, conversion may be required
829
    }
830
}
831

832
void Material::setPhysicalValue(const QString& name, int value)
833
{
834
    setPhysicalEditState(name);
835

836
    if (hasPhysicalProperty(name)) {
837
        _physical[name]->setInt(value);
838
    }
839
}
840

841
void Material::setPhysicalValue(const QString& name, double value)
842
{
843
    setPhysicalEditState(name);
844

845
    if (hasPhysicalProperty(name)) {
846
        _physical[name]->setFloat(value);
847
    }
848
}
849

850
void Material::setPhysicalValue(const QString& name, const Base::Quantity& value)
851
{
852
    setPhysicalEditState(name);
853

854
    if (hasPhysicalProperty(name)) {
855
        _physical[name]->setQuantity(value);
856
    }
857
}
858

859
void Material::setPhysicalValue(const QString& name, const std::shared_ptr<MaterialValue>& value)
860
{
861
    setPhysicalEditState(name);
862

863
    if (hasPhysicalProperty(name)) {
864
        _physical[name]->setValue(value);
865
    }
866
}
867

868
void Material::setPhysicalValue(const QString& name, const std::shared_ptr<QList<QVariant>>& value)
869
{
870
    setPhysicalEditState(name);
871

872
    if (hasPhysicalProperty(name)) {
873
        _physical[name]->setList(*value);
874
    }
875
}
876

877
void Material::setPhysicalValue(const QString& name, const QVariant& value)
878
{
879
    setPhysicalEditState(name);
880

881
    if (hasPhysicalProperty(name)) {
882
        _physical[name]->setValue(value);
883
    }
884
}
885

886
void Material::setAppearanceValue(const QString& name, const QString& value)
887
{
888
    setAppearanceEditState(name);
889

890
    if (hasAppearanceProperty(name)) {
891
        _appearance[name]->setValue(value);  // may not be a string type, conversion may be required
892
    }
893
}
894

895
void Material::setAppearanceValue(const QString& name, const std::shared_ptr<MaterialValue>& value)
896
{
897
    setAppearanceEditState(name);
898

899
    if (hasAppearanceProperty(name)) {
900
        _appearance[name]->setValue(value);
901
    }
902
}
903

904
void Material::setAppearanceValue(const QString& name,
905
                                  const std::shared_ptr<QList<QVariant>>& value)
906
{
907
    setAppearanceEditState(name);
908

909
    if (hasAppearanceProperty(name)) {
910
        _appearance[name]->setList(*value);
911
    }
912
}
913

914
void Material::setAppearanceValue(const QString& name, const QVariant& value)
915
{
916
    setAppearanceEditState(name);
917

918
    if (hasAppearanceProperty(name)) {
919
        _appearance[name]->setValue(value);
920
    }
921
}
922

923
void Material::setValue(const QString& name, const QString& value)
924
{
925
    if (hasPhysicalProperty(name)) {
926
        setPhysicalValue(name, value);
927
    }
928
    else if (hasAppearanceProperty(name)) {
929
        setAppearanceValue(name, value);
930
    }
931
    else {
932
        throw PropertyNotFound();
933
    }
934
}
935

936
void Material::setValue(const QString& name, const QVariant& value)
937
{
938
    if (hasPhysicalProperty(name)) {
939
        setPhysicalValue(name, value);
940
    }
941
    else {
942
        throw PropertyNotFound();
943
    }
944
}
945

946
void Material::setLegacyValue(const QString& name, const QString& value)
947
{
948
    setEditStateAlter();
949

950
    _legacy[name] = value;
951
}
952

953
std::shared_ptr<MaterialProperty> Material::getPhysicalProperty(const QString& name)
954
{
955
    try {
956
        return _physical.at(name);
957
    }
958
    catch (std::out_of_range const&) {
959
        throw PropertyNotFound();
960
    }
961
}
962

963
std::shared_ptr<MaterialProperty> Material::getPhysicalProperty(const QString& name) const
964
{
965
    try {
966
        return _physical.at(name);
967
    }
968
    catch (std::out_of_range const&) {
969
        throw PropertyNotFound();
970
    }
971
}
972

973
std::shared_ptr<MaterialProperty> Material::getAppearanceProperty(const QString& name)
974
{
975
    try {
976
        return _appearance.at(name);
977
    }
978
    catch (std::out_of_range const&) {
979
        throw PropertyNotFound();
980
    }
981
}
982

983
std::shared_ptr<MaterialProperty> Material::getAppearanceProperty(const QString& name) const
984
{
985
    try {
986
        return _appearance.at(name);
987
    }
988
    catch (std::out_of_range const&) {
989
        throw PropertyNotFound();
990
    }
991
}
992

993
std::shared_ptr<MaterialProperty> Material::getProperty(const QString& name)
994
{
995
    if (hasPhysicalProperty(name)) {
996
        return getPhysicalProperty(name);
997
    }
998
    if (hasAppearanceProperty(name)) {
999
        return getAppearanceProperty(name);
1000
    }
1001
    throw PropertyNotFound();
1002
}
1003

1004
std::shared_ptr<MaterialProperty> Material::getProperty(const QString& name) const
1005
{
1006
    if (hasPhysicalProperty(name)) {
1007
        return getPhysicalProperty(name);
1008
    }
1009
    if (hasAppearanceProperty(name)) {
1010
        return getAppearanceProperty(name);
1011
    }
1012
    throw PropertyNotFound();
1013
}
1014

1015
QVariant
1016
Material::getValue(const std::map<QString, std::shared_ptr<MaterialProperty>>& propertyList,
1017
                   const QString& name)
1018
{
1019
    try {
1020
        return propertyList.at(name)->getValue();
1021
    }
1022
    catch (std::out_of_range const&) {
1023
        throw PropertyNotFound();
1024
    }
1025
}
1026

1027
QString
1028
Material::getValueString(const std::map<QString, std::shared_ptr<MaterialProperty>>& propertyList,
1029
                         const QString& name)
1030
{
1031
    try {
1032
        const auto& property = propertyList.at(name);
1033
        if (property->isNull()) {
1034
            return {};
1035
        }
1036
        if (property->getType() == MaterialValue::Quantity) {
1037
            auto value = property->getValue();
1038
            if (value.isNull()) {
1039
                return {};
1040
            }
1041
            return value.value<Base::Quantity>().getUserString();
1042
        }
1043
        if (property->getType() == MaterialValue::Float) {
1044
            auto value = property->getValue();
1045
            if (value.isNull()) {
1046
                return {};
1047
            }
1048
            return QString(QLatin1String("%L1"))
1049
                .arg(value.toFloat(), 0, 'g', MaterialProperty::PRECISION);
1050
        }
1051
        return property->getValue().toString();
1052
    }
1053
    catch (std::out_of_range const&) {
1054
        throw PropertyNotFound();
1055
    }
1056
}
1057

1058
QVariant Material::getPhysicalValue(const QString& name) const
1059
{
1060
    return getValue(_physical, name);
1061
}
1062

1063
Base::Quantity Material::getPhysicalQuantity(const QString& name) const
1064
{
1065
    return getValue(_physical, name).value<Base::Quantity>();
1066
}
1067

1068
QString Material::getPhysicalValueString(const QString& name) const
1069
{
1070
    return getValueString(_physical, name);
1071
}
1072

1073
QVariant Material::getAppearanceValue(const QString& name) const
1074
{
1075
    return getValue(_appearance, name);
1076
}
1077

1078
Base::Quantity Material::getAppearanceQuantity(const QString& name) const
1079
{
1080
    return getValue(_appearance, name).value<Base::Quantity>();
1081
}
1082

1083
QString Material::getAppearanceValueString(const QString& name) const
1084
{
1085
    return getValueString(_appearance, name);
1086
}
1087

1088
bool Material::hasPhysicalProperty(const QString& name) const
1089
{
1090
    try {
1091
        static_cast<void>(_physical.at(name));
1092
    }
1093
    catch (std::out_of_range const&) {
1094
        return false;
1095
    }
1096
    return true;
1097
}
1098

1099
bool Material::hasAppearanceProperty(const QString& name) const
1100
{
1101
    try {
1102
        static_cast<void>(_appearance.at(name));
1103
    }
1104
    catch (std::out_of_range const&) {
1105
        return false;
1106
    }
1107
    return true;
1108
}
1109

1110
bool Material::hasNonLegacyProperty(const QString& name) const
1111
{
1112
    if (hasPhysicalProperty(name) || hasAppearanceProperty(name)) {
1113
        return true;
1114
    }
1115
    return false;
1116
}
1117

1118
bool Material::hasLegacyProperties() const
1119
{
1120
    return !_legacy.empty();
1121
}
1122

1123
bool Material::isInherited(const QString& uuid) const
1124
{
1125
    if (_physicalUuids.contains(uuid)) {
1126
        return false;
1127
    }
1128
    if (_appearanceUuids.contains(uuid)) {
1129
        return false;
1130
    }
1131

1132
    return _allUuids.contains(uuid);
1133
}
1134

1135
bool Material::hasModel(const QString& uuid) const
1136
{
1137
    return _allUuids.contains(uuid);
1138
}
1139

1140
bool Material::hasPhysicalModel(const QString& uuid) const
1141
{
1142
    if (!hasModel(uuid)) {
1143
        return false;
1144
    }
1145

1146
    ModelManager manager;
1147

1148
    try {
1149
        auto model = manager.getModel(uuid);
1150
        if (model->getType() == Model::ModelType_Physical) {
1151
            return true;
1152
        }
1153
    }
1154
    catch (ModelNotFound const&) {
1155
    }
1156

1157
    return false;
1158
}
1159

1160
bool Material::hasAppearanceModel(const QString& uuid) const
1161
{
1162
    if (!hasModel(uuid)) {
1163
        return false;
1164
    }
1165

1166
    ModelManager manager;
1167

1168
    try {
1169
        auto model = manager.getModel(uuid);
1170
        if (model->getType() == Model::ModelType_Appearance) {
1171
            return true;
1172
        }
1173
    }
1174
    catch (ModelNotFound const&) {
1175
    }
1176

1177
    return false;
1178
}
1179

1180
bool Material::isPhysicalModelComplete(const QString& uuid) const
1181
{
1182
    if (!hasPhysicalModel(uuid)) {
1183
        return false;
1184
    }
1185

1186
    ModelManager manager;
1187

1188
    try {
1189
        auto model = manager.getModel(uuid);
1190
        for (auto& it : *model) {
1191
            QString propertyName = it.first;
1192
            auto property = getPhysicalProperty(propertyName);
1193

1194
            if (property->isNull()) {
1195
                return false;
1196
            }
1197
        }
1198
    }
1199
    catch (ModelNotFound const&) {
1200
        return false;
1201
    }
1202

1203
    return true;
1204
}
1205

1206
bool Material::isAppearanceModelComplete(const QString& uuid) const
1207
{
1208
    if (!hasAppearanceModel(uuid)) {
1209
        return false;
1210
    }
1211

1212
    ModelManager manager;
1213

1214
    try {
1215
        auto model = manager.getModel(uuid);
1216
        for (auto& it : *model) {
1217
            QString propertyName = it.first;
1218
            auto property = getAppearanceProperty(propertyName);
1219

1220
            if (property->isNull()) {
1221
                return false;
1222
            }
1223
        }
1224
    }
1225
    catch (ModelNotFound const&) {
1226
        return false;
1227
    }
1228

1229
    return true;
1230
}
1231

1232
void Material::saveGeneral(QTextStream& stream) const
1233
{
1234
    stream << "General:\n";
1235
    stream << "  UUID: \"" << _uuid << "\"\n";
1236
    stream << "  Name: \"" << MaterialValue::escapeString(_name) << "\"\n";
1237
    if (!_author.isEmpty()) {
1238
        stream << "  Author: \"" << MaterialValue::escapeString(_author) << "\"\n";
1239
    }
1240
    if (!_license.isEmpty()) {
1241
        stream << "  License: \"" << MaterialValue::escapeString(_license) << "\"\n";
1242
    }
1243
    if (!_description.isEmpty()) {
1244
        stream << "  Description: \"" << MaterialValue::escapeString(_description) << "\"\n";
1245
    }
1246
    if (!_url.isEmpty()) {
1247
        stream << "  SourceURL: \"" << MaterialValue::escapeString(_url) << "\"\n";
1248
    }
1249
    if (!_reference.isEmpty()) {
1250
        stream << "  ReferenceSource: \"" << MaterialValue::escapeString(_reference) << "\"\n";
1251
    }
1252
}
1253

1254
void Material::saveInherits(QTextStream& stream) const
1255
{
1256
    if (!_parentUuid.isEmpty()) {
1257
        MaterialManager manager;
1258

1259
        try {
1260
            auto material = manager.getMaterial(_parentUuid);
1261

1262
            stream << "Inherits:\n";
1263
            stream << "  " << material->getName() << ":\n";
1264
            stream << "    UUID: \"" << _parentUuid << "\"\n";
1265
        }
1266
        catch (const MaterialNotFound&) {
1267
        }
1268
    }
1269
}
1270

1271
bool Material::modelChanged(const std::shared_ptr<Material>& parent,
1272
                            const std::shared_ptr<Model>& model) const
1273
{
1274
    for (auto& it : *model) {
1275
        QString propertyName = it.first;
1276
        auto property = getPhysicalProperty(propertyName);
1277
        try {
1278
            auto parentProperty = parent->getPhysicalProperty(propertyName);
1279

1280
            if (*property != *parentProperty) {
1281
                return true;
1282
            }
1283
        }
1284
        catch (const PropertyNotFound&) {
1285
            return true;
1286
        }
1287
    }
1288

1289
    return false;
1290
}
1291

1292
bool Material::modelAppearanceChanged(const std::shared_ptr<Material>& parent,
1293
                                      const std::shared_ptr<Model>& model) const
1294
{
1295
    for (auto& it : *model) {
1296
        QString propertyName = it.first;
1297
        auto property = getAppearanceProperty(propertyName);
1298
        try {
1299
            auto parentProperty = parent->getAppearanceProperty(propertyName);
1300

1301
            if (*property != *parentProperty) {
1302
                return true;
1303
            }
1304
        }
1305
        catch (const PropertyNotFound&) {
1306
            return true;
1307
        }
1308
    }
1309

1310
    return false;
1311
}
1312

1313
void Material::saveModels(QTextStream& stream, bool saveInherited) const
1314
{
1315
    if (_physical.empty()) {
1316
        return;
1317
    }
1318

1319
    ModelManager modelManager;
1320
    MaterialManager materialManager;
1321

1322
    bool inherited = saveInherited && (_parentUuid.size() > 0);
1323
    std::shared_ptr<Material> parent;
1324
    if (inherited) {
1325
        try {
1326
            parent = materialManager.getMaterial(_parentUuid);
1327
        }
1328
        catch (const MaterialNotFound&) {
1329
            inherited = false;
1330
        }
1331
    }
1332

1333
    bool headerPrinted = false;
1334
    for (auto& itm : _physicalUuids) {
1335
        auto model = modelManager.getModel(itm);
1336
        if (!inherited || modelChanged(parent, model)) {
1337
            if (!headerPrinted) {
1338
                stream << "Models:\n";
1339
                headerPrinted = true;
1340
            }
1341
            stream << "  " << MaterialValue::escapeString(model->getName()) << ":\n";
1342
            stream << "    UUID: \"" << model->getUUID() << "\"\n";
1343
            for (const auto& it : *model) {
1344
                QString propertyName = it.first;
1345
                std::shared_ptr<MaterialProperty> property = getPhysicalProperty(propertyName);
1346
                std::shared_ptr<MaterialProperty> parentProperty;
1347
                try {
1348
                    if (inherited) {
1349
                        parentProperty = parent->getPhysicalProperty(propertyName);
1350
                    }
1351
                }
1352
                catch (const PropertyNotFound&) {
1353
                    Base::Console().Log("Material::saveModels Property not found '%s'\n",
1354
                                        propertyName.toStdString().c_str());
1355
                }
1356

1357
                if (!inherited || !parentProperty || (*property != *parentProperty)) {
1358
                    if (!property->isNull()) {
1359
                        stream << "    " << *property << "\n";
1360
                    }
1361
                }
1362
            }
1363
        }
1364
    }
1365
}
1366

1367
void Material::saveAppearanceModels(QTextStream& stream, bool saveInherited) const
1368
{
1369
    if (_appearance.empty()) {
1370
        return;
1371
    }
1372

1373
    ModelManager modelManager;
1374
    MaterialManager materialManager;
1375

1376
    bool inherited = saveInherited && (_parentUuid.size() > 0);
1377
    std::shared_ptr<Material> parent;
1378
    if (inherited) {
1379
        try {
1380
            parent = materialManager.getMaterial(_parentUuid);
1381
        }
1382
        catch (const MaterialNotFound&) {
1383
            inherited = false;
1384
        }
1385
    }
1386

1387
    bool headerPrinted = false;
1388
    for (auto& itm : _appearanceUuids) {
1389
        auto model = modelManager.getModel(itm);
1390
        if (!inherited || modelAppearanceChanged(parent, model)) {
1391
            if (!headerPrinted) {
1392
                stream << "AppearanceModels:\n";
1393
                headerPrinted = true;
1394
            }
1395
            stream << "  " << MaterialValue::escapeString(model->getName()) << ":\n";
1396
            stream << "    UUID: \"" << model->getUUID() << "\"\n";
1397
            for (const auto& it : *model) {
1398
                QString propertyName = it.first;
1399
                std::shared_ptr<MaterialProperty> property = getAppearanceProperty(propertyName);
1400
                std::shared_ptr<MaterialProperty> parentProperty;
1401
                try {
1402
                    if (inherited) {
1403
                        parentProperty = parent->getAppearanceProperty(propertyName);
1404
                    }
1405
                }
1406
                catch (const PropertyNotFound&) {
1407
                }
1408

1409
                if (!inherited || !parentProperty || (*property != *parentProperty)) {
1410
                    if (!property->isNull()) {
1411
                        stream << "    " << *property << "\n";
1412
                    }
1413
                }
1414
            }
1415
        }
1416
    }
1417
}
1418

1419
void Material::newUuid()
1420
{
1421
    _uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
1422
}
1423

1424
QString Material::getModelByName(const QString& name) const
1425
{
1426
    ModelManager manager;
1427

1428
    for (auto& it : _allUuids) {
1429
        try {
1430
            auto model = manager.getModel(it);
1431
            if (model->getName() == name) {
1432
                return it;
1433
            }
1434
        }
1435
        catch (ModelNotFound const&) {
1436
        }
1437
    }
1438

1439
    return {};
1440
}
1441

1442
void Material::save(QTextStream& stream, bool overwrite, bool saveAsCopy, bool saveInherited)
1443
{
1444
    if (saveInherited && !saveAsCopy) {
1445
        // Check to see if we're an original or if we're already in the list of
1446
        // models
1447
        MaterialManager materialManager;
1448
        if (materialManager.exists(_uuid) && !overwrite) {
1449
            // Make a new version based on the current
1450
            setParentUUID(_uuid);
1451
        }
1452
    }
1453

1454
    // Prevent self inheritance
1455
    if (_parentUuid == _uuid) {
1456
        _parentUuid = QString();
1457
    }
1458

1459
    if (saveAsCopy) {
1460
        // Save it in the same format as the parent
1461
        if (_parentUuid.isEmpty()) {
1462
            saveInherited = false;
1463
        }
1464
        else {
1465
            saveInherited = true;
1466
        }
1467
    }
1468
    else {
1469
        if (!overwrite) {
1470
            // Creating a new derived model when overwriting sets itself as a
1471
            // parent, that will no longer exist because it's been overwritten
1472
            newUuid();
1473
        }
1474
    }
1475

1476
    stream << "---\n";
1477
    stream << "# File created by " << QString::fromStdString(App::Application::Config()["ExeName"])
1478
           << " " << QString::fromStdString(App::Application::Config()["ExeVersion"])
1479
           << " Revision: " << QString::fromStdString(App::Application::Config()["BuildRevision"])
1480
           << "\n";
1481
    saveGeneral(stream);
1482
    if (saveInherited) {
1483
        saveInherits(stream);
1484
    }
1485
    saveModels(stream, saveInherited);
1486
    saveAppearanceModels(stream, saveInherited);
1487

1488
    setOldFormat(false);
1489
}
1490

1491
Material& Material::operator=(const Material& other)
1492
{
1493
    if (this == &other) {
1494
        return *this;
1495
    }
1496

1497
    _library = other._library;
1498
    _directory = other._directory;
1499
    _uuid = other._uuid;
1500
    _name = other._name;
1501
    _author = other._author;
1502
    _license = other._license;
1503
    _parentUuid = other._parentUuid;
1504
    _description = other._description;
1505
    _url = other._url;
1506
    _reference = other._reference;
1507
    _dereferenced = other._dereferenced;
1508
    _oldFormat = other._oldFormat;
1509
    _editState = other._editState;
1510

1511
    _tags.clear();
1512
    for (auto& it : other._tags) {
1513
        _tags.insert(it);
1514
    }
1515
    _physicalUuids.clear();
1516
    for (auto& it : other._physicalUuids) {
1517
        _physicalUuids.insert(it);
1518
    }
1519
    _appearanceUuids.clear();
1520
    for (auto& it : other._appearanceUuids) {
1521
        _appearanceUuids.insert(it);
1522
    }
1523
    _allUuids.clear();
1524
    for (auto& it : other._allUuids) {
1525
        _allUuids.insert(it);
1526
    }
1527

1528
    // Create copies of the properties rather than modify the originals
1529
    _physical.clear();
1530
    for (auto& it : other._physical) {
1531
        MaterialProperty prop(it.second);
1532
        _physical[it.first] = std::make_shared<MaterialProperty>(prop);
1533
    }
1534
    _appearance.clear();
1535
    for (auto& it : other._appearance) {
1536
        MaterialProperty prop(it.second);
1537
        _appearance[it.first] = std::make_shared<MaterialProperty>(prop);
1538
    }
1539
    _legacy.clear();
1540
    for (auto& it : other._legacy) {
1541
        _legacy[it.first] = it.second;
1542
    }
1543

1544
    return *this;
1545
}
1546

1547
Material& Material::operator=(const App::Material& other)
1548
{
1549
    if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Basic)) {
1550
        addAppearance(ModelUUIDs::ModelUUID_Rendering_Basic);
1551
    }
1552

1553
    getAppearanceProperty(QLatin1String("AmbientColor"))->setColor(other.ambientColor);
1554
    getAppearanceProperty(QLatin1String("DiffuseColor"))->setColor(other.diffuseColor);
1555
    getAppearanceProperty(QLatin1String("SpecularColor"))->setColor(other.specularColor);
1556
    getAppearanceProperty(QLatin1String("EmissiveColor"))->setColor(other.emissiveColor);
1557
    getAppearanceProperty(QLatin1String("Shininess"))->setFloat(other.shininess);
1558
    getAppearanceProperty(QLatin1String("Transparency"))->setFloat(other.transparency);
1559

1560
    if (!other.image.empty() || !other.imagePath.empty()) {
1561
        if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Texture)) {
1562
            addAppearance(ModelUUIDs::ModelUUID_Rendering_Texture);
1563
        }
1564

1565
        getAppearanceProperty(QLatin1String("TextureImage"))->setString(other.image);
1566
        getAppearanceProperty(QLatin1String("TexturePath"))->setString(other.imagePath);
1567
    }
1568

1569
    return *this;
1570
}
1571

1572
/*
1573
 * Normalize models by removing any inherited models
1574
 */
1575
QStringList Material::normalizeModels(const QStringList& models)
1576
{
1577
    QStringList normalized;
1578

1579
    ModelManager manager;
1580

1581
    for (auto& uuid : models) {
1582
        auto model = manager.getModel(uuid);
1583

1584
        bool found = false;
1585
        for (auto& childUuid : models) {
1586
            if (uuid != childUuid) {
1587
                auto childModel = manager.getModel(childUuid);
1588
                if (childModel->inherits(childUuid)) {
1589
                    // We're an inherited model
1590
                    found = true;
1591
                    break;
1592
                }
1593
            }
1594
        }
1595
        if (!found) {
1596
            normalized << uuid;
1597
        }
1598
    }
1599

1600
    return normalized;
1601
}
1602

1603
/*
1604
 * Set or change the base material for the current material, updating the
1605
 * properties as required.
1606
 */
1607
void Material::updateInheritance([[maybe_unused]] const QString& parent)
1608
{}
1609

1610
/*
1611
 * Return a list of models that are defined in the parent material but not in
1612
 * this one
1613
 */
1614
QStringList Material::inheritedMissingModels(const Material& parent) const
1615
{
1616
    QStringList missing;
1617
    for (auto& uuid : parent._allUuids) {
1618
        if (!hasModel(uuid)) {
1619
            missing << uuid;
1620
        }
1621
    }
1622

1623
    return normalizeModels(missing);
1624
}
1625

1626
/*
1627
 * Return a list of models that are defined in this model but not the parent
1628
 */
1629
QStringList Material::inheritedAddedModels(const Material& parent) const
1630
{
1631
    QStringList added;
1632
    for (auto& uuid : _allUuids) {
1633
        if (!parent.hasModel(uuid)) {
1634
            added << uuid;
1635
        }
1636
    }
1637

1638
    return normalizeModels(added);
1639
}
1640

1641
/*
1642
 * Return a list of properties that have different values from the parent
1643
 * material
1644
 */
1645
void Material::inheritedPropertyDiff([[maybe_unused]] const QString& parent)
1646
{}
1647

1648
/*
1649
 * Return an App::Material object describing the materials appearance, or DEFAULT if
1650
 * undefined.
1651
 */
1652
App::Material Material::getMaterialAppearance() const
1653
{
1654
    App::Material material(App::Material::DEFAULT);
1655

1656
    bool custom = false;
1657
    if (hasAppearanceProperty(QLatin1String("AmbientColor"))) {
1658
        material.ambientColor = getAppearanceProperty(QLatin1String("AmbientColor"))->getColor();
1659
        custom = true;
1660
    }
1661
    if (hasAppearanceProperty(QLatin1String("DiffuseColor"))) {
1662
        material.diffuseColor = getAppearanceProperty(QLatin1String("DiffuseColor"))->getColor();
1663
        custom = true;
1664
    }
1665
    if (hasAppearanceProperty(QLatin1String("SpecularColor"))) {
1666
        material.specularColor = getAppearanceProperty(QLatin1String("SpecularColor"))->getColor();
1667
        custom = true;
1668
    }
1669
    if (hasAppearanceProperty(QLatin1String("EmissiveColor"))) {
1670
        material.emissiveColor = getAppearanceProperty(QLatin1String("EmissiveColor"))->getColor();
1671
        custom = true;
1672
    }
1673
    if (hasAppearanceProperty(QLatin1String("Shininess"))) {
1674
        material.shininess = getAppearanceProperty(QLatin1String("Shininess"))->getFloat();
1675
        custom = true;
1676
    }
1677
    if (hasAppearanceProperty(QLatin1String("Transparency"))) {
1678
        material.transparency = getAppearanceProperty(QLatin1String("Transparency"))->getFloat();
1679
        custom = true;
1680
    }
1681
    if (hasAppearanceProperty(QLatin1String("TextureImage"))) {
1682
        auto property = getAppearanceProperty(QLatin1String("TextureImage"));
1683
        if (!property->isNull()) {
1684
            Base::Console().Log("Has 'TextureImage'\n");
1685
            material.image = property->getString().toStdString();
1686
        }
1687

1688
        custom = true;
1689
    }
1690
    else if (hasAppearanceProperty(QLatin1String("TexturePath"))) {
1691
        auto property = getAppearanceProperty(QLatin1String("TexturePath"));
1692
        if (!property->isNull()) {
1693
            Base::Console().Log("Has 'TexturePath'\n");
1694
            material.imagePath = property->getString().toStdString();
1695
        }
1696

1697
        custom = true;
1698
    }
1699

1700
    if (custom) {
1701
        material.setType(App::Material::USER_DEFINED);
1702
        material.uuid = getUUID().toStdString();
1703
    }
1704

1705
    return material;
1706
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.