]> Shamusworld >> Repos - architektonas/blob - src/base/insert.cpp
Bugfixes related to removing Snapper class.
[architektonas] / src / base / insert.cpp
1 // insert.cpp
2 //
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 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
9 //
10 // JLH = James L. Hammons <jlhamm@acm.org>
11 //
12 // Who  When        What
13 // ---  ----------  -----------------------------------------------------------
14 // JLH  06/01/2010  Added this text. :-)
15 //
16
17 #include "insert.h"
18
19 #include "block.h"
20 #include "drawing.h"
21
22 /**
23  * @param parent The graphic this block belongs to.
24  */
25 Insert::Insert(EntityContainer * parent, const InsertData & d):
26         EntityContainer(parent), data(d)
27 {
28         block = NULL;
29
30         if (data.updateMode != RS2::NoUpdate)
31         {
32                 update();
33                 //calculateBorders();
34         }
35 }
36
37 /**
38  * Destructor.
39  */
40 Insert::~Insert()
41 {
42 }
43
44 /*virtual*/ Entity * Insert::clone()
45 {
46         Insert * i = new Insert(*this);
47 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
48 //      i->entities.setAutoDelete(entities.autoDelete());
49         i->initId();
50         i->detach();
51         return i;
52 }
53
54 /** @return RS2::EntityInsert */
55 /*virtual*/ RS2::EntityType Insert::rtti() const
56 {
57         return RS2::EntityInsert;
58 }
59
60 /** @return Copy of data that defines the insert. **/
61 InsertData Insert::getData() const
62 {
63         return data;
64 }
65
66 /**
67  * Reimplementation of reparent. Invalidates block cache pointer.
68  */
69 /*virtual*/ void Insert::reparent(EntityContainer * parent)
70 {
71         Entity::reparent(parent);
72         block = NULL;
73 }
74
75 /**
76  * @return Pointer to the block associated with this Insert or
77  *   NULL if the block couldn't be found. Blocks are requested
78  *   from the blockSource if one was supplied and otherwise from
79  *   the closest parent graphic.
80  */
81 Block * Insert::getBlockForInsert()
82 {
83         if (block)
84                 return block;
85
86         BlockList * blkList;
87
88         if (!data.blockSource)
89         {
90                 blkList = (getGraphic() ? getGraphic()->getBlockList() : NULL);
91         }
92         else
93         {
94                 blkList = data.blockSource;
95         }
96
97         Block * blk = NULL;
98
99         if (blkList)
100                 blk = blkList->find(data.name);
101
102 /*???
103         if (blk)
104         {
105         }
106 */
107
108         block = blk;
109
110         return blk;
111 }
112
113 /**
114  * Updates the entity buffer of this insert entity. This method
115  * needs to be called whenever the block this insert is based on changes.
116  */
117 void Insert::update()
118 {
119         DEBUG->print("Insert::update");
120         DEBUG->print("Insert::update: name: %s", data.name.toLatin1().data());
121         DEBUG->print("Insert::update: insertionPoint: %f/%f",
122                 data.insertionPoint.x, data.insertionPoint.y);
123
124         if (!updateEnabled)
125                 return;
126
127         clear();
128         Block * blk = getBlockForInsert();
129
130         if (!blk)
131         {
132                 DEBUG->print("Insert::update: Block is NULL");
133                 return;
134         }
135
136         if (isUndone())
137         {
138                 DEBUG->print("Insert::update: Insert is in undo list");
139                 return;
140         }
141
142         if (fabs(data.scaleFactor.x) < 1.0e-6 || fabs(data.scaleFactor.y) < 1.0e-6)
143         {
144                 DEBUG->print("Insert::update: scale factor is 0");
145                 return;
146         }
147
148         Pen tmpPen;
149
150         /*Q3PtrListIterator<Entity> it = createIterator();
151         Entity* e;
152         while ( (e = it.current()) != NULL ) {
153                 ++it;*/
154
155         DEBUG->print("Insert::update: cols: %d, rows: %d", data.cols, data.rows);
156         DEBUG->print("Insert::update: block has %d entities", blk->count());
157
158         for(Entity * e=blk->firstEntity(); e!=NULL; e=blk->nextEntity())
159         {
160                 for(int c=0; c<data.cols; ++c)
161                 {
162                         DEBUG->print("Insert::update: col %d", c);
163
164                         for(int r=0; r<data.rows; ++r)
165                         {
166                                 DEBUG->print("Insert::update: row %d", r);
167
168                                 if (e->rtti() == RS2::EntityInsert && data.updateMode != RS2::PreviewUpdate)
169                                 {
170                                         DEBUG->print("Insert::update: updating sub-insert");
171                                         ((Insert *)e)->update();
172                                 }
173
174                                 DEBUG->print("Insert::update: cloning entity");
175
176                                 Entity * ne = e->clone();
177                                 ne->initId();
178                                 ne->setUpdateEnabled(false);
179                                 ne->setParent(this);
180                                 ne->setVisible(getFlag(RS2::FlagVisible));
181
182                                 DEBUG->print("Insert::update: transforming entity");
183
184                                 // Move:
185                                 DEBUG->print("Insert::update: move 1");
186                                 if (fabs(data.scaleFactor.x) > 1.0e-6 && fabs(data.scaleFactor.y) > 1.0e-6)
187                                 {
188                                         ne->move(data.insertionPoint + Vector(data.spacing.x / data.scaleFactor.x * c, data.spacing.y / data.scaleFactor.y * r));
189                                 }
190                                 else
191                                 {
192                                         ne->move(data.insertionPoint);
193                                 }
194
195                                 // Move because of block base point:
196                                 DEBUG->print("Insert::update: move 2");
197                                 ne->move(blk->getBasePoint() * -1);
198                                 // Scale:
199                                 DEBUG->print("Insert::update: scale");
200                                 ne->scale(data.insertionPoint, data.scaleFactor);
201                                 // Rotate:
202                                 DEBUG->print("Insert::update: rotate");
203                                 ne->rotate(data.insertionPoint, data.angle);
204                                 // Select:
205                                 ne->setSelected(isSelected());
206
207                                 // individual entities can be on indiv. layers
208                                 tmpPen = ne->getPen(false);
209
210                                 // color from block (free floating):
211                                 if (tmpPen.getColor() == Color(RS2::FlagByBlock))
212                                         tmpPen.setColor(getPen().getColor());
213
214                                 // line width from block (free floating):
215                                 if (tmpPen.getWidth() == RS2::WidthByBlock)
216                                         tmpPen.setWidth(getPen().getWidth());
217
218                                 // line type from block (free floating):
219                                 if (tmpPen.getLineType() == RS2::LineByBlock)
220                                         tmpPen.setLineType(getPen().getLineType());
221
222                                 // now that we've evaluated all flags, let's strip them:
223                                 // TODO: strip all flags (width, line type)
224                                 //tmpPen.setColor(tmpPen.getColor().stripFlags());
225
226                                 ne->setPen(tmpPen);
227
228                                 ne->setUpdateEnabled(true);
229
230                                 if (data.updateMode != RS2::PreviewUpdate)
231                                 {
232                                         DEBUG->print("Insert::update: updating new entity");
233                                         ne->update();
234                                 }
235
236                                 DEBUG->print("Insert::update: adding new entity");
237                                 addEntity(ne);
238                         }
239                 }
240         }
241
242         calculateBorders();
243
244         DEBUG->print("Insert::update: OK");
245 }
246
247 QString Insert::getName() const
248 {
249         return data.name;
250 }
251
252 void Insert::setName(const QString & newName)
253 {
254         data.name = newName;
255         update();
256 }
257
258 Vector Insert::getInsertionPoint() const
259 {
260         return data.insertionPoint;
261 }
262
263 void Insert::setInsertionPoint(const Vector & i)
264 {
265         data.insertionPoint = i;
266 }
267
268 Vector Insert::getScale() const
269 {
270         return data.scaleFactor;
271 }
272
273 void Insert::setScale(const Vector & s)
274 {
275         data.scaleFactor = s;
276 }
277
278 double Insert::getAngle() const
279 {
280         return data.angle;
281 }
282
283 void Insert::setAngle(double a)
284 {
285         data.angle = a;
286 }
287
288 int Insert::getCols() const
289 {
290         return data.cols;
291 }
292
293 void Insert::setCols(int c)
294 {
295         data.cols = c;
296 }
297
298 int Insert::getRows() const
299 {
300         return data.rows;
301 }
302
303 void Insert::setRows(int r)
304 {
305         data.rows = r;
306 }
307
308 Vector Insert::getSpacing() const
309 {
310         return data.spacing;
311 }
312
313 void Insert::setSpacing(const Vector & s)
314 {
315         data.spacing = s;
316 }
317
318 /**
319  * Is this insert visible? (re-implementation from Entity)
320  *
321  * @return true Only if the entity and the block and the layer it is on
322  * are visible.
323  * The Layer might also be NULL. In that case the layer visiblity
324  * is ignored.
325  * The Block might also be NULL. In that case the block visiblity
326  * is ignored.
327  */
328 bool Insert::isVisible()
329 {
330         Block * blk = getBlockForInsert();
331
332         if (blk != NULL)
333         {
334                 if (blk->isFrozen())
335                 {
336                         return false;
337                 }
338         }
339
340         return Entity::isVisible();
341 }
342
343 VectorSolutions Insert::getRefPoints()
344 {
345         VectorSolutions ret(data.insertionPoint);
346         return ret;
347 }
348
349 Vector Insert::getNearestRef(const Vector & coord, double * dist)
350 {
351         return getRefPoints().getClosest(coord, dist);
352 }
353
354 void Insert::move(Vector offset)
355 {
356         DEBUG->print("Insert::move: offset: %f/%f",
357                 offset.x, offset.y);
358         DEBUG->print("Insert::move1: insertionPoint: %f/%f",
359                 data.insertionPoint.x, data.insertionPoint.y);
360     data.insertionPoint.move(offset);
361         DEBUG->print("Insert::move2: insertionPoint: %f/%f",
362                 data.insertionPoint.x, data.insertionPoint.y);
363     update();
364 }
365
366 void Insert::rotate(Vector center, double angle)
367 {
368         DEBUG->print("Insert::rotate1: insertionPoint: %f/%f "
369             "/ center: %f/%f",
370                 data.insertionPoint.x, data.insertionPoint.y,
371                 center.x, center.y);
372     data.insertionPoint.rotate(center, angle);
373     data.angle = Math::correctAngle(data.angle + angle);
374         DEBUG->print("Insert::rotate2: insertionPoint: %f/%f",
375                 data.insertionPoint.x, data.insertionPoint.y);
376     update();
377 }
378
379 void Insert::scale(Vector center, Vector factor)
380 {
381         DEBUG->print("Insert::scale1: insertionPoint: %f/%f",
382                 data.insertionPoint.x, data.insertionPoint.y);
383     data.insertionPoint.scale(center, factor);
384     data.scaleFactor.scale(Vector(0.0, 0.0), factor);
385     data.spacing.scale(Vector(0.0, 0.0), factor);
386         DEBUG->print("Insert::scale2: insertionPoint: %f/%f",
387                 data.insertionPoint.x, data.insertionPoint.y);
388     update();
389 }
390
391 void Insert::mirror(Vector axisPoint1, Vector axisPoint2)
392 {
393         data.insertionPoint.mirror(axisPoint1, axisPoint2);
394
395         Vector vec;
396         vec.setPolar(1.0, data.angle);
397         vec.mirror(Vector(0.0, 0.0), axisPoint2 - axisPoint1);
398         data.angle = vec.angle();
399
400         data.scaleFactor.y *= -1;
401
402     update();
403 }
404
405 std::ostream & operator<<(std::ostream & os, const Insert & i)
406 {
407     os << " Insert: " << i.getData() << std::endl;
408     return os;
409 }