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