FreeCAD

Форк
0
/
Builder3D.cpp 
1290 строк · 33.7 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2011 Jürgen Riegel <juergen.riegel@web.de>              *
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

24
#include "PreCompiled.h"
25

26
#ifndef _PreComp_
27
#include <algorithm>
28
#include <cassert>
29
#include <exception>
30
#include <string>
31
#include <string_view>
32
#include <fstream>
33
#include <boost/algorithm/string.hpp>
34
#include <boost/algorithm/string/predicate.hpp>
35
#include <boost/lexical_cast.hpp>
36
#include <boost/tokenizer.hpp>
37
#endif
38

39
#include "Builder3D.h"
40
#include "Console.h"
41
#include "Exception.h"
42
#include "FileInfo.h"
43
#include "Matrix.h"
44
#include "Stream.h"
45
#include "Tools.h"
46

47

48
using namespace Base;
49

50

51
constexpr float valueMinLegal {-1.0F};
52
constexpr float valueMaxLegal {1.0F};
53

54
ColorRGB::ColorRGB()
55
    : Rgb {1.0F, 1.0F, 1.0F}
56
{}
57

58
ColorRGB::ColorRGB(float red, float green, float blue)
59
    : Rgb {valueInRange(red), valueInRange(green), valueInRange(blue)}
60
{}
61

62
float ColorRGB::valueInRange(float value)
63
{
64
    return std::clamp(value, valueMinLegal, valueMaxLegal);
65
}
66

67
const char* DrawStyle::styleAsString() const
68
{
69
    switch (style) {
70
        case Style::Filled:
71
            return "FILLED";
72
        case Style::Lines:
73
            return "LINES";
74
        case Style::Points:
75
            return "POINTS";
76
        case Style::Invisible:
77
            return "INVISIBLE";
78
    }
79
    return "FILLED";
80
}
81

82
std::string DrawStyle::patternAsString() const
83
{
84
    std::stringstream str;
85
    str << "0x" << std::hex << linePattern;
86
    return str.str();
87
}
88

89
const char* VertexOrdering::toString() const
90
{
91
    switch (ordering) {
92
        case Ordering::UnknownOrdering:
93
            return "UNKNOWN_ORDERING";
94
        case Ordering::Clockwise:
95
            return "CLOCKWISE";
96
        case Ordering::CounterClockwise:
97
            return "COUNTERCLOCKWISE";
98
    }
99
    return "UNKNOWN_ORDERING";
100
}
101

102
const char* ShapeType::toString() const
103
{
104
    switch (type) {
105
        case Type::UnknownShapeType:
106
            return "UNKNOWN_SHAPE_TYPE";
107
        case Type::Convex:
108
            return "SOLID";
109
    }
110
    return "UNKNOWN_SHAPE_TYPE";
111
}
112

113
const char* BindingElement::bindingAsString() const
114
{
115
    switch (value) {
116
        case Binding::PerPart:
117
            return "PER_PART";
118
        case Binding::PerPartIndexed:
119
            return "PER_PART_INDEXED";
120
        case Binding::PerFace:
121
            return "PER_FACE";
122
        case Binding::PerFaceIndexed:
123
            return "PER_FACE_INDEXED";
124
        case Binding::PerVertex:
125
            return "PER_VERTEX";
126
        case Binding::PerVertexIndexed:
127
            return "PER_VERTEX_INDEXED";
128
        default:
129
            return "OVERALL";
130
    }
131
}
132

133
const char* PolygonOffset::styleAsString() const
134
{
135
    switch (style) {
136
        case Style::Filled:
137
            return "FILLED";
138
        case Style::Lines:
139
            return "LINES";
140
        case Style::Points:
141
            return "POINTS";
142
    }
143
    return "FILLED";
144
}
145

146
// -----------------------------------------------------------------------------
147

148
InventorOutput::InventorOutput(std::ostream& result, Indentation& indent)
149
    : result(result)
150
    , indent(indent)
151
{}
152

153
std::ostream& InventorOutput::stream()
154
{
155
    return result;
156
}
157

158
std::ostream& InventorOutput::write()
159
{
160
    result << indent;
161
    return result;
162
}
163

164
std::ostream& InventorOutput::write(const char* str)
165
{
166
    result << indent << str;
167
    return result;
168
}
169

170
std::ostream& InventorOutput::write(const std::string& str)
171
{
172
    result << indent << str;
173
    return result;
174
}
175

176
std::ostream& InventorOutput::writeLine()
177
{
178
    result << indent << '\n';
179
    return result;
180
}
181

182
std::ostream& InventorOutput::writeLine(const char* str)
183
{
184
    result << indent << str << '\n';
185
    return result;
186
}
187

188
std::ostream& InventorOutput::writeLine(const std::string& str)
189
{
190
    result << indent << str << '\n';
191
    return result;
192
}
193

194
void InventorOutput::increaseIndent()
195
{
196
    indent.increaseIndent();
197
}
198

199
void InventorOutput::decreaseIndent()
200
{
201
    indent.decreaseIndent();
202
}
203

204
// -----------------------------------------------------------------------------
205

206
namespace Base
207
{
208
template<class type>
209
struct field_traits
210
{
211
};
212

213
template<>
214
struct field_traits<float>
215
{
216
    using field_type = float;
217
    static std::ostream& write(std::ostream& out, const field_type& item)
218
    {
219
        out << item;
220
        return out;
221
    }
222
};
223

224
template<>
225
struct field_traits<Vector3f>
226
{
227
    using field_type = Vector3f;
228
    static std::ostream& write(std::ostream& out, const field_type& item)
229
    {
230
        out << item.x << " " << item.y << " " << item.z;
231
        return out;
232
    }
233
};
234

235
template<>
236
struct field_traits<ColorRGB>
237
{
238
    using field_type = ColorRGB;
239
    static std::ostream& write(std::ostream& out, const field_type& item)
240
    {
241
        out << item.red() << " " << item.green() << " " << item.blue();
242
        return out;
243
    }
244
};
245

246
/**
247
 * Writes a field type to a stream.
248
 * @author Werner Mayer
249
 */
250
class InventorFieldWriter
251
{
252
public:
253
    template<typename T>
254
    void write(const char* fieldName, const std::vector<T>& fieldData, InventorOutput& out) const;
255
};
256

257
template<typename T>
258
void InventorFieldWriter::write(const char* fieldName,
259
                                const std::vector<T>& fieldData,
260
                                InventorOutput& out) const
261
{
262
    if (fieldData.empty()) {
263
        return;
264
    }
265

266
    if (fieldData.size() == 1) {
267
        out.write() << fieldName << " ";
268
        field_traits<T>::write(out.stream(), fieldData[0]) << '\n';
269
    }
270
    else {
271
        out.write() << fieldName << " [\n";
272
        out.increaseIndent();
273
        for (auto it : fieldData) {
274
            out.write();
275
            field_traits<T>::write(out.stream(), it) << '\n';
276
        }
277
        out.decreaseIndent();
278
        out.write() << "]\n";
279
    }
280
}
281

282
template<>
283
void InventorFieldWriter::write<int>(const char* fieldName,
284
                                     const std::vector<int>& fieldData,
285
                                     InventorOutput& out) const
286
{
287
    if (fieldData.empty()) {
288
        return;
289
    }
290

291
    out.write() << fieldName << " [\n";
292
    out.increaseIndent();
293
    std::size_t last_index {fieldData.size()};
294
    std::size_t index {};
295
    for (auto it : fieldData) {
296
        if (index % 8 == 0) {
297
            out.write();
298
        }
299
        if (index < last_index) {
300
            out.stream() << it << ", ";
301
        }
302
        else {
303
            out.stream() << it << " ] \n";
304
        }
305
        if (++index % 8 == 0) {
306
            out.stream() << '\n';
307
        }
308
    }
309
    out.decreaseIndent();
310
    out.write() << "]\n";
311
}
312
}  // namespace Base
313

314
// -----------------------------------------------------------------------------
315

316
LabelItem::LabelItem(std::string text)
317
    : text(std::move(text))
318
{}
319

320
void LabelItem::write(InventorOutput& out) const
321
{
322
    out.write("Label {\n");
323
    out.write() << "  label \"" << text << "\"\n";
324
    out.write("}\n");
325
}
326

327
// -----------------------------------------------------------------------------
328

329
InfoItem::InfoItem(std::string text)
330
    : text(std::move(text))
331
{}
332

333
void InfoItem::write(InventorOutput& out) const
334
{
335
    out.write("Info {\n");
336
    out.write() << "  string \"" << text << "\"\n";
337
    out.write("}\n");
338
}
339

340
// -----------------------------------------------------------------------------
341

342
BaseColorItem::BaseColorItem(const ColorRGB& rgb)
343
    : rgb(rgb)
344
{}
345

346
void BaseColorItem::write(InventorOutput& out) const
347
{
348
    out.write("BaseColor {\n");
349
    out.write() << "  rgb " << rgb.red() << " " << rgb.green() << " " << rgb.blue() << '\n';
350
    out.write("}\n");
351
}
352

353
// -----------------------------------------------------------------------------
354

355
PointItem::PointItem(const Base::Vector3f& point, DrawStyle drawStyle, const ColorRGB& rgb)
356
    : point(point)
357
    , drawStyle(drawStyle)
358
    , rgb(rgb)
359
{}
360

361
void PointItem::write(InventorOutput& out) const
362
{
363
    out.write() << "Separator { \n";
364
    out.write() << "  Material { \n";
365
    out.write() << "    diffuseColor " << rgb.red() << " " << rgb.green() << " " << rgb.blue()
366
                << '\n';
367
    out.write() << "  }\n";
368
    out.write() << "  MaterialBinding { value PER_PART }\n";
369
    out.write() << "  DrawStyle { pointSize " << drawStyle.pointSize << "}\n";
370
    out.write() << "  Coordinate3 {\n";
371
    out.write() << "    point [ " << point.x << " " << point.y << " " << point.z << "]\n";
372
    out.write() << "  }\n";
373
    out.write() << "  PointSet { }\n";
374
    out.write() << "}\n";
375
}
376

377
// -----------------------------------------------------------------------------
378

379
LineItem::LineItem(const Base::Line3f& line, DrawStyle drawStyle, const ColorRGB& rgb)
380
    : line(line)
381
    , drawStyle(drawStyle)
382
    , rgb(rgb)
383
{}
384

385
void LineItem::write(InventorOutput& out) const
386
{
387
    std::string pattern = drawStyle.patternAsString();
388

389
    out.write("  Separator { \n");
390
    out.write() << "    Material { diffuseColor " << rgb.red() << " " << rgb.green() << " "
391
                << rgb.blue() << "} \n";
392
    out.write() << "    DrawStyle { lineWidth " << drawStyle.lineWidth << " linePattern " << pattern
393
                << " } \n";
394
    out.write() << "    Coordinate3 { \n";
395
    out.write() << "      point [ ";
396
    out.write() << line.p1.x << " " << line.p1.y << " " << line.p1.z << ",";
397
    out.write() << line.p2.x << " " << line.p2.y << " " << line.p2.z;
398
    out.write() << " ] \n";
399
    out.write() << "    } \n";
400
    out.write() << "    LineSet { } \n";
401
    out.write() << "  } \n";
402
}
403

404
// -----------------------------------------------------------------------------
405

406
MultiLineItem::MultiLineItem(std::vector<Vector3f> points, DrawStyle drawStyle, const ColorRGB& rgb)
407
    : points {std::move(points)}
408
    , drawStyle {drawStyle}
409
    , rgb {rgb}
410
{}
411

412
void MultiLineItem::write(InventorOutput& out) const
413
{
414
    std::string pattern = drawStyle.patternAsString();
415

416
    out.write() << "Separator {\n";
417
    out.write() << "  Material { diffuseColor " << rgb.red() << " " << rgb.green() << " "
418
                << rgb.blue() << "}\n";
419
    out.write() << "  DrawStyle { lineWidth " << drawStyle.lineWidth << " linePattern " << pattern
420
                << " }\n";
421
    out.write() << "  Coordinate3 {\n";
422

423
    InventorFieldWriter writer;
424
    writer.write<Vector3f>("point", points, out);
425

426
    out.write() << "  }\n";
427
    out.write() << "  LineSet {\n";
428
    out.write() << "    numVertices [ -1 ]\n";
429
    out.write() << "  }\n";
430
    out.write() << "}\n";
431
}
432

433
// -----------------------------------------------------------------------------
434

435
ArrowItem::ArrowItem(const Base::Line3f& line, DrawStyle drawStyle, const ColorRGB& rgb)
436
    : line(line)
437
    , drawStyle(drawStyle)
438
    , rgb(rgb)
439
{}
440

441
void ArrowItem::write(InventorOutput& out) const
442
{
443
    float length = line.Length();
444
    float coneLength = length / 10.0F;
445
    float coneRadius = coneLength / 2.0F;
446
    float sf1 = length - coneLength;
447
    float sf2 = length - coneLength / 2.0F;
448

449
    Vector3f dir = line.GetDirection();
450
    dir.Normalize();
451
    dir.Scale(sf1, sf1, sf1);
452
    Vector3f pt2s = line.p1 + dir;
453
    dir.Normalize();
454
    dir.Scale(sf2, sf2, sf2);
455
    Vector3f cpt = line.p1 + dir;
456

457
    Vector3f rot = Vector3f(0.0F, 1.0F, 0.0F) % dir;
458
    rot.Normalize();
459
    float angle = Vector3f(0.0F, 1.0F, 0.0F).GetAngle(dir);
460

461
    out.write() << "Separator {\n";
462
    out.write() << "  Material { diffuseColor " << rgb.red() << " " << rgb.green() << " "
463
                << rgb.blue() << "}\n";
464
    out.write() << "  DrawStyle { lineWidth " << drawStyle.lineWidth << " }\n";
465
    out.write() << "  Coordinate3 {\n";
466
    out.write() << "    point [ ";
467
    out.write() << line.p1.x << " " << line.p1.y << " " << line.p1.z << ", ";
468
    out.write() << pt2s.x << " " << pt2s.y << " " << pt2s.z;
469
    out.write() << " ]\n";
470
    out.write() << "  }\n";
471
    out.write() << "  LineSet { }\n";
472
    out.write() << "  Transform { \n";
473
    out.write() << "    translation " << cpt.x << " " << cpt.y << " " << cpt.z << '\n';
474
    out.write() << "    rotation " << rot.x << " " << rot.y << " " << rot.z << " " << angle << '\n';
475
    out.write() << "  }\n";
476
    out.write() << "  Cone { bottomRadius " << coneRadius << " height " << coneLength << "} \n";
477
    out.write() << "}\n";
478
}
479

480
// -----------------------------------------------------------------------------
481

482
BoundingBoxItem::BoundingBoxItem(const Vector3f& pt1,
483
                                 const Vector3f& pt2,
484
                                 DrawStyle drawStyle,
485
                                 const ColorRGB& rgb)
486
    : pt1 {pt1}
487
    , pt2 {pt2}
488
    , drawStyle {drawStyle}
489
    , rgb {rgb}
490
{}
491

492
void BoundingBoxItem::write(InventorOutput& out) const
493
{
494
    std::vector<Base::Vector3f> points(8);
495
    points[0].Set(pt1.x, pt1.y, pt1.z);
496
    points[1].Set(pt1.x, pt1.y, pt2.z);
497
    points[2].Set(pt1.x, pt2.y, pt1.z);
498
    points[3].Set(pt1.x, pt2.y, pt2.z);
499
    points[4].Set(pt2.x, pt1.y, pt1.z);
500
    points[5].Set(pt2.x, pt1.y, pt2.z);
501
    points[6].Set(pt2.x, pt2.y, pt1.z);
502
    points[7].Set(pt2.x, pt2.y, pt2.z);
503

504
    std::vector<int> lineset = {0, 2, 6,  4, 0, -1, 1, 5, 7,  3, 1, -1, 7, 6, 2,
505
                                3, 7, -1, 3, 2, 0,  1, 3, -1, 5, 1, 0,  4, 5, -1};
506

507
    out.write() << "Separator {\n";
508
    out.write() << "  Material { diffuseColor " << rgb.red() << " " << rgb.green() << " "
509
                << rgb.blue() << "}\n";
510
    out.write() << "  DrawStyle { lineWidth " << drawStyle.lineWidth << "}\n";
511

512
    Coordinate3Item coords {points};
513
    out.increaseIndent();
514
    coords.write(out);
515
    out.decreaseIndent();
516

517
    IndexedLineSetItem indexed {lineset};
518
    out.increaseIndent();
519
    indexed.write(out);
520
    out.decreaseIndent();
521

522
    out.write() << "}\n";
523
}
524

525
// -----------------------------------------------------------------------------
526

527
void MaterialItem::setAmbientColor(const std::vector<ColorRGB>& rgb)
528
{
529
    ambientColor = rgb;
530
}
531

532
void MaterialItem::setDiffuseColor(const std::vector<ColorRGB>& rgb)
533
{
534
    diffuseColor = rgb;
535
}
536

537
void MaterialItem::setSpecularColor(const std::vector<ColorRGB>& rgb)
538
{
539
    specularColor = rgb;
540
}
541

542
void MaterialItem::setEmissiveColor(const std::vector<ColorRGB>& rgb)
543
{
544
    emissiveColor = rgb;
545
}
546

547
void MaterialItem::setShininess(const std::vector<float>& value)
548
{
549
    shininess = value;
550
}
551

552
void MaterialItem::setTransparency(const std::vector<float>& value)
553
{
554
    transparency = value;
555
}
556

557
void MaterialItem::write(InventorOutput& out) const
558
{
559
    beginMaterial(out);
560
    writeAmbientColor(out);
561
    writeDiffuseColor(out);
562
    writeSpecularColor(out);
563
    writeEmissiveColor(out);
564
    writeShininess(out);
565
    writeTransparency(out);
566
    endMaterial(out);
567
}
568

569
void MaterialItem::beginMaterial(InventorOutput& out) const
570
{
571
    out.writeLine("Material {");
572
    out.increaseIndent();
573
}
574

575
void MaterialItem::endMaterial(InventorOutput& out) const
576
{
577
    out.decreaseIndent();
578
    out.writeLine("}");
579
}
580

581
void MaterialItem::writeAmbientColor(InventorOutput& out) const
582
{
583
    InventorFieldWriter writer;
584
    writer.write<ColorRGB>("ambientColor", ambientColor, out);
585
}
586

587
void MaterialItem::writeDiffuseColor(InventorOutput& out) const
588
{
589
    InventorFieldWriter writer;
590
    writer.write<ColorRGB>("diffuseColor", diffuseColor, out);
591
}
592

593
void MaterialItem::writeSpecularColor(InventorOutput& out) const
594
{
595
    InventorFieldWriter writer;
596
    writer.write<ColorRGB>("specularColor", specularColor, out);
597
}
598

599
void MaterialItem::writeEmissiveColor(InventorOutput& out) const
600
{
601
    InventorFieldWriter writer;
602
    writer.write<ColorRGB>("emissiveColor", emissiveColor, out);
603
}
604

605
void MaterialItem::writeShininess(InventorOutput& out) const
606
{
607
    InventorFieldWriter writer;
608
    writer.write<float>("shininess", shininess, out);
609
}
610

611
void MaterialItem::writeTransparency(InventorOutput& out) const
612
{
613
    InventorFieldWriter writer;
614
    writer.write<float>("transparency", transparency, out);
615
}
616

617
// -----------------------------------------------------------------------------
618

619
MaterialBindingItem::MaterialBindingItem(BindingElement::Binding bind)
620
{
621
    value.value = bind;
622
}
623

624
void MaterialBindingItem::setValue(BindingElement::Binding bind)
625
{
626
    value.value = bind;
627
}
628

629
void MaterialBindingItem::write(InventorOutput& out) const
630
{
631
    out.write() << "MaterialBinding { value " << value.bindingAsString() << " } \n";
632
}
633

634
// -----------------------------------------------------------------------------
635

636
DrawStyleItem::DrawStyleItem(DrawStyle value)
637
    : style {value}
638
{}
639

640
void DrawStyleItem::setValue(DrawStyle value)
641
{
642
    style = value;
643
}
644

645
void DrawStyleItem::write(InventorOutput& out) const
646
{
647
    out.write() << "DrawStyle {\n";
648
    out.write() << "  style " << style.styleAsString() << '\n';
649
    out.write() << "  pointSize " << style.pointSize << '\n';
650
    out.write() << "  lineWidth " << style.lineWidth << '\n';
651
    out.write() << "  linePattern " << style.patternAsString() << '\n';
652
    out.write() << "}\n";
653
}
654

655
// -----------------------------------------------------------------------------
656

657
ShapeHintsItem::ShapeHintsItem(float creaseAngle)
658
    : creaseAngle(creaseAngle)
659
{}
660

661
void ShapeHintsItem::setVertexOrdering(VertexOrdering::Ordering value)
662
{
663
    vertexOrdering.ordering = value;
664
}
665

666
void ShapeHintsItem::setShapeType(ShapeType::Type value)
667
{
668
    shapeType.type = value;
669
}
670

671
void ShapeHintsItem::write(InventorOutput& out) const
672
{
673
    out.write() << "ShapeHints {\n";
674
    out.write() << "  creaseAngle " << creaseAngle << '\n';
675
    out.write() << "  vertexOrdering " << vertexOrdering.toString() << '\n';
676
    out.write() << "  shapeType " << shapeType.toString() << '\n';
677
    out.write() << "}\n";
678
}
679

680
// -----------------------------------------------------------------------------
681

682
void PolygonOffsetItem::setValue(PolygonOffset value)
683
{
684
    offset = value;
685
}
686

687
void PolygonOffsetItem::write(InventorOutput& out) const
688
{
689
    out.write() << "PolygonOffset {\n";
690
    out.write() << "  factor " << offset.factor << '\n';
691
    out.write() << "  units " << offset.units << '\n';
692
    out.write() << "  styles " << offset.styleAsString() << '\n';
693
    out.write() << "  on " << (offset.on ? "TRUE" : "FALSE") << '\n';
694
    out.write() << "}\n";
695
}
696

697
// -----------------------------------------------------------------------------
698

699
Coordinate3Item::Coordinate3Item(std::vector<Vector3f> points)
700
    : points(std::move(points))
701
{}
702

703
void Coordinate3Item::write(InventorOutput& out) const
704
{
705
    beginPoint(out);
706
    InventorFieldWriter writer;
707
    writer.write<Vector3f>("point", points, out);
708
    endPoint(out);
709
}
710

711
void Coordinate3Item::beginPoint(InventorOutput& out) const
712
{
713
    out.writeLine("Coordinate3 {");
714
    out.increaseIndent();
715
}
716

717
void Coordinate3Item::endPoint(InventorOutput& out) const
718
{
719
    out.decreaseIndent();
720
    out.writeLine("}");
721
}
722

723
// -----------------------------------------------------------------------------
724

725
void PointSetItem::write(InventorOutput& out) const
726
{
727
    out.writeLine("PointSet { }");
728
}
729

730
// -----------------------------------------------------------------------------
731

732
void LineSetItem::write(InventorOutput& out) const
733
{
734
    out.writeLine("LineSet { }");
735
}
736

737
// -----------------------------------------------------------------------------
738

739
FaceSetItem::FaceSetItem(std::vector<int> indices)
740
    : indices(std::move(indices))
741
{}
742

743
void FaceSetItem::write(InventorOutput& out) const
744
{
745
    out.write() << "FaceSet {\n";
746
    out.increaseIndent();
747
    InventorFieldWriter writer;
748
    writer.write<int>("numVertices", indices, out);
749
    out.decreaseIndent();
750
    out.write() << "}\n";
751
}
752

753
// -----------------------------------------------------------------------------
754

755
IndexedLineSetItem::IndexedLineSetItem(std::vector<int> indices)
756
    : indices(std::move(indices))
757
{}
758

759
void IndexedLineSetItem::write(InventorOutput& out) const
760
{
761
    out.write() << "IndexedLineSet {\n";
762
    out.increaseIndent();
763
    InventorFieldWriter writer;
764
    writer.write<int>("coordIndex", indices, out);
765
    out.decreaseIndent();
766
    out.write() << "}\n";
767
}
768

769
// -----------------------------------------------------------------------------
770

771
IndexedFaceSetItem::IndexedFaceSetItem(std::vector<int> indices)
772
    : indices(std::move(indices))
773
{}
774

775
void IndexedFaceSetItem::write(InventorOutput& out) const
776
{
777
    out.write() << "IndexedFaceSet {\n";
778
    out.increaseIndent();
779
    InventorFieldWriter writer;
780
    writer.write<int>("coordIndex", indices, out);
781
    out.decreaseIndent();
782
    out.write() << "}\n";
783
}
784

785
// -----------------------------------------------------------------------------
786

787
NormalItem::NormalItem(std::vector<Base::Vector3f> vec)
788
    : vector(std::move(vec))
789
{}
790

791
void NormalItem::write(InventorOutput& out) const
792
{
793
    beginNormal(out);
794
    InventorFieldWriter writer;
795
    writer.write<Vector3f>("vector", vector, out);
796
    endNormal(out);
797
}
798

799
void NormalItem::beginNormal(InventorOutput& out) const
800
{
801
    out.writeLine("Normal {");
802
    out.increaseIndent();
803
}
804

805
void NormalItem::endNormal(InventorOutput& out) const
806
{
807
    out.decreaseIndent();
808
    out.writeLine("}");
809
}
810

811
// -----------------------------------------------------------------------------
812

813
void NormalBindingItem::setValue(BindingElement::Binding bind)
814
{
815
    value.value = bind;
816
}
817

818
void NormalBindingItem::write(InventorOutput& out) const
819
{
820
    out.write() << "NormalBinding { value " << value.bindingAsString() << " }\n";
821
}
822

823
// -----------------------------------------------------------------------------
824

825
void CylinderItem::setRadius(float value)
826
{
827
    radius = value;
828
}
829

830
void CylinderItem::setHeight(float value)
831
{
832
    height = value;
833
}
834

835
void CylinderItem::write(InventorOutput& out) const
836
{
837
    out.write() << "Cylinder {\n";
838
    out.write() << "  radius " << radius << "\n";
839
    out.write() << "  height " << height << "\n";
840
    out.write() << "  parts (SIDES | TOP | BOTTOM)\n";
841
    out.write() << "}\n";
842
}
843

844
// -----------------------------------------------------------------------------
845

846
void ConeItem::setBottomRadius(float value)
847
{
848
    bottomRadius = value;
849
}
850

851
void ConeItem::setHeight(float value)
852
{
853
    height = value;
854
}
855

856
void ConeItem::write(InventorOutput& out) const
857
{
858
    out.write() << "Cone { bottomRadius " << bottomRadius << " height " << height << " }\n";
859
}
860

861
// -----------------------------------------------------------------------------
862

863
void SphereItem::setRadius(float value)
864
{
865
    radius = value;
866
}
867

868
void SphereItem::write(InventorOutput& out) const
869
{
870
    out.write() << "Sphere { radius " << radius << " }\n";
871
}
872

873
// -----------------------------------------------------------------------------
874

875
void NurbsSurfaceItem::setControlPoints(int numU, int numV)
876
{
877
    numUControlPoints = numU;
878
    numVControlPoints = numV;
879
}
880

881
void NurbsSurfaceItem::setKnotVector(const std::vector<float>& uKnots,
882
                                     const std::vector<float>& vKnots)
883
{
884
    uKnotVector = uKnots;
885
    vKnotVector = vKnots;
886
}
887

888
void NurbsSurfaceItem::write(InventorOutput& out) const
889
{
890
    out.write() << "NurbsSurface {\n";
891
    out.write() << "  numUControlPoints " << numUControlPoints << '\n';
892
    out.write() << "  numVControlPoints " << numVControlPoints << '\n';
893
    out.increaseIndent();
894
    InventorFieldWriter writer;
895
    writer.write<float>("uKnotVector", uKnotVector, out);
896
    writer.write<float>("vKnotVector", vKnotVector, out);
897
    out.decreaseIndent();
898
    out.write() << "}\n";
899
}
900

901
// -----------------------------------------------------------------------------
902

903
Text2Item::Text2Item(std::string string)
904
    : string(std::move(string))
905
{}
906

907
void Text2Item::write(InventorOutput& out) const
908
{
909
    out.write() << "Text2 { string \"" << string << "\" "
910
                << "}\n";
911
}
912

913
// -----------------------------------------------------------------------------
914

915
// NOLINTNEXTLINE
916
TransformItem::TransformItem(const Base::Placement& placement)
917
    : placement(placement)
918
{}
919

920
TransformItem::TransformItem(const Matrix4D& transform)
921
{
922
    placement.fromMatrix(transform);
923
}
924

925
void TransformItem::write(InventorOutput& out) const
926
{
927
    Base::Vector3d translation = placement.getPosition();
928
    Base::Vector3d rotationaxis;
929
    double angle {};
930
    placement.getRotation().getValue(rotationaxis, angle);
931

932
    out.write() << "Transform {\n";
933
    out.write() << "  translation " << translation.x << " " << translation.y << " " << translation.z
934
                << '\n';
935
    out.write() << "  rotation " << rotationaxis.x << " " << rotationaxis.y << " " << rotationaxis.z
936
                << " " << angle << '\n';
937
    out.write() << "}" << '\n';
938
}
939

940
// -----------------------------------------------------------------------------
941

942
InventorBuilder::InventorBuilder(std::ostream& str)
943
    : result(str)
944
{
945
    addHeader();
946
}
947

948
InventorBuilder::~InventorBuilder() = default;
949

950
void InventorBuilder::addHeader()
951
{
952
    result << "#Inventor V2.1 ascii \n\n";
953
}
954

955
void InventorBuilder::increaseIndent()
956
{
957
    indent.increaseIndent();
958
}
959

960
void InventorBuilder::decreaseIndent()
961
{
962
    indent.decreaseIndent();
963
}
964

965
void InventorBuilder::addNode(const NodeItem& node)
966
{
967
    InventorOutput out(result, indent);
968
    node.write(out);
969
}
970

971
void InventorBuilder::beginSeparator()
972
{
973
    result << indent << "Separator { \n";
974
    increaseIndent();
975
}
976

977
void InventorBuilder::endSeparator()
978
{
979
    decreaseIndent();
980
    result << indent << "}\n";
981
}
982

983
// -----------------------------------------------------------------------------
984

985
/**
986
 * A constructor.
987
 * A more elaborate description of the constructor.
988
 */
989
Builder3D::Builder3D()
990
    : result {}
991
    , builder {result}
992
{}
993

994
/**
995
 * A destructor.
996
 * A more elaborate description of the destructor.
997
 */
998
Builder3D::~Builder3D() = default;
999

1000
void Builder3D::clear()
1001
{
1002
    // under gcc stringstream::str() returns a copy not a reference
1003
#if defined(_MSC_VER)
1004
    result.str().clear();
1005
#endif
1006
    result.clear();
1007
}
1008

1009
/**
1010
 * Save the resulting inventor 3D representation to the Console().Log() facility.
1011
 * In DEBUG mode the Gui (if running) will trigger on that and show the representation in
1012
 * the active Viewer/Document. It shows only one representation on time. If you need to
1013
 * show more then one representation use saveToFile() instead.
1014
 * @see saveToFile()
1015
 */
1016
void Builder3D::saveToLog()
1017
{
1018
    ILogger* obs = Base::Console().Get("StatusBar");
1019
    if (obs) {
1020
        obs->SendLog("Builder3D",
1021
                     result.str(),
1022
                     Base::LogStyle::Log,
1023
                     Base::IntendedRecipient::Developer,
1024
                     Base::ContentType::Untranslatable);
1025
    }
1026
}
1027

1028
/**
1029
 * Save the resulting inventor 3D representation to a file. Ending should be *.iv.
1030
 * That enables you to show the result in a Inventor Viewer or in FreeCAD by:
1031
 * /code
1032
 * Gui.document().addAnnotation("Debug","MyFile.iv")
1033
 * /endcode
1034
 * @see saveToFile()
1035
 */
1036
void Builder3D::saveToFile(const char* FileName)
1037
{
1038
    Base::FileInfo fi(FileName);
1039
    Base::ofstream file(fi);
1040
    if (!file) {
1041
        throw FileException("Cannot open file");
1042
    }
1043

1044
    file << result.str();
1045
}
1046

1047
void Builder3D::addNode(const NodeItem& item)
1048
{
1049
    builder.addNode(item);
1050
}
1051

1052
void Builder3D::beginSeparator()
1053
{
1054
    builder.beginSeparator();
1055
}
1056

1057
void Builder3D::endSeparator()
1058
{
1059
    builder.endSeparator();
1060
}
1061

1062
// -----------------------------------------------------------------------------
1063

1064
template<typename T>
1065
std::vector<T> InventorLoader::readData(const char* fieldName) const
1066
{
1067
    std::vector<T> fieldValues;
1068
    std::string str;
1069

1070
    // search for 'fieldName' and '['
1071
    bool found = false;
1072
    while (std::getline(inp, str)) {
1073
        std::string::size_type point = str.find(fieldName);
1074
        std::string::size_type open = str.find('[');
1075
        if (point != std::string::npos && open > point) {
1076
            str = str.substr(open);
1077
            found = true;
1078
            break;
1079
        }
1080
    }
1081

1082
    if (!found) {
1083
        return {};
1084
    }
1085

1086
    do {
1087
        boost::char_separator<char> sep(" ,");
1088
        boost::tokenizer<boost::char_separator<char>> tokens(str, sep);
1089
        std::vector<std::string> token_results;
1090
        token_results.assign(tokens.begin(), tokens.end());
1091

1092
        for (const auto& it : token_results) {
1093
            try {
1094
                T value = boost::lexical_cast<T>(it);
1095
                fieldValues.emplace_back(value);
1096
            }
1097
            catch (const boost::bad_lexical_cast&) {
1098
            }
1099
        }
1100

1101
        // search for ']' to finish the reading
1102
        if (str.find(']') != std::string::npos) {
1103
            break;
1104
        }
1105
    } while (std::getline(inp, str));
1106

1107
    return fieldValues;
1108
}
1109

1110
std::vector<Vector3f> InventorLoader::convert(const std::vector<float>& data) const
1111
{
1112
    if (data.size() % 3 != 0) {
1113
        throw std::string("Reading failed");
1114
    }
1115

1116
    std::size_t len = data.size() / 3;
1117
    std::vector<Vector3f> points;
1118
    points.reserve(len);
1119

1120
    for (std::size_t i = 0; i < len; i++) {
1121
        float x = data[3 * i];
1122
        float y = data[3 * i + 1];
1123
        float z = data[3 * i + 2];
1124
        points.emplace_back(x, y, z);
1125
    }
1126

1127
    return points;
1128
}
1129

1130
std::vector<InventorLoader::Face> InventorLoader::convert(const std::vector<int32_t>& data) const
1131
{
1132
    std::vector<Face> faces;
1133
    faces.reserve(data.size());
1134
    int32_t coordIndex = 0;
1135
    for (const auto it : data) {
1136
        if (it == 3) {
1137
            faces.emplace_back(coordIndex, coordIndex + 1, coordIndex + 2);
1138
        }
1139
        else if (it == 4) {
1140
            faces.emplace_back(coordIndex, coordIndex + 1, coordIndex + 2);
1141
            faces.emplace_back(coordIndex, coordIndex + 2, coordIndex + 3);
1142
        }
1143
        coordIndex += it;
1144
    }
1145
    return faces;
1146
}
1147

1148
std::vector<std::vector<int32_t>> InventorLoader::split(const std::vector<int32_t>& data)
1149
{
1150
    std::vector<std::vector<int32_t>> splitdata;
1151
    std::vector<int32_t>::const_iterator begin = data.cbegin();
1152
    std::vector<int32_t>::const_iterator it = begin;
1153

1154
    while ((it = std::find(begin, data.cend(), -1)) != data.cend()) {
1155
        splitdata.emplace_back(begin, it);
1156
        begin = it;
1157
        std::advance(begin, 1);
1158
    }
1159
    return splitdata;
1160
}
1161

1162
std::vector<InventorLoader::Face>
1163
InventorLoader::convert(const std::vector<std::vector<int32_t>>& coordIndex) const
1164
{
1165
    std::vector<Face> faces;
1166
    faces.reserve(coordIndex.size());
1167
    for (const auto& it : coordIndex) {
1168
        if (it.size() == 3) {
1169
            faces.emplace_back(it[0], it[1], it[2]);
1170
        }
1171
        else if (it.size() == 4) {
1172
            faces.emplace_back(it[0], it[1], it[2]);
1173
            faces.emplace_back(it[0], it[2], it[3]);
1174
        }
1175
    }
1176
    return faces;
1177
}
1178

1179
void InventorLoader::readNormals()
1180
{
1181
    auto data = readData<float>("vector");
1182
    vector = convert(data);
1183
}
1184

1185
void InventorLoader::readCoords()
1186
{
1187
    auto data = readData<float>("point");
1188
    points = convert(data);
1189
}
1190

1191
void InventorLoader::readIndexedFaceSet()
1192
{
1193
    auto data = readData<int32_t>("coordIndex");
1194
    faces = convert(split(data));
1195
}
1196

1197
void InventorLoader::readFaceSet()
1198
{
1199
    auto data = readData<int32_t>("numVertices");
1200
    faces = convert(data);
1201
    isnonindexed = true;
1202
}
1203

1204
bool InventorLoader::read()
1205
{
1206
    if (!inp || inp.bad()) {
1207
        return false;
1208
    }
1209

1210
    std::string line;
1211

1212
    // Verify it's an Inventor 2.1 file
1213
    std::getline(inp, line);
1214
    if (line.find("#Inventor V2.1 ascii") == std::string::npos) {
1215
        return false;
1216
    }
1217

1218
    while (std::getline(inp, line)) {
1219
        // read the normals if they are defined
1220
        if (line.find("Normal {") != std::string::npos) {
1221
            readNormals();
1222
        }
1223
        else if (line.find("Coordinate3 {") != std::string::npos) {
1224
            readCoords();
1225
        }
1226
        else if (line.find("IndexedFaceSet {") != std::string::npos) {
1227
            readIndexedFaceSet();
1228
            break;
1229
        }
1230
        else if (line.find("FaceSet {") != std::string::npos) {
1231
            readFaceSet();
1232
            break;
1233
        }
1234
    }
1235
    return true;
1236
}
1237

1238
bool InventorLoader::isValid() const
1239
{
1240
    int32_t value {static_cast<int32_t>(points.size())};
1241
    auto inRange = [value](const Face& face) {
1242
        if (face.p1 < 0 || face.p1 >= value) {
1243
            return false;
1244
        }
1245
        if (face.p2 < 0 || face.p2 >= value) {
1246
            return false;
1247
        }
1248
        if (face.p3 < 0 || face.p3 >= value) {
1249
            return false;
1250
        }
1251
        return true;
1252
    };
1253

1254
    return std::all_of(faces.cbegin(), faces.cend(), [&inRange](const Face& face) {
1255
        return inRange(face);
1256
    });
1257
}
1258

1259
namespace Base
1260
{
1261
BaseExport Vector3f to_vector(std::string str)
1262
{
1263
    std::string_view view = str;
1264
    if (!boost::starts_with(view, "(") || !boost::ends_with(str, ")")) {
1265
        throw std::runtime_error("string is not a tuple");
1266
    }
1267

1268
    view.remove_prefix(1);
1269
    view.remove_suffix(1);
1270

1271
    str = view;
1272

1273
    boost::char_separator<char> sep(" ,");
1274
    boost::tokenizer<boost::char_separator<char>> tokens(str, sep);
1275
    std::vector<std::string> token_results;
1276
    token_results.assign(tokens.begin(), tokens.end());
1277

1278
    if (token_results.size() != 3) {
1279
        throw std::runtime_error("not a tuple of three floats");
1280
    }
1281

1282
    Base::Vector3f vec;
1283
    vec.x = boost::lexical_cast<float>(token_results.at(0));
1284
    vec.y = boost::lexical_cast<float>(token_results.at(1));
1285
    vec.z = boost::lexical_cast<float>(token_results.at(2));
1286

1287
    return vec;
1288
}
1289

1290
}  // namespace Base
1291

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

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

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

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