3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // Portions copyright (C) 2001-2003 RibbonSoft
7 // Copyright (C) 2010 Underground Software
8 // See the README and GPLv2 files for licensing and warranty information
10 // JLH = James L. Hammons <jlhamm@acm.org>
13 // --- ---------- -----------------------------------------------------------
14 // JLH 06/02/2010 Added this text. :-)
20 #include "graphicview.h"
22 #include "paintinterface.h"
27 Spline::Spline(EntityContainer * parent, const SplineData & d):
28 EntityContainer(parent), data(d)
40 Entity * Spline::clone()
42 Spline * l = new Spline(*this);
43 #warning "!!! Need to deal with setAutoDelete() Qt3->Qt4 !!!"
44 // l->entities.setAutoDelete(entities.autoDelete());
50 /** @return RS2::EntitySpline */
51 /*virtual*/ RS2::EntityType Spline::rtti() const
53 return RS2::EntitySpline;
57 /*virtual*/ bool Spline::isEdge() const
62 /** @return Copy of data that defines the spline. */
63 SplineData Spline::getData() const
68 /** Sets the splines degree (1-3). */
69 void Spline::setDegree(int deg)
71 if (deg >= 1 && deg <= 3)
75 /** @return Degree of this spline curve (1-3).*/
76 int Spline::getDegree()
82 int Spline::getNumberOfKnots()
87 /** @return Number of control points. */
88 int Spline::getNumberOfControlPoints()
90 return data.controlPoints.count();
94 * @retval true if the spline is closed.
95 * @retval false otherwise.
97 bool Spline::isClosed()
103 * Sets the closed falg of this spline.
105 void Spline::setClosed(bool c)
111 void Spline::calculateBorders()
113 /*minV = Vector::minimum(data.startpoint, data.endpoint);
114 maxV = Vector::maximum(data.startpoint, data.endpoint);
116 Q3ValueList<Vector>::iterator it;
117 for (it = data.controlPoints.begin();
118 it!=data.controlPoints.end(); ++it) {
120 minV = Vector::minimum(*it, minV);
121 maxV = Vector::maximum(*it, maxV);
126 VectorSolutions Spline::getRefPoints()
128 VectorSolutions ret(data.controlPoints.count());
131 QList<Vector>::iterator it;
133 for(it=data.controlPoints.begin(); it!=data.controlPoints.end(); ++it, ++i)
141 Vector Spline::getNearestRef(const Vector & coord, double * dist)
143 //return getRefPoints().getClosest(coord, dist);
144 return Entity::getNearestRef(coord, dist);
147 Vector Spline::getNearestSelectedRef(const Vector & coord, double * dist)
149 //return getRefPoints().getClosest(coord, dist);
150 return Entity::getNearestSelectedRef(coord, dist);
154 * Updates the internal polygon of this spline. Called when the
155 * spline or it's data, position, .. changes.
157 void Spline::update()
159 DEBUG->print("Spline::update");
166 if (data.degree < 1 || data.degree > 3)
168 DEBUG->print("Spline::update: invalid degree: %d", data.degree);
172 if (data.controlPoints.count() < (uint)data.degree + 1)
174 DEBUG->print("Spline::update: not enough control points");
180 // Q3ValueList<Vector> tControlPoints = data.controlPoints;
181 QList<Vector> tControlPoints = data.controlPoints;
185 for(int i=0; i<data.degree; ++i)
186 tControlPoints.append(data.controlPoints[i]);
190 int npts = tControlPoints.count();
192 int k = data.degree + 1;
194 int p1 = getGraphicVariableInt("$SPLINESEGS", 8) * npts;
196 double * b = new double[npts * 3 + 1];
197 double * h = new double[npts + 1];
198 double * p = new double[p1 * 3 + 1];
200 // Q3ValueList<Vector>::iterator it;
201 QList<Vector>::iterator it;
204 for(it=tControlPoints.begin(); it!=tControlPoints.end(); ++it)
210 DEBUG->print("Spline::update: b[%d]: %f/%f", i, b[i], b[i + 1]);
214 // set all homogeneous weighting factors to 1.0
215 for(i=1; i<=npts; i++)
218 for(i=1; i<=3*p1; i++)
222 rbsplinu(npts, k, p1, b, h, p);
224 rbspline(npts, k, p1, b, h, p);
228 for(i=1; i<=3*p1; i=i+3)
232 Line * line = new Line(this, LineData(prev, Vector(p[i], p[i + 1])));
233 line->setLayer(NULL);
234 line->setPen(Pen(RS2::FlagInvalid));
238 prev = Vector(p[i], p[i+1]);
239 minV = Vector::minimum(prev, minV);
240 maxV = Vector::maximum(prev, maxV);
248 Vector Spline::getNearestEndpoint(const Vector & coord, double * dist)
250 double minDist = RS_MAXDOUBLE;
254 for (uint i=0; i<data.controlPoints.count(); i++) {
255 d = data.controlPoints[i].distanceTo(coord);
259 ret = data.controlPoints[i];
269 // The default implementation of EntityContainer is inaccurate but
270 // has to do for now..
271 Vector Spline::getNearestPointOnEntity(const Vector& coord,
272 bool onEntity, double* dist, Entity** entity) {
276 Vector Spline::getNearestCenter(const Vector & /*coord*/, double * dist)
279 *dist = RS_MAXDOUBLE;
281 return Vector(false);
284 Vector Spline::getNearestMiddle(const Vector & /*coord*/, double * dist)
287 *dist = RS_MAXDOUBLE;
289 return Vector(false);
292 Vector Spline::getNearestDist(double /*distance*/, const Vector & /*coord*/, double * dist)
295 *dist = RS_MAXDOUBLE;
297 return Vector(false);
300 void Spline::move(Vector offset)
302 // Q3ValueList<Vector>::iterator it;
303 QList<Vector>::iterator it;
305 for(it=data.controlPoints.begin(); it!=data.controlPoints.end(); ++it)
311 void Spline::rotate(Vector center, double angle)
313 // Q3ValueList<Vector>::iterator it;
314 QList<Vector>::iterator it;
316 for(it=data.controlPoints.begin(); it!=data.controlPoints.end(); ++it)
317 (*it).rotate(center, angle);
322 void Spline::scale(Vector center, Vector factor)
324 // Q3ValueList<Vector>::iterator it;
325 QList<Vector>::iterator it;
327 for(it=data.controlPoints.begin(); it!=data.controlPoints.end(); ++it)
328 (*it).scale(center, factor);
333 void Spline::mirror(Vector axisPoint1, Vector axisPoint2)
335 // Q3ValueList<Vector>::iterator it;
336 QList<Vector>::iterator it;
338 for(it=data.controlPoints.begin(); it!=data.controlPoints.end(); ++it)
339 (*it).mirror(axisPoint1, axisPoint2);
344 void Spline::moveRef(const Vector & ref, const Vector & offset)
346 // Q3ValueList<Vector>::iterator it;
347 QList<Vector>::iterator it;
349 for(it=data.controlPoints.begin(); it!=data.controlPoints.end(); ++it)
351 if (ref.distanceTo(*it) < 1.0e-4)
358 void Spline::draw(PaintInterface * painter, GraphicView * view, double /*patternOffset*/)
360 if (painter == NULL || view == NULL)
363 Entity * e = firstEntity(RS2::ResolveNone);
369 offset += e->getLength();
370 //DEBUG->print("offset: %f\nlength was: %f", offset, e->getLength());
373 for (Entity * e=nextEntity(RS2::ResolveNone); e!=NULL; e = nextEntity(RS2::ResolveNone))
375 view->drawEntityPlain(e, -offset);
376 offset += e->getLength();
377 //DEBUG->print("offset: %f\nlength was: %f", offset, e->getLength());
382 * Todo: draw the spline, user patterns.
385 void Spline::draw(RS_Painter* painter, GraphicView* view) {
386 if (painter==NULL || view==NULL) {
391 if (data.controlPoints.count()>0) {
393 Q3ValueList<Vector>::iterator it;
394 for (it = data.controlPoints.begin(); it!=data.controlPoints.end(); ++it) {
396 painter->drawLine(view->toGui(prev),
405 int npts = data.controlPoints.count();
411 double* b = new double[npts*3+1];
412 double* h = new double[npts+1];
413 double* p = new double[p1*3+1];
415 Q3ValueList<Vector>::iterator it;
417 for (it = data.controlPoints.begin(); it!=data.controlPoints.end(); ++it) {
422 DEBUG->print("Spline::draw: b[%d]: %f/%f", i, b[i], b[i+1]);
426 // set all homogeneous weighting factors to 1.0
427 for (i=1; i <= npts; i++) {
432 for (i = 1; i <= 3*p1; i++) {
436 rbspline(npts,k,p1,b,h,p);
439 for (i = 1; i <= 3*p1; i=i+3) {
441 painter->drawLine(view->toGui(prev),
442 view->toGui(Vector(p[i], p[i+1])));
444 prev = Vector(p[i], p[i+1]);
450 * @return The reference points of the spline.
452 //Q3ValueList<Vector> Spline::getControlPoints()
453 QList<Vector> Spline::getControlPoints()
455 return data.controlPoints;
459 * Appends the given point to the control points.
461 void Spline::addControlPoint(const Vector & v)
463 data.controlPoints.append(v);
467 * Removes the control point that was last added.
469 void Spline::removeLastControlPoint()
471 data.controlPoints.pop_back();
475 * Generates B-Spline open knot vector with multiplicity
476 * equal to the order at the ends.
478 void Spline::knot(int num, int order, int knotVector[])
482 for(int i=2; i<=num+order; i++)
484 if ((i > order) && (i < num + 2))
486 knotVector[i] = knotVector[i - 1] + 1;
490 knotVector[i] = knotVector[i - 1];
496 * Generates rational B-spline basis functions for an open knot vector.
498 void Spline::rbasis(int c, double t, int npts, int x[], double h[], double r[])
508 double * temp = new double[nplusc + 1];
510 // calculate the first order nonrational basis functions n[i]
511 for(i=1; i<=nplusc-1; i++)
513 if ((t >= x[i]) && (t < x[i + 1]))
519 /* calculate the higher order nonrational basis functions */
523 for(i=1; i<=nplusc-k; i++)
525 // if the lower order basis function is zero skip the calculation
527 d = ((t - x[i]) * temp[i]) / (x[i + k - 1] - x[i]);
531 // if the lower order basis function is zero skip the calculation
532 if (temp[i + 1] != 0)
533 e = ((x[i + k] - t) * temp[i + 1]) / (x[i + k] - x[i + 1]);
541 // pick up last point
542 if (t == (double)x[nplusc])
545 // calculate sum for denominator of rational basis functions
548 for(i=1; i<=npts; i++)
549 sum = sum + temp[i] * h[i];
551 // form rational basis functions and put in r vector
552 for(i=1; i<=npts; i++)
555 r[i] = (temp[i] * h[i]) / (sum);
564 * Generates a rational B-spline curve using a uniform open knot vector.
566 void Spline::rbspline(int npts, int k, int p1, double b[], double h[], double p[])
568 int i, j, icount, jcount;
570 //int x[30]; /* allows for 20 data points with basis function of order 5 */
580 int * x = new int[nplusc + 1];
581 double * nbasis = new double[npts + 1];
583 // zero and redimension the knot vector and the basis array
585 for(i = 0; i <= npts; i++)
588 for(i = 0; i <= nplusc; i++)
591 // generate the uniform open knot vector
596 // calculate the points on the rational B-spline curve
598 step = ((double)x[nplusc]) / ((double)(p1 - 1));
600 for(i1=1; i1<= p1; i1++)
602 if ((double)x[nplusc] - t < 5e-6)
603 t = (double)x[nplusc];
605 // generate the basis function for this value of t
606 rbasis(k, t, npts, x, h, nbasis);
608 // generate a point on the curve
614 // Do local matrix multiplication
615 for(i=1; i<=npts; i++)
617 temp = nbasis[i] * b[jcount];
618 p[icount + j] = p[icount + j] + temp;
631 void Spline::knotu(int num, int order, int knotVector[])
633 int nplusc = num + order;
634 int nplus2 = num + 2;
637 for(int i=2; i<=nplusc; i++)
638 knotVector[i] = i - 1;
641 void Spline::rbsplinu(int npts, int k, int p1, double b[], double h[], double p[])
643 int i, j, icount, jcount;
645 //int x[30]; /* allows for 20 data points with basis function of order 5 */
655 int * x = new int[nplusc + 1];
656 double * nbasis = new double[npts + 1];
658 /* zero and redimension the knot vector and the basis array */
660 for(i=0; i<=npts; i++)
663 for(i=0; i<=nplusc; i++)
666 /* generate the uniform periodic knot vector */
671 printf("The knot vector is ");
672 for (i = 1; i <= nplusc; i++){
673 printf(" %d ", x[i]);
677 printf("The usable parameter range is ");
678 for (i = k; i <= npts+1; i++){
679 printf(" %d ", x[i]);
686 /* calculate the points on the rational B-spline curve */
689 step = ((double)((npts) - (k - 1))) / ((double)(p1 - 1));
691 for(i1=1; i1<=p1; i1++)
693 if ((double)x[nplusc] - t < 5e-6)
694 t = (double)x[nplusc];
696 rbasis(k, t, npts, x, h, nbasis); /* generate the basis function for this value of t */
698 printf("t = %f \n",t);
700 for (i = 1; i <= npts; i++){
701 printf("%f ",nbasis[i]);
705 for(j=1; j<=3; j++) /* generate a point on the curve */
710 for(i=1; i<=npts; i++) /* Do local matrix multiplication */
712 temp = nbasis[i] * b[jcount];
713 p[icount + j] = p[icount + j] + temp;
715 printf("jcount,nbasis,b,nbasis*b,p = %d %f %f %f %f\n",jcount,nbasis[i],b[jcount],temp,p[icount+j]);
721 printf("icount, p %d %f %f %f \n",icount,p[icount+1],p[icount+2],p[icount+3]);
732 * Dumps the spline's data to stdout.
734 std::ostream & operator<<(std::ostream & os, const Spline & l)
736 os << " Spline: " << l.getData() << "\n";