FreeCAD

Форк
0
/
ReaderOBJ.cpp 
368 строк · 14.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2022 Werner Mayer <wmayer[at]users.sourceforge.net>     *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <boost/lexical_cast.hpp>
26
#include <boost/regex.hpp>
27
#include <boost/tokenizer.hpp>
28
#include <istream>
29
#endif
30

31
#include "Core/MeshIO.h"
32
#include "Core/MeshKernel.h"
33
#include <Base/Tools.h>
34

35
#include "ReaderOBJ.h"
36

37

38
using namespace MeshCore;
39

40
ReaderOBJ::ReaderOBJ(MeshKernel& kernel, Material* material)
41
    : _kernel(kernel)
42
    , _material(material)
43
{}
44

45
bool ReaderOBJ::Load(std::istream& str)
46
{
47
    boost::regex rx_m("^mtllib\\s+(.+)\\s*$");
48
    boost::regex rx_u(R"(^usemtl\s+([\x21-\x7E]+)\s*$)");
49
    boost::regex rx_g(R"(^g\s+([\x21-\x7E]+)\s*$)");
50
    boost::regex rx_p("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
51
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
52
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$");
53
    boost::regex rx_c("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
54
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
55
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
56
                      "\\s+(\\d{1,3})\\s+(\\d{1,3})\\s+(\\d{1,3})\\s*$");
57
    boost::regex rx_t("^v\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
58
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
59
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
60
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
61
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
62
                      "\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$");
63
    boost::regex rx_f3("^f\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
64
                       "\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
65
                       "\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*\\s*$");
66
    boost::regex rx_f4("^f\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
67
                       "\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
68
                       "\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*"
69
                       "\\s+([-+]?[0-9]+)/?[-+]?[0-9]*/?[-+]?[0-9]*\\s*$");
70
    boost::cmatch what;
71

72
    unsigned long segment = 0;
73
    MeshPointArray meshPoints;
74
    MeshFacetArray meshFacets;
75

76
    std::string line;
77
    float fX {}, fY {}, fZ {};
78
    int i1 = 1, i2 = 1, i3 = 1, i4 = 1;
79
    MeshFacet item;
80

81
    if (!str || str.bad()) {
82
        return false;
83
    }
84

85
    std::streambuf* buf = str.rdbuf();
86
    if (!buf) {
87
        return false;
88
    }
89

90
    MeshIO::Binding rgb_value = MeshIO::OVERALL;
91
    bool new_segment = true;
92
    std::string groupName;
93
    std::string materialName;
94
    unsigned long countMaterialFacets = 0;
95

96
    while (std::getline(str, line)) {
97
        if (boost::regex_match(line.c_str(), what, rx_p)) {
98
            fX = (float)std::atof(what[1].first);
99
            fY = (float)std::atof(what[4].first);
100
            fZ = (float)std::atof(what[7].first);
101
            meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
102
        }
103
        else if (boost::regex_match(line.c_str(), what, rx_c)) {
104
            fX = (float)std::atof(what[1].first);
105
            fY = (float)std::atof(what[4].first);
106
            fZ = (float)std::atof(what[7].first);
107
            float r = std::min<int>(std::atof(what[10].first), 255) / 255.0f;
108
            float g = std::min<int>(std::atof(what[11].first), 255) / 255.0f;
109
            float b = std::min<int>(std::atof(what[12].first), 255) / 255.0f;
110
            meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
111

112
            App::Color c(r, g, b);
113
            unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
114
            meshPoints.back().SetProperty(prop);
115
            rgb_value = MeshIO::PER_VERTEX;
116
        }
117
        else if (boost::regex_match(line.c_str(), what, rx_t)) {
118
            fX = (float)std::atof(what[1].first);
119
            fY = (float)std::atof(what[4].first);
120
            fZ = (float)std::atof(what[7].first);
121
            float r = static_cast<float>(std::atof(what[10].first));
122
            float g = static_cast<float>(std::atof(what[13].first));
123
            float b = static_cast<float>(std::atof(what[16].first));
124
            meshPoints.push_back(MeshPoint(Base::Vector3f(fX, fY, fZ)));
125

126
            App::Color c(r, g, b);
127
            unsigned long prop = static_cast<uint32_t>(c.getPackedValue());
128
            meshPoints.back().SetProperty(prop);
129
            rgb_value = MeshIO::PER_VERTEX;
130
        }
131
        else if (boost::regex_match(line.c_str(), what, rx_g)) {
132
            new_segment = true;
133
            groupName = Base::Tools::escapedUnicodeToUtf8(what[1].first);
134
        }
135
        else if (boost::regex_match(line.c_str(), what, rx_m)) {
136
            if (_material) {
137
                _material->library = Base::Tools::escapedUnicodeToUtf8(what[1].first);
138
            }
139
        }
140
        else if (boost::regex_match(line.c_str(), what, rx_u)) {
141
            if (!materialName.empty()) {
142
                _materialNames.emplace_back(materialName, countMaterialFacets);
143
            }
144
            materialName = Base::Tools::escapedUnicodeToUtf8(what[1].first);
145
            countMaterialFacets = 0;
146
        }
147
        else if (boost::regex_match(line.c_str(), what, rx_f3)) {
148
            // starts a new segment
149
            if (new_segment) {
150
                if (!groupName.empty()) {
151
                    _groupNames.push_back(groupName);
152
                    groupName.clear();
153
                }
154
                new_segment = false;
155
                segment++;
156
            }
157

158
            // 3-vertex face
159
            i1 = std::atoi(what[1].first);
160
            i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
161
            i2 = std::atoi(what[2].first);
162
            i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
163
            i3 = std::atoi(what[3].first);
164
            i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
165
            item.SetVertices(i1, i2, i3);
166
            item.SetProperty(segment);
167
            meshFacets.push_back(item);
168
            countMaterialFacets++;
169
        }
170
        else if (boost::regex_match(line.c_str(), what, rx_f4)) {
171
            // starts a new segment
172
            if (new_segment) {
173
                if (!groupName.empty()) {
174
                    _groupNames.push_back(groupName);
175
                    groupName.clear();
176
                }
177
                new_segment = false;
178
                segment++;
179
            }
180

181
            // 4-vertex face
182
            i1 = std::atoi(what[1].first);
183
            i1 = i1 > 0 ? i1 - 1 : i1 + static_cast<int>(meshPoints.size());
184
            i2 = std::atoi(what[2].first);
185
            i2 = i2 > 0 ? i2 - 1 : i2 + static_cast<int>(meshPoints.size());
186
            i3 = std::atoi(what[3].first);
187
            i3 = i3 > 0 ? i3 - 1 : i3 + static_cast<int>(meshPoints.size());
188
            i4 = std::atoi(what[4].first);
189
            i4 = i4 > 0 ? i4 - 1 : i4 + static_cast<int>(meshPoints.size());
190

191
            item.SetVertices(i1, i2, i3);
192
            item.SetProperty(segment);
193
            meshFacets.push_back(item);
194
            countMaterialFacets++;
195

196
            item.SetVertices(i3, i4, i1);
197
            item.SetProperty(segment);
198
            meshFacets.push_back(item);
199
            countMaterialFacets++;
200
        }
201
    }
202

203
    // Add the last added material name
204
    if (!materialName.empty()) {
205
        _materialNames.emplace_back(materialName, countMaterialFacets);
206
    }
207

208
    // now get back the colors from the vertex property
209
    if (rgb_value == MeshIO::PER_VERTEX) {
210
        if (_material) {
211
            _material->binding = MeshIO::PER_VERTEX;
212
            _material->diffuseColor.reserve(meshPoints.size());
213

214
            for (const auto& it : meshPoints) {
215
                unsigned long prop = it._ulProp;
216
                App::Color c;
217
                c.setPackedValue(static_cast<uint32_t>(prop));
218
                _material->diffuseColor.push_back(c);
219
            }
220
        }
221
    }
222
    else if (!materialName.empty()) {
223
        // At this point the materials from the .mtl file are not known and will be read-in by the
224
        // calling instance but the color list is pre-filled with a default value
225
        if (_material) {
226
            _material->binding = MeshIO::PER_FACE;
227
            _material->diffuseColor.resize(meshFacets.size(), App::Color(0.8f, 0.8f, 0.8f));
228
        }
229
    }
230

231
    _kernel.Clear();  // remove all data before
232

233
    MeshCleanup meshCleanup(meshPoints, meshFacets);
234
    if (_material) {
235
        meshCleanup.SetMaterial(_material);
236
    }
237
    meshCleanup.RemoveInvalids();
238
    MeshPointFacetAdjacency meshAdj(meshPoints.size(), meshFacets);
239
    meshAdj.SetFacetNeighbourhood();
240
    _kernel.Adopt(meshPoints, meshFacets);
241

242
    return true;
243
}
244

245
bool ReaderOBJ::LoadMaterial(std::istream& str)
246
{
247
    std::string line;
248

249
    if (!_material) {
250
        return false;
251
    }
252

253
    if (!str || str.bad()) {
254
        return false;
255
    }
256

257
    std::streambuf* buf = str.rdbuf();
258
    if (!buf) {
259
        return false;
260
    }
261

262
    std::map<std::string, App::Color> materialAmbientColor;
263
    std::map<std::string, App::Color> materialDiffuseColor;
264
    std::map<std::string, App::Color> materialSpecularColor;
265
    std::map<std::string, float> materialTransparency;
266
    std::string materialName;
267
    std::vector<App::Color> ambientColor;
268
    std::vector<App::Color> diffuseColor;
269
    std::vector<App::Color> specularColor;
270
    std::vector<float> transparency;
271

272
    auto readColor = [](const std::vector<std::string>& tokens) -> App::Color {
273
        if (tokens.size() == 2) {
274
            // If only R is given then G and B will be equal
275
            float r = boost::lexical_cast<float>(tokens[1]);
276
            return App::Color(r, r, r);
277
        }
278
        else if (tokens.size() == 4) {
279
            float r = boost::lexical_cast<float>(tokens[1]);
280
            float g = boost::lexical_cast<float>(tokens[2]);
281
            float b = boost::lexical_cast<float>(tokens[3]);
282
            return App::Color(r, g, b);
283
        }
284

285
        throw std::length_error("Unexpected number of tokens");
286
    };
287

288
    while (std::getline(str, line)) {
289
        boost::char_separator<char> sep(" ");
290
        boost::tokenizer<boost::char_separator<char>> tokens(line, sep);
291
        std::vector<std::string> token_results;
292
        token_results.assign(tokens.begin(), tokens.end());
293

294
        try {
295
            if (token_results.size() >= 2) {
296
                if (token_results[0] == "newmtl") {
297
                    materialName = Base::Tools::escapedUnicodeToUtf8(token_results[1]);
298
                }
299
                else if (token_results[0] == "d") {
300
                    float a = boost::lexical_cast<float>(token_results[1]);
301
                    materialTransparency[materialName] = 1.0f - a;
302
                }
303
                // If only R is given then G and B will be equal
304
                else if (token_results[0] == "Ka") {
305
                    materialAmbientColor[materialName] = readColor(token_results);
306
                }
307
                else if (token_results[0] == "Kd") {
308
                    materialDiffuseColor[materialName] = readColor(token_results);
309
                }
310
                else if (token_results[0] == "Ks") {
311
                    materialSpecularColor[materialName] = readColor(token_results);
312
                }
313
            }
314
        }
315
        catch (const boost::bad_lexical_cast&) {
316
        }
317
        catch (const std::exception&) {
318
        }
319
    }
320

321
    for (const auto& it : _materialNames) {
322
        {
323
            auto jt = materialAmbientColor.find(it.first);
324
            if (jt != materialAmbientColor.end()) {
325
                std::vector<App::Color> mat(it.second, jt->second);
326
                ambientColor.insert(ambientColor.end(), mat.begin(), mat.end());
327
            }
328
        }
329
        {
330
            auto jt = materialDiffuseColor.find(it.first);
331
            if (jt != materialDiffuseColor.end()) {
332
                std::vector<App::Color> mat(it.second, jt->second);
333
                diffuseColor.insert(diffuseColor.end(), mat.begin(), mat.end());
334
            }
335
        }
336
        {
337
            auto jt = materialSpecularColor.find(it.first);
338
            if (jt != materialSpecularColor.end()) {
339
                std::vector<App::Color> mat(it.second, jt->second);
340
                specularColor.insert(specularColor.end(), mat.begin(), mat.end());
341
            }
342
        }
343
        {
344
            auto jt = materialTransparency.find(it.first);
345
            if (jt != materialTransparency.end()) {
346
                std::vector<float> transp(it.second, jt->second);
347
                transparency.insert(transparency.end(), transp.begin(), transp.end());
348
            }
349
        }
350
    }
351

352
    if (diffuseColor.size() == _material->diffuseColor.size()) {
353
        _material->binding = MeshIO::PER_FACE;
354
        _material->ambientColor.swap(ambientColor);
355
        _material->diffuseColor.swap(diffuseColor);
356
        _material->specularColor.swap(specularColor);
357
        _material->transparency.swap(transparency);
358
        return true;
359
    }
360
    else {
361
        _material->binding = MeshIO::OVERALL;
362
        _material->ambientColor.clear();
363
        _material->diffuseColor.clear();
364
        _material->specularColor.clear();
365
        _material->transparency.clear();
366
        return false;
367
    }
368
}
369

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

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

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

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