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