3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
8 // JLH = James L. Hammons <jlhamm@acm.org>
11 // --- ---------- -----------------------------------------------------------
12 // JLH 05/28/2010 Added this text. :-)
15 #include "rs_entity.h"
19 #include "rs_circle.h"
21 #include "rs_document.h"
22 #include "rs_ellipse.h"
24 #include "rs_graphicview.h"
25 #include "rs_insert.h"
29 #include "rs_polyline.h"
34 * Default constructor.
35 * @param parent The parent entity of this entity.
36 * E.g. a line might have a graphic entity or
37 * a polyline entity as parent.
39 RS_Entity::RS_Entity(RS_EntityContainer * parent)
41 this->parent = parent;
48 /*RS_Entity::RS_Entity(const RS_Entity& e) : RS_Flags(e.getFlags()) {
49 cout << "copy constructor called\n";
53 //setFlag(e.getFlags());
62 RS_Entity::~RS_Entity()
66 /*virtual*/ void RS_Entity::reparent(RS_EntityContainer * parent)
68 this->parent = parent;
72 * Initialisation. Called from all constructors.
74 void RS_Entity::init()
78 setFlag(RS2::FlagVisible);
88 * Gives this entity a new unique id.
90 void RS_Entity::initId()
92 static unsigned long int idCounter = 0;
97 * Resets the borders of this element.
99 void RS_Entity::resetBorders()
101 // TODO: Check that. windoze XP crashes with MAXDOUBLE
102 double maxd = RS_MAXDOUBLE;
103 double mind = RS_MINDOUBLE;
105 minV.set(maxd, maxd, maxd);
106 maxV.set(mind, mind, mind);
110 * Must be overwritten to return the rtti of this entity
111 * (e.g. RS2::EntityArc).
113 /*virtual*/ RS2::EntityType RS_Entity::rtti() const
115 return RS2::EntityUnknown;
119 * Identify all entities as undoable entities.
120 * @return RS2::UndoableEntity
122 /*virtual*/ RS2::UndoableType RS_Entity::undoRtti()
124 return RS2::UndoableEntity;
128 * @return Unique Id of this entity.
130 unsigned long int RS_Entity::getId() const
136 * Must be overwritten to return true if an entity type
137 * is a potential edge entity of a contour. By default
138 * this returns false.
140 /*virtual*/ bool RS_Entity::isEdge() const
146 * @return true for all document entities (e.g. Graphics or Blocks).
149 /*virtual*/ bool RS_Entity::isDocument() const
155 * Selects or deselects this entity.
157 * @param select True to select, false to deselect.
159 bool RS_Entity::setSelected(bool select)
162 if (select && isLocked())
166 setFlag(RS2::FlagSelected);
168 delFlag(RS2::FlagSelected);
174 * Toggles select on this entity.
176 bool RS_Entity::toggleSelected()
178 return setSelected(!isSelected());
179 //toggleFlag(RS2::FlagSelected);
183 * @return True if the entity is selected. Note that an entity might
184 * not be selected but one of its parents is selected. In that case
185 * this function returns false.
187 bool RS_Entity::isSelected() const
189 return getFlag(RS2::FlagSelected);
193 * @return true if a parent entity of this entity is selected.
195 bool RS_Entity::isParentSelected()
197 RS_Entity * p = this;
203 if (p != NULL && p->isSelected() == true)
212 * Sets or resets the processed flag of this entity.
214 * @param on True to set, false to reset.
216 void RS_Entity::setProcessed(bool on)
219 setFlag(RS2::FlagProcessed);
221 delFlag(RS2::FlagProcessed);
225 * @return True if the processed flag is set.
227 bool RS_Entity::isProcessed() const
229 return getFlag(RS2::FlagProcessed);
233 * Called when the undo state changed.
235 * @param undone true: entity has become invisible.
236 * false: entity has become visible.
238 void RS_Entity::undoStateChanged(bool /*undone*/)
245 * @return true if this entity or any parent entities are undone.
247 bool RS_Entity::isUndone() const
250 return RS_Undoable::isUndone();
252 return RS_Undoable::isUndone() || parent->isUndone();
256 * @return True if the entity is in the given range.
258 bool RS_Entity::isInWindow(Vector v1, Vector v2)
260 double right, left, top, bottom;
262 right = std::max(v1.x, v2.x);
263 left = std::min(v1.x, v2.x);
264 top = std::max(v1.y, v2.y);
265 bottom = std::min(v1.y, v2.y);
267 return (getMin().x >= left && getMax().x <= right
268 && getMin().y >= bottom && getMax().y <= top);
272 * @param tolerance Tolerance.
274 * @retval true if the given point is on this entity.
275 * @retval false otherwise
277 bool RS_Entity::isPointOnEntity(const Vector & coord, double tolerance)
279 double dist = getDistanceToPoint(coord, NULL, RS2::ResolveNone);
280 return (dist <= tolerance);
283 /*virtual*/ bool RS_Entity::hasEndpointsWithinWindow(Vector /*v1*/, Vector /*v2*/)
289 * Is this entity visible?
291 * @return true Only if the entity and the layer it is on are visible.
292 * The Layer might also be NULL. In that case the layer visiblity
295 /*virtual*/ bool RS_Entity::isVisible()
297 if (!getFlag(RS2::FlagVisible))
303 /*RS_EntityCotnainer* parent = getParent();
304 if (parent!=NULL && parent->isUndone()) {
308 if (getLayer() == NULL)
311 // inserts are usually visible - the entities in them have their own
312 // layers which might be frozen
313 // upd: i'm not sure if that is the best behaviour
314 //if (rtti()==RS2::EntityInsert) {
318 if (layer != NULL /*&& layer->getName()!="ByBlock"*/)
320 if (!layer->isFrozen())
326 if (layer == NULL /*&& getLayer()->getName()!="ByBlock"*/)
328 if (getLayer() == NULL)
332 if (!getLayer()->isFrozen())
339 if (getBlockOrInsert() == NULL)
342 if (getBlockOrInsert()->rtti() == RS2::EntityBlock)
344 if (getLayer(false) == NULL || !getLayer(false)->isFrozen())
351 if (getBlockOrInsert()->getLayer() == NULL)
354 if (!getBlockOrInsert()->getLayer()->isFrozen())
360 /*virtual*/ void RS_Entity::setVisible(bool v)
363 setFlag(RS2::FlagVisible);
365 delFlag(RS2::FlagVisible);
369 * Sets the highlight status of the entity. Highlighted entities
370 * usually indicate a feedback to a user action.
372 void RS_Entity::setHighlighted(bool on)
375 setFlag(RS2::FlagHighlighted);
377 delFlag(RS2::FlagHighlighted);
381 * @return true if the entity is highlighted.
383 bool RS_Entity::isHighlighted()
385 return getFlag(RS2::FlagHighlighted);
389 * @return true if the layer this entity is on is locked.
391 bool RS_Entity::isLocked()
393 if (getLayer(true) != NULL && getLayer()->isLocked())
400 * Implementations must return the total length of the entity
401 * or a negative number if the entity has no length (e.g. a text or hatch).
403 /*virtual*/ double RS_Entity::getLength()
409 * @return Parent of this entity or NULL if this is a root entity.
411 RS_EntityContainer * RS_Entity::getParent() const
417 * Reparents this entity.
419 void RS_Entity::setParent(RS_EntityContainer * p)
425 * @return The parent graphic in which this entity is stored
426 * or the parent's parent graphic or NULL if none of the parents
427 * are stored in a graphic.
429 Drawing * RS_Entity::getGraphic()
431 if (rtti() == RS2::EntityGraphic)
432 return (Drawing *)this;
433 else if (parent == NULL)
436 return parent->getGraphic();
440 * @return The parent block in which this entity is stored
441 * or the parent's parent block or NULL if none of the parents
442 * are stored in a block.
444 RS_Block * RS_Entity::getBlock()
446 if (rtti() == RS2::EntityBlock)
447 return (RS_Block *)this;
448 else if (parent == NULL)
451 return parent->getBlock();
455 * @return The parent insert in which this entity is stored
456 * or the parent's parent block or NULL if none of the parents
457 * are stored in a block.
459 RS_Insert * RS_Entity::getInsert()
461 if (rtti() == RS2::EntityInsert)
462 return (RS_Insert *)this;
463 else if (parent == NULL)
466 return parent->getInsert();
470 * @return The parent block or insert in which this entity is stored
471 * or the parent's parent block or insert or NULL if none of the parents
472 * are stored in a block or insert.
474 RS_Entity * RS_Entity::getBlockOrInsert()
476 if (rtti() == RS2::EntityBlock || rtti() == RS2::EntityInsert)
478 else if (parent == NULL)
481 return parent->getBlockOrInsert();
485 * @return The parent document in which this entity is stored
486 * or the parent's parent document or NULL if none of the parents
487 * are stored in a document. Note that a document is usually
488 * either a Graphic or a Block.
490 RS_Document * RS_Entity::getDocument()
492 if (isDocument() == true)
493 return (RS_Document *)this;
494 else if (parent == NULL)
497 return parent->getDocument();
501 * Can be implemented by child classes to update the entities
502 * temporary subentities. update() is called if the entity's
503 * paramters or undo state changed.
505 /*virtual*/ void RS_Entity::update()
509 /*virtual*/ void RS_Entity::setUpdateEnabled(bool on)
515 * This method doesn't do any calculations.
516 * @return minimum coordinate of the entity.
517 * @see calculateBorders()
519 Vector RS_Entity::getMin() const
525 * This method doesn't do any calculations.
526 * @return minimum coordinate of the entity.
527 * @see calculateBorders()
529 Vector RS_Entity::getMax() const
535 * This method returns the difference of max and min returned
536 * by the above functions.
537 * @return size of the entity.
538 * @see calculateBorders()
542 Vector RS_Entity::getSize() const
548 * Sets a variable value for the parent graphic object.
550 * @param key Variable name (e.g. "$DIMASZ")
551 * @param val Default value
553 void RS_Entity::addGraphicVariable(const QString & key, double val, int code)
555 Drawing * graphic = getGraphic();
558 graphic->addVariable(key, val, code);
562 * Sets a variable value for the parent graphic object.
564 * @param key Variable name (e.g. "$DIMASZ")
565 * @param val Default value
567 void RS_Entity::addGraphicVariable(const QString & key, int val, int code)
569 Drawing * graphic = getGraphic();
572 graphic->addVariable(key, val, code);
576 * Sets a variable value for the parent graphic object.
578 * @param key Variable name (e.g. "$DIMASZ")
579 * @param val Default value
581 void RS_Entity::addGraphicVariable(const QString & key, const QString & val, int code)
583 Drawing * graphic = getGraphic();
586 graphic->addVariable(key, val, code);
590 * A safe member function to return the given variable.
592 * @param key Variable name (e.g. "$DIMASZ")
593 * @param def Default value
595 * @return value of variable or default value if the given variable
598 double RS_Entity::getGraphicVariableDouble(const QString & key, double def)
600 Drawing * graphic = getGraphic();
604 ret = graphic->getVariableDouble(key, def);
610 * A safe member function to return the given variable.
612 * @param key Variable name (e.g. "$DIMASZ")
613 * @param def Default value
615 * @return value of variable or default value if the given variable
618 int RS_Entity::getGraphicVariableInt(const QString & key, int def)
620 Drawing * graphic = getGraphic();
624 ret = graphic->getVariableInt(key, def);
630 * A safe member function to return the given variable.
632 * @param key Variable name (e.g. "$DIMASZ")
633 * @param def Default value
635 * @return value of variable or default value if the given variable
638 QString RS_Entity::getGraphicVariableString(const QString & key, const QString & def)
640 Drawing * graphic = getGraphic();
644 ret = graphic->getVariableString(key, def);
650 * @return The unit the parent graphic works on or None if there's no
653 RS2::Unit RS_Entity::getGraphicUnit()
655 Drawing * graphic = getGraphic();
656 RS2::Unit ret = RS2::None;
659 ret = graphic->getUnit();
665 * Must be overwritten to get all reference points of the entity.
667 /*virtual*/ VectorSolutions RS_Entity::getRefPoints()
674 * Must be overwritten to get the point with a given
675 * distance to the start- or endpoint to the given coordinate for this entity.
677 * @param distance Distance to endpoint.
678 * @param startp true = measured from Startpoint, false = measured from Endpoint
680 * @return The point with the given distance to the start- or endpoint.
682 /*virtual*/ Vector RS_Entity::getNearestDist(double /*distance*/, bool /*startp*/)
684 return Vector(false);
688 * Must be overwritten to get the nearest reference point for this entity.
690 * @param coord Coordinate (typically a mouse coordinate)
691 * @param dist Pointer to a value which will contain the measured
692 * distance between 'coord' and the closest point. The passed
693 * pointer can also be NULL in which case the distance will be
696 * @return The closest point with the given distance to the endpoint.
698 /*virtual*/ Vector RS_Entity::getNearestRef(const Vector & coord, double * dist/*= NULL*/)
700 VectorSolutions s = getRefPoints();
702 return s.getClosest(coord, dist);
706 * Gets the nearest reference point of this entity if it is selected.
707 * Containers re-implement this method to return the nearest reference
708 * point of a selected sub entity.
710 * @param coord Coordinate (typically a mouse coordinate)
711 * @param dist Pointer to a value which will contain the measured
712 * distance between 'coord' and the closest point. The passed
713 * pointer can also be NULL in which case the distance will be
716 * @return The closest point with the given distance to the endpoint.
718 /*virtual*/ Vector RS_Entity::getNearestSelectedRef(const Vector & coord, double * dist/*= NULL*/)
721 return getNearestRef(coord, dist);
723 return Vector(false);
727 * Acts like scale(Vector) but with equal factors.
728 * Equal to scale(center, Vector(factor, factor)).
730 /*virtual*/ void RS_Entity::scale(Vector center, double factor)
732 scale(center, Vector(factor, factor));
736 * Implementations must drag the reference point(s) of all
737 * (sub-)entities that are very close to ref by offset.
739 /*virtual*/ void RS_Entity::moveRef(const Vector & /*ref*/, const Vector & /*offset*/)
745 * Implementations must drag the reference point(s) of selected
746 * (sub-)entities that are very close to ref by offset.
748 /*virtual*/ void RS_Entity::moveSelectedRef(const Vector & /*ref*/, const Vector & /*offset*/)
754 * Returns a pointer to the layer this entity is on or NULL.
756 * @para resolve true: if the layer is ByBlock, the layer of the
757 * block this entity is in is returned.
758 * false: the layer of the entity is returned.
760 * @return pointer to the layer this entity is on. If the layer
761 * is set to NULL the layer of the next parent that is not on
762 * layer NULL is returned. If all parents are on layer NULL, NULL
765 RS_Layer * RS_Entity::getLayer(bool resolve) const
769 // we have no layer but a parent that might have one.
770 // return parent's layer instead:
771 if (layer == NULL /*|| layer->getName()=="ByBlock"*/)
774 return parent->getLayer(true);
780 // return our layer. might still be NULL:
785 * Sets the layer of this entity to the layer with the given name
787 void RS_Entity::setLayer(const QString & name)
789 Drawing * graphic = getGraphic();
792 layer = graphic->findLayer(name);
798 * Sets the layer of this entity to the layer given.
800 void RS_Entity::setLayer(RS_Layer * l)
806 * Sets the layer of this entity to the current layer of
807 * the graphic this entity is in. If this entity (and none
808 * of its parents) are in a graphic the layer is set to NULL.
810 void RS_Entity::setLayerToActive()
812 Drawing * graphic = getGraphic();
815 layer = graphic->getActiveLayer();
821 * Gets the pen needed to draw this entity.
822 * The attributes can also come from the layer this entity is on
823 * if the flags are set accordingly.
825 * @param resolve true: Resolve the pen to a drawable pen (e.g. the pen
826 * from the layer or parent..)
827 * false: Don't resolve and return a pen or ByLayer, ByBlock, ...
829 * @return Pen for this entity.
831 RS_Pen RS_Entity::getPen(bool resolve) const
838 RS_Layer * l = getLayer(true);
840 // use parental attributes (e.g. vertex of a polyline, block
841 // entities when they are drawn in block documents):
842 if (!p.isValid() || p.getColor().isByBlock())
845 p = parent->getPen();
847 // use layer attributes:
850 // layer is "ByBlock":
851 /*if (layer->getName()=="ByBlock" && getBlockOrInsert()!=NULL) {
852 p = getBlockOrInsert()->getPen();
855 // use layer's color:
856 if (p.getColor().isByLayer())
857 p.setColor(l->getPen().getColor());
859 // use layer's width:
860 if (p.getWidth() == RS2::WidthByLayer)
861 p.setWidth(l->getPen().getWidth());
863 // use layer's linetype:
864 if (p.getLineType() == RS2::LineByLayer)
865 p.setLineType(l->getPen().getLineType());
874 * Sets the explicit pen for this entity or a pen with special
875 * attributes such as BY_LAYER, ..
877 void RS_Entity::setPen(const RS_Pen & pen)
883 * Sets the pen of this entity to the current pen of
884 * the graphic this entity is in. If this entity (and none
885 * of its parents) are in a graphic the pen is not changed.
887 void RS_Entity::setPenToActive()
889 RS_Document * doc = getDocument();
892 pen = doc->getActivePen();
895 //RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Entity::setPenToActive(): "
896 // "No document / active pen linked to this entity.");
904 * Implementations must stretch the given range of the entity
905 * by the given offset. This default implementation moves the
906 * whole entity if it is completely inside the given range.
908 void RS_Entity::stretch(Vector firstCorner, Vector secondCorner, Vector offset)
910 //e->calculateBorders();
911 if (getMin().isInWindow(firstCorner, secondCorner)
912 && getMax().isInWindow(firstCorner, secondCorner))
917 * @return Factor for scaling the line styles considering the current
918 * paper scaling and the fact that styles are stored in Millimeter.
920 double RS_Entity::getStyleFactor(RS_GraphicView * view)
922 double styleFactor = 1.0;
926 if (view->isPrinting() == false && view->isDraftMode())
927 styleFactor = 1.0 / view->getFactor().x;
930 //styleFactor = getStyleFactor();
931 // the factor caused by the unit:
932 RS2::Unit unit = RS2::None;
933 Drawing * g = getGraphic();
938 //double scale = g->getPaperScale();
939 styleFactor = RS_Units::convert(1.0, RS2::Millimeter, unit);
943 // the factor caused by the line width:
944 if (((int)getPen(true).getWidth()) > 0)
945 styleFactor *= ((double)getPen(true).getWidth() / 100.0);
946 else if (((int)getPen(true).getWidth()) == 0)
950 if (view->isPrinting() || view->isPrintPreview() || view->isDraftMode() == false)
952 Drawing * graphic = getGraphic();
954 if (graphic != NULL && graphic->getPaperScale() > 1.0e-6)
955 styleFactor /= graphic->getPaperScale();
959 //RS_DEBUG->print("stylefactor: %f", styleFactor);
960 //RS_DEBUG->print("viewfactor: %f", view->getFactor().x);
962 if (styleFactor * view->getFactor().x < 0.2)
969 * @return User defined variable connected to this entity.
971 QString * RS_Entity::getUserDefVar(QString key)
973 // return (this->varList.find(key));
974 return (this->varList.value(key));
978 * Add a user defined variable to this entity.
980 void RS_Entity::setUserDefVar(QString key, QString val)
982 varList.insert(key, new QString(val));
986 * Deletes the given user defined variable.
988 void RS_Entity::delUserDefVar(QString key)
994 * @return A list of all keys connected to this entity.
996 QStringList RS_Entity::getAllKeys()
999 // Q3DictIterator<QString> it(varList);
1000 QHashIterator<QString, QString *> it(varList);
1002 // for(; it.current(); ++it)
1003 // keys.append(it.currentKey());
1004 while (it.hasNext())
1007 keys.append(it.key());
1014 * Dumps the elements data to stdout.
1016 std::ostream & operator<<(std::ostream & os, RS_Entity & e)
1018 //os << "Warning: Virtual entity!\n";
1021 os << " {Entity id: " << e.id;
1023 if (e.parent != NULL)
1024 os << " | parent id: " << e.parent->getId() << "\n";
1026 os << " | no parent\n";
1028 os << " flags: " << (e.getFlag(RS2::FlagVisible) ? "RS2::FlagVisible" : "");
1029 os << (e.getFlag(RS2::FlagUndone) ? " RS2::FlagUndone" : "");
1030 os << (e.getFlag(RS2::FlagSelected) ? " RS2::FlagSelected" : "");
1033 if (e.layer == NULL)
1034 os << " layer: NULL ";
1036 os << " layer: " << e.layer->getName().toLatin1().data() << " "
1037 << " layer address: " << (int)(e.layer) << " ";
1039 os << e.pen << "\n";
1041 os << "variable list:\n";
1042 // Q3DictIterator<QString> it(e.varList); // See QDictIterator
1043 QHashIterator<QString, QString *> it(e.varList);
1046 for( ; it.current(); ++it )
1048 #warning "Removed output (Qt3 style iterator)... !!! FIX !!!"
1049 // os << it.currentKey() << ": " << *it.current() << ", ";
1052 while (it.hasNext())
1055 os << (it.key()).toAscii().data() << ": " << (*it.value()).toAscii().data() << ", ";
1059 // There should be a better way then this...
1062 case RS2::EntityPoint:
1063 os << (RS_Point &)e;
1066 case RS2::EntityLine:
1070 case RS2::EntityPolyline:
1071 os << (RS_Polyline &)e;
1074 case RS2::EntityArc:
1078 case RS2::EntityCircle:
1079 os << (RS_Circle &)e;
1082 case RS2::EntityEllipse:
1083 os << (RS_Ellipse &)e;
1086 case RS2::EntityInsert:
1087 os << (RS_Insert &)e;
1090 case RS2::EntityText:
1095 os << "Unknown Entity";