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