File size: 20,115 Bytes
985c397
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
// SPDX-License-Identifier: LGPL-2.1-or-later

/****************************************************************************

 *                                                                          *

 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>               *

 *   Copyright (c) 2022 Zheng, Lei <realthunder.dev@gmail.com>              *

 *   Copyright (c) 2023 FreeCAD Project Association                         *

 *                                                                          *

 *   This file is part of FreeCAD.                                          *

 *                                                                          *

 *   FreeCAD is free software: you can redistribute it and/or modify it     *

 *   under the terms of the GNU Lesser General Public License as            *

 *   published by the Free Software Foundation, either version 2.1 of the   *

 *   License, or (at your option) any later version.                        *

 *                                                                          *

 *   FreeCAD is distributed in the hope that it will be useful, but         *

 *   WITHOUT ANY WARRANTY; without even the implied warranty of             *

 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU       *

 *   Lesser General Public License for more details.                        *

 *                                                                          *

 *   You should have received a copy of the GNU Lesser General Public       *

 *   License along with FreeCAD. If not, see                                *

 *   <https://www.gnu.org/licenses/>.                                       *

 *                                                                          *

 ***************************************************************************/


#ifndef APP_COMPLEX_GEO_DATA_H
#define APP_COMPLEX_GEO_DATA_H

#include <algorithm>
#include <optional>

#include <Base/Handle.h>
#include <Base/Matrix.h>
#include <Base/Persistence.h>
#include "MappedName.h"
#include "MappedElement.h"
#include "ElementMap.h"
#include "StringHasher.h"

#ifdef __GNUC__
#include <cstdint>
#endif


namespace Base
{
class Placement;
class Rotation;
template<class _Precision>
class BoundBox3;  // NOLINT
using BoundBox3d = BoundBox3<double>;
}  // namespace Base

namespace Data
{

// struct MappedChildElements;
/// Option for App::GeoFeature::searchElementCache()
enum class SearchOption

{
    /// Whether to compare shape geometry
    CheckGeometry = 1,
    SingleResult = 2,
};
typedef Base::Flags<SearchOption> SearchOptions;

/** Segments

 *  Sub-element type of the ComplexGeoData type

 *  It is used to split an object in further sub-parts.

 */
class AppExport Segment: public Base::BaseClass
{
    TYPESYSTEM_HEADER_WITH_OVERRIDE();  // NOLINT

public:
    ~Segment() override = default;
    virtual std::string getName() const = 0;
};

enum ElementMapResetPolicy

{
    AllowNoMap,
    ForceEmptyMap
};

/** ComplexGeoData Object

 */
class AppExport ComplexGeoData: public Base::Persistence, public Base::Handled
{
    TYPESYSTEM_HEADER_WITH_OVERRIDE();  // NOLINT

public:
    struct Line

    {
        uint32_t I1;
        uint32_t I2;
    };
    struct Facet

    {
        uint32_t I1;
        uint32_t I2;
        uint32_t I3;
    };
    struct Domain

    {
        std::vector<Base::Vector3d> points;
        std::vector<Facet> facets;
    };

    /// Constructor
    ComplexGeoData();
    /// Destructor
    ~ComplexGeoData() override = default;

    /** @name Sub-element management */
    //@{
    /** Sub type list

     *  List of different sub-element types

     *  its NOT a list of the sub-elements itself

     */
    virtual std::vector<const char*> getElementTypes() const = 0;
    virtual unsigned long countSubElements(const char* Type) const = 0;
    /// Returns a generic element type and index. The determined element type isn't
    /// necessarily supported by this geometry.
    static std::pair<std::string, unsigned long> getTypeAndIndex(const char* Name);
    /// get the sub-element by type and number
    virtual Segment* getSubElement(const char* Type, unsigned long) const = 0;
    /// get sub-element by combined name
    virtual Segment* getSubElementByName(const char* Name) const;
    /** Get lines from segment */
    virtual void getLinesFromSubElement(const Segment*,

                                        std::vector<Base::Vector3d>& Points,

                                        std::vector<Line>& lines) const;
    /** Get faces from segment */
    virtual void getFacesFromSubElement(const Segment*,

                                        std::vector<Base::Vector3d>& Points,

                                        std::vector<Base::Vector3d>& PointNormals,

                                        std::vector<Facet>& faces) const;
    //@}

    /** @name Placement control */
    //@{
    /** Applies an additional transformation to the current transformation. */
    void applyTransform(const Base::Matrix4D& rclTrf);
    /** Applies an additional translation to the current transformation. */
    void applyTranslation(const Base::Vector3d&);
    /** Applies an additional rotation to the current transformation. */
    void applyRotation(const Base::Rotation&);
    /** Override the current transformation with a placement

     * using the setTransform() method.

     */
    void setPlacement(const Base::Placement& rclPlacement);
    /** Return the current transformation as placement using

     * getTransform().

     */
    Base::Placement getPlacement() const;
    /** Override the current transformation with the new one.

     * This method has to be handled by the child classes.

     * the actual placement and matrix is not part of this class.

     */
    virtual void setTransform(const Base::Matrix4D& rclTrf) = 0;
    /** Return the current matrix

     * This method has to be handled by the child classes.

     * the actual placement and matrix is not part of this class.

     */
    virtual Base::Matrix4D getTransform() const = 0;
    //@}

    /** @name Modification */
    //@{
    /// Applies a transformation on the real geometric data type
    virtual void transformGeometry(const Base::Matrix4D& rclMat) = 0;
    //@}

    /** @name Getting basic geometric entities */
    //@{
    /// Get the standard accuracy to be used with getPoints, getLines or getFaces
    virtual double getAccuracy() const;
    /// Get the bound box
    virtual Base::BoundBox3d getBoundBox() const = 0;
    /** Get point from line object intersection  */
    virtual Base::Vector3d getPointFromLineIntersection(const Base::Vector3f& base,

                                                        const Base::Vector3f& dir) const;
    /** Get points from object with given accuracy */
    virtual void getPoints(std::vector<Base::Vector3d>& Points,

                           std::vector<Base::Vector3d>& Normals,

                           double Accuracy,

                           uint16_t flags = 0) const;
    /** Get lines from object with given accuracy */
    virtual void getLines(std::vector<Base::Vector3d>& Points,

                          std::vector<Line>& lines,

                          double Accuracy,

                          uint16_t flags = 0) const;
    /** Get faces from object with given accuracy */
    virtual void getFaces(std::vector<Base::Vector3d>& Points,

                          std::vector<Facet>& faces,

                          double Accuracy,

                          uint16_t flags = 0) const;
    /** Get the center of gravity

     * If this method is implemented then true is returned and the center of gravity.

     * The default implementation only returns false.

     */
    virtual bool getCenterOfGravity(Base::Vector3d& center) const;
    virtual std::optional<Base::Vector3d> centerOfGravity() const;
    //@}

    static const std::string& elementMapPrefix();

    /** @name Element name mapping */
    //@{

    /** Get element indexed name

     *

     * @param name: the input name

     * @param sid: optional output of and App::StringID involved forming this mapped name

     *

     * @return Returns an indexed name.

     */
    IndexedName getIndexedName(const MappedName& name, ElementIDRefs* sid = nullptr) const;

    /** Get element mapped name

     *

     * @param name: the input name

     * @param allowUnmapped: If the queried element is not mapped, then return

     *                       an empty name if \c allowUnmapped is false, or

     *                       else, return the indexed name.

     * @param sid: optional output of and App::StringID involved forming this mapped name

     * @return Returns the mapped name.

     */
    MappedName getMappedName(const IndexedName& element,

                             bool allowUnmapped = false,

                             ElementIDRefs* sid = nullptr) const;

    /** Return a pair of indexed name and mapped name

     *

     * @param name: the input name.

     * @param sid: optional output of any App::StringID involved in forming

     *             this mapped name

     * @param copy: if true, copy the name string, or else use it as constant

     *              string, and caller must make sure the memory is not freed.

     *

     * @return Returns the MappedElement which contains both the indexed and

     * mapped name.

     *

     * This function guesses whether the input name is an indexed name or

     * mapped, and perform a lookup and return the names found. If the input

     * name contains only alphabets and underscore followed by optional digits,

     * it will be treated as indexed name. Or else, it will be treated as

     * mapped name.

     */
    MappedElement
    getElementName(const char* name, ElementIDRefs* sid = nullptr, bool copy = false) const;

    /** Add a sub-element name mapping.

     *

     * @param element: the original \c Type + \c Index element name

     * @param name: the mapped sub-element name. May or may not start with

     * elementMapPrefix().

     * @param sid: in case you use a hasher to hash the element name, pass in

     * the string id reference using this parameter. You can have more than one

     * string id associated with the same name.

     * @param overwrite: if true, it will overwrite existing names

     *

     * @return Returns the stored mapped element name.

     *

     * An element can have multiple mapped names. However, a name can only be

     * mapped to one element

     *

     * Note: the original proc was in the context of ComplexGeoData, which provided `Tag` access,

     *   now you must pass in `long masterTag` explicitly.

     */
    MappedName setElementName(const IndexedName& element,

                              const MappedName& name,

                              long masterTag,

                              const ElementIDRefs* sid = nullptr,

                              bool overwrite = false)
    {
        return _elementMap->setElementName(element, name, masterTag, sid, overwrite);
    }

    bool hasElementMap() const
    {
        return _elementMap != nullptr;
    }

    /** Get mapped element names

     *

     * @param element: original element name with \c Type + \c Index

     * @param needUnmapped: if true, return the original element name if no

     * mapping is found

     *

     * @return a list of mapped names of the give element along with their

     * associated string ID references

     */
    std::vector<std::pair<MappedName, ElementIDRefs>>
    getElementMappedNames(const IndexedName& element, bool needUnmapped = false) const;

    /// Hash the child element map postfixes to shorten element name from hierarchical maps
    void hashChildMaps();

    /// Check if there is child element map
    bool hasChildElementMap() const;

    /// Append the Tag (if and only if it is non zero) into the element map
    virtual void
    reTagElementMap(long tag, App::StringHasherRef hasher, const char* postfix = nullptr)
    {
        (void)tag;
        (void)hasher;
        (void)postfix;
    }

    // NOTE: getElementHistory is now in ElementMap
    long getElementHistory(const MappedName& name,

                           MappedName* original = nullptr,

                           std::vector<MappedName>* history = nullptr) const
    {
        if (_elementMap != nullptr) {
            return _elementMap->getElementHistory(name, Tag, original, history);
        }
        return 0;
    };

    void setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements>& children);
    std::vector<Data::ElementMap::MappedChildElements> getMappedChildElements() const;

    char elementType(const Data::MappedName&) const;
    char elementType(const Data::IndexedName&) const;
    char elementType(const char* name) const;

    /** Reset/swap the element map

     *

     * @param elementMap: optional new element map

     *

     * @return Returns the existing element map.

     */
    virtual ElementMapPtr resetElementMap(ElementMapPtr elementMap = ElementMapPtr());

    /// Get the entire element map
    std::vector<MappedElement> getElementMap() const;

    /// Set the entire element map
    void setElementMap(const std::vector<MappedElement>& elements);

    /// Get the current element map size
    size_t getElementMapSize(bool flush = true) const;

    /// Return the higher level element names of the given element
    virtual std::vector<IndexedName> getHigherElements(const char* name, bool silent = false) const;

    /// Return the current element map version
    virtual std::string getElementMapVersion() const;

    /// Return true to signal element map version change
    virtual bool checkElementMapVersion(const char* ver) const;

    /// Check if the given sub-name only contains an element name
    static bool isElementName(const char* subName)
    {
        return (subName != nullptr) && (*subName != 0) && findElementName(subName) == subName;
    }

    /** Iterate through the history of the give element name with a given callback

     *

     * @param name: the input element name

     * @param cb: trace callback with call signature.

     * @sa TraceCallback

     */
    void traceElement(const MappedName& name, TraceCallback cb) const
    {
        _elementMap->traceElement(name, Tag, std::move(cb));
    }

    /** Flush an internal buffering for element mapping */
    virtual void flushElementMap() const;
    //@}

    /** @name Save/restore */
    //@{
    void Save(Base::Writer& writer) const override;
    void Restore(Base::XMLReader& reader) override;
    void SaveDocFile(Base::Writer& writer) const override;
    void RestoreDocFile(Base::Reader& reader) override;
    unsigned int getMemSize() const override;
    void setPersistenceFileName(const char* name) const;
    virtual void beforeSave() const;
    bool isRestoreFailed() const
    {
        return _restoreFailed;
    }
    void resetRestoreFailure() const
    {
        _restoreFailed = true;
    }
    //@}

    /**

     * Debugging method to dump an entire element map in human readable form to a stream

     * @param stream

     */
    void dumpElementMap(std::ostream& stream) const;
    /**

     * Debugging method to dump an entire element map in human readable form into a string

     * @return The string

     */
    const std::string dumpElementMap() const;

protected:
    /// from local to outside
    inline Base::Vector3d transformPointToOutside(const Base::Vector3f& vec) const
    {
        // clang-format off
        return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
                                               static_cast<double>(vec.y),
                                               static_cast<double>(vec.z));
        // clang-format on
    }
    /// from local to outside
    template<typename Vec>
    inline std::vector<Base::Vector3d> transformPointsToOutside(const std::vector<Vec>& input) const
    {
        // clang-format off
        std::vector<Base::Vector3d> output;
        output.reserve(input.size());
        Base::Matrix4D mat(getTransform());
        std::transform(input.cbegin(), input.cend(), std::back_inserter(output),
                       [&mat](const Vec& vec) {
                           return mat * Base::Vector3d(static_cast<double>(vec.x),
                                                       static_cast<double>(vec.y),
                                                       static_cast<double>(vec.z));
                       });

        return output;
        // clang-format on
    }
    inline Base::Vector3d transformVectorToOutside(const Base::Vector3f& vec) const
    {
        // clang-format off
        Base::Matrix4D mat(getTransform());
        mat.setCol(3, Base::Vector3d());
        return mat * Base::Vector3d(static_cast<double>(vec.x),
                                   static_cast<double>(vec.y),
                                   static_cast<double>(vec.z));
        // clang-format on
    }
    template<typename Vec>
    std::vector<Base::Vector3d> transformVectorsToOutside(const std::vector<Vec>& input) const
    {
        // clang-format off
        std::vector<Base::Vector3d> output;
        output.reserve(input.size());
        Base::Matrix4D mat(getTransform());
        mat.setCol(3, Base::Vector3d());
        std::transform(input.cbegin(), input.cend(), std::back_inserter(output),
                       [&mat](const Vec& vec) {
                           return mat * Base::Vector3d(static_cast<double>(vec.x),
                                                       static_cast<double>(vec.y),
                                                       static_cast<double>(vec.z));
                       });

        return output;
        // clang-format on
    }
    /// from local to inside
    inline Base::Vector3f transformPointToInside(const Base::Vector3d& vec) const
    {
        Base::Matrix4D tmpM(getTransform());
        tmpM.inverse();
        Base::Vector3d tmp = tmpM * vec;
        return Base::Vector3f(static_cast<float>(tmp.x),
                              static_cast<float>(tmp.y),
                              static_cast<float>(tmp.z));
    }

public:
    mutable long Tag {0};

    /// String hasher for element name shortening
    mutable App::StringHasherRef Hasher;

protected:
    void restoreStream(std::istream& stream, std::size_t count);
    void readElements(Base::XMLReader& reader, size_t count);

    /// from local to outside
    inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
    {
        // clang-format off
        return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
                                               static_cast<double>(vec.y),
                                               static_cast<double>(vec.z));
        // clang-format on
    }
    /// from local to inside
    inline Base::Vector3f transformToInside(const Base::Vector3d& vec) const
    {
        Base::Matrix4D tmpM(getTransform());
        tmpM.inverse();
        Base::Vector3d tmp = tmpM * vec;
        return Base::Vector3f(static_cast<float>(tmp.x),
                              static_cast<float>(tmp.y),
                              static_cast<float>(tmp.z));
    }

protected:
    ElementMapPtr elementMap(bool flush = true) const;
    ElementMapPtr ensureElementMap(bool flush = true);

private:
    ElementMapPtr _elementMap;

protected:
    mutable std::string _persistenceName;
    mutable bool _restoreFailed = false;
};

}  // namespace Data

ENABLE_BITMASK_OPERATORS(Data::SearchOption)
#endif