~librecad-dev/librecad/librecad

« back to all changes in this revision

Viewing changes to librecad/src/lib/engine/rs_polyline.cpp

  • Committer: Scott Howard
  • Date: 2014-02-21 19:07:55 UTC
  • Revision ID: showard@debian.org-20140221190755-csjax9wb146hgdq4
first commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
28
#include "rs_polyline.h"
 
29
 
 
30
#include "rs_debug.h"
 
31
#include "rs_line.h"
 
32
#include "rs_arc.h"
 
33
#include "rs_graphicview.h"
 
34
//#include "rs_modification.h"
 
35
#include "rs_information.h"
 
36
 
 
37
 
 
38
/**
 
39
 * Constructor.
 
40
 */
 
41
RS_Polyline::RS_Polyline(RS_EntityContainer* parent)
 
42
        :RS_EntityContainer(parent) {
 
43
 
 
44
    closingEntity = NULL;
 
45
    nextBulge = 0.0;
 
46
}
 
47
 
 
48
 
 
49
/**
 
50
 * Constructor.
 
51
 * @param d Polyline data
 
52
 */
 
53
RS_Polyline::RS_Polyline(RS_EntityContainer* parent,
 
54
                         const RS_PolylineData& d)
 
55
        :RS_EntityContainer(parent), data(d) {
 
56
 
 
57
    closingEntity = NULL;
 
58
    nextBulge = 0.0;
 
59
    calculateBorders();
 
60
}
 
61
 
 
62
 
 
63
/**
 
64
 * Destructor
 
65
 */
 
66
RS_Polyline::~RS_Polyline() {}
 
67
 
 
68
 
 
69
/**
 
70
 * Removes the last vertex of this polyline.
 
71
 */
 
72
void RS_Polyline::removeLastVertex() {
 
73
        RS_Entity* last = lastEntity();
 
74
        if (last!=NULL) {
 
75
                removeEntity(last);
 
76
                last = lastEntity();
 
77
                if (last!=NULL) {
 
78
                        if (last->isAtomic()) {
 
79
                                data.endpoint = ((RS_AtomicEntity*)last)->getEndpoint();
 
80
                        }
 
81
                        else {
 
82
                                RS_DEBUG->print(RS_Debug::D_WARNING,
 
83
                                        "RS_Polyline::removeLastVertex: "
 
84
                                        "polyline contains non-atomic entity");
 
85
                        }
 
86
                }
 
87
        }
 
88
}
 
89
 
 
90
 
 
91
/**
 
92
 * Adds a vertex from the endpoint of the last segment or
 
93
 * from the startpoint of the first segment to 'v' or
 
94
 * sets the startpoint to the point 'v'.
 
95
 *
 
96
 * The very first vertex added with this method is the startpoint.
 
97
 *
 
98
 * @param v vertex coordinate to be added
 
99
 * @param bulge The bulge of the arc or 0 for a line segment (see DXF documentation)
 
100
 * @param prepend true: prepend at start instead of append at end
 
101
 *
 
102
 * @return Pointer to the entity that was addded or NULL if this
 
103
 *         was the first vertex added.
 
104
 */
 
105
RS_Entity* RS_Polyline::addVertex(const RS_Vector& v, double bulge, bool prepend) {
 
106
 
 
107
    RS_Entity* entity=NULL;
 
108
    //static double nextBulge = 0.0;
 
109
 
 
110
    // very first vertex:
 
111
    if (!data.startpoint.valid) {
 
112
        data.startpoint = data.endpoint = v;
 
113
        nextBulge = bulge;
 
114
    }
 
115
 
 
116
    // consequent vertices:
 
117
    else {
 
118
        // add entity to the polyline:
 
119
        entity = createVertex(v, nextBulge, prepend);
 
120
        if (entity!=NULL) {
 
121
                        if (prepend==false) {
 
122
                RS_EntityContainer::addEntity(entity);
 
123
                                data.endpoint = v;
 
124
                        }
 
125
                        else {
 
126
                RS_EntityContainer::insertEntity(0, entity);
 
127
                                data.startpoint = v;
 
128
                        }
 
129
        }
 
130
        nextBulge = bulge;
 
131
        endPolyline();
 
132
    }
 
133
    //data.endpoint = v;
 
134
 
 
135
    return entity;
 
136
}
 
137
 
 
138
 
 
139
/**
 
140
 * Appends a vertex list from the endpoint of the last segment
 
141
 * sets the startpoint to the first point if not exist.
 
142
 *
 
143
 * The very first vertex added with this method is the startpoint if not exists.
 
144
 *
 
145
 * @param vl list of vertexs coordinate to be added
 
146
 * @param Pair are RS_Vector of coord and the bulge of the arc or 0 for a line segment (see DXF documentation)
 
147
 *
 
148
 * @return None
 
149
 */
 
150
void RS_Polyline::appendVertexs(const QList< QPair<RS_Vector*, double> > vl) {
 
151
    RS_Entity* entity=NULL;
 
152
    //static double nextBulge = 0.0;
 
153
    if (vl.isEmpty()) return;
 
154
    int idx = 0;
 
155
    // very first vertex:
 
156
    if (!data.startpoint.valid) {
 
157
        data.startpoint = data.endpoint = *(vl.at(idx).first);
 
158
        nextBulge = vl.at(idx++).second;
 
159
    }
 
160
 
 
161
    // consequent vertices:
 
162
    for (; idx< vl.size();idx++){
 
163
        entity = createVertex(*(vl.at(idx).first), nextBulge, false);
 
164
        data.endpoint = entity->getEndpoint();
 
165
        RS_EntityContainer::addEntity(entity);
 
166
        nextBulge = vl.at(idx).second;
 
167
    }
 
168
 
 
169
    endPolyline();
 
170
}
 
171
 
 
172
 
 
173
/**
 
174
 * Creates a vertex from the endpoint of the last element or
 
175
 * sets the startpoint to the point 'v'.
 
176
 *
 
177
 * The very first vertex added is the starting point.
 
178
 *
 
179
 * @param v vertex coordinate
 
180
 * @param bulge The bulge of the arc (see DXF documentation)
 
181
 * @param prepend true: Prepend instead of append at end
 
182
 *
 
183
 * @return Pointer to the entity that was created or NULL if this
 
184
 *         was the first vertex added.
 
185
 */
 
186
RS_Entity* RS_Polyline::createVertex(const RS_Vector& v, double bulge, bool prepend) {
 
187
 
 
188
    RS_Entity* entity=NULL;
 
189
 
 
190
    RS_DEBUG->print("RS_Polyline::createVertex: %f/%f to %f/%f bulge: %f",
 
191
                    data.endpoint.x, data.endpoint.y, v.x, v.y, bulge);
 
192
 
 
193
    // create line for the polyline:
 
194
    if (fabs(bulge)<RS_TOLERANCE) {
 
195
                if (prepend==false) {
 
196
                entity = new RS_Line(this, RS_LineData(data.endpoint, v));
 
197
                }
 
198
                else {
 
199
                entity = new RS_Line(this, RS_LineData(v, data.startpoint));
 
200
                }
 
201
        entity->setSelected(isSelected());
 
202
        entity->setPen(RS_Pen(RS2::FlagInvalid));
 
203
        entity->setLayer(NULL);
 
204
        //RS_EntityContainer::addEntity(entity);
 
205
        //data.endpoint = v;
 
206
    }
 
207
 
 
208
    // create arc for the polyline:
 
209
    else {
 
210
        bool reversed = (bulge<0.0);
 
211
        double alpha = atan(bulge)*4.0;
 
212
 
 
213
        double radius;
 
214
        RS_Vector center;
 
215
        RS_Vector middle;
 
216
        double dist;
 
217
        double angle;
 
218
 
 
219
                if (prepend==false) {
 
220
                middle = (data.endpoint+v)/2.0;
 
221
            dist = data.endpoint.distanceTo(v)/2.0;
 
222
                angle = data.endpoint.angleTo(v);
 
223
                }
 
224
                else {
 
225
                middle = (data.startpoint+v)/2.0;
 
226
            dist = data.startpoint.distanceTo(v)/2.0;
 
227
                angle = v.angleTo(data.startpoint);
 
228
                }
 
229
 
 
230
        // alpha can't be 0.0 at this point
 
231
        radius = fabs(dist / sin(alpha/2.0));
 
232
 
 
233
        double wu = fabs(RS_Math::pow(radius, 2.0) - RS_Math::pow(dist, 2.0));
 
234
        double h = sqrt(wu);
 
235
 
 
236
        if (bulge>0.0) {
 
237
            angle+=M_PI/2.0;
 
238
        } else {
 
239
            angle-=M_PI/2.0;
 
240
        }
 
241
 
 
242
        if (fabs(alpha)>M_PI) {
 
243
            h*=-1.0;
 
244
        }
 
245
 
 
246
        center.setPolar(h, angle);
 
247
        center+=middle;
 
248
 
 
249
                double a1;
 
250
                double a2;
 
251
 
 
252
                if (prepend==false) {
 
253
                        a1 = center.angleTo(data.endpoint);
 
254
                        a2 = center.angleTo(v);
 
255
                }
 
256
                else {
 
257
                        a1 = center.angleTo(v);
 
258
                        a2 = center.angleTo(data.startpoint);
 
259
                }
 
260
 
 
261
        RS_ArcData d(center, radius,
 
262
                     a1, a2,
 
263
                     reversed);
 
264
 
 
265
        entity = new RS_Arc(this, d);
 
266
        entity->setSelected(isSelected());
 
267
        entity->setPen(RS_Pen(RS2::FlagInvalid));
 
268
        entity->setLayer(NULL);
 
269
    }
 
270
 
 
271
    return entity;
 
272
}
 
273
 
 
274
 
 
275
/**
 
276
 * Ends polyline and adds the last entity if the polyline is closed
 
277
 */
 
278
void RS_Polyline::endPolyline() {
 
279
        RS_DEBUG->print("RS_Polyline::endPolyline");
 
280
 
 
281
    if (isClosed()) {
 
282
                RS_DEBUG->print("RS_Polyline::endPolyline: adding closing entity");
 
283
 
 
284
        // remove old closing entity:
 
285
        if (closingEntity!=NULL) {
 
286
            removeEntity(closingEntity);
 
287
        }
 
288
 
 
289
        // add closing entity to the polyline:
 
290
        closingEntity = createVertex(data.startpoint, nextBulge);
 
291
        if (closingEntity!=NULL) {
 
292
            RS_EntityContainer::addEntity(closingEntity);
 
293
            //data.endpoint = data.startpoint;
 
294
        }
 
295
    }
 
296
    calculateBorders();
 
297
}
 
298
 
 
299
//RLZ: rewrite this:
 
300
void RS_Polyline::setClosed(bool cl, double bulge) {
 
301
    Q_UNUSED(bulge);
 
302
    bool areClosed = isClosed();
 
303
    setClosed(cl);
 
304
    if (isClosed()) {
 
305
        endPolyline();
 
306
    } else if (areClosed){
 
307
        removeLastVertex();
 
308
    }
 
309
}
 
310
 
 
311
 
 
312
/**
 
313
 * @return The bulge of the closing entity.
 
314
 */
 
315
double RS_Polyline::getClosingBulge() {
 
316
    if (isClosed()) {
 
317
                RS_Entity* e = lastEntity();
 
318
                if (e!=NULL && e->rtti()==RS2::EntityArc) {
 
319
                        return ((RS_Arc*)e)->getBulge();
 
320
                }
 
321
        }
 
322
 
 
323
        return 0.0;
 
324
}
 
325
 
 
326
 
 
327
/**
 
328
 * Sets the polylines start and endpoint to match the first and last vertex.
 
329
 */
 
330
void RS_Polyline::updateEndpoints() {
 
331
        RS_Entity* e1 = firstEntity();
 
332
        if (e1!=NULL && e1->isAtomic()) {
 
333
                RS_Vector v = ((RS_AtomicEntity*)e1)->getStartpoint();
 
334
                setStartpoint(v);
 
335
        }
 
336
 
 
337
        RS_Entity* e2 = lastEntity();
 
338
        if (isClosed()) {
 
339
                e2 = prevEntity();
 
340
        }
 
341
        if (e2!=NULL && e2->isAtomic()) {
 
342
                RS_Vector v = ((RS_AtomicEntity*)e2)->getEndpoint();
 
343
                setEndpoint(v);
 
344
    }
 
345
}
 
346
 
 
347
 
 
348
 
 
349
/**
 
350
 * Reimplementation of the addEntity method for a normal container.
 
351
 * This reimplementation deletes the given entity!
 
352
 *
 
353
 * To add entities use addVertex() or addSegment() instead.
 
354
 */
 
355
void RS_Polyline::addEntity(RS_Entity* entity) {
 
356
    RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Polyline::addEntity:"
 
357
                    " should never be called");
 
358
 
 
359
    if (entity==NULL) {
 
360
        return;
 
361
    }
 
362
    delete entity;
 
363
}
 
364
 
 
365
 
 
366
/**
 
367
 * Adds a segment to the polyline.
 
368
 */
 
369
/*void RS_Polyline::addSegment(RS_Entity* entity) {
 
370
        RS_EntityContainer::addEntity(entity);
 
371
        // TODO: reorder and check polyline
 
372
}*/
 
373
 
 
374
 
 
375
 
 
376
RS_VectorSolutions RS_Polyline::getRefPoints() {
 
377
    RS_VectorSolutions ret;
 
378
 
 
379
    ret.push_back(data.startpoint);
 
380
 
 
381
    for (RS_Entity* e=firstEntity(RS2::ResolveNone);
 
382
         e!=NULL;
 
383
         e = nextEntity(RS2::ResolveNone)) {
 
384
        if (e->isAtomic()) {
 
385
            ret.push_back(((RS_AtomicEntity*)e)->getEndpoint());
 
386
        }
 
387
    }
 
388
 
 
389
    ret.push_back( data.endpoint);
 
390
 
 
391
    return ret;
 
392
}
 
393
 
 
394
RS_Vector RS_Polyline::getNearestRef(const RS_Vector& coord,
 
395
                                   double* dist) {
 
396
 
 
397
    return RS_Entity::getNearestRef(coord, dist);
 
398
}
 
399
 
 
400
RS_Vector RS_Polyline::getNearestSelectedRef(const RS_Vector& coord,
 
401
        double* dist) {
 
402
 
 
403
    return RS_Entity::getNearestSelectedRef(coord, dist);
 
404
}
 
405
 
 
406
 
 
407
 
 
408
/*
 
409
void RS_Polyline::reorder() {
 
410
        // current point:
 
411
        RS_Vector cp;
 
412
 
 
413
        bool done = false;
 
414
        do {
 
415
 
 
416
        } while(!done);
 
417
}
 
418
*/
 
419
 
 
420
 
 
421
/**
 
422
  * this should handle modifyOffset
 
423
  *@ coord, indicate direction of offset
 
424
  *@ distance of offset
 
425
  *
 
426
  *@Author, Dongxu Li
 
427
  */
 
428
bool RS_Polyline::offset(const RS_Vector& coord, const double& distance){
 
429
    double dist;
 
430
    //find the nearest one
 
431
    int length=count();
 
432
        QVector<RS_Vector> intersections(length);
 
433
    if(length>1){//sort the polyline entity start/end point order
 
434
        int i(0);
 
435
        double d0,d1;
 
436
        RS_Entity* en0(entityAt(0));
 
437
        RS_Entity* en1(entityAt(1));
 
438
 
 
439
        RS_Vector vStart(en0->getStartpoint());
 
440
        RS_Vector vEnd(en0->getEndpoint());
 
441
        en1->getNearestEndpoint(vStart,&d0);
 
442
        en1->getNearestEndpoint(vEnd,&d1);
 
443
        if(d0<d1) en0->revertDirection();
 
444
        for(i=1;i<length;en0=en1){
 
445
                //linked to head-tail chain
 
446
            en1=entityAt(i);
 
447
            vStart=en1->getStartpoint();
 
448
            vEnd=en1->getEndpoint();
 
449
            en0->getNearestEndpoint(vStart,&d0);
 
450
            en0->getNearestEndpoint(vEnd,&d1);
 
451
            if(d0>d1) en1->revertDirection();
 
452
            intersections[i-1]=(en0->getEndpoint()+en1->getStartpoint())*0.5;
 
453
            i++;
 
454
        }
 
455
 
 
456
    }
 
457
    RS_Entity* en(getNearestEntity(coord, &dist, RS2::ResolveNone));
 
458
    if(en==NULL) return false;
 
459
    int indexNearest=findEntity(en);
 
460
    //        RS_Vector vp(en->getNearestPointOnEntity(coord,false));
 
461
    //        RS_Vector direction(en->getTangentDirection(vp));
 
462
    //        RS_Vector vp1(-direction.y,direction.x);//normal direction
 
463
    //        double a2(vp1.squared());
 
464
    //        if(a2<RS_TOLERANCE2) return false;
 
465
    //        vp1 *= distance/sqrt(a2);
 
466
    //        move(vp1);
 
467
    //        return true;
 
468
 
 
469
    RS_Polyline* pnew= static_cast<RS_Polyline*>(clone());
 
470
    int i;
 
471
    i=indexNearest;
 
472
    int previousIndex(i);
 
473
    pnew->entityAt(i)->offset(coord,distance);
 
474
    RS_Vector vp;
 
475
    //offset all
 
476
    //fixme, this is too ugly
 
477
    for(i=indexNearest-1;i>=0;i--){
 
478
        RS_VectorSolutions sol0=RS_Information::getIntersection(pnew->entityAt(previousIndex),entityAt(i),true);
 
479
//        RS_VectorSolutions sol1;
 
480
        double dmax(RS_TOLERANCE15);
 
481
        RS_Vector trimP(false);
 
482
        for(int j=0;j<sol0.getNumber();j++){
 
483
 
 
484
            double d0( (sol0.get(j) - pnew->entityAt(previousIndex)->getStartpoint()).squared());//potential bug, need to trim better
 
485
            if(d0>dmax) {
 
486
                dmax=d0;
 
487
                trimP=sol0.get(j);
 
488
            }
 
489
        }
 
490
        if(trimP.valid){
 
491
            static_cast<RS_AtomicEntity*>(pnew->entityAt(previousIndex))->trimStartpoint(trimP);
 
492
            static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimEndpoint(trimP);
 
493
            vp=pnew->entityAt(previousIndex)->getMiddlePoint();
 
494
        }else{
 
495
            vp=pnew->entityAt(previousIndex)->getStartpoint();
 
496
            vp.rotate(entityAt(previousIndex)->getStartpoint(),entityAt(i)->getDirection2()-entityAt(previousIndex)->getDirection1()+M_PI);
 
497
        }
 
498
        pnew->entityAt(i)->offset(vp,distance);
 
499
        previousIndex=i;
 
500
    }
 
501
 
 
502
    previousIndex=indexNearest;
 
503
    for(i=indexNearest+1;i<length;i++){
 
504
        RS_VectorSolutions sol0=RS_Information::getIntersection(pnew->entityAt(previousIndex),entityAt(i),true);
 
505
//        RS_VectorSolutions sol1;
 
506
        double dmax(RS_TOLERANCE15);
 
507
        RS_Vector trimP(false);
 
508
        for(int j=0;j<sol0.getNumber();j++){
 
509
            double d0( (sol0.get(j) - pnew->entityAt(previousIndex)->getEndpoint()).squared());//potential bug, need to trim better
 
510
            if(d0>dmax) {
 
511
                dmax=d0;
 
512
                trimP=sol0.get(j);
 
513
            }
 
514
        }
 
515
        if(trimP.valid){
 
516
            static_cast<RS_AtomicEntity*>(pnew->entityAt(previousIndex))->trimEndpoint(trimP);
 
517
            static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimStartpoint(trimP);
 
518
            vp=pnew->entityAt(previousIndex)->getMiddlePoint();
 
519
        }else{
 
520
            vp=pnew->entityAt(previousIndex)->getEndpoint();
 
521
            vp.rotate(entityAt(previousIndex)->getEndpoint(),entityAt(i)->getDirection1()-entityAt(previousIndex)->getDirection2()+M_PI);
 
522
        }
 
523
        pnew->entityAt(i)->offset(vp,distance);
 
524
        previousIndex=i;
 
525
    }
 
526
    //trim
 
527
    //connect and trim        RS_Modification m(*container, graphicView);
 
528
    for(i=0;i<length-1;i++){
 
529
        RS_VectorSolutions sol0=RS_Information::getIntersection(pnew->entityAt(i),pnew->entityAt(i+1),true);
 
530
        if(sol0.getNumber()==0) {
 
531
            sol0=RS_Information::getIntersection(pnew->entityAt(i),pnew->entityAt(i+1));
 
532
//            RS_Vector vp0(pnew->entityAt(i)->getEndpoint());
 
533
//            RS_Vector vp1(pnew->entityAt(i+1)->getStartpoint());
 
534
//            double a0(intersections.at(i).angleTo(vp0));
 
535
//            double a1(intersections.at(i).angleTo(vp1));
 
536
            RS_VectorSolutions sol1;
 
537
            for(int j=0;j<sol0.getNumber();j++){
 
538
                if(RS_Math::isAngleBetween(intersections.at(i).angleTo(sol0.get(j)),
 
539
                                           pnew->entityAt(i)->getDirection2(),
 
540
                                           pnew->entityAt(i+1)->getDirection1(),
 
541
                                           false)==false){
 
542
                    sol1.push_back(sol0.get(j));
 
543
                }
 
544
            }
 
545
            if(sol1.getNumber()==0) continue;
 
546
            RS_Vector trimP(sol1.getClosest(intersections.at(i)));
 
547
            static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimEndpoint(trimP);
 
548
            static_cast<RS_AtomicEntity*>(pnew->entityAt(i+1))->trimStartpoint(trimP);
 
549
        }else{
 
550
            RS_Vector trimP(sol0.getClosest(pnew->entityAt(i)->getStartpoint()));
 
551
            static_cast<RS_AtomicEntity*>(pnew->entityAt(i))->trimEndpoint(trimP);
 
552
            static_cast<RS_AtomicEntity*>(pnew->entityAt(i+1))->trimStartpoint(trimP);
 
553
        }
 
554
 
 
555
    }
 
556
 
 
557
    *this = *pnew;
 
558
    return true;
 
559
 
 
560
 
 
561
}
 
562
 
 
563
void RS_Polyline::move(const RS_Vector& offset) {
 
564
    RS_EntityContainer::move(offset);
 
565
    data.startpoint.move(offset);
 
566
    data.endpoint.move(offset);
 
567
}
 
568
 
 
569
 
 
570
 
 
571
void RS_Polyline::rotate(const RS_Vector& center, const double& angle) {
 
572
    rotate(center, RS_Vector(angle));
 
573
}
 
574
 
 
575
 
 
576
void RS_Polyline::rotate(const RS_Vector& center, const RS_Vector& angleVector) {
 
577
    RS_EntityContainer::rotate(center, angleVector);
 
578
    data.startpoint.rotate(center, angleVector);
 
579
    data.endpoint.rotate(center, angleVector);
 
580
}
 
581
 
 
582
 
 
583
 
 
584
void RS_Polyline::scale(const RS_Vector& center, const RS_Vector& factor) {
 
585
    RS_EntityContainer::scale(center, factor);
 
586
    data.startpoint.scale(center, factor);
 
587
    data.endpoint.scale(center, factor);
 
588
}
 
589
 
 
590
 
 
591
 
 
592
void RS_Polyline::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
 
593
    RS_EntityContainer::mirror(axisPoint1, axisPoint2);
 
594
    data.startpoint.mirror(axisPoint1, axisPoint2);
 
595
    data.endpoint.mirror(axisPoint1, axisPoint2);
 
596
}
 
597
 
 
598
 
 
599
 
 
600
void RS_Polyline::moveRef(const RS_Vector& ref, const RS_Vector& offset) {
 
601
        RS_EntityContainer::moveRef(ref, offset);
 
602
    if (ref.distanceTo(data.startpoint)<1.0e-4) {
 
603
       data.startpoint.move(offset);
 
604
    }
 
605
    if (ref.distanceTo(data.endpoint)<1.0e-4) {
 
606
       data.endpoint.move(offset);
 
607
    }
 
608
    //update();
 
609
}
 
610
 
 
611
void RS_Polyline::revertDirection() {
 
612
        RS_EntityContainer::revertDirection();
 
613
        RS_Vector tmp = data.startpoint;
 
614
        data.startpoint = data.endpoint;
 
615
        data.endpoint = tmp;
 
616
}
 
617
 
 
618
void RS_Polyline::stretch(const RS_Vector& firstCorner,
 
619
                          const RS_Vector& secondCorner,
 
620
                          const RS_Vector& offset) {
 
621
 
 
622
    if (data.startpoint.isInWindow(firstCorner, secondCorner)) {
 
623
        data.startpoint.move(offset);
 
624
    }
 
625
    if (data.endpoint.isInWindow(firstCorner, secondCorner)) {
 
626
        data.endpoint.move(offset);
 
627
    }
 
628
 
 
629
        RS_EntityContainer::stretch(firstCorner, secondCorner, offset);
 
630
}
 
631
 
 
632
 
 
633
/**
 
634
 * Slightly optimized drawing for polylines.
 
635
 */
 
636
void RS_Polyline::draw(RS_Painter* painter,RS_GraphicView* view, double& /*patternOffset*/) {
 
637
 
 
638
    if (view==NULL) {
 
639
        return;
 
640
    }
 
641
 
 
642
    // draw first entity and set correct pen:
 
643
    RS_Entity* e = firstEntity(RS2::ResolveNone);
 
644
    // We get the pen from the entitycontainer and apply it to the
 
645
    // first line so that subsequent line are draw in the right color
 
646
    //prevent segfault if polyline is empty
 
647
    if (e != NULL) {
 
648
        RS_Pen p=this->getPen(true);
 
649
        e->setPen(p);
 
650
        double patternOffset=0.;
 
651
        view->drawEntity(painter, e, patternOffset);
 
652
 
 
653
        e = nextEntity(RS2::ResolveNone);
 
654
        while(e!=NULL) {
 
655
            view->drawEntityPlain(painter, e, patternOffset);
 
656
            e = nextEntity(RS2::ResolveNone);
 
657
            //RS_DEBUG->print("offset: %f\nlength was: %f", offset, e->getLength());
 
658
        }
 
659
    }
 
660
}
 
661
 
 
662
 
 
663
 
 
664
 
 
665
/**
 
666
 * Dumps the point's data to stdout.
 
667
 */
 
668
std::ostream& operator << (std::ostream& os, const RS_Polyline& l) {
 
669
    os << " Polyline: " << l.getData() << " {\n";
 
670
 
 
671
    os << (RS_EntityContainer&)l;
 
672
 
 
673
    os << "\n}\n";
 
674
 
 
675
    return os;
 
676
}
 
677