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