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