1 /****************************************************************************
2 ** $Id: rs_polyline.cpp 1959 2005-03-08 14:09:02Z js $
4 ** Copyright (C) 2001-2003 RibbonSoft. All rights reserved.
6 ** This file is part of the qcadlib Library project.
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.
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.
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.
20 ** See http://www.ribbonsoft.com for further details.
22 ** Contact info@ribbonsoft.com if any conditions of this licensing are
25 **********************************************************************/
27 #include "rs_polyline.h"
32 #include "rs_graphicview.h"
33 #include "paintintf.h"
38 RS_Polyline::RS_Polyline(RS_EntityContainer * parent): RS_EntityContainer(parent),
39 closingEntity(NULL), nextBulge(0.0)
45 * @param d Polyline data
47 RS_Polyline::RS_Polyline(RS_EntityContainer* parent, const RS_PolylineData& d):
48 RS_EntityContainer(parent), data(d)
58 RS_Polyline::~RS_Polyline()
62 /*virtual*/ RS_Entity * RS_Polyline::clone()
64 RS_Polyline * p = new RS_Polyline(*this);
65 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
66 // p->entities.setAutoDelete(entities.autoDelete());
72 /** @return RS2::EntityPolyline */
73 /*virtual*/ RS2::EntityType RS_Polyline::rtti() const
75 return RS2::EntityPolyline;
78 /** @return Copy of data that defines the polyline. */
79 RS_PolylineData RS_Polyline::getData() const
84 /** sets a new start point of the polyline */
85 void RS_Polyline::setStartpoint(Vector & v)
89 if (!data.endpoint.valid)
93 /** @return Start point of the entity */
94 Vector RS_Polyline::getStartpoint()
96 return data.startpoint;
99 /** sets a new end point of the polyline */
100 void RS_Polyline::setEndpoint(Vector & v)
105 /** @return End point of the entity */
106 Vector RS_Polyline::getEndpoint()
108 return data.endpoint;
112 * Removes the last vertex of this polyline.
114 void RS_Polyline::removeLastVertex()
116 RS_Entity * last = lastEntity();
125 if (last->isAtomic())
126 data.endpoint = ((RS_AtomicEntity*)last)->getEndpoint();
128 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Polyline::removeLastVertex: "
129 "polyline contains non-atomic entity");
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'.
139 * The very first vertex added with this method is the startpoint.
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
145 * @return Pointer to the entity that was addded or NULL if this
146 * was the first vertex added.
148 RS_Entity * RS_Polyline::addVertex(const Vector & v, double bulge, bool prepend)
150 RS_Entity * entity = NULL;
151 //static double nextBulge = 0.0;
153 // very first vertex:
154 if (!data.startpoint.valid)
156 data.startpoint = data.endpoint = v;
160 // consequent vertices:
162 // add entity to the polyline:
163 entity = createVertex(v, nextBulge, prepend);
165 if (prepend==false) {
166 RS_EntityContainer::addEntity(entity);
170 RS_EntityContainer::insertEntity(0, entity);
185 * Creates a vertex from the endpoint of the last element or
186 * sets the startpoint to the point 'v'.
188 * The very first vertex added is the starting point.
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
194 * @return Pointer to the entity that was created or NULL if this
195 * was the first vertex added.
197 RS_Entity* RS_Polyline::createVertex(const Vector& v, double bulge, bool prepend) {
199 RS_Entity* entity=NULL;
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);
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));
210 entity = new RS_Line(this, RS_LineData(v, data.startpoint));
212 entity->setSelected(isSelected());
213 entity->setPen(RS_Pen(RS2::FlagInvalid));
214 entity->setLayer(NULL);
215 //RS_EntityContainer::addEntity(entity);
219 // create arc for the polyline:
221 bool reversed = (bulge<0.0);
222 double alpha = atan(bulge)*4.0;
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);
236 middle = (data.startpoint+v)/2.0;
237 dist = data.startpoint.distanceTo(v)/2.0;
238 angle = v.angleTo(data.startpoint);
241 // alpha can't be 0.0 at this point
242 radius = fabs(dist / sin(alpha/2.0));
244 double wu = fabs(RS_Math::pow(radius, 2.0) - RS_Math::pow(dist, 2.0));
253 if (fabs(alpha)>M_PI) {
257 center.setPolar(h, angle);
263 if (prepend==false) {
264 a1 = center.angleTo(data.endpoint);
265 a2 = center.angleTo(v);
268 a1 = center.angleTo(v);
269 a2 = center.angleTo(data.startpoint);
272 RS_ArcData d(center, radius,
276 entity = new RS_Arc(this, d);
277 entity->setSelected(isSelected());
278 entity->setPen(RS_Pen(RS2::FlagInvalid));
279 entity->setLayer(NULL);
286 * Ends polyline and adds the last entity if the polyline is closed
288 void RS_Polyline::endPolyline()
290 RS_DEBUG->print("RS_Polyline::endPolyline");
294 RS_DEBUG->print("RS_Polyline::endPolyline: adding closing entity");
296 // remove old closing entity:
297 if (closingEntity!=NULL)
299 removeEntity(closingEntity);
302 // add closing entity to the polyline:
303 closingEntity = createVertex(data.startpoint, nextBulge);
304 if (closingEntity!=NULL)
306 RS_EntityContainer::addEntity(closingEntity);
307 //data.endpoint = data.startpoint;
313 * @return The bulge of the closing entity.
315 double RS_Polyline::getClosingBulge()
318 RS_Entity* e = lastEntity();
319 if (e!=NULL && e->rtti()==RS2::EntityArc) {
320 return ((RS_Arc*)e)->getBulge();
328 * Sets the polylines start and endpoint to match the first and last vertex.
330 void RS_Polyline::updateEndpoints()
332 RS_Entity * e1 = firstEntity();
334 if (e1 != NULL && e1->isAtomic())
336 Vector v = ((RS_AtomicEntity *)e1)->getStartpoint();
340 RS_Entity * e2 = lastEntity();
347 if (e2 != NULL && e2->isAtomic())
349 Vector v = ((RS_AtomicEntity *)e2)->getEndpoint();
354 /** @return true if the polyline is closed. false otherwise */
355 bool RS_Polyline::isClosed() const
357 return data.getFlag(RS2::FlagClosed);
360 void RS_Polyline::setClosed(bool cl)
363 data.setFlag(RS2::FlagClosed);
365 data.delFlag(RS2::FlagClosed);
369 * Reimplementation of the addEntity method for a normal container.
370 * This reimplementation deletes the given entity!
372 * To add entities use addVertex() or addSegment() instead.
374 void RS_Polyline::addEntity(RS_Entity * entity)
376 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Polyline::addEntity: should never be called");
384 /*virtual*/ void RS_Polyline::setNextBulge(double bulge)
390 * Adds a segment to the polyline.
392 /*void RS_Polyline::addSegment(RS_Entity* entity) {
393 RS_EntityContainer::addEntity(entity);
394 // TODO: reorder and check polyline
397 VectorSolutions RS_Polyline::getRefPoints()
399 VectorSolutions ret(count()+1);
402 ret.set(0, data.startpoint);
405 for (RS_Entity* e=firstEntity(RS2::ResolveNone);
407 e = nextEntity(RS2::ResolveNone), i++) {
409 ret.set(i, ((RS_AtomicEntity*)e)->getEndpoint());
413 ret.set(count(), data.endpoint);
418 Vector RS_Polyline::getNearestRef(const Vector& coord,
421 return RS_Entity::getNearestRef(coord, dist);
424 Vector RS_Polyline::getNearestSelectedRef(const Vector& coord,
427 return RS_Entity::getNearestSelectedRef(coord, dist);
433 void RS_Polyline::reorder() {
446 void RS_Polyline::move(Vector offset) {
447 RS_EntityContainer::move(offset);
448 data.startpoint.move(offset);
449 data.endpoint.move(offset);
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);
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);
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);
476 void RS_Polyline::moveRef(const Vector & ref, const Vector & offset)
478 RS_EntityContainer::moveRef(ref, offset);
480 if (ref.distanceTo(data.startpoint) < 1.0e-4)
481 data.startpoint.move(offset);
483 if (ref.distanceTo(data.endpoint) < 1.0e-4)
484 data.endpoint.move(offset);
489 void RS_Polyline::stretch(Vector firstCorner, Vector secondCorner, Vector offset)
491 if (data.startpoint.isInWindow(firstCorner, secondCorner))
492 data.startpoint.move(offset);
494 if (data.endpoint.isInWindow(firstCorner, secondCorner))
495 data.endpoint.move(offset);
497 RS_EntityContainer::stretch(firstCorner, secondCorner, offset);
501 * Slightly optimized drawing for polylines.
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*/)
506 if (painter == NULL || view == NULL)
509 // draw first entity and set correct pen:
510 RS_Entity * e = firstEntity(RS2::ResolveNone);
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);
519 * Dumps the point's data to stdout.
521 std::ostream & operator<<(std::ostream & os, const RS_Polyline & l)
523 os << " Polyline: " << l.getData() << " {\n";
524 os << (RS_EntityContainer &)l;