~librecad-dev/librecad/librecad

« back to all changes in this revision

Viewing changes to librecad/src/lib/engine/rs_entitycontainer.cpp

  • Committer: Scott Howard
  • Date: 2014-02-21 19:07:55 UTC
  • Revision ID: showard@debian.org-20140221190755-csjax9wb146hgdq4
first commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** This file is part of the LibreCAD project, a 2D CAD program
 
4
**
 
5
** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
 
6
** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
 
7
**
 
8
**
 
9
** This file may be distributed and/or modified under the terms of the
 
10
** GNU General Public License version 2 as published by the Free Software
 
11
** Foundation and appearing in the file gpl-2.0.txt included in the
 
12
** packaging of this file.
 
13
**
 
14
** This program is distributed in the hope that it will be useful,
 
15
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
** GNU General Public License for more details.
 
18
**
 
19
** You should have received a copy of the GNU General Public License
 
20
** along with this program; if not, write to the Free Software
 
21
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
22
**
 
23
** This copyright notice MUST APPEAR in all copies of the script!
 
24
**
 
25
**********************************************************************/
 
26
 
 
27
 
 
28
#include <QDebug>
 
29
#include "rs_entitycontainer.h"
 
30
 
 
31
#include "rs_debug.h"
 
32
#include "rs_dimension.h"
 
33
#include "rs_layer.h"
 
34
#include "rs_line.h"
 
35
#include "rs_insert.h"
 
36
#include "rs_spline.h"
 
37
#include "rs_solid.h"
 
38
#include "rs_information.h"
 
39
#include "rs_graphicview.h"
 
40
 
 
41
#if QT_VERSION < 0x040400
 
42
#include "emu_qt44.h"
 
43
#endif
 
44
 
 
45
bool RS_EntityContainer::autoUpdateBorders = true;
 
46
 
 
47
/**
 
48
 * Default constructor.
 
49
 *
 
50
 * @param owner True if we own and also delete the entities.
 
51
 */
 
52
RS_EntityContainer::RS_EntityContainer(RS_EntityContainer* parent,
 
53
                                       bool owner)
 
54
    : RS_Entity(parent) {
 
55
 
 
56
    autoDelete=owner;
 
57
    RS_DEBUG->print("RS_EntityContainer::RS_EntityContainer: "
 
58
                    "owner: %d", (int)owner);
 
59
    subContainer = NULL;
 
60
    //autoUpdateBorders = true;
 
61
    entIdx = -1;
 
62
}
 
63
 
 
64
 
 
65
/**
 
66
 * Copy constructor. Makes a deep copy of all entities.
 
67
 */
 
68
/*
 
69
RS_EntityContainer::RS_EntityContainer(const RS_EntityContainer& ec)
 
70
 : RS_Entity(ec) {
 
71
 
 
72
}
 
73
*/
 
74
 
 
75
 
 
76
 
 
77
/**
 
78
 * Destructor.
 
79
 */
 
80
RS_EntityContainer::~RS_EntityContainer() {
 
81
    clear();
 
82
}
 
83
 
 
84
 
 
85
 
 
86
RS_Entity* RS_EntityContainer::clone() {
 
87
    RS_DEBUG->print("RS_EntityContainer::clone: ori autoDel: %d",
 
88
                    autoDelete);
 
89
 
 
90
    RS_EntityContainer* ec = new RS_EntityContainer(*this);
 
91
    ec->setOwner(autoDelete);
 
92
 
 
93
    RS_DEBUG->print("RS_EntityContainer::clone: clone autoDel: %d",
 
94
                    ec->isOwner());
 
95
 
 
96
    ec->detach();
 
97
    ec->initId();
 
98
 
 
99
    return ec;
 
100
}
 
101
 
 
102
 
 
103
 
 
104
/**
 
105
 * Detaches shallow copies and creates deep copies of all subentities.
 
106
 * This is called after cloning entity containers.
 
107
 */
 
108
void RS_EntityContainer::detach() {
 
109
    QList<RS_Entity*> tmp;
 
110
    bool autoDel = isOwner();
 
111
    RS_DEBUG->print("RS_EntityContainer::detach: autoDel: %d",
 
112
                    (int)autoDel);
 
113
    setOwner(false);
 
114
 
 
115
    // make deep copies of all entities:
 
116
    for (RS_Entity* e=firstEntity();
 
117
         e!=NULL;
 
118
         e=nextEntity()) {
 
119
        if (!e->getFlag(RS2::FlagTemp)) {
 
120
            tmp.append(e->clone());
 
121
        }
 
122
    }
 
123
 
 
124
    // clear shared pointers:
 
125
    entities.clear();
 
126
    setOwner(autoDel);
 
127
 
 
128
    // point to new deep copies:
 
129
    for (int i = 0; i < tmp.size(); ++i) {
 
130
        RS_Entity* e = tmp.at(i);
 
131
        entities.append(e);
 
132
        e->reparent(this);
 
133
    }
 
134
}
 
135
 
 
136
 
 
137
 
 
138
void RS_EntityContainer::reparent(RS_EntityContainer* parent) {
 
139
    RS_Entity::reparent(parent);
 
140
 
 
141
    // All sub-entities:
 
142
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
143
         e!=NULL;
 
144
         e=nextEntity(RS2::ResolveNone)) {
 
145
        e->reparent(parent);
 
146
    }
 
147
}
 
148
 
 
149
 
 
150
 
 
151
/**
 
152
 * Called when the undo state changed. Forwards the event to all sub-entities.
 
153
 *
 
154
 * @param undone true: entity has become invisible.
 
155
 *               false: entity has become visible.
 
156
 */
 
157
void RS_EntityContainer::undoStateChanged(bool undone) {
 
158
 
 
159
    RS_Entity::undoStateChanged(undone);
 
160
 
 
161
    // ! don't pass on to subentities. undo list handles them
 
162
    // All sub-entities:
 
163
    /*for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
164
            e!=NULL;
 
165
            e=nextEntity(RS2::ResolveNone)) {
 
166
        e->setUndoState(undone);
 
167
}*/
 
168
}
 
169
 
 
170
 
 
171
 
 
172
void RS_EntityContainer::setVisible(bool v) {
 
173
    //    RS_DEBUG->print("RS_EntityContainer::setVisible: %d", v);
 
174
    RS_Entity::setVisible(v);
 
175
 
 
176
    // All sub-entities:
 
177
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
178
         e!=NULL;
 
179
         e=nextEntity(RS2::ResolveNone)) {
 
180
        //        RS_DEBUG->print("RS_EntityContainer::setVisible: subentity: %d", v);
 
181
        e->setVisible(v);
 
182
    }
 
183
}
 
184
 
 
185
 
 
186
 
 
187
/**
 
188
 * @return Total length of all entities in this container.
 
189
 */
 
190
double RS_EntityContainer::getLength() const {
 
191
    double ret = 0.0;
 
192
 
 
193
    for (RS_Entity* e=const_cast<RS_EntityContainer*>(this)->firstEntity(RS2::ResolveNone);
 
194
         e!=NULL;
 
195
         e=const_cast<RS_EntityContainer*>(this)->nextEntity(RS2::ResolveNone)) {
 
196
        if (e->isVisible()) {
 
197
            double l = e->getLength();
 
198
            if (l<0.0) {
 
199
                ret = -1.0;
 
200
                break;
 
201
            } else {
 
202
                ret += l;
 
203
            }
 
204
        }
 
205
    }
 
206
 
 
207
    return ret;
 
208
}
 
209
 
 
210
 
 
211
/**
 
212
 * Selects this entity.
 
213
 */
 
214
bool RS_EntityContainer::setSelected(bool select) {
 
215
    // This entity's select:
 
216
    if (RS_Entity::setSelected(select)) {
 
217
 
 
218
        // All sub-entity's select:
 
219
        for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
220
             e!=NULL;
 
221
             e=nextEntity(RS2::ResolveNone)) {
 
222
            if (e->isVisible()) {
 
223
                e->setSelected(select);
 
224
            }
 
225
        }
 
226
        return true;
 
227
    } else {
 
228
        return false;
 
229
    }
 
230
}
 
231
 
 
232
 
 
233
 
 
234
/**
 
235
 * Toggles select on this entity.
 
236
 */
 
237
bool RS_EntityContainer::toggleSelected() {
 
238
    // Toggle this entity's select:
 
239
    if (RS_Entity::toggleSelected()) {
 
240
 
 
241
        // Toggle all sub-entity's select:
 
242
        /*for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
243
                e!=NULL;
 
244
                e=nextEntity(RS2::ResolveNone)) {
 
245
            e->toggleSelected();
 
246
    }*/
 
247
        return true;
 
248
    } else {
 
249
        return false;
 
250
    }
 
251
}
 
252
 
 
253
 
 
254
 
 
255
/**
 
256
 * Selects all entities within the given area.
 
257
 *
 
258
 * @param select True to select, False to deselect the entities.
 
259
 */
 
260
void RS_EntityContainer::selectWindow(RS_Vector v1, RS_Vector v2,
 
261
                                      bool select, bool cross) {
 
262
 
 
263
    bool included;
 
264
 
 
265
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
266
         e!=NULL;
 
267
         e=nextEntity(RS2::ResolveNone)) {
 
268
 
 
269
        included = false;
 
270
 
 
271
        if (e->isVisible()) {
 
272
            if (e->isInWindow(v1, v2)) {
 
273
                //e->setSelected(select);
 
274
                included = true;
 
275
            } else if (cross==true) {
 
276
                RS_Line l[] =
 
277
                {
 
278
                    RS_Line(NULL, RS_LineData(v1, RS_Vector(v2.x, v1.y))),
 
279
                    RS_Line(NULL, RS_LineData(RS_Vector(v2.x, v1.y), v2)),
 
280
                    RS_Line(NULL, RS_LineData(v2, RS_Vector(v1.x, v2.y))),
 
281
                    RS_Line(NULL, RS_LineData(RS_Vector(v1.x, v2.y), v1))
 
282
                };
 
283
                RS_VectorSolutions sol;
 
284
 
 
285
                if (e->isContainer()) {
 
286
                    RS_EntityContainer* ec = (RS_EntityContainer*)e;
 
287
                    for (RS_Entity* se=ec->firstEntity(RS2::ResolveAll);
 
288
                         se!=NULL && included==false;
 
289
                         se=ec->nextEntity(RS2::ResolveAll)) {
 
290
 
 
291
                        if (se->rtti() == RS2::EntitySolid){
 
292
                            included = ((RS_Solid *)se)->isInCrossWindow(v1,v2);
 
293
                        } else {
 
294
                            for (int i=0; i<4; ++i) {
 
295
                                sol = RS_Information::getIntersection(
 
296
                                            se, &l[i], true);
 
297
                                if (sol.hasValid()) {
 
298
                                    included = true;
 
299
                                    break;
 
300
                                }
 
301
                            }
 
302
                        }
 
303
                    }
 
304
                } else if (e->rtti() == RS2::EntitySolid){
 
305
                    included = ((RS_Solid *)e)->isInCrossWindow(v1,v2);
 
306
                } else {
 
307
                    for (int i=0; i<4; ++i) {
 
308
                        sol = RS_Information::getIntersection(e, &l[i], true);
 
309
                        if (sol.hasValid()) {
 
310
                            included = true;
 
311
                            break;
 
312
                        }
 
313
                    }
 
314
                }
 
315
            }
 
316
        }
 
317
 
 
318
        if (included) {
 
319
            e->setSelected(select);
 
320
        }
 
321
    }
 
322
}
 
323
 
 
324
 
 
325
 
 
326
/**
 
327
 * Adds a entity to this container and updates the borders of this
 
328
 * entity-container if autoUpdateBorders is true.
 
329
 */
 
330
void RS_EntityContainer::addEntity(RS_Entity* entity) {
 
331
    /*
 
332
       if (isDocument()) {
 
333
           RS_LayerList* lst = getDocument()->getLayerList();
 
334
           if (lst!=NULL) {
 
335
               RS_Layer* l = lst->getActive();
 
336
               if (l!=NULL && l->isLocked()) {
 
337
                   return;
 
338
               }
 
339
           }
 
340
       }
 
341
    */
 
342
 
 
343
    if (entity==NULL) {
 
344
        return;
 
345
    }
 
346
 
 
347
    if (entity->rtti()==RS2::EntityImage ||
 
348
            entity->rtti()==RS2::EntityHatch) {
 
349
        entities.prepend(entity);
 
350
    } else {
 
351
        entities.append(entity);
 
352
    }
 
353
    if (autoUpdateBorders) {
 
354
        adjustBorders(entity);
 
355
    }
 
356
}
 
357
 
 
358
 
 
359
/**
 
360
 * Insert a entity at the end of entities list and updates the
 
361
 * borders of this entity-container if autoUpdateBorders is true.
 
362
 */
 
363
void RS_EntityContainer::appendEntity(RS_Entity* entity){
 
364
    if (entity==NULL)
 
365
        return;
 
366
    entities.append(entity);
 
367
    if (autoUpdateBorders)
 
368
        adjustBorders(entity);
 
369
}
 
370
 
 
371
/**
 
372
 * Insert a entity at the start of entities list and updates the
 
373
 * borders of this entity-container if autoUpdateBorders is true.
 
374
 */
 
375
void RS_EntityContainer::prependEntity(RS_Entity* entity){
 
376
    if (entity==NULL)
 
377
        return;
 
378
    entities.prepend(entity);
 
379
    if (autoUpdateBorders)
 
380
        adjustBorders(entity);
 
381
}
 
382
 
 
383
/**
 
384
 * Move a entity list in this container at the given position,
 
385
 * the borders of this entity-container if autoUpdateBorders is true.
 
386
 */
 
387
void RS_EntityContainer::moveEntity(int index, QList<RS_Entity *> entList){
 
388
    if (entList.isEmpty()) return;
 
389
    int ci = 0; //current index for insert without invert order
 
390
    bool ret, into = false;
 
391
    RS_Entity *mid = NULL;
 
392
    if (index < 1) {
 
393
        ci = 0;
 
394
    } else if (index >= entities.size() ) {
 
395
        ci = entities.size() - entList.size();
 
396
    } else {
 
397
        into = true;
 
398
        mid = entities.at(index);
 
399
    }
 
400
 
 
401
    for (int i = 0; i < entList.size(); ++i) {
 
402
        RS_Entity *e = entList.at(i);
 
403
        ret = entities.removeOne(e);
 
404
        //if e not exist in entities list remove from entList
 
405
        if (!ret) {
 
406
            entList.removeAt(i);
 
407
        }
 
408
    }
 
409
    if (into) {
 
410
        ci = entities.indexOf(mid);
 
411
    }
 
412
 
 
413
    for (int i = 0; i < entList.size(); ++i) {
 
414
        RS_Entity *e = entList.at(i);
 
415
            entities.insert(ci++, e);
 
416
    }
 
417
}
 
418
 
 
419
/**
 
420
 * Inserts a entity to this container at the given position and updates
 
421
 * the borders of this entity-container if autoUpdateBorders is true.
 
422
 */
 
423
void RS_EntityContainer::insertEntity(int index, RS_Entity* entity) {
 
424
    if (entity==NULL) {
 
425
        return;
 
426
    }
 
427
 
 
428
    entities.insert(index, entity);
 
429
 
 
430
    if (autoUpdateBorders) {
 
431
        adjustBorders(entity);
 
432
    }
 
433
}
 
434
 
 
435
 
 
436
 
 
437
/**
 
438
 * Replaces the entity at the given index with the given entity
 
439
 * and updates the borders of this entity-container if autoUpdateBorders is true.
 
440
 */
 
441
/*RLZ unused function
 
442
void RS_EntityContainer::replaceEntity(int index, RS_Entity* entity) {
 
443
//RLZ TODO: is needed to delete the old entity? not documented in Q3PtrList
 
444
//    investigate in qt3support code if reactivate this function.
 
445
    if (entity==NULL) {
 
446
        return;
 
447
    }
 
448
 
 
449
    entities.replace(index, entity);
 
450
 
 
451
    if (autoUpdateBorders) {
 
452
        adjustBorders(entity);
 
453
    }
 
454
}RLZ*/
 
455
 
 
456
 
 
457
 
 
458
/**
 
459
 * Removes an entity from this container and updates the borders of
 
460
 * this entity-container if autoUpdateBorders is true.
 
461
 */
 
462
bool RS_EntityContainer::removeEntity(RS_Entity* entity) {
 
463
    //RLZ TODO: in Q3PtrList if 'entity' is NULL remove the current item-> at.(entIdx)
 
464
    //    and sets 'entIdx' in next() or last() if 'entity' is the last item in the list.
 
465
    //    in LibreCAD is never called with NULL
 
466
    bool ret;
 
467
#if QT_VERSION < 0x040400
 
468
    ret = emu_qt44_removeOne(entities, entity);
 
469
#else
 
470
    ret = entities.removeOne(entity);
 
471
#endif
 
472
 
 
473
    if (autoDelete && ret) {
 
474
        delete entity;
 
475
    }
 
476
    if (autoUpdateBorders) {
 
477
        calculateBorders();
 
478
    }
 
479
    return ret;
 
480
}
 
481
 
 
482
 
 
483
 
 
484
/**
 
485
 * Erases all entities in this container and resets the borders..
 
486
 */
 
487
void RS_EntityContainer::clear() {
 
488
    if (autoDelete) {
 
489
        while (!entities.isEmpty())
 
490
            delete entities.takeFirst();
 
491
    } else
 
492
        entities.clear();
 
493
    resetBorders();
 
494
}
 
495
 
 
496
 
 
497
/**
 
498
 * Counts all entities (branches of the tree).
 
499
 */
 
500
unsigned int RS_EntityContainer::count() {
 
501
    return entities.size();
 
502
}
 
503
unsigned int RS_EntityContainer::count() const{
 
504
    return entities.size();
 
505
}
 
506
 
 
507
 
 
508
/**
 
509
 * Counts all entities (leaves of the tree).
 
510
 */
 
511
unsigned int RS_EntityContainer::countDeep() {
 
512
    unsigned long int c=0;
 
513
 
 
514
    for (RS_Entity* t=firstEntity(RS2::ResolveNone);
 
515
         t!=NULL;
 
516
         t=nextEntity(RS2::ResolveNone)) {
 
517
        c+=t->countDeep();
 
518
    }
 
519
 
 
520
    return c;
 
521
}
 
522
 
 
523
 
 
524
 
 
525
/**
 
526
 * Counts the selected entities in this container.
 
527
 */
 
528
unsigned int RS_EntityContainer::countSelected() {
 
529
    unsigned int c=0;
 
530
 
 
531
    for (RS_Entity* t=firstEntity(RS2::ResolveNone);
 
532
         t!=NULL;
 
533
         t=nextEntity(RS2::ResolveNone)) {
 
534
 
 
535
        if (t->isSelected()) {
 
536
            c++;
 
537
        }
 
538
    }
 
539
 
 
540
    return c;
 
541
}
 
542
 
 
543
/**
 
544
 * Counts the selected entities in this container.
 
545
 */
 
546
double RS_EntityContainer::totalSelectedLength() {
 
547
    double ret(0.0);
 
548
    for (RS_Entity* e = firstEntity(RS2::ResolveNone);
 
549
         e != NULL;
 
550
         e = nextEntity(RS2::ResolveNone)) {
 
551
 
 
552
        if (e->isVisible() && e->isSelected()) {
 
553
            double l = e->getLength();
 
554
            if (l>=0.) {
 
555
                ret += l;
 
556
            }
 
557
        }
 
558
    }
 
559
    return ret;
 
560
}
 
561
 
 
562
 
 
563
/**
 
564
 * Adjusts the borders of this graphic (max/min values)
 
565
 */
 
566
void RS_EntityContainer::adjustBorders(RS_Entity* entity) {
 
567
    //RS_DEBUG->print("RS_EntityContainer::adjustBorders");
 
568
    //resetBorders();
 
569
 
 
570
    if (entity!=NULL) {
 
571
        // make sure a container is not empty (otherwise the border
 
572
        //   would get extended to 0/0):
 
573
        if (!entity->isContainer() || entity->count()>0) {
 
574
            minV = RS_Vector::minimum(entity->getMin(),minV);
 
575
            maxV = RS_Vector::maximum(entity->getMax(),maxV);
 
576
        }
 
577
 
 
578
        // Notify parents. The border for the parent might
 
579
        // also change TODO: Check for efficiency
 
580
        //if(parent!=NULL) {
 
581
        //parent->adjustBorders(this);
 
582
        //}
 
583
    }
 
584
}
 
585
 
 
586
 
 
587
/**
 
588
 * Recalculates the borders of this entity container.
 
589
 */
 
590
void RS_EntityContainer::calculateBorders() {
 
591
    RS_DEBUG->print("RS_EntityContainer::calculateBorders");
 
592
 
 
593
    resetBorders();
 
594
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
595
         e!=NULL;
 
596
         e=nextEntity(RS2::ResolveNone)) {
 
597
 
 
598
        RS_Layer* layer = e->getLayer();
 
599
 
 
600
        //        RS_DEBUG->print("RS_EntityContainer::calculateBorders: "
 
601
        //                        "isVisible: %d", (int)e->isVisible());
 
602
 
 
603
        if (e->isVisible() && (layer==NULL || !layer->isFrozen())) {
 
604
            e->calculateBorders();
 
605
            adjustBorders(e);
 
606
        }
 
607
    }
 
608
 
 
609
    RS_DEBUG->print("RS_EntityContainer::calculateBorders: size 1: %f,%f",
 
610
                    getSize().x, getSize().y);
 
611
 
 
612
    // needed for correcting corrupt data (PLANS.dxf)
 
613
    if (minV.x>maxV.x || minV.x>RS_MAXDOUBLE || maxV.x>RS_MAXDOUBLE
 
614
            || minV.x<RS_MINDOUBLE || maxV.x<RS_MINDOUBLE) {
 
615
 
 
616
        minV.x = 0.0;
 
617
        maxV.x = 0.0;
 
618
    }
 
619
    if (minV.y>maxV.y || minV.y>RS_MAXDOUBLE || maxV.y>RS_MAXDOUBLE
 
620
            || minV.y<RS_MINDOUBLE || maxV.y<RS_MINDOUBLE) {
 
621
 
 
622
        minV.y = 0.0;
 
623
        maxV.y = 0.0;
 
624
    }
 
625
 
 
626
    RS_DEBUG->print("RS_EntityCotnainer::calculateBorders: size: %f,%f",
 
627
                    getSize().x, getSize().y);
 
628
 
 
629
    //RS_DEBUG->print("  borders: %f/%f %f/%f", minV.x, minV.y, maxV.x, maxV.y);
 
630
 
 
631
    //printf("borders: %lf/%lf  %lf/%lf\n", minV.x, minV.y, maxV.x, maxV.y);
 
632
    //RS_Entity::calculateBorders();
 
633
}
 
634
 
 
635
 
 
636
 
 
637
/**
 
638
 * Recalculates the borders of this entity container including
 
639
 * invisible entities.
 
640
 */
 
641
void RS_EntityContainer::forcedCalculateBorders() {
 
642
    //RS_DEBUG->print("RS_EntityContainer::calculateBorders");
 
643
 
 
644
    resetBorders();
 
645
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
646
         e!=NULL;
 
647
         e=nextEntity(RS2::ResolveNone)) {
 
648
 
 
649
        //RS_Layer* layer = e->getLayer();
 
650
 
 
651
        if (e->isContainer()) {
 
652
            ((RS_EntityContainer*)e)->forcedCalculateBorders();
 
653
        } else {
 
654
            e->calculateBorders();
 
655
        }
 
656
        adjustBorders(e);
 
657
    }
 
658
 
 
659
    // needed for correcting corrupt data (PLANS.dxf)
 
660
    if (minV.x>maxV.x || minV.x>RS_MAXDOUBLE || maxV.x>RS_MAXDOUBLE
 
661
            || minV.x<RS_MINDOUBLE || maxV.x<RS_MINDOUBLE) {
 
662
 
 
663
        minV.x = 0.0;
 
664
        maxV.x = 0.0;
 
665
    }
 
666
    if (minV.y>maxV.y || minV.y>RS_MAXDOUBLE || maxV.y>RS_MAXDOUBLE
 
667
            || minV.y<RS_MINDOUBLE || maxV.y<RS_MINDOUBLE) {
 
668
 
 
669
        minV.y = 0.0;
 
670
        maxV.y = 0.0;
 
671
    }
 
672
 
 
673
    //RS_DEBUG->print("  borders: %f/%f %f/%f", minV.x, minV.y, maxV.x, maxV.y);
 
674
 
 
675
    //printf("borders: %lf/%lf  %lf/%lf\n", minV.x, minV.y, maxV.x, maxV.y);
 
676
    //RS_Entity::calculateBorders();
 
677
}
 
678
 
 
679
 
 
680
 
 
681
/**
 
682
 * Updates all Dimension entities in this container and / or
 
683
 * reposition their labels.
 
684
 *
 
685
 * @param autoText Automatically reposition the text label bool autoText=true
 
686
 */
 
687
void RS_EntityContainer::updateDimensions(bool autoText) {
 
688
 
 
689
    RS_DEBUG->print("RS_EntityContainer::updateDimensions()");
 
690
 
 
691
    //for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
692
    //        e!=NULL;
 
693
    //        e=nextEntity(RS2::ResolveNone)) {
 
694
 
 
695
    RS_Entity* e;
 
696
    for (int i = 0; i < entities.size(); ++i) {
 
697
        e = entities.at(i);
 
698
        if (RS_Information::isDimension(e->rtti())) {
 
699
            // update and reposition label:
 
700
            ((RS_Dimension*)e)->updateDim(autoText);
 
701
        } else if (e->isContainer()) {
 
702
            ((RS_EntityContainer*)e)->updateDimensions(autoText);
 
703
        }
 
704
    }
 
705
 
 
706
    RS_DEBUG->print("RS_EntityContainer::updateDimensions() OK");
 
707
}
 
708
 
 
709
 
 
710
 
 
711
/**
 
712
 * Updates all Insert entities in this container.
 
713
 */
 
714
void RS_EntityContainer::updateInserts() {
 
715
 
 
716
    RS_DEBUG->print("RS_EntityContainer::updateInserts()");
 
717
 
 
718
    //for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
719
    //        e!=NULL;
 
720
    //        e=nextEntity(RS2::ResolveNone)) {
 
721
    RS_Entity* e;
 
722
    for (int i = 0; i < entities.size(); ++i) {
 
723
        e = entities.at(i);
 
724
        //// Only update our own inserts and not inserts of inserts
 
725
        if (e->rtti()==RS2::EntityInsert  /*&& e->getParent()==this*/) {
 
726
            ((RS_Insert*)e)->update();
 
727
        } else if (e->isContainer() && e->rtti()!=RS2::EntityHatch) {
 
728
            ((RS_EntityContainer*)e)->updateInserts();
 
729
        }
 
730
    }
 
731
 
 
732
    RS_DEBUG->print("RS_EntityContainer::updateInserts() OK");
 
733
}
 
734
 
 
735
 
 
736
 
 
737
/**
 
738
 * Renames all inserts with name 'oldName' to 'newName'. This is
 
739
 *   called after a block was rename to update the inserts.
 
740
 */
 
741
void RS_EntityContainer::renameInserts(const QString& oldName,
 
742
                                       const QString& newName) {
 
743
    RS_DEBUG->print("RS_EntityContainer::renameInserts()");
 
744
 
 
745
    //for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
746
    //        e!=NULL;
 
747
    //        e=nextEntity(RS2::ResolveNone)) {
 
748
 
 
749
    RS_Entity* e;
 
750
    for (int j = 0; j < entities.size(); ++j) {
 
751
        e = entities.at(j);
 
752
        if (e->rtti()==RS2::EntityInsert) {
 
753
            RS_Insert* i = ((RS_Insert*)e);
 
754
            if (i->getName()==oldName) {
 
755
                i->setName(newName);
 
756
            }
 
757
        } else if (e->isContainer()) {
 
758
            ((RS_EntityContainer*)e)->renameInserts(oldName, newName);
 
759
        }
 
760
    }
 
761
 
 
762
    RS_DEBUG->print("RS_EntityContainer::renameInserts() OK");
 
763
 
 
764
}
 
765
 
 
766
 
 
767
 
 
768
/**
 
769
 * Updates all Spline entities in this container.
 
770
 */
 
771
void RS_EntityContainer::updateSplines() {
 
772
 
 
773
    RS_DEBUG->print("RS_EntityContainer::updateSplines()");
 
774
 
 
775
    //for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
776
    //        e!=NULL;
 
777
    //        e=nextEntity(RS2::ResolveNone)) {
 
778
    RS_Entity* e;
 
779
    for (int i = 0; i < entities.size(); ++i) {
 
780
        e = entities.at(i);
 
781
        //// Only update our own inserts and not inserts of inserts
 
782
        if (e->rtti()==RS2::EntitySpline  /*&& e->getParent()==this*/) {
 
783
            ((RS_Spline*)e)->update();
 
784
        } else if (e->isContainer() && e->rtti()!=RS2::EntityHatch) {
 
785
            ((RS_EntityContainer*)e)->updateSplines();
 
786
        }
 
787
    }
 
788
 
 
789
    RS_DEBUG->print("RS_EntityContainer::updateSplines() OK");
 
790
}
 
791
 
 
792
 
 
793
/**
 
794
 * Updates the sub entities of this container.
 
795
 */
 
796
void RS_EntityContainer::update() {
 
797
    //for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
798
    //        e!=NULL;
 
799
    //        e=nextEntity(RS2::ResolveNone)) {
 
800
    for (int i = 0; i < entities.size(); ++i) {
 
801
        entities.at(i)->update();
 
802
    }
 
803
}
 
804
 
 
805
 
 
806
 
 
807
/**
 
808
 * Returns the first entity or NULL if this graphic is empty.
 
809
 * @param level
 
810
 */
 
811
RS_Entity* RS_EntityContainer::firstEntity(RS2::ResolveLevel level) {
 
812
    RS_Entity* e = NULL;
 
813
    entIdx = -1;
 
814
    switch (level) {
 
815
    case RS2::ResolveNone:
 
816
        if (!entities.isEmpty()) {
 
817
            entIdx = 0;
 
818
            return entities.first();
 
819
        }
 
820
        break;
 
821
 
 
822
    case RS2::ResolveAllButInserts: {
 
823
        subContainer=NULL;
 
824
        if (!entities.isEmpty()) {
 
825
            entIdx = 0;
 
826
            e = entities.first();
 
827
        }
 
828
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityInsert) {
 
829
            subContainer = (RS_EntityContainer*)e;
 
830
            e = ((RS_EntityContainer*)e)->firstEntity(level);
 
831
            // emtpy container:
 
832
            if (e==NULL) {
 
833
                subContainer = NULL;
 
834
                e = nextEntity(level);
 
835
            }
 
836
        }
 
837
        return e;
 
838
    }
 
839
        break;
 
840
 
 
841
    case RS2::ResolveAllButTextImage:
 
842
    case RS2::ResolveAllButTexts: {
 
843
        subContainer=NULL;
 
844
        if (!entities.isEmpty()) {
 
845
            entIdx = 0;
 
846
            e = entities.first();
 
847
        }
 
848
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityText && e->rtti()!=RS2::EntityMText) {
 
849
            subContainer = (RS_EntityContainer*)e;
 
850
            e = ((RS_EntityContainer*)e)->firstEntity(level);
 
851
            // emtpy container:
 
852
            if (e==NULL) {
 
853
                subContainer = NULL;
 
854
                e = nextEntity(level);
 
855
            }
 
856
        }
 
857
        return e;
 
858
    }
 
859
        break;
 
860
 
 
861
    case RS2::ResolveAll: {
 
862
        subContainer=NULL;
 
863
        if (!entities.isEmpty()) {
 
864
            entIdx = 0;
 
865
            e = entities.first();
 
866
        }
 
867
        if (e!=NULL && e->isContainer()) {
 
868
            subContainer = (RS_EntityContainer*)e;
 
869
            e = ((RS_EntityContainer*)e)->firstEntity(level);
 
870
            // emtpy container:
 
871
            if (e==NULL) {
 
872
                subContainer = NULL;
 
873
                e = nextEntity(level);
 
874
            }
 
875
        }
 
876
        return e;
 
877
    }
 
878
        break;
 
879
    }
 
880
 
 
881
    return NULL;
 
882
}
 
883
 
 
884
 
 
885
 
 
886
/**
 
887
 * Returns the last entity or \p NULL if this graphic is empty.
 
888
 *
 
889
 * @param level \li \p 0 Groups are not resolved
 
890
 *              \li \p 1 (default) only Groups are resolved
 
891
 *              \li \p 2 all Entity Containers are resolved
 
892
 */
 
893
RS_Entity* RS_EntityContainer::lastEntity(RS2::ResolveLevel level) {
 
894
    RS_Entity* e = NULL;
 
895
    entIdx = entities.size()-1;
 
896
    switch (level) {
 
897
    case RS2::ResolveNone:
 
898
        if (!entities.isEmpty())
 
899
            return entities.last();
 
900
        break;
 
901
 
 
902
    case RS2::ResolveAllButInserts: {
 
903
        if (!entities.isEmpty())
 
904
            e = entities.last();
 
905
        subContainer = NULL;
 
906
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityInsert) {
 
907
            subContainer = (RS_EntityContainer*)e;
 
908
            e = ((RS_EntityContainer*)e)->lastEntity(level);
 
909
        }
 
910
        return e;
 
911
    }
 
912
        break;
 
913
    case RS2::ResolveAllButTextImage:
 
914
    case RS2::ResolveAllButTexts: {
 
915
        if (!entities.isEmpty())
 
916
            e = entities.last();
 
917
        subContainer = NULL;
 
918
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityText && e->rtti()!=RS2::EntityMText) {
 
919
            subContainer = (RS_EntityContainer*)e;
 
920
            e = ((RS_EntityContainer*)e)->lastEntity(level);
 
921
        }
 
922
        return e;
 
923
    }
 
924
        break;
 
925
 
 
926
    case RS2::ResolveAll: {
 
927
        if (!entities.isEmpty())
 
928
            e = entities.last();
 
929
        subContainer = NULL;
 
930
        if (e!=NULL && e->isContainer()) {
 
931
            subContainer = (RS_EntityContainer*)e;
 
932
            e = ((RS_EntityContainer*)e)->lastEntity(level);
 
933
        }
 
934
        return e;
 
935
    }
 
936
        break;
 
937
    }
 
938
 
 
939
    return NULL;
 
940
}
 
941
 
 
942
 
 
943
/**
 
944
 * Returns the next entity or container or \p NULL if the last entity
 
945
 * returned by \p next() was the last entity in the container.
 
946
 */
 
947
RS_Entity* RS_EntityContainer::nextEntity(RS2::ResolveLevel level) {
 
948
 
 
949
    //set entIdx pointing in next entity and check if is out of range
 
950
    ++entIdx;
 
951
    switch (level) {
 
952
    case RS2::ResolveNone:
 
953
        if ( entIdx < entities.size() )
 
954
            return entities.at(entIdx);
 
955
        break;
 
956
 
 
957
    case RS2::ResolveAllButInserts: {
 
958
        RS_Entity* e=NULL;
 
959
        if (subContainer!=NULL) {
 
960
            e = subContainer->nextEntity(level);
 
961
            if (e!=NULL) {
 
962
                --entIdx; //return a sub-entity, index not advanced
 
963
                return e;
 
964
            } else {
 
965
                if ( entIdx < entities.size() )
 
966
                    e = entities.at(entIdx);
 
967
            }
 
968
        } else {
 
969
            if ( entIdx < entities.size() )
 
970
                e = entities.at(entIdx);
 
971
        }
 
972
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityInsert) {
 
973
            subContainer = (RS_EntityContainer*)e;
 
974
            e = ((RS_EntityContainer*)e)->firstEntity(level);
 
975
            // emtpy container:
 
976
            if (e==NULL) {
 
977
                subContainer = NULL;
 
978
                e = nextEntity(level);
 
979
            }
 
980
        }
 
981
        return e;
 
982
    }
 
983
        break;
 
984
 
 
985
    case RS2::ResolveAllButTextImage:
 
986
    case RS2::ResolveAllButTexts: {
 
987
        RS_Entity* e=NULL;
 
988
        if (subContainer!=NULL) {
 
989
            e = subContainer->nextEntity(level);
 
990
            if (e!=NULL) {
 
991
                --entIdx; //return a sub-entity, index not advanced
 
992
                return e;
 
993
            } else {
 
994
                if ( entIdx < entities.size() )
 
995
                    e = entities.at(entIdx);
 
996
            }
 
997
        } else {
 
998
            if ( entIdx < entities.size() )
 
999
                e = entities.at(entIdx);
 
1000
        }
 
1001
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityText && e->rtti()!=RS2::EntityMText ) {
 
1002
            subContainer = (RS_EntityContainer*)e;
 
1003
            e = ((RS_EntityContainer*)e)->firstEntity(level);
 
1004
            // emtpy container:
 
1005
            if (e==NULL) {
 
1006
                subContainer = NULL;
 
1007
                e = nextEntity(level);
 
1008
            }
 
1009
        }
 
1010
        return e;
 
1011
    }
 
1012
        break;
 
1013
 
 
1014
    case RS2::ResolveAll: {
 
1015
        RS_Entity* e=NULL;
 
1016
        if (subContainer!=NULL) {
 
1017
            e = subContainer->nextEntity(level);
 
1018
            if (e!=NULL) {
 
1019
                --entIdx; //return a sub-entity, index not advanced
 
1020
                return e;
 
1021
            } else {
 
1022
                if ( entIdx < entities.size() )
 
1023
                    e = entities.at(entIdx);
 
1024
            }
 
1025
        } else {
 
1026
            if ( entIdx < entities.size() )
 
1027
                e = entities.at(entIdx);
 
1028
        }
 
1029
        if (e!=NULL && e->isContainer()) {
 
1030
            subContainer = (RS_EntityContainer*)e;
 
1031
            e = ((RS_EntityContainer*)e)->firstEntity(level);
 
1032
            // emtpy container:
 
1033
            if (e==NULL) {
 
1034
                subContainer = NULL;
 
1035
                e = nextEntity(level);
 
1036
            }
 
1037
        }
 
1038
        return e;
 
1039
    }
 
1040
        break;
 
1041
    }
 
1042
    return NULL;
 
1043
}
 
1044
 
 
1045
 
 
1046
 
 
1047
/**
 
1048
 * Returns the prev entity or container or \p NULL if the last entity
 
1049
 * returned by \p prev() was the first entity in the container.
 
1050
 */
 
1051
RS_Entity* RS_EntityContainer::prevEntity(RS2::ResolveLevel level) {
 
1052
    //set entIdx pointing in prev entity and check if is out of range
 
1053
    --entIdx;
 
1054
    switch (level) {
 
1055
 
 
1056
    case RS2::ResolveNone:
 
1057
        if (entIdx >= 0)
 
1058
            return entities.at(entIdx);
 
1059
        break;
 
1060
 
 
1061
    case RS2::ResolveAllButInserts: {
 
1062
        RS_Entity* e=NULL;
 
1063
        if (subContainer!=NULL) {
 
1064
            e = subContainer->prevEntity(level);
 
1065
            if (e!=NULL) {
 
1066
                return e;
 
1067
            } else {
 
1068
                if (entIdx >= 0)
 
1069
                    e = entities.at(entIdx);
 
1070
            }
 
1071
        } else {
 
1072
            if (entIdx >= 0)
 
1073
                e = entities.at(entIdx);
 
1074
        }
 
1075
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityInsert) {
 
1076
            subContainer = (RS_EntityContainer*)e;
 
1077
            e = ((RS_EntityContainer*)e)->lastEntity(level);
 
1078
            // emtpy container:
 
1079
            if (e==NULL) {
 
1080
                subContainer = NULL;
 
1081
                e = prevEntity(level);
 
1082
            }
 
1083
        }
 
1084
        return e;
 
1085
    }
 
1086
 
 
1087
    case RS2::ResolveAllButTextImage:
 
1088
    case RS2::ResolveAllButTexts: {
 
1089
        RS_Entity* e=NULL;
 
1090
        if (subContainer!=NULL) {
 
1091
            e = subContainer->prevEntity(level);
 
1092
            if (e!=NULL) {
 
1093
                return e;
 
1094
            } else {
 
1095
                if (entIdx >= 0)
 
1096
                    e = entities.at(entIdx);
 
1097
            }
 
1098
        } else {
 
1099
            if (entIdx >= 0)
 
1100
                e = entities.at(entIdx);
 
1101
        }
 
1102
        if (e!=NULL && e->isContainer() && e->rtti()!=RS2::EntityText && e->rtti()!=RS2::EntityMText) {
 
1103
            subContainer = (RS_EntityContainer*)e;
 
1104
            e = ((RS_EntityContainer*)e)->lastEntity(level);
 
1105
            // emtpy container:
 
1106
            if (e==NULL) {
 
1107
                subContainer = NULL;
 
1108
                e = prevEntity(level);
 
1109
            }
 
1110
        }
 
1111
        return e;
 
1112
    }
 
1113
 
 
1114
    case RS2::ResolveAll: {
 
1115
        RS_Entity* e=NULL;
 
1116
        if (subContainer!=NULL) {
 
1117
            e = subContainer->prevEntity(level);
 
1118
            if (e!=NULL) {
 
1119
                ++entIdx; //return a sub-entity, index not advanced
 
1120
                return e;
 
1121
            } else {
 
1122
                if (entIdx >= 0)
 
1123
                    e = entities.at(entIdx);
 
1124
            }
 
1125
        } else {
 
1126
            if (entIdx >= 0)
 
1127
                e = entities.at(entIdx);
 
1128
        }
 
1129
        if (e!=NULL && e->isContainer()) {
 
1130
            subContainer = (RS_EntityContainer*)e;
 
1131
            e = ((RS_EntityContainer*)e)->lastEntity(level);
 
1132
            // emtpy container:
 
1133
            if (e==NULL) {
 
1134
                subContainer = NULL;
 
1135
                e = prevEntity(level);
 
1136
            }
 
1137
        }
 
1138
        return e;
 
1139
    }
 
1140
    }
 
1141
    return NULL;
 
1142
}
 
1143
 
 
1144
 
 
1145
 
 
1146
/**
 
1147
 * @return Entity at the given index or NULL if the index is out of range.
 
1148
 */
 
1149
RS_Entity* RS_EntityContainer::entityAt(int index) {
 
1150
    if (entities.size() > index && index >= 0)
 
1151
        return entities.at(index);
 
1152
    else
 
1153
        return NULL;
 
1154
}
 
1155
 
 
1156
 
 
1157
 
 
1158
/**
 
1159
 * @return Current index.
 
1160
 */
 
1161
/*RLZ unused
 
1162
int RS_EntityContainer::entityAt() {
 
1163
    return entIdx;
 
1164
} RLZ unused*/
 
1165
 
 
1166
 
 
1167
/**
 
1168
 * Finds the given entity and makes it the current entity if found.
 
1169
 */
 
1170
int RS_EntityContainer::findEntity(RS_Entity* entity) {
 
1171
    entIdx = entities.indexOf(entity);
 
1172
    return entIdx;
 
1173
}
 
1174
 
 
1175
 
 
1176
 
 
1177
/**
 
1178
 * Returns the copy to a new iterator for traversing the entities.
 
1179
 */
 
1180
QListIterator<RS_Entity*> RS_EntityContainer::createIterator() {
 
1181
    return QListIterator<RS_Entity*>(entities);
 
1182
}
 
1183
 
 
1184
 
 
1185
/**
 
1186
 * @return The point which is closest to 'coord'
 
1187
 * (one of the vertexes)
 
1188
 */
 
1189
RS_Vector RS_EntityContainer::getNearestEndpoint(const RS_Vector& coord,
 
1190
                                                 double* dist  )const {
 
1191
 
 
1192
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1193
    double curDist;                 // currently measured distance
 
1194
    RS_Vector closestPoint(false);  // closest found endpoint
 
1195
    RS_Vector point;                // endpoint found
 
1196
 
 
1197
    //QListIterator<RS_Entity> it = createIterator();
 
1198
    //RS_Entity* en;
 
1199
    //while ( (en = it.current()) != NULL ) {
 
1200
    //    ++it;
 
1201
    for (RS_Entity* en = const_cast<RS_EntityContainer*>(this)->firstEntity();
 
1202
         en != NULL;
 
1203
         en = const_cast<RS_EntityContainer*>(this)->nextEntity()) {
 
1204
 
 
1205
        if (en->isVisible()
 
1206
                //&& en->getParent()->rtti() != RS2::EntityInsert         /**Insert*/
 
1207
                //&& en->rtti() != RS2::EntityPoint         /**Point*/
 
1208
                //&& en->getParent()->rtti() != RS2::EntitySpline
 
1209
                //&& en->getParent()->rtti() != RS2::EntityMText        /**< Text 15*/
 
1210
                //&& en->getParent()->rtti() != RS2::EntityText         /**< Text 15*/
 
1211
                && en->getParent()->rtti() != RS2::EntityDimAligned   /**< Aligned Dimension */
 
1212
                && en->getParent()->rtti() != RS2::EntityDimLinear    /**< Linear Dimension */
 
1213
                && en->getParent()->rtti() != RS2::EntityDimRadial    /**< Radial Dimension */
 
1214
                && en->getParent()->rtti() != RS2::EntityDimDiametric /**< Diametric Dimension */
 
1215
                && en->getParent()->rtti() != RS2::EntityDimAngular   /**< Angular Dimension */
 
1216
                && en->getParent()->rtti() != RS2::EntityDimLeader    /**< Leader Dimension */
 
1217
                ){//no end point for Insert, text, Dim
 
1218
            point = en->getNearestEndpoint(coord, &curDist);
 
1219
            if (point.valid && curDist<minDist) {
 
1220
                closestPoint = point;
 
1221
                minDist = curDist;
 
1222
                if (dist!=NULL) {
 
1223
                    *dist = curDist;
 
1224
                }
 
1225
            }
 
1226
        }
 
1227
    }
 
1228
 
 
1229
    return closestPoint;
 
1230
}
 
1231
 
 
1232
 
 
1233
 
 
1234
/**
 
1235
 * @return The point which is closest to 'coord'
 
1236
 * (one of the vertexes)
 
1237
 */
 
1238
RS_Vector RS_EntityContainer::getNearestEndpoint(const RS_Vector& coord,
 
1239
                                                 double* dist,  RS_Entity** pEntity)const {
 
1240
 
 
1241
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1242
    double curDist;                 // currently measured distance
 
1243
    RS_Vector closestPoint(false);  // closest found endpoint
 
1244
    RS_Vector point;                // endpoint found
 
1245
 
 
1246
    //QListIterator<RS_Entity> it = createIterator();
 
1247
    //RS_Entity* en;
 
1248
    //while ( (en = it.current()) != NULL ) {
 
1249
    //    ++it;
 
1250
 
 
1251
    unsigned i0=0;
 
1252
    for (RS_Entity* en = const_cast<RS_EntityContainer*>(this)->firstEntity();
 
1253
         en != NULL;
 
1254
         en = const_cast<RS_EntityContainer*>(this)->nextEntity()) {
 
1255
 
 
1256
 
 
1257
        if (/*en->isVisible()*/
 
1258
                //&& en->getParent()->rtti() != RS2::EntityInsert         /**Insert*/
 
1259
                //&& en->rtti() != RS2::EntityPoint         /**Point*/
 
1260
                //&& en->getParent()->rtti() != RS2::EntitySpline
 
1261
                //&& en->getParent()->rtti() != RS2::EntityMText        /**< Text 15*/
 
1262
                //&& en->getParent()->rtti() != RS2::EntityText         /**< Text 15*/
 
1263
                /*&&*/ en->getParent()->rtti() != RS2::EntityDimAligned   /**< Aligned Dimension */
 
1264
                && en->getParent()->rtti() != RS2::EntityDimLinear    /**< Linear Dimension */
 
1265
                && en->getParent()->rtti() != RS2::EntityDimRadial    /**< Radial Dimension */
 
1266
                && en->getParent()->rtti() != RS2::EntityDimDiametric /**< Diametric Dimension */
 
1267
                && en->getParent()->rtti() != RS2::EntityDimAngular   /**< Angular Dimension */
 
1268
                && en->getParent()->rtti() != RS2::EntityDimLeader    /**< Leader Dimension */
 
1269
                ){//no end point for Insert, text, Dim
 
1270
//            std::cout<<"find nearest for entity "<<i0<<std::endl;
 
1271
            point = en->getNearestEndpoint(coord, &curDist);
 
1272
            if (point.valid && curDist<minDist) {
 
1273
                closestPoint = point;
 
1274
                minDist = curDist;
 
1275
                if (dist!=NULL) {
 
1276
                    *dist = curDist;
 
1277
                }
 
1278
                if(pEntity!=NULL){
 
1279
                    *pEntity=en;
 
1280
                }
 
1281
            }
 
1282
        }
 
1283
        i0++;
 
1284
    }
 
1285
 
 
1286
//    std::cout<<__FILE__<<" : "<<__FUNCTION__<<" : line "<<__LINE__<<std::endl;
 
1287
//    std::cout<<"count()="<<const_cast<RS_EntityContainer*>(this)->count()<<"\tminDist= "<<minDist<<"\tclosestPoint="<<closestPoint;
 
1288
//    if(pEntity != NULL) std::cout<<"\t*pEntity="<<*pEntity;
 
1289
//    std::cout<<std::endl;
 
1290
    return closestPoint;
 
1291
}
 
1292
 
 
1293
 
 
1294
 
 
1295
RS_Vector RS_EntityContainer::getNearestPointOnEntity(const RS_Vector& coord,
 
1296
                                                      bool onEntity, double* dist, RS_Entity** entity)const {
 
1297
 
 
1298
    RS_Vector point(false);
 
1299
 
 
1300
    RS_Entity* en = const_cast<RS_EntityContainer*>(this)->getNearestEntity(coord, dist, RS2::ResolveNone);
 
1301
 
 
1302
    if (en!=NULL ) {
 
1303
        if ( en->isVisible()
 
1304
             && en->getParent()->rtti() != RS2::EntityInsert         /**Insert*/
 
1305
             //&& en->rtti() != RS2::EntityPoint         /**Point*/
 
1306
             && en->getParent()->rtti() != RS2::EntitySpline
 
1307
             && en->getParent()->rtti() != RS2::EntityMText        /**< Text 15*/
 
1308
             && en->getParent()->rtti() != RS2::EntityText         /**< Text 15*/
 
1309
             && en->getParent()->rtti() != RS2::EntityDimAligned   /**< Aligned Dimension */
 
1310
             && en->getParent()->rtti() != RS2::EntityDimLinear    /**< Linear Dimension */
 
1311
             && en->getParent()->rtti() != RS2::EntityDimRadial    /**< Radial Dimension */
 
1312
             && en->getParent()->rtti() != RS2::EntityDimDiametric /**< Diametric Dimension */
 
1313
             && en->getParent()->rtti() != RS2::EntityDimAngular   /**< Angular Dimension */
 
1314
             && en->getParent()->rtti() != RS2::EntityDimLeader    /**< Leader Dimension */
 
1315
             ){//no middle point for Spline, Insert, text, Dim
 
1316
            point = en->getNearestPointOnEntity(coord, onEntity, dist, entity);
 
1317
        }
 
1318
    }
 
1319
 
 
1320
    return point;
 
1321
}
 
1322
 
 
1323
 
 
1324
 
 
1325
RS_Vector RS_EntityContainer::getNearestCenter(const RS_Vector& coord,
 
1326
                                               double* dist) {
 
1327
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1328
    double curDist = RS_MAXDOUBLE;  // currently measured distance
 
1329
    RS_Vector closestPoint(false);  // closest found endpoint
 
1330
    RS_Vector point;                // endpoint found
 
1331
 
 
1332
    for (RS_Entity* en = const_cast<RS_EntityContainer*>(this)->firstEntity();
 
1333
         en != NULL;
 
1334
         en = const_cast<RS_EntityContainer*>(this)->nextEntity()) {
 
1335
 
 
1336
        if (en->isVisible()
 
1337
                && en->getParent()->rtti() != RS2::EntitySpline
 
1338
                && en->getParent()->rtti() != RS2::EntityMText        /**< Text 16*/
 
1339
                && en->getParent()->rtti() != RS2::EntityText         /**< Text 17*/
 
1340
                && en->getParent()->rtti() != RS2::EntityDimAligned   /**< Aligned Dimension */
 
1341
                && en->getParent()->rtti() != RS2::EntityDimLinear    /**< Linear Dimension */
 
1342
                && en->getParent()->rtti() != RS2::EntityDimRadial    /**< Radial Dimension */
 
1343
                && en->getParent()->rtti() != RS2::EntityDimDiametric /**< Diametric Dimension */
 
1344
                && en->getParent()->rtti() != RS2::EntityDimAngular   /**< Angular Dimension */
 
1345
                && en->getParent()->rtti() != RS2::EntityDimLeader    /**< Leader Dimension */
 
1346
                ){//no center point for spline, text, Dim
 
1347
            point = en->getNearestCenter(coord, &curDist);
 
1348
            if (point.valid && curDist<minDist) {
 
1349
                closestPoint = point;
 
1350
                minDist = curDist;
 
1351
            }
 
1352
        }
 
1353
    }
 
1354
    if (dist!=NULL) {
 
1355
        *dist = curDist;
 
1356
    }
 
1357
 
 
1358
    return closestPoint;
 
1359
}
 
1360
 
 
1361
/** @return the nearest of equidistant middle points of the line. */
 
1362
 
 
1363
RS_Vector RS_EntityContainer::getNearestMiddle(const RS_Vector& coord,
 
1364
                                               double* dist,
 
1365
                                               int middlePoints
 
1366
                                               ) const{
 
1367
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1368
    double curDist = RS_MAXDOUBLE;  // currently measured distance
 
1369
    RS_Vector closestPoint(false);  // closest found endpoint
 
1370
    RS_Vector point;                // endpoint found
 
1371
 
 
1372
    for (RS_Entity* en = const_cast<RS_EntityContainer*>(this)->firstEntity();
 
1373
         en != NULL;
 
1374
         en = const_cast<RS_EntityContainer*>(this)->nextEntity()) {
 
1375
 
 
1376
        if (en->isVisible()
 
1377
                && en->getParent()->rtti() != RS2::EntitySpline
 
1378
                && en->getParent()->rtti() != RS2::EntityMText        /**< Text 16*/
 
1379
                && en->getParent()->rtti() != RS2::EntityText         /**< Text 17*/
 
1380
                && en->getParent()->rtti() != RS2::EntityDimAligned   /**< Aligned Dimension */
 
1381
                && en->getParent()->rtti() != RS2::EntityDimLinear    /**< Linear Dimension */
 
1382
                && en->getParent()->rtti() != RS2::EntityDimRadial    /**< Radial Dimension */
 
1383
                && en->getParent()->rtti() != RS2::EntityDimDiametric /**< Diametric Dimension */
 
1384
                && en->getParent()->rtti() != RS2::EntityDimAngular   /**< Angular Dimension */
 
1385
                && en->getParent()->rtti() != RS2::EntityDimLeader    /**< Leader Dimension */
 
1386
                ){//no midle point for spline, text, Dim
 
1387
            point = en->getNearestMiddle(coord, &curDist, middlePoints);
 
1388
            if (point.valid && curDist<minDist) {
 
1389
                closestPoint = point;
 
1390
                minDist = curDist;
 
1391
            }
 
1392
        }
 
1393
    }
 
1394
    if (dist!=NULL) {
 
1395
        *dist = curDist;
 
1396
    }
 
1397
 
 
1398
    return closestPoint;
 
1399
}
 
1400
 
 
1401
 
 
1402
 
 
1403
RS_Vector RS_EntityContainer::getNearestDist(double distance,
 
1404
                                             const RS_Vector& coord,
 
1405
                                             double* dist) {
 
1406
 
 
1407
    RS_Vector point(false);
 
1408
    RS_Entity* closestEntity;
 
1409
 
 
1410
    closestEntity = getNearestEntity(coord, NULL, RS2::ResolveNone);
 
1411
 
 
1412
    if (closestEntity!=NULL) {
 
1413
        point = closestEntity->getNearestDist(distance, coord, dist);
 
1414
    }
 
1415
 
 
1416
    return point;
 
1417
}
 
1418
 
 
1419
 
 
1420
 
 
1421
/**
 
1422
 * @return The intersection which is closest to 'coord'
 
1423
 */
 
1424
RS_Vector RS_EntityContainer::getNearestIntersection(const RS_Vector& coord,
 
1425
                                                     double* dist) {
 
1426
 
 
1427
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1428
    double curDist = RS_MAXDOUBLE;  // currently measured distance
 
1429
    RS_Vector closestPoint(false);  // closest found endpoint
 
1430
    RS_Vector point;                // endpoint found
 
1431
    RS_VectorSolutions sol;
 
1432
    RS_Entity* closestEntity;
 
1433
 
 
1434
    closestEntity = getNearestEntity(coord, NULL, RS2::ResolveAllButTextImage);
 
1435
 
 
1436
    if (closestEntity!=NULL) {
 
1437
        for (RS_Entity* en = firstEntity(RS2::ResolveAllButTextImage);
 
1438
             en != NULL;
 
1439
             en = nextEntity(RS2::ResolveAllButTextImage)) {
 
1440
            if (
 
1441
                    !en->isVisible()
 
1442
                    || en == closestEntity
 
1443
                    || en->rtti() == RS2::EntityPoint         /**Point*/
 
1444
                    || en->getParent()->rtti() == RS2::EntityMText        /**< Text 15*/
 
1445
                    || en->getParent()->rtti() == RS2::EntityText         /**< Text 15*/
 
1446
                    || en->getParent()->rtti() == RS2::EntityDimAligned   /**< Aligned Dimension */
 
1447
                    || en->getParent()->rtti() == RS2::EntityDimLinear    /**< Linear Dimension */
 
1448
                    || en->getParent()->rtti() == RS2::EntityDimRadial    /**< Radial Dimension */
 
1449
                    || en->getParent()->rtti() == RS2::EntityDimDiametric /**< Diametric Dimension */
 
1450
                    || en->getParent()->rtti() == RS2::EntityDimAngular   /**< Angular Dimension */
 
1451
                    || en->getParent()->rtti() == RS2::EntityDimLeader    /**< Leader Dimension */
 
1452
                    || en->getParent()->rtti() == RS2::EntityImage    /**< Leader Dimension */
 
1453
                    ){//do not do intersection for point, text, Dim
 
1454
                continue;
 
1455
            }
 
1456
 
 
1457
            sol = RS_Information::getIntersection(closestEntity,
 
1458
                                                  en,
 
1459
                                                  true);
 
1460
 
 
1461
            point=sol.getClosest(coord,&curDist,NULL);
 
1462
            if(sol.getNumber()>0 && curDist<minDist){
 
1463
                closestPoint=point;
 
1464
                minDist=curDist;
 
1465
            }
 
1466
 
 
1467
        }
 
1468
    }
 
1469
    if(dist!=NULL && closestPoint.valid) {
 
1470
        *dist=minDist;
 
1471
    }
 
1472
 
 
1473
    return closestPoint;
 
1474
}
 
1475
 
 
1476
 
 
1477
 
 
1478
RS_Vector RS_EntityContainer::getNearestRef(const RS_Vector& coord,
 
1479
                                            double* dist) {
 
1480
 
 
1481
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1482
    double curDist;                 // currently measured distance
 
1483
    RS_Vector closestPoint(false);  // closest found endpoint
 
1484
    RS_Vector point;                // endpoint found
 
1485
 
 
1486
    for (RS_Entity* en = firstEntity();
 
1487
         en != NULL;
 
1488
         en = nextEntity()) {
 
1489
 
 
1490
        if (en->isVisible()) {
 
1491
            point = en->getNearestRef(coord, &curDist);
 
1492
            if (point.valid && curDist<minDist) {
 
1493
                closestPoint = point;
 
1494
                minDist = curDist;
 
1495
                if (dist!=NULL) {
 
1496
                    *dist = curDist;
 
1497
                }
 
1498
            }
 
1499
        }
 
1500
    }
 
1501
 
 
1502
    return closestPoint;
 
1503
}
 
1504
 
 
1505
 
 
1506
RS_Vector RS_EntityContainer::getNearestSelectedRef(const RS_Vector& coord,
 
1507
                                                    double* dist) {
 
1508
 
 
1509
    double minDist = RS_MAXDOUBLE;  // minimum measured distance
 
1510
    double curDist;                 // currently measured distance
 
1511
    RS_Vector closestPoint(false);  // closest found endpoint
 
1512
    RS_Vector point;                // endpoint found
 
1513
 
 
1514
    for (RS_Entity* en = firstEntity();
 
1515
         en != NULL;
 
1516
         en = nextEntity()) {
 
1517
 
 
1518
        if (en->isVisible() && en->isSelected() && !en->isParentSelected()) {
 
1519
            point = en->getNearestSelectedRef(coord, &curDist);
 
1520
            if (point.valid && curDist<minDist) {
 
1521
                closestPoint = point;
 
1522
                minDist = curDist;
 
1523
                if (dist!=NULL) {
 
1524
                    *dist = curDist;
 
1525
                }
 
1526
            }
 
1527
        }
 
1528
    }
 
1529
 
 
1530
    return closestPoint;
 
1531
}
 
1532
 
 
1533
 
 
1534
double RS_EntityContainer::getDistanceToPoint(const RS_Vector& coord,
 
1535
                                              RS_Entity** entity,
 
1536
                                              RS2::ResolveLevel level,
 
1537
                                              double solidDist) const{
 
1538
 
 
1539
    RS_DEBUG->print("RS_EntityContainer::getDistanceToPoint");
 
1540
 
 
1541
 
 
1542
    double minDist = RS_MAXDOUBLE;      // minimum measured distance
 
1543
    double curDist;                     // currently measured distance
 
1544
    RS_Entity* closestEntity = NULL;    // closest entity found
 
1545
    RS_Entity* subEntity = NULL;
 
1546
 
 
1547
    //int k=0;
 
1548
    for (RS_Entity* e =const_cast<RS_EntityContainer*>(this)-> firstEntity(level);
 
1549
         e != NULL;
 
1550
         e =const_cast<RS_EntityContainer*>(this)-> nextEntity(level)) {
 
1551
 
 
1552
        if (e->isVisible()) {
 
1553
            RS_DEBUG->print("entity: getDistanceToPoint");
 
1554
            RS_DEBUG->print("entity: %d", e->rtti());
 
1555
            // bug#426, need to ignore Images to find nearest intersections
 
1556
            if(level==RS2::ResolveAllButTextImage && e->rtti()==RS2::EntityImage) continue;
 
1557
            curDist = e->getDistanceToPoint(coord, &subEntity, level, solidDist);
 
1558
 
 
1559
            RS_DEBUG->print("entity: getDistanceToPoint: OK");
 
1560
 
 
1561
            if (curDist<minDist) {
 
1562
                if (level!=RS2::ResolveAll) {
 
1563
                    closestEntity = e;
 
1564
                } else {
 
1565
                    closestEntity = subEntity;
 
1566
                }
 
1567
                minDist = curDist;
 
1568
            }
 
1569
        }
 
1570
    }
 
1571
 
 
1572
    if (entity!=NULL) {
 
1573
        *entity = closestEntity;
 
1574
    }
 
1575
    RS_DEBUG->print("RS_EntityContainer::getDistanceToPoint: OK");
 
1576
 
 
1577
    return minDist;
 
1578
}
 
1579
 
 
1580
 
 
1581
 
 
1582
RS_Entity* RS_EntityContainer::getNearestEntity(const RS_Vector& coord,
 
1583
                                                double* dist,
 
1584
                                                RS2::ResolveLevel level) {
 
1585
 
 
1586
    RS_DEBUG->print("RS_EntityContainer::getNearestEntity");
 
1587
 
 
1588
    RS_Entity* e = NULL;
 
1589
 
 
1590
    // distance for points inside solids:
 
1591
    double solidDist = RS_MAXDOUBLE;
 
1592
    if (dist!=NULL) {
 
1593
        solidDist = *dist;
 
1594
    }
 
1595
 
 
1596
    double d = getDistanceToPoint(coord, &e, level, solidDist);
 
1597
 
 
1598
    if (e!=NULL && e->isVisible()==false) {
 
1599
        e = NULL;
 
1600
    }
 
1601
 
 
1602
    // if d is negative, use the default distance (used for points inside solids)
 
1603
    if (dist!=NULL) {
 
1604
        *dist = d;
 
1605
    }
 
1606
    RS_DEBUG->print("RS_EntityContainer::getNearestEntity: OK");
 
1607
 
 
1608
    return e;
 
1609
}
 
1610
 
 
1611
 
 
1612
 
 
1613
/**
 
1614
 * Rearranges the atomic entities in this container in a way that connected
 
1615
 * entities are stored in the right order and direction.
 
1616
 * Non-recoursive. Only affects atomic entities in this container.
 
1617
 *
 
1618
 * @retval true all contours were closed
 
1619
 * @retval false at least one contour is not closed
 
1620
 
 
1621
 * to do: find closed contour by flood-fill
 
1622
 */
 
1623
bool RS_EntityContainer::optimizeContours() {
 
1624
//    std::cout<<"RS_EntityContainer::optimizeContours: begin"<<std::endl;
 
1625
 
 
1626
//    DEBUG_HEADER();
 
1627
//    std::cout<<"loop with count()="<<count()<<std::endl;
 
1628
    RS_DEBUG->print("RS_EntityContainer::optimizeContours");
 
1629
 
 
1630
    RS_EntityContainer tmp;
 
1631
    tmp.setAutoUpdateBorders(false);
 
1632
    bool closed=true;
 
1633
 
 
1634
    /** accept all full circles **/
 
1635
    QList<RS_Entity*> enList;
 
1636
    for (unsigned ci=0; ci<count(); ++ci) {
 
1637
        RS_Entity* e1=entityAt(ci);
 
1638
        if (!e1->isEdge() || e1->isContainer() ) {
 
1639
            enList<<e1;
 
1640
            continue;
 
1641
        }
 
1642
        if(e1->rtti()==RS2::EntityCircle) {
 
1643
            //directly detect circles, bug#3443277
 
1644
            tmp.addEntity(e1->clone());
 
1645
            enList<<e1;
 
1646
            continue;
 
1647
        }
 
1648
        if(e1->rtti()==RS2::EntityEllipse) {
 
1649
            if(static_cast<RS_Ellipse*>(e1)->isArc() == false){
 
1650
            tmp.addEntity(e1->clone());
 
1651
            enList<<e1;
 
1652
            continue;
 
1653
            }
 
1654
}
 
1655
    }
 
1656
    //    std::cout<<"RS_EntityContainer::optimizeContours: 1"<<std::endl;
 
1657
 
 
1658
    /** remove unsupported entities */
 
1659
    const auto itEnd=enList.end();
 
1660
    for(auto it=enList.begin();it!=itEnd;it++){
 
1661
        removeEntity(*it);
 
1662
    }
 
1663
 
 
1664
    /** check and form a closed contour **/
 
1665
//    std::cout<<"RS_EntityContainer::optimizeContours: 2"<<std::endl;
 
1666
    /** the first entity **/
 
1667
    RS_Entity* current(NULL);
 
1668
    if(count()>0) {
 
1669
        current=entityAt(0)->clone();
 
1670
        tmp.addEntity(current);
 
1671
        removeEntity(entityAt(0));
 
1672
    }else {
 
1673
        if(tmp.count()==0) return false;
 
1674
    }
 
1675
//    std::cout<<"RS_EntityContainer::optimizeContours: 3"<<std::endl;
 
1676
    RS_Vector vpStart;
 
1677
    RS_Vector vpEnd;
 
1678
    if(current!=NULL){
 
1679
        vpStart=current->getStartpoint();
 
1680
        vpEnd=current->getEndpoint();
 
1681
    }
 
1682
        RS_Entity* next(NULL);
 
1683
//    std::cout<<"RS_EntityContainer::optimizeContours: 4"<<std::endl;
 
1684
    /** connect entities **/
 
1685
    while(count()>0){
 
1686
        double dist(0.);
 
1687
//        std::cout<<" count()="<<count()<<std::endl;
 
1688
        getNearestEndpoint(vpEnd,&dist,&next);
 
1689
        if(dist>1e-8) {
 
1690
            if(vpEnd.squaredTo(vpStart)<1e-8){
 
1691
                RS_Entity* e2=entityAt(0);
 
1692
                tmp.addEntity(e2->clone());
 
1693
                vpStart=e2->getStartpoint();
 
1694
                vpEnd=e2->getEndpoint();
 
1695
                removeEntity(e2);
 
1696
                continue;
 
1697
            }
 
1698
            closed=false;
 
1699
        }
 
1700
        if(next && closed){                     //workaround if next is NULL
 
1701
            next->setProcessed(true);
 
1702
            RS_Entity* eTmp = next->clone();
 
1703
            if(vpEnd.squaredTo(next->getStartpoint())>1e-8)
 
1704
                eTmp->revertDirection();
 
1705
            vpEnd=( vpEnd.squaredTo(next->getStartpoint()) > vpEnd.squaredTo(next->getEndpoint()) )? next->getStartpoint():next->getEndpoint();
 
1706
            tmp.addEntity(eTmp);
 
1707
                removeEntity(next);
 
1708
        } else {                        //workaround if next is NULL
 
1709
//                  std::cout<<"RS_EntityContainer::optimizeContours: next is NULL" <<std::endl;
 
1710
 
 
1711
                closed=false;   //workaround if next is NULL
 
1712
                break;                  //workaround if next is NULL
 
1713
        }                                       //workaround if next is NULL
 
1714
    }
 
1715
//    DEBUG_HEADER();
 
1716
    if(vpEnd.valid && vpEnd.squaredTo(vpStart)>1e-8) {
 
1717
//        std::cout<<"ds2="<<vpEnd.squaredTo(vpStart)<<std::endl;
 
1718
        closed=false;
 
1719
    }
 
1720
//    std::cout<<"RS_EntityContainer::optimizeContours: 5"<<std::endl;
 
1721
 
 
1722
 
 
1723
    // add new sorted entities:
 
1724
    for (RS_Entity* en=tmp.firstEntity(); en!=NULL; en=tmp.nextEntity()) {
 
1725
        en->setProcessed(false);
 
1726
        addEntity(en->clone());
 
1727
    }
 
1728
//    std::cout<<"RS_EntityContainer::optimizeContours: 6"<<std::endl;
 
1729
 
 
1730
    RS_DEBUG->print("RS_EntityContainer::optimizeContours: OK");
 
1731
//    std::cout<<"RS_EntityContainer::optimizeContours: end: count()="<<count()<<std::endl;
 
1732
//    std::cout<<"RS_EntityContainer::optimizeContours: closed="<<closed<<std::endl;
 
1733
    return closed;
 
1734
}
 
1735
 
 
1736
 
 
1737
bool RS_EntityContainer::hasEndpointsWithinWindow(const RS_Vector& v1, const RS_Vector& v2) {
 
1738
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1739
         e!=NULL;
 
1740
         e=nextEntity(RS2::ResolveNone)) {
 
1741
        if (e->hasEndpointsWithinWindow(v1, v2))  {
 
1742
            return true;
 
1743
        }
 
1744
    }
 
1745
 
 
1746
    return false;
 
1747
}
 
1748
 
 
1749
 
 
1750
void RS_EntityContainer::move(const RS_Vector& offset) {
 
1751
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1752
         e!=NULL;
 
1753
         e=nextEntity(RS2::ResolveNone)) {
 
1754
        e->move(offset);
 
1755
        if (autoUpdateBorders) {
 
1756
            e->moveBorders(offset);
 
1757
        }
 
1758
    }
 
1759
    if (autoUpdateBorders) {
 
1760
        moveBorders(offset);
 
1761
    }
 
1762
}
 
1763
 
 
1764
 
 
1765
 
 
1766
void RS_EntityContainer::rotate(const RS_Vector& center, const double& angle) {
 
1767
    RS_Vector angleVector(angle);
 
1768
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1769
         e!=NULL;
 
1770
         e=nextEntity(RS2::ResolveNone)) {
 
1771
        e->rotate(center, angleVector);
 
1772
    }
 
1773
    if (autoUpdateBorders) {
 
1774
        calculateBorders();
 
1775
    }
 
1776
}
 
1777
 
 
1778
 
 
1779
void RS_EntityContainer::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
 
1780
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1781
         e!=NULL;
 
1782
         e=nextEntity(RS2::ResolveNone)) {
 
1783
        e->rotate(center, angleVector);
 
1784
    }
 
1785
    if (autoUpdateBorders) {
 
1786
        calculateBorders();
 
1787
    }
 
1788
}
 
1789
 
 
1790
 
 
1791
void RS_EntityContainer::scale(const RS_Vector& center, const RS_Vector& factor) {
 
1792
    if (fabs(factor.x)>RS_TOLERANCE && fabs(factor.y)>RS_TOLERANCE) {
 
1793
        for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1794
             e!=NULL;
 
1795
             e=nextEntity(RS2::ResolveNone)) {
 
1796
            e->scale(center, factor);
 
1797
        }
 
1798
    }
 
1799
    if (autoUpdateBorders) {
 
1800
        calculateBorders();
 
1801
    }
 
1802
}
 
1803
 
 
1804
 
 
1805
 
 
1806
void RS_EntityContainer::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
 
1807
    if (axisPoint1.distanceTo(axisPoint2)>1.0e-6) {
 
1808
        for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1809
             e!=NULL;
 
1810
             e=nextEntity(RS2::ResolveNone)) {
 
1811
            e->mirror(axisPoint1, axisPoint2);
 
1812
        }
 
1813
    }
 
1814
}
 
1815
 
 
1816
 
 
1817
void RS_EntityContainer::stretch(const RS_Vector& firstCorner,
 
1818
                                 const RS_Vector& secondCorner,
 
1819
                                 const RS_Vector& offset) {
 
1820
 
 
1821
    if (getMin().isInWindow(firstCorner, secondCorner) &&
 
1822
            getMax().isInWindow(firstCorner, secondCorner)) {
 
1823
 
 
1824
        move(offset);
 
1825
    } else {
 
1826
        for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1827
             e!=NULL;
 
1828
             e=nextEntity(RS2::ResolveNone)) {
 
1829
            e->stretch(firstCorner, secondCorner, offset);
 
1830
        }
 
1831
    }
 
1832
 
 
1833
    // some entitiycontainers might need an update (e.g. RS_Leader):
 
1834
    update();
 
1835
}
 
1836
 
 
1837
 
 
1838
 
 
1839
void RS_EntityContainer::moveRef(const RS_Vector& ref,
 
1840
                                 const RS_Vector& offset) {
 
1841
 
 
1842
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1843
         e!=NULL;
 
1844
         e=nextEntity(RS2::ResolveNone)) {
 
1845
        e->moveRef(ref, offset);
 
1846
    }
 
1847
    if (autoUpdateBorders) {
 
1848
        calculateBorders();
 
1849
    }
 
1850
}
 
1851
 
 
1852
 
 
1853
void RS_EntityContainer::moveSelectedRef(const RS_Vector& ref,
 
1854
                                         const RS_Vector& offset) {
 
1855
 
 
1856
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1857
         e!=NULL;
 
1858
         e=nextEntity(RS2::ResolveNone)) {
 
1859
        e->moveSelectedRef(ref, offset);
 
1860
    }
 
1861
    if (autoUpdateBorders) {
 
1862
        calculateBorders();
 
1863
    }
 
1864
}
 
1865
 
 
1866
void RS_EntityContainer::revertDirection() {
 
1867
        for(int k = 0; k < entities.size() / 2; k++) {
 
1868
                entities.swap(k, entities.size() - 1 - k);
 
1869
        }
 
1870
 
 
1871
        foreach(RS_Entity* entity, entities) {
 
1872
                entity->revertDirection();
 
1873
        }
 
1874
}
 
1875
 
 
1876
 
 
1877
 
 
1878
void RS_EntityContainer::draw(RS_Painter* painter, RS_GraphicView* view,
 
1879
                              double& /*patternOffset*/) {
 
1880
 
 
1881
    if (painter==NULL || view==NULL) {
 
1882
        return;
 
1883
    }
 
1884
 
 
1885
    QList<RS_Entity*> entities;
 
1886
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
1887
         e!=NULL;
 
1888
         e = nextEntity(RS2::ResolveNone)) {
 
1889
        //view->drawEntity(painter, e);
 
1890
        entities<<e;
 
1891
    }
 
1892
    std::stable_sort(entities.begin(), entities.end(), [](const RS_Entity* e1, const RS_Entity* e2)->bool{
 
1893
        const RS_Layer* l1=e1->getLayer();
 
1894
        const RS_Layer* l2=e2->getLayer();
 
1895
        if(l1 != NULL || l2 != NULL ) {
 
1896
            if(l1==NULL) return false;
 
1897
            if(l2==NULL) return true;
 
1898
            if (e1->getLayer()->getName() < e2->getLayer()->getName()) return true;
 
1899
            else
 
1900
                if (e1->getLayer()->getName() > e2->getLayer()->getName()) return false;
 
1901
        }
 
1902
        return e1->getId() < e2->getId();
 
1903
    });
 
1904
    for(RS_Entity* e: entities){
 
1905
        view->drawEntity(painter, e);
 
1906
    }
 
1907
}
 
1908
 
 
1909
 
 
1910
/**
 
1911
 * Dumps the entities to stdout.
 
1912
 */
 
1913
std::ostream& operator << (std::ostream& os, RS_EntityContainer& ec) {
 
1914
 
 
1915
    static int indent = 0;
 
1916
 
 
1917
    char* tab = new char[indent*2+1];
 
1918
    for(int i=0; i<indent*2; ++i) {
 
1919
        tab[i] = ' ';
 
1920
    }
 
1921
    tab[indent*2] = '\0';
 
1922
 
 
1923
    ++indent;
 
1924
 
 
1925
    unsigned long int id = ec.getId();
 
1926
 
 
1927
    os << tab << "EntityContainer[" << id << "]: \n";
 
1928
    os << tab << "Borders[" << id << "]: "
 
1929
       << ec.minV << " - " << ec.maxV << "\n";
 
1930
    //os << tab << "Unit[" << id << "]: "
 
1931
    //<< RS_Units::unit2string (ec.unit) << "\n";
 
1932
    if (ec.getLayer()!=NULL) {
 
1933
        os << tab << "Layer[" << id << "]: "
 
1934
           << ec.getLayer()->getName().toLatin1().data() << "\n";
 
1935
    } else {
 
1936
        os << tab << "Layer[" << id << "]: <NULL>\n";
 
1937
    }
 
1938
    //os << ec.layerList << "\n";
 
1939
 
 
1940
    os << tab << " Flags[" << id << "]: "
 
1941
       << (ec.getFlag(RS2::FlagVisible) ? "RS2::FlagVisible" : "");
 
1942
    os << (ec.getFlag(RS2::FlagUndone) ? " RS2::FlagUndone" : "");
 
1943
    os << (ec.getFlag(RS2::FlagSelected) ? " RS2::FlagSelected" : "");
 
1944
    os << "\n";
 
1945
 
 
1946
 
 
1947
    os << tab << "Entities[" << id << "]: \n";
 
1948
    for (RS_Entity* t=ec.firstEntity();
 
1949
         t!=NULL;
 
1950
         t=ec.nextEntity()) {
 
1951
 
 
1952
        switch (t->rtti()) {
 
1953
        case RS2::EntityInsert:
 
1954
            os << tab << *((RS_Insert*)t);
 
1955
            os << tab << *((RS_Entity*)t);
 
1956
            os << tab << *((RS_EntityContainer*)t);
 
1957
            break;
 
1958
        default:
 
1959
            if (t->isContainer()) {
 
1960
                os << tab << *((RS_EntityContainer*)t);
 
1961
            } else {
 
1962
                os << tab << *t;
 
1963
            }
 
1964
            break;
 
1965
        }
 
1966
    }
 
1967
    os << tab << "\n\n";
 
1968
    --indent;
 
1969
 
 
1970
    delete[] tab;
 
1971
    return os;
 
1972
}
 
1973