1 /****************************************************************************
2 **
3 ** This file is part of the LibreCAD project, a 2D CAD program
4 **
5 ** Copyright (C) 2010 R. van Twisk (librecad@rvt.dds.nl)
6 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
7 **
8 **
9 ** This file may be distributed and/or modified under the terms of the
10 ** GNU General Public License version 2 as published by the Free Software
11 ** Foundation and appearing in the file gpl-2.0.txt included in the
12 ** packaging of this file.
13 **
14 ** This program is distributed in the hope that it will be useful,
15 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ** GNU General Public License for more details.
18 **
19 ** You should have received a copy of the GNU General Public License
20 ** along with this program; if not, write to the Free Software
21 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 **
23 ** This copyright notice MUST APPEAR in all copies of the script!
24 **
25 **********************************************************************/
26 
27 #include<iostream>
28 #include<cmath>
29 #include "rs_insert.h"
30 
31 #include "rs_arc.h"
32 #include "rs_circle.h"
33 #include "rs_ellipse.h"
34 #include "rs_block.h"
35 #include "rs_graphic.h"
36 #include "rs_layer.h"
37 #include "rs_math.h"
38 #include "rs_debug.h"
39 
RS_InsertData(const QString & _name,RS_Vector _insertionPoint,RS_Vector _scaleFactor,double _angle,int _cols,int _rows,RS_Vector _spacing,RS_BlockList * _blockSource,RS2::UpdateMode _updateMode)40 RS_InsertData::RS_InsertData(const QString& _name,
41 							 RS_Vector _insertionPoint,
42 							 RS_Vector _scaleFactor,
43 							 double _angle,
44 							 int _cols, int _rows, RS_Vector _spacing,
45 							 RS_BlockList* _blockSource ,
46 							 RS2::UpdateMode _updateMode ):
47 	name(_name)
48   ,insertionPoint(_insertionPoint)
49   ,scaleFactor(_scaleFactor)
50   ,angle(_angle)
51   ,cols(_cols)
52   ,rows(_rows)
53   ,spacing(_spacing)
54   ,blockSource(_blockSource)
55   ,updateMode(_updateMode)
56 {
57 }
58 
operator <<(std::ostream & os,const RS_InsertData & d)59 std::ostream& operator << (std::ostream& os,
60 									 const RS_InsertData& d) {
61 	   os << "(" << d.name.toLatin1().data() << ")";
62 	   return os;
63    }
64 /**
65  * @param parent The graphic this block belongs to.
66  */
RS_Insert(RS_EntityContainer * parent,const RS_InsertData & d)67 RS_Insert::RS_Insert(RS_EntityContainer* parent,
68                      const RS_InsertData& d)
69         : RS_EntityContainer(parent), data(d) {
70 
71 		block = nullptr;
72 
73     if (data.updateMode!=RS2::NoUpdate) {
74         update();
75         //calculateBorders();
76     }
77 }
78 
79 
clone() const80 RS_Entity* RS_Insert::clone() const{
81 	RS_Insert* i = new RS_Insert(*this);
82 	i->setOwner(isOwner());
83 	i->initId();
84 	i->detach();
85 	return i;
86 }
87 
88 
89 /**
90  * Updates the entity buffer of this insert entity. This method
91  * needs to be called whenever the block this insert is based on changes.
92  */
update()93 void RS_Insert::update() {
94 
95         RS_DEBUG->print("RS_Insert::update");
96         RS_DEBUG->print("RS_Insert::update: name: %s", data.name.toLatin1().data());
97 //        RS_DEBUG->print("RS_Insert::update: insertionPoint: %f/%f",
98 //                data.insertionPoint.x, data.insertionPoint.y);
99 
100         if (updateEnabled==false) {
101                 return;
102         }
103 
104     clear();
105 
106     RS_Block* blk = getBlockForInsert();
107 	if (!blk) {
108 		//return nullptr;
109 				RS_DEBUG->print("RS_Insert::update: Block is nullptr");
110         return;
111     }
112 
113     if (isUndone()) {
114                 RS_DEBUG->print("RS_Insert::update: Insert is in undo list");
115         return;
116     }
117 
118         if (fabs(data.scaleFactor.x)<1.0e-6 || fabs(data.scaleFactor.y)<1.0e-6) {
119                 RS_DEBUG->print("RS_Insert::update: scale factor is 0");
120                 return;
121         }
122 
123     RS_Pen tmpPen;
124 
125         /*QListIterator<RS_Entity> it = createIterator();
126     RS_Entity* e;
127 	while ( (e = it.current())  ) {
128         ++it;*/
129 
130         RS_DEBUG->print("RS_Insert::update: cols: %d, rows: %d",
131                 data.cols, data.rows);
132         RS_DEBUG->print("RS_Insert::update: block has %d entities",
133                 blk->count());
134 //int i_en_counts=0;
135 		for(auto e: *blk){
136         for (int c=0; c<data.cols; ++c) {
137 //            RS_DEBUG->print("RS_Insert::update: col %d", c);
138             for (int r=0; r<data.rows; ++r) {
139 //                i_en_counts++;
140 //                RS_DEBUG->print("RS_Insert::update: row %d", r);
141 
142                 if (e->rtti()==RS2::EntityInsert &&
143                     data.updateMode!=RS2::PreviewUpdate) {
144 
145 //                                        RS_DEBUG->print("RS_Insert::update: updating sub-insert");
146 					static_cast<RS_Insert*>(e)->update();
147                 }
148 
149 //                                RS_DEBUG->print("RS_Insert::update: cloning entity");
150 
151                 RS_Entity* ne;
152                 if ( (data.scaleFactor.x - data.scaleFactor.y)>1.0e-6) {
153                     if (e->rtti()== RS2::EntityArc) {
154 						RS_Arc* a= static_cast<RS_Arc*>(e);
155 						ne = new RS_Ellipse{this,
156 						{a->getCenter(), {a->getRadius(), 0.},
157 								1, a->getAngle1(), a->getAngle2(),
158 								a->isReversed()}
159 					};
160                         ne->setLayer(e->getLayer());
161                         ne->setPen(e->getPen(false));
162                     } else if (e->rtti()== RS2::EntityCircle) {
163 						RS_Circle* a= static_cast<RS_Circle*>(e);
164 						ne = new RS_Ellipse{this,
165 						{ a->getCenter(), {a->getRadius(), 0.}, 1, 0., 2.*M_PI, false}
166 					};
167                         ne->setLayer(e->getLayer());
168                         ne->setPen(e->getPen(false));
169                     } else
170                         ne = e->clone();
171                 } else
172                     ne = e->clone();
173                 ne->initId();
174                 ne->setUpdateEnabled(false);
175                 // if entity layer are 0 set to insert layer to allow "1 layer control" bug ID #3602152
176                 RS_Layer *l= ne->getLayer();//special fontchar block don't have
177 				if (l  && ne->getLayer()->getName() == "0")
178                     ne->setLayer(this->getLayer());
179                 ne->setParent(this);
180                 ne->setVisible(getFlag(RS2::FlagVisible));
181 
182 //                                RS_DEBUG->print("RS_Insert::update: transforming entity");
183 
184                 // Move:
185 //                                RS_DEBUG->print("RS_Insert::update: move 1");
186                 if (fabs(data.scaleFactor.x)>1.0e-6 &&
187                         fabs(data.scaleFactor.y)>1.0e-6) {
188                     ne->move(data.insertionPoint +
189                              RS_Vector(data.spacing.x/data.scaleFactor.x*c,
190                                        data.spacing.y/data.scaleFactor.y*r));
191                 }
192                 else {
193                     ne->move(data.insertionPoint);
194                 }
195                 // Move because of block base point:
196 //                                RS_DEBUG->print("RS_Insert::update: move 2");
197                 ne->move(blk->getBasePoint()*-1);
198                 // Scale:
199 //                                RS_DEBUG->print("RS_Insert::update: scale");
200                 ne->scale(data.insertionPoint, data.scaleFactor);
201                 // Rotate:
202 //                                RS_DEBUG->print("RS_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()==RS_Color(RS2::FlagByBlock)) {
212                     tmpPen.setColor(getPen().getColor());
213                 }
214 
215                 // line width from block (free floating):
216                 if (tmpPen.getWidth()==RS2::WidthByBlock) {
217                     tmpPen.setWidth(getPen().getWidth());
218                 }
219 
220                 // line type from block (free floating):
221                 if (tmpPen.getLineType()==RS2::LineByBlock) {
222                     tmpPen.setLineType(getPen().getLineType());
223                 }
224 
225                 // now that we've evaluated all flags, let's strip them:
226                 // TODO: strip all flags (width, line type)
227                 //tmpPen.setColor(tmpPen.getColor().stripFlags());
228 
229                 ne->setPen(tmpPen);
230 
231                 ne->setUpdateEnabled(true);
232 
233                 // insert must be updated even in preview mode
234                 if (data.updateMode != RS2::PreviewUpdate
235                         || ne->rtti() == RS2::EntityInsert) {
236                     //RS_DEBUG->print("RS_Insert::update: updating new entity");
237                     ne->update();
238                 }
239 
240 //                                RS_DEBUG->print("RS_Insert::update: adding new entity");
241                 appendEntity(ne);
242 //                std::cout<<"done # of entity: "<<i_en_counts<<std::endl;
243             }
244         }
245     }
246     calculateBorders();
247 
248         RS_DEBUG->print("RS_Insert::update: OK");
249 }
250 
251 
252 
253 /**
254  * @return Pointer to the block associated with this Insert or
255  *   nullptr if the block couldn't be found. Blocks are requested
256  *   from the blockSource if one was supplied and otherwise from
257  *   the closest parent graphic.
258  */
getBlockForInsert() const259 RS_Block* RS_Insert::getBlockForInsert() const{
260 	RS_Block* blk = nullptr;
261 		if (block) {
262 			blk=block;
263 			return blk;
264         }
265 
266     RS_BlockList* blkList;
267 
268 	if (!data.blockSource) {
269 		if (getGraphic()) {
270             blkList = getGraphic()->getBlockList();
271         } else {
272 			blkList = nullptr;
273         }
274     } else {
275         blkList = data.blockSource;
276     }
277 
278 	if (blkList) {
279         blk = blkList->find(data.name);
280     }
281 
282 	if (blk) {
283     }
284 
285         block = blk;
286 
287     return blk;
288 }
289 
290 
291 /**
292  * Is this insert visible? (re-implementation from RS_Entity)
293  *
294  * @return true Only if the entity and the block and the layer it is on
295  * are visible.
296  * The Layer might also be nullptr. In that case the layer visibility
297  * is ignored.
298  * The Block might also be nullptr. In that case the block visibility
299  * is ignored.
300  */
isVisible() const301 bool RS_Insert::isVisible() const
302 {
303     RS_Block* blk = getBlockForInsert();
304 	if (blk) {
305         if (blk->isFrozen()) {
306             return false;
307         }
308     }
309 
310     return RS_Entity::isVisible();
311 }
312 
313 
getRefPoints() const314 RS_VectorSolutions RS_Insert::getRefPoints() const
315 {
316 	return RS_VectorSolutions{data.insertionPoint};
317 }
318 
319 
320 
getNearestRef(const RS_Vector & coord,double * dist) const321 RS_Vector RS_Insert::getNearestRef(const RS_Vector& coord,
322 									 double* dist) const{
323 
324         return getRefPoints().getClosest(coord, dist);
325 }
326 
327 
328 
move(const RS_Vector & offset)329 void RS_Insert::move(const RS_Vector& offset) {
330         RS_DEBUG->print("RS_Insert::move: offset: %f/%f",
331                 offset.x, offset.y);
332         RS_DEBUG->print("RS_Insert::move1: insertionPoint: %f/%f",
333                 data.insertionPoint.x, data.insertionPoint.y);
334     data.insertionPoint.move(offset);
335         RS_DEBUG->print("RS_Insert::move2: insertionPoint: %f/%f",
336                 data.insertionPoint.x, data.insertionPoint.y);
337     update();
338 }
339 
340 
341 
rotate(const RS_Vector & center,const double & angle)342 void RS_Insert::rotate(const RS_Vector& center, const double& angle) {
343         RS_DEBUG->print("RS_Insert::rotate1: insertionPoint: %f/%f "
344             "/ center: %f/%f",
345                 data.insertionPoint.x, data.insertionPoint.y,
346                 center.x, center.y);
347     data.insertionPoint.rotate(center, angle);
348     data.angle = RS_Math::correctAngle(data.angle+angle);
349         RS_DEBUG->print("RS_Insert::rotate2: insertionPoint: %f/%f",
350                 data.insertionPoint.x, data.insertionPoint.y);
351     update();
352 }
rotate(const RS_Vector & center,const RS_Vector & angleVector)353 void RS_Insert::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
354         RS_DEBUG->print("RS_Insert::rotate1: insertionPoint: %f/%f "
355             "/ center: %f/%f",
356                 data.insertionPoint.x, data.insertionPoint.y,
357                 center.x, center.y);
358     data.insertionPoint.rotate(center, angleVector);
359     data.angle = RS_Math::correctAngle(data.angle+angleVector.angle());
360         RS_DEBUG->print("RS_Insert::rotate2: insertionPoint: %f/%f",
361                 data.insertionPoint.x, data.insertionPoint.y);
362     update();
363 }
364 
365 
366 
scale(const RS_Vector & center,const RS_Vector & factor)367 void RS_Insert::scale(const RS_Vector& center, const RS_Vector& factor) {
368         RS_DEBUG->print("RS_Insert::scale1: insertionPoint: %f/%f",
369                 data.insertionPoint.x, data.insertionPoint.y);
370     data.insertionPoint.scale(center, factor);
371     data.scaleFactor.scale(RS_Vector(0.0, 0.0), factor);
372     data.spacing.scale(RS_Vector(0.0, 0.0), factor);
373         RS_DEBUG->print("RS_Insert::scale2: insertionPoint: %f/%f",
374                 data.insertionPoint.x, data.insertionPoint.y);
375     update();
376 }
377 
378 
379 
mirror(const RS_Vector & axisPoint1,const RS_Vector & axisPoint2)380 void RS_Insert::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
381     data.insertionPoint.mirror(axisPoint1, axisPoint2);
382 
383 		RS_Vector vec = RS_Vector::polar(1.0, data.angle);
384         vec.mirror(RS_Vector(0.0,0.0), axisPoint2-axisPoint1);
385         data.angle = RS_Math::correctAngle(vec.angle()-M_PI);
386 
387         data.scaleFactor.x*=-1;
388 
389     update();
390 }
391 
392 
operator <<(std::ostream & os,const RS_Insert & i)393 std::ostream& operator << (std::ostream& os, const RS_Insert& i) {
394     os << " Insert: " << i.getData() << std::endl;
395     return os;
396 }
397 
398