File size: 12,308 Bytes
a5ffdcd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/****************************************************************************
**
** This file is part of the LibreCAD project, a 2D CAD program
**
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
**
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file gpl-2.0.txt included in the
** packaging of this file.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
** This copyright notice MUST APPEAR in all copies of the script!
**
**********************************************************************/


#ifndef RS_ENTITYCONTAINER_H
#define RS_ENTITYCONTAINER_H

#include <QList>
#include "rs_entity.h"

/**
 * Class representing a tree of entities.
 * Typical entity containers are graphics, polylines, groups, texts, ...)
 *
 * @author Andrew Mustun
 */
class RS_EntityContainer : public RS_Entity {

public:
    using value_type = RS_Entity * ;

    struct RefInfo{
        RS_Vector ref;
        RS_Entity* entity = nullptr;
    };

    struct LC_SelectionInfo{
        unsigned count = 0;
        double length = 0.0;
    };

    RS_EntityContainer(RS_EntityContainer* parent=nullptr, bool owner=true);
    RS_EntityContainer(const RS_EntityContainer& other);
    RS_EntityContainer(const RS_EntityContainer& other, bool copyChildren);
    RS_EntityContainer& operator = (const RS_EntityContainer& other);
    RS_EntityContainer(RS_EntityContainer&& other);
    RS_EntityContainer& operator = (RS_EntityContainer&& other);
    //RS_EntityContainer(const RS_EntityContainer& ec);

    ~RS_EntityContainer() override;

    RS_Entity* clone() const override;
    virtual void detach();

    /** @return RS2::EntityContainer */
    RS2::EntityType rtti() const override{
        return RS2::EntityContainer;
    }

    void reparent(RS_EntityContainer* parent) override;

    /**
     * @return true: because entities made from this class
	 *         and subclasses are containers for other entities.
     */
    bool isContainer() const override{
        return true;
    }

    /**
     * @return false: because entities made from this class
     *         and subclasses are containers for other entities.
     */
    bool isAtomic() const override{
        return false;
    }

    double getLength() const override;

    void setVisible(bool v) override;

    bool setSelected(bool select=true) override;
    bool toggleSelected() override;

    void setHighlighted(bool on) override;

/*virtual void selectWindow(RS_Vector v1, RS_Vector v2,
   bool select=true, bool cross=false);*/
    virtual void selectWindow(enum RS2::EntityType typeToSelect, RS_Vector v1, RS_Vector v2,
                              bool select=true, bool cross=false);
    virtual void selectWindow(const QList<RS2::EntityType> &typesToSelect, RS_Vector v1, RS_Vector v2,
                              bool select=true, bool cross=false);
    virtual void addEntity(RS_Entity* entity);
    virtual void appendEntity(RS_Entity* entity);
    virtual void prependEntity(RS_Entity* entity);
    virtual void moveEntity(int index, QList<RS_Entity *>& entList);
    void adjustBordersIfNeeded(RS_Entity* entity);
    virtual void insertEntity(int index, RS_Entity* entity);
    virtual bool removeEntity(RS_Entity* entity);

//!
//! \brief addRectangle add four lines to form a rectangle by
//! the diagonal vertices v0,v1
//! \param v0,v1 diagonal vertices of the rectangle
//!
    void addRectangle(RS_Vector const& v0, RS_Vector const& v1);
    void addRectangle(RS_Vector const& v0, RS_Vector const& v1,RS_Vector const& v2, RS_Vector const& v3);

    virtual RS_Entity* firstEntity(RS2::ResolveLevel level=RS2::ResolveNone) const;
    virtual RS_Entity* lastEntity(RS2::ResolveLevel level=RS2::ResolveNone) const;
    virtual RS_Entity* nextEntity(RS2::ResolveLevel level=RS2::ResolveNone) const;
    virtual RS_Entity* prevEntity(RS2::ResolveLevel level=RS2::ResolveNone) const;
    virtual RS_Entity* entityAt(int index) const;
    virtual void setEntityAt(int index,RS_Entity* en);
    virtual int findEntity(RS_Entity const* const entity);
    int findEntityIndex(RS_Entity const* const entity);
    bool areNeighborsEntities(RS_Entity const *const  e1, RS_Entity const *const  e2);
    virtual void clear();

    //virtual unsigned long int count() {
    //	return count(false);
    //}
    virtual bool isEmpty() const {
        return count()==0;
    }
    bool empty() const {
        return isEmpty();
    }
    unsigned count() const override;
    unsigned countDeep() const override;
    size_t size() const
    {
        return m_entities.size();
    }
//virtual unsigned long int countLayerEntities(RS_Layer* layer);
/** \brief countSelected number of selected
* @param deep count sub-containers, if true
* @param types if is not empty, only counts by types listed
*/
    virtual unsigned countSelected(bool deep=true, QList<RS2::EntityType> const& types = {});
    virtual void collectSelected(std::vector<RS_Entity*> &collect, bool deep, QList<RS2::EntityType> const &types = {});
    virtual double totalSelectedLength();
    LC_SelectionInfo getSelectionInfo(/*bool deep, */QList<RS2::EntityType> const& types = {});

    /**
     * Enables / disables automatic update of borders on entity removals
     * and additions. By default this is turned on.
     */
    void setAutoUpdateBorders(bool enable) {
        m_autoUpdateBorders = enable;
    }
    bool getAutoUpdateBorders() const {
        return m_autoUpdateBorders;
    }
    virtual void adjustBorders(RS_Entity* entity);
    void calculateBorders() override;
    void forcedCalculateBorders();
    int updateDimensions( bool autoText=true);
    int updateVisibleDimensions( bool autoText=true);
    virtual void updateInserts();
    virtual void updateSplines();
    void update() override;
    virtual void renameInserts(const QString& oldName,
                               const QString& newName);

    RS_Vector getNearestEndpoint(const RS_Vector& coord,
                                 double* dist = nullptr)const override;
    RS_Vector getNearestEndpoint(const RS_Vector& coord,
                                 double* dist, RS_Entity** pEntity ) const;

    RS_Entity* getNearestEntity(const RS_Vector& point,
                                double* dist = nullptr,
                                RS2::ResolveLevel level=RS2::ResolveAll) const;

    RS_Vector getNearestPointOnEntity(const RS_Vector& coord,
                                      bool onEntity = true,
                                      double* dist = nullptr,
                                      RS_Entity** entity=nullptr)const override;

    RS_Vector getNearestCenter(const RS_Vector& coord,
                               double* dist = nullptr)const override;
    RS_Vector getNearestMiddle(const RS_Vector& coord,
                               double* dist = nullptr,
                               int middlePoints = 1
    )const override;
    RS_Vector getNearestDist(double distance,
                             const RS_Vector& coord,
                             double* dist = nullptr) const override;
    RS_Vector getNearestIntersection(const RS_Vector& coord,
                                     double* dist = nullptr);
    RS_Vector getNearestVirtualIntersection(const RS_Vector& coord,
                                            const double& angle,
                                            double* dist);
    RS_Vector getNearestRef(const RS_Vector& coord,
                            double* dist = nullptr) const override;
    RS_Vector getNearestSelectedRef(const RS_Vector& coord,
                                    double* dist = nullptr) const override;

    RefInfo getNearestSelectedRefInfo(const RS_Vector& coord,
                                      double* dist = nullptr) const;

    double getDistanceToPoint(const RS_Vector& coord,
                              RS_Entity** entity,
                              RS2::ResolveLevel level=RS2::ResolveNone,
                              double solidDist = RS_MAXDOUBLE) const override;

    virtual bool optimizeContours();

    bool hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) const override;

    void move(const RS_Vector& offset) override;
    void rotate(const RS_Vector& center, double angle) override;
    void rotate(const RS_Vector& center, const RS_Vector& angleVector) override;
    void scale(const RS_Vector& center, const RS_Vector& factor) override;
    void mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2a) override;
    RS_Entity& shear(double k) override;

    void stretch(const RS_Vector& firstCorner,
                 const RS_Vector& secondCorner,
                 const RS_Vector& offset) override;
    void calculateBordersIfNeeded();
    void moveRef(const RS_Vector& ref, const RS_Vector& offset) override;
    void moveSelectedRef(const RS_Vector& ref, const RS_Vector& offset) override;
    void revertDirection() override;

    void draw(RS_Painter* painter) override;

    friend std::ostream& operator << (std::ostream& os, RS_EntityContainer& ec);

    bool isOwner() const {return autoDelete;}
    void setOwner(bool owner) {autoDelete=owner;}
    /**
     * @brief areaLineIntegral, line integral for contour area calculation by Green's Theorem
     * Contour Area =\oint x dy
     * @return line integral \oint x dy along the entity
     * returns absolute value
     */
    double areaLineIntegral() const override;
    /**
	 * @brief ignoreForModification ignore this entity for entity catch for certain actions
     * like catching circles to create tangent circles
     * @return, true, indicate this entity container should be ignored
     */
    bool ignoredOnModification() const;

    void push_back(RS_Entity* entity) {
        m_entities.push_back(entity);
    }
    void pop_back() {
        if (!isEmpty())
            m_entities.pop_back();
    }
/**
 * @brief begin/end to support range based loop
 * @return iterator
 */
    QList<RS_Entity *>::const_iterator begin() const;
    QList<RS_Entity *>::const_iterator end() const;
    QList<RS_Entity *>::const_iterator cbegin() const;
    QList<RS_Entity *>::const_iterator cend() const;
    QList<RS_Entity *>::iterator begin() ;
    QList<RS_Entity *>::iterator end() ;
//! \{
//! first and last without resolving into children, assume the container is
//! not empty
    RS_Entity* last() const;
    RS_Entity* first() const;
//! \}

    const QList<RS_Entity*>& getEntityList();
    inline RS_Entity* unsafeEntityAt(int index) const {return m_entities.at(index);}
    void drawAsChild(RS_Painter *painter) override;
    RS_Entity *cloneProxy() const override;
protected:
    /**
     * @brief getLoops for hatch, split closed loops into single simple loops. All returned containers are owned by
     * the returned object.
     * @return std::vector<std::unique_ptr<RS_EntityContainer>> - each container contains edge entities of a single
     * closed loop. Each loop is assumed to be simply closed, and loops never cross each other.
     */
    virtual std::vector<std::unique_ptr<RS_EntityContainer>> getLoops() const;

    /** sub container used only temporarily for iteration. */
    mutable RS_EntityContainer* subContainer = nullptr;
private:
/**
 * @brief ignoredSnap whether snapping is ignored
 * @return true when entity of this container won't be considered for snapping points
 */
    bool ignoredSnap() const;

    /** m_entities in the container */
    QList<RS_Entity *> m_entities;
    /**
     * Automatically update the borders of the container when entities
     * are added or removed.
     */
    bool m_autoUpdateBorders = true;
    mutable int entIdx = 0;
    bool autoDelete = false;
};

#endif