~ubuntu-branches/debian/sid/librecad/sid

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Scott Howard
  • Date: 2011-02-03 19:04:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110203190409-202riehiqzmkydth
Tags: upstream-1.0.0~beta5
ImportĀ upstreamĀ versionĀ 1.0.0~beta5

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