]> Shamusworld >> Repos - architektonas/blob - src/base/rs_polyline.cpp
Initial import
[architektonas] / src / base / rs_polyline.cpp
1 /****************************************************************************
2 ** $Id: rs_polyline.cpp 1959 2005-03-08 14:09:02Z js $
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_polyline.h"
28
29 #include "rs_debug.h"
30 #include "rs_line.h"
31 #include "rs_arc.h"
32 #include "rs_graphicview.h"
33 #include "paintintf.h"
34
35 /**
36  * Constructor.
37  */
38 RS_Polyline::RS_Polyline(RS_EntityContainer * parent): RS_EntityContainer(parent),
39         closingEntity(NULL), nextBulge(0.0)
40 {
41 }
42
43 /**
44  * Constructor.
45  * @param d Polyline data
46  */
47 RS_Polyline::RS_Polyline(RS_EntityContainer* parent, const RS_PolylineData& d):
48         RS_EntityContainer(parent), data(d)
49 {
50     closingEntity = NULL;
51     nextBulge = 0.0;
52     calculateBorders();
53 }
54
55 /**
56  * Destructor
57  */
58 RS_Polyline::~RS_Polyline()
59 {
60 }
61
62 /*virtual*/ RS_Entity * RS_Polyline::clone()
63 {
64         RS_Polyline * p = new RS_Polyline(*this);
65 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
66 //      p->entities.setAutoDelete(entities.autoDelete());
67         p->initId();
68         p->detach();
69         return p;
70 }
71
72 /**     @return RS2::EntityPolyline */
73 /*virtual*/ RS2::EntityType RS_Polyline::rtti() const
74 {
75         return RS2::EntityPolyline;
76 }
77
78 /** @return Copy of data that defines the polyline. */
79 RS_PolylineData RS_Polyline::getData() const
80 {
81         return data;
82 }
83
84 /** sets a new start point of the polyline */
85 void RS_Polyline::setStartpoint(Vector & v)
86 {
87         data.startpoint = v;
88
89         if (!data.endpoint.valid)
90                 data.endpoint = v;
91 }
92
93 /** @return Start point of the entity */
94 Vector RS_Polyline::getStartpoint()
95 {
96         return data.startpoint;
97 }
98
99 /** sets a new end point of the polyline */
100 void RS_Polyline::setEndpoint(Vector & v)
101 {
102         data.endpoint = v;
103 }
104
105 /** @return End point of the entity */
106 Vector RS_Polyline::getEndpoint()
107 {
108         return data.endpoint;
109 }
110
111 /**
112  * Removes the last vertex of this polyline.
113  */
114 void RS_Polyline::removeLastVertex()
115 {
116         RS_Entity * last = lastEntity();
117
118         if (last != NULL)
119         {
120                 removeEntity(last);
121                 last = lastEntity();
122
123                 if (last != NULL)
124                 {
125                         if (last->isAtomic())
126                                 data.endpoint = ((RS_AtomicEntity*)last)->getEndpoint();
127                         else
128                                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Polyline::removeLastVertex: "
129                                         "polyline contains non-atomic entity");
130                 }
131         }
132 }
133
134 /**
135  * Adds a vertex from the endpoint of the last segment or
136  * from the startpoint of the first segment to 'v' or
137  * sets the startpoint to the point 'v'.
138  *
139  * The very first vertex added with this method is the startpoint.
140  *
141  * @param v vertex coordinate to be added
142  * @param bulge The bulge of the arc or 0 for a line segment (see DXF documentation)
143  * @param prepend true: prepend at start instead of append at end
144  *
145  * @return Pointer to the entity that was addded or NULL if this
146  *         was the first vertex added.
147  */
148 RS_Entity * RS_Polyline::addVertex(const Vector & v, double bulge, bool prepend)
149 {
150     RS_Entity * entity = NULL;
151     //static double nextBulge = 0.0;
152
153     // very first vertex:
154     if (!data.startpoint.valid)
155         {
156         data.startpoint = data.endpoint = v;
157         nextBulge = bulge;
158     }
159
160     // consequent vertices:
161     else {
162         // add entity to the polyline:
163         entity = createVertex(v, nextBulge, prepend);
164         if (entity!=NULL) {
165                         if (prepend==false) {
166                 RS_EntityContainer::addEntity(entity);
167                                 data.endpoint = v;
168                         }
169                         else {
170                 RS_EntityContainer::insertEntity(0, entity);
171                                 data.startpoint = v;
172                         }
173         }
174         nextBulge = bulge;
175         endPolyline();
176     }
177     //data.endpoint = v;
178
179     return entity;
180 }
181
182
183
184 /**
185  * Creates a vertex from the endpoint of the last element or
186  * sets the startpoint to the point 'v'.
187  *
188  * The very first vertex added is the starting point.
189  *
190  * @param v vertex coordinate
191  * @param bulge The bulge of the arc (see DXF documentation)
192  * @param prepend true: Prepend instead of append at end
193  *
194  * @return Pointer to the entity that was created or NULL if this
195  *         was the first vertex added.
196  */
197 RS_Entity* RS_Polyline::createVertex(const Vector& v, double bulge, bool prepend) {
198
199     RS_Entity* entity=NULL;
200
201     RS_DEBUG->print("RS_Polyline::createVertex: %f/%f to %f/%f bulge: %f",
202                     data.endpoint.x, data.endpoint.y, v.x, v.y, bulge);
203
204     // create line for the polyline:
205     if (fabs(bulge)<RS_TOLERANCE) {
206                 if (prepend==false) {
207                 entity = new RS_Line(this, RS_LineData(data.endpoint, v));
208                 }
209                 else {
210                 entity = new RS_Line(this, RS_LineData(v, data.startpoint));
211                 }
212         entity->setSelected(isSelected());
213         entity->setPen(RS_Pen(RS2::FlagInvalid));
214         entity->setLayer(NULL);
215         //RS_EntityContainer::addEntity(entity);
216         //data.endpoint = v;
217     }
218
219     // create arc for the polyline:
220     else {
221         bool reversed = (bulge<0.0);
222         double alpha = atan(bulge)*4.0;
223
224         double radius;
225         Vector center;
226         Vector middle;
227         double dist;
228         double angle;
229
230                 if (prepend==false) {
231                 middle = (data.endpoint+v)/2.0;
232             dist = data.endpoint.distanceTo(v)/2.0;
233                 angle = data.endpoint.angleTo(v);
234                 }
235                 else {
236                 middle = (data.startpoint+v)/2.0;
237             dist = data.startpoint.distanceTo(v)/2.0;
238                 angle = v.angleTo(data.startpoint);
239                 }
240
241         // alpha can't be 0.0 at this point
242         radius = fabs(dist / sin(alpha/2.0));
243
244         double wu = fabs(RS_Math::pow(radius, 2.0) - RS_Math::pow(dist, 2.0));
245         double h = sqrt(wu);
246
247         if (bulge>0.0) {
248             angle+=M_PI/2.0;
249         } else {
250             angle-=M_PI/2.0;
251         }
252
253         if (fabs(alpha)>M_PI) {
254             h*=-1.0;
255         }
256
257         center.setPolar(h, angle);
258         center+=middle;
259
260                 double a1;
261                 double a2;
262
263                 if (prepend==false) {
264                         a1 = center.angleTo(data.endpoint);
265                         a2 = center.angleTo(v);
266                 }
267                 else {
268                         a1 = center.angleTo(v);
269                         a2 = center.angleTo(data.startpoint);
270                 }
271
272         RS_ArcData d(center, radius,
273                      a1, a2,
274                      reversed);
275
276         entity = new RS_Arc(this, d);
277         entity->setSelected(isSelected());
278         entity->setPen(RS_Pen(RS2::FlagInvalid));
279         entity->setLayer(NULL);
280     }
281
282     return entity;
283 }
284
285 /**
286  * Ends polyline and adds the last entity if the polyline is closed
287  */
288 void RS_Polyline::endPolyline()
289 {
290         RS_DEBUG->print("RS_Polyline::endPolyline");
291
292     if (isClosed())
293         {
294                 RS_DEBUG->print("RS_Polyline::endPolyline: adding closing entity");
295
296         // remove old closing entity:
297         if (closingEntity!=NULL)
298                 {
299             removeEntity(closingEntity);
300         }
301
302         // add closing entity to the polyline:
303         closingEntity = createVertex(data.startpoint, nextBulge);
304         if (closingEntity!=NULL)
305                 {
306             RS_EntityContainer::addEntity(closingEntity);
307             //data.endpoint = data.startpoint;
308         }
309     }
310 }
311
312 /**
313  * @return The bulge of the closing entity.
314  */
315 double RS_Polyline::getClosingBulge()
316 {
317     if (isClosed()) {
318                 RS_Entity* e = lastEntity();
319                 if (e!=NULL && e->rtti()==RS2::EntityArc) {
320                         return ((RS_Arc*)e)->getBulge();
321                 }
322         }
323
324         return 0.0;
325 }
326
327 /**
328  * Sets the polylines start and endpoint to match the first and last vertex.
329  */
330 void RS_Polyline::updateEndpoints()
331 {
332         RS_Entity * e1 = firstEntity();
333
334         if (e1 != NULL && e1->isAtomic())
335         {
336                 Vector v = ((RS_AtomicEntity *)e1)->getStartpoint();
337                 setStartpoint(v);
338         }
339
340         RS_Entity * e2 = lastEntity();
341
342         if (isClosed())
343         {
344                 e2 = prevEntity();
345         }
346
347         if (e2 != NULL && e2->isAtomic())
348         {
349                 Vector v = ((RS_AtomicEntity *)e2)->getEndpoint();
350                 setEndpoint(v);
351         }
352 }
353
354 /** @return true if the polyline is closed. false otherwise */
355 bool RS_Polyline::isClosed() const
356 {
357         return data.getFlag(RS2::FlagClosed);
358 }
359
360 void RS_Polyline::setClosed(bool cl)
361 {
362         if (cl)
363                 data.setFlag(RS2::FlagClosed);
364         else
365                 data.delFlag(RS2::FlagClosed);
366 }
367
368 /**
369  * Reimplementation of the addEntity method for a normal container.
370  * This reimplementation deletes the given entity!
371  *
372  * To add entities use addVertex() or addSegment() instead.
373  */
374 void RS_Polyline::addEntity(RS_Entity * entity)
375 {
376         RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Polyline::addEntity: should never be called");
377
378         if (entity == NULL)
379                 return;
380
381         delete entity;
382 }
383
384 /*virtual*/ void RS_Polyline::setNextBulge(double bulge)
385 {
386         nextBulge = bulge;
387 }
388
389 /**
390  * Adds a segment to the polyline.
391  */
392 /*void RS_Polyline::addSegment(RS_Entity* entity) {
393         RS_EntityContainer::addEntity(entity);
394         // TODO: reorder and check polyline
395 }*/
396
397 VectorSolutions RS_Polyline::getRefPoints()
398 {
399     VectorSolutions ret(count()+1);
400
401     int i=0;
402     ret.set(0, data.startpoint);
403         i++;
404
405         for (RS_Entity* e=firstEntity(RS2::ResolveNone);
406             e!=NULL;
407             e = nextEntity(RS2::ResolveNone), i++) {
408                 if (e->isAtomic()) {
409                 ret.set(i, ((RS_AtomicEntity*)e)->getEndpoint());
410                 }
411     }
412
413         ret.set(count(), data.endpoint);
414
415     return ret;
416 }
417
418 Vector RS_Polyline::getNearestRef(const Vector& coord,
419                                    double* dist) {
420
421     return RS_Entity::getNearestRef(coord, dist);
422 }
423
424 Vector RS_Polyline::getNearestSelectedRef(const Vector& coord,
425         double* dist) {
426
427     return RS_Entity::getNearestSelectedRef(coord, dist);
428 }
429
430
431
432 /*
433 void RS_Polyline::reorder() {
434         // current point:
435         Vector cp;
436
437         bool done = false;
438         do {
439
440         } while(!done);
441 }
442 */
443
444
445
446 void RS_Polyline::move(Vector offset) {
447     RS_EntityContainer::move(offset);
448     data.startpoint.move(offset);
449     data.endpoint.move(offset);
450 }
451
452
453
454 void RS_Polyline::rotate(Vector center, double angle) {
455     RS_EntityContainer::rotate(center, angle);
456     data.startpoint.rotate(center, angle);
457     data.endpoint.rotate(center, angle);
458 }
459
460
461
462 void RS_Polyline::scale(Vector center, Vector factor) {
463     RS_EntityContainer::scale(center, factor);
464     data.startpoint.scale(center, factor);
465     data.endpoint.scale(center, factor);
466 }
467
468
469
470 void RS_Polyline::mirror(Vector axisPoint1, Vector axisPoint2) {
471     RS_EntityContainer::mirror(axisPoint1, axisPoint2);
472     data.startpoint.mirror(axisPoint1, axisPoint2);
473     data.endpoint.mirror(axisPoint1, axisPoint2);
474 }
475
476 void RS_Polyline::moveRef(const Vector & ref, const Vector & offset)
477 {
478         RS_EntityContainer::moveRef(ref, offset);
479
480         if (ref.distanceTo(data.startpoint) < 1.0e-4)
481                 data.startpoint.move(offset);
482
483         if (ref.distanceTo(data.endpoint) < 1.0e-4)
484                 data.endpoint.move(offset);
485
486         //update();
487 }
488
489 void RS_Polyline::stretch(Vector firstCorner, Vector secondCorner, Vector offset)
490 {
491         if (data.startpoint.isInWindow(firstCorner, secondCorner))
492                 data.startpoint.move(offset);
493
494         if (data.endpoint.isInWindow(firstCorner, secondCorner))
495                 data.endpoint.move(offset);
496
497         RS_EntityContainer::stretch(firstCorner, secondCorner, offset);
498 }
499
500 /**
501  * Slightly optimized drawing for polylines.
502  */
503 //void RS_Polyline::draw(RS_Painter * painter, RS_GraphicView * view, double /*patternOffset*/)
504 void RS_Polyline::draw(PaintInterface * painter, RS_GraphicView * view, double /*patternOffset*/)
505 {
506         if (painter == NULL || view == NULL)
507                 return;
508
509         // draw first entity and set correct pen:
510         RS_Entity * e = firstEntity(RS2::ResolveNone);
511         view->drawEntity(e);
512
513         // draw subsequent entities with same pen:
514         for(RS_Entity * e=nextEntity(RS2::ResolveNone); e!=NULL; e = nextEntity(RS2::ResolveNone))
515                 view->drawEntityPlain(e);
516 }
517
518 /**
519  * Dumps the point's data to stdout.
520  */
521 std::ostream & operator<<(std::ostream & os, const RS_Polyline & l)
522 {
523         os << " Polyline: " << l.getData() << " {\n";
524         os << (RS_EntityContainer &)l;
525         os << "\n}\n";
526
527         return os;
528 }