~ubuntu-branches/ubuntu/breezy/koffice/breezy

« back to all changes in this revision

Viewing changes to kontour/GBezier.cc

  • Committer: Bazaar Package Importer
  • Author(s): Ben Burton
  • Date: 2004-05-09 11:33:00 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040509113300-vfrdadqsvjfuhn3b
Tags: 1:1.3.1-1
* New upstream bugfix release.
* Built against newer imagemagick (closes: #246623).
* Made koffice-libs/kformula recommend/depend on latex-xft-fonts, which
  provides mathematical fonts that the formula editor can use.  Also
  patched the kformula part to make these fonts the default.
* Changed kword menu hint from "WordProcessors" to "Word processors"
  (closes: #246209).
* Spellchecker configuration is now fixed (closes: #221256, #227568).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- C++ -*-
2
 
 
3
 
  $Id: GBezier.cc,v 1.47 2001/05/21 13:12:48 neundorf Exp $
4
 
  This file is part of KIllustrator.
5
 
  Copyright (C) 1998 Kai-Uwe Sattler (kus@iti.cs.uni-magdeburg.de)
6
 
 
7
 
  This program is free software; you can redistribute it and/or modify
8
 
  it under the terms of the GNU Library General Public License as
9
 
  published by
10
 
  the Free Software Foundation; either version 2 of the License, or
11
 
  (at your option) any later version.
12
 
 
13
 
  This program is distributed in the hope that it will be useful,
14
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
  GNU General Public License for more details.
17
 
 
18
 
  You should have received a copy of the GNU Library General Public License
19
 
  along with this program; if not, write to the Free Software
20
 
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 
 
22
 
*/
23
 
 
24
 
#include <float.h>
25
 
#if defined(__FreeBSD__) || defined(__NetBSD__)
26
 
#include <math.h>
27
 
#else
28
 
#include <values.h>
29
 
#endif
30
 
#include <GBezier.h>
31
 
#include <GCurve.h>
32
 
#include <Arrow.h>
33
 
#include <Painter.h>
34
 
#include <stdlib.h>
35
 
 
36
 
#include <qdom.h>
37
 
#include <qpointarray.h>
38
 
#include <qpainter.h>
39
 
#include <klocale.h>
40
 
#include <kdebug.h>
41
 
#include "GDocument.h"
42
 
#define DELTA 0.05
43
 
 
44
 
static bool bezier_segment_part_contains (int x0, int y0, int x1,int y1,
45
 
                                          const Coord& pp) {
46
 
  float  m, n, yp, xp;
47
 
  int xh, yh;
48
 
 
49
 
  if(pp.x () <= QMAX(x0,x1) + 5 && pp.x() >= QMIN(x0,x1) - 5 &&
50
 
     pp.y () <= QMAX(y0,y1) + 5 && pp.y() >= QMIN(y0,y1) - 5) {
51
 
 
52
 
    if (x1 <= x0) {
53
 
      // swap the points
54
 
      xh = x1;
55
 
      yh = y1;
56
 
      x1 = x0;
57
 
      y1 = y0;
58
 
      x0 = xh;
59
 
      y0 = yh;
60
 
    }
61
 
 
62
 
    if (x0 - 5 <= pp.x () && pp.x () <= x1 + 5) {
63
 
      if (abs (int (x0 - x1)) < 5) {
64
 
        if ((y0 <= pp.y () && pp.y () <= y1) ||
65
 
            (y1 <= pp.y () && pp.y () <= y0)) {
66
 
          return true;
67
 
        }
68
 
      }
69
 
      else {
70
 
        // y = m * x + n;
71
 
        m = (float)(y1 - y0) / (float)(x1 - x0);
72
 
        n = (float)y0 - m * (float)x0;
73
 
 
74
 
        if (m > 1) {
75
 
          xp = ((float) pp.y () - n) / m;
76
 
          if (xp - 5 <= pp.x () && pp.x () <= xp + 5) {
77
 
            return true;
78
 
 
79
 
          }
80
 
        }
81
 
        else {
82
 
          yp = m * (float) pp.x () + n;
83
 
          if (yp - 5 <= pp.y () && pp.y () <= yp + 5) {
84
 
            return true;
85
 
          }
86
 
        }
87
 
      }
88
 
    }
89
 
  }
90
 
  return false;
91
 
}
92
 
 
93
 
bool GBezier::bezier_segment_contains (const Coord& p0, const Coord& p1,
94
 
                                       const Coord& p2, const Coord& p3,
95
 
                                       const Coord& c)
96
 
{
97
 
  /** every bezier_segment contains 1/DELTA lines, we have to compute the
98
 
      lines
99
 
      to check later in bezier_segment_part_contains, if the Coord c on a
100
 
      line
101
 
  **/
102
 
 
103
 
  float th,th2,th3;
104
 
  float t,t2,t3;
105
 
  int x0,y0,x1,y1;
106
 
 
107
 
  x1 = (int)p0.x();
108
 
  y1 = (int)p0.y();
109
 
  for(t = 0; t < 1.01; t += DELTA) {
110
 
    x0 = x1;
111
 
    y0 = y1;
112
 
    th = 1 - t;
113
 
    t2= t*t;
114
 
    t3 = t2*t;
115
 
    th2 = th*th;
116
 
    th3 = th2*th;
117
 
    x1 = (int) (th3*  p0.x() +
118
 
                3*t*th2*p1.x() +
119
 
                3*t2*th*p2.x() +
120
 
                t3*p3.x());
121
 
    y1 = (int) (th3* p0.y() +
122
 
                3*t*th2*p1.y() +
123
 
                3*t2*th*p2.y() +
124
 
                t3*p3.y());
125
 
    if (bezier_segment_part_contains(x0, y0, x1, y1, c)) return true;
126
 
  }
127
 
 
128
 
  return false;
129
 
}
130
 
 
131
 
GBezier::GBezier (GDocument *doc )
132
 
: GPolyline (doc)
133
 
{
134
 
  wSegment = 0; closed = false;
135
 
}
136
 
 
137
 
GBezier::GBezier (GDocument *doc, const QDomElement &element)
138
 
:GPolyline (doc, element.namedItem("polyline").toElement())
139
 
{
140
 
 
141
 
    wSegment = -1;
142
 
    closed=(element.attribute("closed").toInt()==1);
143
 
    calcBoundingBox();
144
 
    computePPoints();
145
 
}
146
 
 
147
 
GBezier::GBezier (const GBezier& obj) : GPolyline (obj) {
148
 
  wSegment = -1;
149
 
  closed = obj.closed;
150
 
  ppoints = obj.ppoints;
151
 
  calcBoundingBox();
152
 
}
153
 
 
154
 
void GBezier::setPoint (int idx, const Coord& p) {
155
 
  Coord np = p.transform (iMatrix);
156
 
 
157
 
  points.at (idx)->x (np.x ());
158
 
  points.at (idx)->y (np.y());
159
 
  if (! isEndPoint (idx))
160
 
    updateBasePoint (cPoint (idx));
161
 
  else {
162
 
    computePPoints ();
163
 
    updateRegion ();
164
 
  }
165
 
}
166
 
 
167
 
void GBezier::movePoint (int idx, float dx, float dy, bool ctrlPressed) {
168
 
  float x = points.at (idx)->x ();
169
 
  float y = points.at (idx)->y ();
170
 
  float ndx, ndy;
171
 
  int cidx = -1; // >= 0, if the curve is closed and we move
172
 
                 // the first or last point
173
 
 
174
 
  ndx = dx * iMatrix.m11 () + dy * iMatrix.m21 ();
175
 
  ndy = dy * iMatrix.m22 () + dx * iMatrix.m12 ();
176
 
 
177
 
  points.at (idx)->x (x + ndx);
178
 
  points.at (idx)->y (y + ndy);
179
 
  if (closed) {
180
 
    int n = points.count ();
181
 
    if (idx < 3) {
182
 
      cidx = n - (3 - idx);
183
 
      points.at (cidx)->x (x + ndx);
184
 
      points.at (cidx)->y (y + ndy);
185
 
    }
186
 
    else if (idx + 3 >= (int) points.count ()) {
187
 
      cidx = 3 - (n - idx);
188
 
      points.at (cidx)->x (x + ndx);
189
 
      points.at (cidx)->y (y + ndy);
190
 
    }
191
 
  }
192
 
  if (isEndPoint (idx) && !ctrlPressed) {
193
 
      points.at (idx - 1)->x (points.at (idx - 1)->x () + ndx);
194
 
      points.at (idx - 1)->y (points.at (idx - 1)->y () + ndy);
195
 
      points.at (idx + 1)->x (points.at (idx + 1)->x () + ndx);
196
 
      points.at (idx + 1)->y (points.at (idx + 1)->y () + ndy);
197
 
      if (cidx >= 0) {
198
 
          points.at (cidx - 1)->x (points.at (cidx - 1)->x () + ndx);
199
 
          points.at (cidx - 1)->y (points.at (cidx - 1)->y () + ndy);
200
 
          points.at (cidx + 1)->x (points.at (cidx + 1)->x () + ndx);
201
 
          points.at (cidx + 1)->y (points.at (cidx + 1)->y () + ndy);
202
 
      }
203
 
  }
204
 
  else if(!ctrlPressed) {
205
 
    updateBasePoint (cPoint (idx));
206
 
    if (cidx >=0)
207
 
      updateBasePoint (cPoint (cidx));
208
 
  }
209
 
  computePPoints ();
210
 
  updateRegion ();
211
 
}
212
 
 
213
 
QString GBezier::typeName () const
214
 
{
215
 
  return i18n("Bezier curve");
216
 
}
217
 
 
218
 
void GBezier::draw (QPainter& p, bool withBasePoints, bool outline, bool) {
219
 
  QPen pen;
220
 
  QBrush brush;
221
 
  int sdx = 0;
222
 
  int sdy = 0;
223
 
  int edx = 0;
224
 
  int edy = 0;
225
 
 
226
 
  initPen (pen);
227
 
  p.save ();
228
 
  p.setPen (pen);
229
 
  p.setWorldMatrix (tmpMatrix, true);
230
 
  unsigned num = points.count ();
231
 
 
232
 
  float w = outlineInfo.width == 0 ? 1.0 : outlineInfo.width;
233
 
 
234
 
  // check for arrows
235
 
  // (xAngle/RAD_FACTOR) doesnt work!?
236
 
  if (sArrow != 0L) {
237
 
    sdx = qRound (w*sArrow->length () * cos (1/(RAD_FACTOR/(sAngle))));
238
 
    sdy = qRound (w*sArrow->length () * sin (1/(RAD_FACTOR/(sAngle))));
239
 
  }
240
 
 
241
 
  if (eArrow != 0L) {
242
 
    edx = qRound (w*eArrow->length () * cos (1/(RAD_FACTOR/(eAngle))));
243
 
    edy = qRound (w*eArrow->length () * sin (1/(RAD_FACTOR/(eAngle))));
244
 
  }
245
 
 
246
 
#if 0
247
 
  for (unsigned int i = 1; i + 3 < num; i += 3) {
248
 
    if (points.at (i + 1)->x () == FLT_MAX ||
249
 
        points.at (i + 2)->x () == FLT_MAX) {
250
 
      p.drawLine (points.at (i)->x (), points.at (i)->y (),
251
 
                  points.at (i + 3)->x (), points.at (i + 3)->y ());
252
 
    }
253
 
    else {
254
 
      p.drawBezier (points,i);
255
 
    }
256
 
  }
257
 
#else
258
 
  if (num > 3) {
259
 
    if (closed) {
260
 
      if (! workInProgress () && !outline) {
261
 
        initBrush (brush);
262
 
        p.setBrush (brush);
263
 
 
264
 
        if (gradientFill ()) {
265
 
          //if (! gShape.valid ())
266
 
            updateGradientShape (p);
267
 
          gShape.draw (p);
268
 
        }
269
 
      }
270
 
      p.drawPolygon (ppoints);
271
 
    }
272
 
    else {
273
 
      //      p.drawPolyline (ppoints);
274
 
      for (unsigned int i = 1; i + 3 < num; i += 3) {
275
 
        if (points.at (i + 1)->x () == FLT_MAX ||
276
 
                  points.at (i + 2)->x () == FLT_MAX) {
277
 
                p.drawLine (qRound (points.at (i)->x () + ((i==1) ? sdx : 0)),
278
 
                            qRound (points.at (i)->y () + ((i==1) ? sdy : 0)),
279
 
                            qRound (points.at (i + 3)->x () + ((i==num-2) ? edx : 0)),
280
 
                            qRound (points.at (i + 3)->y () + ((i==num-2) ? edy : 0)));
281
 
              }
282
 
              else {
283
 
                QPointArray bpoints (4);
284
 
          bpoints.setPoint (0, qRound (points.at (i)->x () + ((i==1) ? sdx : 0)),
285
 
                                           qRound (points.at (i)->y () + ((i==1) ? sdy : 0)));
286
 
          bpoints.setPoint (1, qRound (points.at (i + 1)->x ()),
287
 
                                           qRound (points.at (i + 1)->y ()));
288
 
          bpoints.setPoint (2, qRound (points.at (i + 2)->x ()),
289
 
                                           qRound (points.at (i + 2)->y ()));
290
 
          bpoints.setPoint (3, qRound (points.at (i + 3)->x () + ((i==num-5) ? edx : 0)),
291
 
                                           qRound (points.at (i + 3)->y () + ((i==num-5) ? edy : 0)));
292
 
                p.drawQuadBezier (bpoints);
293
 
              }
294
 
      }
295
 
    }
296
 
  }
297
 
#endif
298
 
  p.setClipping (false);
299
 
  p.restore ();
300
 
  if (sArrow != 0L) {
301
 
    Coord pp = points.at (1)->transform (tmpMatrix);
302
 
    sArrow->draw (p, pp, outlineInfo.color,
303
 
                  outlineInfo.width, sAngle);
304
 
  }
305
 
  if (eArrow != 0L) {
306
 
    Coord pp = points.at (num - 2)->transform (tmpMatrix);
307
 
    eArrow->draw (p, pp, outlineInfo.color,
308
 
                  outlineInfo.width, eAngle);
309
 
  }
310
 
  if (withBasePoints)
311
 
    drawHelpLines (p);
312
 
  if (wSegment != -1)
313
 
    drawHelpLinesForWorkingSegment (p);
314
 
}
315
 
 
316
 
void GBezier::drawHelpLines (QPainter& p) {
317
 
  unsigned int i, num = points.count ();
318
 
 
319
 
  p.save ();
320
 
  for (i = 0; i < num; i++) {
321
 
    Coord c = points.at (i)->transform (tmpMatrix);
322
 
    if (isEndPoint (i))
323
 
      p.setPen (black);
324
 
    else
325
 
      p.setPen (blue);
326
 
    Painter::drawRect (p, c.x () - 2.0, c.y () - 2.0, 4, 4);
327
 
  }
328
 
 
329
 
  QPen pen (blue, 1, DotLine);
330
 
  p.setPen (pen);
331
 
  for (i = 0; i + 2 < num; i += 3) {
332
 
    if (points.at (i)->x () == FLT_MAX ||
333
 
        points.at (i + 2)->x () == FLT_MAX)
334
 
      continue;
335
 
 
336
 
    Coord c = points.at (i + 1)->transform (tmpMatrix);
337
 
    Coord c1 = points.at (i)->transform (tmpMatrix);
338
 
    Coord c2 = points.at (i + 2)->transform (tmpMatrix);
339
 
    Painter::drawLine (p, c1.x (), c1.y (), c.x (), c.y ());
340
 
    Painter::drawLine (p, c.x (), c.y (), c2.x (), c2.y ());
341
 
  }
342
 
  p.restore ();
343
 
}
344
 
 
345
 
void GBezier::drawHelpLinesForWorkingSegment (QPainter& p) {
346
 
  p.save ();
347
 
 
348
 
  QPen pen1 (blue, 1, DotLine);
349
 
  QPen pen2 (blue);
350
 
 
351
 
  for (int i = wSegment * 3; i <= (wSegment + 1) * 3; i += 3) {
352
 
    if (i + 2 >= (int) points.count () ||
353
 
        points.at (i)->x () == FLT_MAX ||
354
 
        points.at (i + 2)->x () == FLT_MAX) {
355
 
      return;
356
 
    }
357
 
 
358
 
    p.setPen (pen1);
359
 
    Coord c = points.at (i + 1)->transform (tmpMatrix);
360
 
    Coord c1 = points.at (i)->transform (tmpMatrix);
361
 
    Coord c2 = points.at (i + 2)->transform (tmpMatrix);
362
 
    Painter::drawLine (p, c1.x (), c1.y (), c.x (), c.y ());
363
 
    Painter::drawLine (p, c.x (), c.y (), c2.x (), c2.y ());
364
 
    p.setPen (pen2);
365
 
    Painter::drawRect (p, c1.x () - 2, c1.y () - 2, 4, 4);
366
 
    Painter::drawRect (p, c2.x () - 2, c2.y () - 2, 4, 4);
367
 
  }
368
 
  p.restore ();
369
 
}
370
 
 
371
 
bool GBezier::contains (const Coord& p) {
372
 
  if (rbox.contains (p)) {
373
 
    Coord pc = p.transform (iMatrix);
374
 
 
375
 
    for (unsigned int i = 1; i + 3 < points.count (); i += 3) {
376
 
      // detect the containing curve segment
377
 
      Rect r;
378
 
      Coord p = *(points.at (i));
379
 
      r.left (p.x ());
380
 
      r.top (p.y ());
381
 
      r.right (p.x ());
382
 
      r.bottom (p.y ());
383
 
 
384
 
      for (unsigned int j = i + 1; j < i + 4; j++) {
385
 
        Coord pn = *(points.at (j));
386
 
        r.left (QMIN(pn.x (), r.left ()));
387
 
        r.top (QMIN(pn.y (), r.top ()));
388
 
        r.right (QMAX(pn.x (), r.right ()));
389
 
        r.bottom (QMAX(pn.y (), r.bottom ()));
390
 
      }
391
 
      if (r.contains (pc)) {
392
 
        if (bezier_segment_contains (*(points.at (i)), *(points.at (i + 1)),
393
 
                                     *(points.at (i + 2)),
394
 
                                     *(points.at (i + 3)), pc))
395
 
        return true;
396
 
      }
397
 
    }
398
 
  }
399
 
  return false;
400
 
}
401
 
 
402
 
GObject* GBezier::copy () {
403
 
  return new GBezier (*this);
404
 
}
405
 
 
406
 
/*GObject* GBezier::create (GDocument *doc, const QDomElement &element)
407
 
{
408
 
  return new GBezier (doc, element);
409
 
}*/
410
 
 
411
 
void GBezier::initBasePoint (int idx) {
412
 
  Coord epoint = *(points.at (idx + 1));
413
 
  float dx = epoint.x ();
414
 
  float dy = epoint.y ();
415
 
  points.at (idx)->x (2 * dx - points.at (idx + 2)->x ());
416
 
  points.at (idx)->y (2 * dy - points.at (idx + 2)->y ());
417
 
  updateRegion (false);
418
 
}
419
 
 
420
 
void GBezier::updateBasePoint (int idx) {
421
 
  int eidx = (idx == 0 ? 1 : (cPoint (idx) < idx ? idx - 1 : idx + 1));
422
 
  if (idx < 0 || eidx < 0)
423
 
    return;
424
 
 
425
 
  Coord epoint = *(points.at (eidx));
426
 
  if (points.at (cPoint (idx))->x () == FLT_MAX)
427
 
    return;
428
 
 
429
 
  float dx = epoint.x ();
430
 
  float dy = epoint.y ();
431
 
  points.at (idx)->x (2 * dx - points.at (cPoint (idx))->x ());
432
 
  points.at (idx)->y (2 * dy - points.at (cPoint (idx))->y ());
433
 
  computePPoints ();
434
 
  updateRegion ();
435
 
}
436
 
 
437
 
void GBezier::setWorkingSegment (int seg) {
438
 
  wSegment = seg;
439
 
  updateRegion (false);
440
 
}
441
 
 
442
 
void GBezier::calcBoundingBox () {
443
 
  Rect r;
444
 
  unsigned int num = points.count ();
445
 
  Coord p = points.at (0)->transform (tmpMatrix);
446
 
 
447
 
  computePPoints ();
448
 
 
449
 
  r.left (p.x ());
450
 
  r.top (p.y ());
451
 
  r.right (p.x ());
452
 
  r.bottom (p.y ());
453
 
  for (unsigned int i = 1; i < num; i++) {
454
 
    Coord p = points.at (i)->transform (tmpMatrix);
455
 
 
456
 
    if (p.x () != FLT_MAX && p.y () != FLT_MAX) {
457
 
      r.left (QMIN(p.x (), r.left ()));
458
 
      r.top (QMIN(p.y (), r.top ()));
459
 
      r.right (QMAX(p.x (), r.right ()));
460
 
      r.bottom (QMAX(p.y (), r.bottom ()));
461
 
    }
462
 
  }
463
 
 
464
 
  float w = outlineInfo.width == 0 ? 1.0 : outlineInfo.width;
465
 
 
466
 
  if (sArrow != 0L && num > 2) {
467
 
    Coord p1 = points.at (0)->transform (tmpMatrix);
468
 
    Coord p2 = points.at (2)->transform (tmpMatrix);
469
 
    sAngle = calcArrowAngle (p1, p2, 0);
470
 
    Rect sr = sArrow->boundingBox (p1, w, sAngle);
471
 
    r = r.unite (sr);
472
 
  }
473
 
  if (eArrow != 0L && num >= 3) {
474
 
    Coord p1 = points.at (num - 3)->transform (tmpMatrix);
475
 
    Coord p2 = points.at (num - 1)->transform (tmpMatrix);
476
 
    eAngle = calcArrowAngle (p1, p2, 1);
477
 
    Rect er = eArrow->boundingBox (p2, w, eAngle);
478
 
    r = r.unite (er);
479
 
  }
480
 
 
481
 
  r.enlarge (2); // for the help lines
482
 
  //  updateBoundingBox (r);
483
 
  rbox = r.normalize ();
484
 
  QRect pbox = ppoints.boundingRect ();
485
 
  box = Rect (pbox.x (), pbox.y (), pbox.width (), pbox.height ());
486
 
  box = box.transform (tmpMatrix);
487
 
}
488
 
 
489
 
void GBezier::removePoint (int idx, bool update) {
490
 
  if (points.count () > 6) {
491
 
    points.remove (idx - 1);
492
 
    points.remove (idx - 1);
493
 
    points.remove (idx - 1);
494
 
    if (update)
495
 
      updateRegion ();
496
 
  }
497
 
}
498
 
 
499
 
void GBezier::insertPoint (int idx, const Coord& p, bool update) {
500
 
  Coord p0 (p.x () - 20, p.y () - 20);
501
 
  Coord p1 (p.x () + 20, p.y () + 20);
502
 
  addPoint (idx, p0, false);
503
 
  addPoint (idx + 1, p, false);
504
 
  addPoint (idx + 2, p1, update);
505
 
}
506
 
 
507
 
int GBezier::containingSegment (float xpos, float ypos) {
508
 
  Coord p (xpos, ypos);
509
 
  Coord pc = p.transform (iMatrix);
510
 
  int seg = 0;
511
 
 
512
 
  for (unsigned int i = 1; i + 3 < points.count (); i += 3) {
513
 
    // detect the containing curve segment
514
 
    Rect r;
515
 
    Coord p = *(points.at (i));
516
 
    r.left (p.x ());
517
 
    r.top (p.y ());
518
 
    r.right (p.x ());
519
 
    r.bottom (p.y ());
520
 
 
521
 
    for (unsigned int j = i + 1; j < i + 4; j++) {
522
 
      Coord pn = *(points.at (j));
523
 
      r.left (QMIN(pn.x (), r.left ()));
524
 
      r.top (QMIN(pn.y (), r.top ()));
525
 
      r.right (QMAX(pn.x (), r.right ()));
526
 
      r.bottom (QMAX(pn.y (), r.bottom ()));
527
 
    }
528
 
    if (r.contains (pc)) {
529
 
      if (bezier_segment_contains (*(points.at (i)), *(points.at (i + 1)),
530
 
                                   *(points.at (i + 2)),
531
 
                                   *(points.at (i + 3)), pc)) {
532
 
        return seg;
533
 
      }
534
 
    }
535
 
    seg++;
536
 
  }
537
 
  return -1;
538
 
}
539
 
 
540
 
int GBezier::cPoint (int idx) {
541
 
  if (idx > 1)
542
 
    return idx + (isEndPoint (idx - 1) ? -2 : 2);
543
 
  else
544
 
    return idx + (isEndPoint (idx + 1) ? 2 : -2);
545
 
}
546
 
 
547
 
QDomElement GBezier::writeToXml (QDomDocument &document) {
548
 
 
549
 
    QDomElement bezier=document.createElement("bezier");
550
 
    bezier.setAttribute ("closed", (int) closed);
551
 
    bezier.appendChild(GPolyline::writeToXml(document));
552
 
    return bezier;
553
 
}
554
 
 
555
 
bool GBezier::findNearestPoint (const Coord& p, float max_dist,
556
 
                                float& dist, int& pidx, bool all) {
557
 
  float dx, dy, min_dist = max_dist + 1, d;
558
 
  pidx = -1;
559
 
 
560
 
  Coord np = p.transform (iMatrix);
561
 
 
562
 
  unsigned int i = 1;
563
 
  while (i <= points.count () - 2) {
564
 
    dx = points.at (i)->x () - np.x ();
565
 
    dy = points.at (i)->y () - np.y ();
566
 
    d = sqrt (dx * dx + dy * dy);
567
 
 
568
 
    if (d < max_dist && d < min_dist) {
569
 
      dist = min_dist = d;
570
 
      pidx = i;
571
 
    }
572
 
 
573
 
    if (! all && i == 1) {
574
 
      // test only first and last point
575
 
      i = points.count () - 2;
576
 
    }
577
 
    else
578
 
      i += 3;
579
 
  }
580
 
  return pidx >= 0;
581
 
}
582
 
 
583
 
void GBezier::computePPoints () {
584
 
  unsigned int i, num = points.count ();
585
 
  unsigned int idx = 0;
586
 
 
587
 
  ppoints.resize (num);
588
 
  for (i = 1; i + 3 < num; i += 3) {
589
 
    if (points.at (i + 1)->x () == FLT_MAX ||
590
 
        points.at (i + 2)->x () == FLT_MAX) {
591
 
      if (ppoints.size () < idx + 2)
592
 
        ppoints.resize (ppoints.size () + 2);
593
 
      ppoints.setPoint (idx++, qRound (points.at (i)->x ()), qRound (points.at (i)->y ()));
594
 
      ppoints.setPoint (idx++, qRound (points.at (i+3)->x ()), qRound (points.at (i+3)->y ()));
595
 
    }
596
 
    else
597
 
      idx = createPolyline (i, idx);
598
 
  }
599
 
  ppoints.resize (idx);
600
 
}
601
 
 
602
 
void GBezier::setClosed (bool flag) {
603
 
  if (flag && points.count () < 6)
604
 
    return;
605
 
 
606
 
  closed = flag;
607
 
  if (closed) {
608
 
    // Point #n-2 := Point #0
609
 
    // Point #n-1 := Point #1
610
 
    // Point #n := Point #2
611
 
    unsigned int n = points.count () - 1;
612
 
    *points.at (n) = *points.at (2);
613
 
    *points.at (n-1) = *points.at (1);
614
 
    *points.at (n-2) = *points.at (0);
615
 
  }
616
 
  computePPoints ();
617
 
}
618
 
 
619
 
int GBezier::createPolyline (int index, int pidx) {
620
 
  double th, th2, th3;
621
 
  double t, t2, t3;
622
 
  int x4, y4;
623
 
 
624
 
  double x0 = points.at (index)->x();
625
 
  double y0 = points.at (index)->y();
626
 
  double x1 = points.at (index+1)->x();
627
 
  double y1 = points.at (index+1)->y();
628
 
  double x2 = points.at (index+2)->x();
629
 
  double y2 = points.at (index+2)->y();
630
 
  double x3 = points.at (index+3)->x();
631
 
  double y3 = points.at (index+3)->y();
632
 
 
633
 
  if (ppoints.size () - pidx < ((points.count ())/ DELTA / 3))
634
 
    ppoints.resize ((static_cast<int>(points.count () /DELTA / 3)) + pidx);
635
 
 
636
 
  for (t = 0; t < 1.01; t += DELTA) {
637
 
    t2 = t * t;
638
 
    t3 = t2 * t;
639
 
    th = 1 - t;
640
 
    th2 = th * th;
641
 
    th3 = th2 * th;
642
 
    x4 = (int) (th3 * x0 + 3. * t * th2 * x1 + 3. *t2 *th *x2 + t3 * x3);
643
 
    y4 = (int) (th3 * y0 + 3. * t * th2 * y1 + 3. * t2 * th * y2 + t3 * y3);
644
 
    ppoints.setPoint (pidx, x4, y4);
645
 
    pidx++;
646
 
  }
647
 
  ppoints.resize (pidx);
648
 
  return pidx;
649
 
}
650
 
 
651
 
void GBezier::updateGradientShape (QPainter& p) {
652
 
  // define the rectangular box for the gradient pixmap
653
 
  // (in object coordinate system)
654
 
  gShape.setBox (calcEnvelope ());
655
 
 
656
 
  // define the clipping region
657
 
  QWMatrix matrix = p.worldMatrix ();
658
 
  gShape.setRegion (QRegion (matrix.map (ppoints)));
659
 
 
660
 
  // update the gradient information
661
 
  gShape.setGradient (fillInfo.gradient);
662
 
 
663
 
  // and create a new gradient pixmap
664
 
  gShape.updatePixmap ();
665
 
}
666
 
 
667
 
void GBezier::getPath (QValueList<Coord>& path) {
668
 
  unsigned int num = ppoints.size ();
669
 
  for (unsigned int i = 0; i < num; i++) {
670
 
    const QPoint& p = ppoints.point (i);
671
 
    Coord pi (p.x (), p.y ());
672
 
    path.append(pi.transform (tMatrix));
673
 
  }
674
 
}
675
 
 
676
 
bool GBezier::intersects (const Rect& r) {
677
 
  return r.intersects (rbox);
678
 
  //  return GObject::intersects (r);
679
 
}
680
 
 
681
 
bool GBezier::splitAt (unsigned int idx, GObject*& obj1, GObject*& obj2) {
682
 
  bool result = false;
683
 
 
684
 
  if (isEndPoint (idx)) {
685
 
    if (closed) {
686
 
      GBezier* other = new GBezier (*this);
687
 
      other->closed = false;
688
 
      other->removeAllPoints ();
689
 
      unsigned int i, num = points.count ();
690
 
      for (i = idx - 1; i < num; i++)
691
 
        other->points.append (new Coord (*points.at (i)));
692
 
      for (i = 0; i <= idx + 1; i++)
693
 
        other->points.append (new Coord (*points.at (i)));
694
 
      other->calcBoundingBox ();
695
 
      result = true;
696
 
      obj1 = other;
697
 
      obj2 = 0L;
698
 
    }
699
 
    else if (idx > 1 && idx < points.count () - 1) {
700
 
      GBezier* other1 = (GBezier *) this->copy ();
701
 
      unsigned int i, num = points.count ();
702
 
      for (i = idx + 2; i < num; i++)
703
 
        other1->points.remove (idx + 2);
704
 
      other1->calcBoundingBox ();
705
 
 
706
 
      GBezier* other2 = (GBezier *) this->copy ();
707
 
      for (i = 0; i < idx - 1; i++)
708
 
        other2->points.remove ((unsigned int) 0);
709
 
      other2->calcBoundingBox ();
710
 
      result = true;
711
 
      obj1 = other1;
712
 
      obj2 = other2;
713
 
    }
714
 
  }
715
 
  return result;
716
 
}
717
 
 
718
 
GCurve* GBezier::convertToCurve () const {
719
 
  unsigned int nsegs = (points.count () - 3) / 3;
720
 
  GCurve* curve = new GCurve (m_gdoc);
721
 
  curve->setOutlineInfo (outlineInfo);
722
 
  QListIterator<Coord> it (points);
723
 
  ++it;
724
 
  Coord p1 = it.current ()->transform (tmpMatrix); ++it;
725
 
  for (unsigned int i = 0; i < nsegs; i++) {
726
 
    Coord p2 = it.current ()->transform (tmpMatrix); ++it;
727
 
    Coord p3 = it.current ()->transform (tmpMatrix); ++it;
728
 
    Coord p4 = it.current ()->transform (tmpMatrix); ++it;
729
 
    curve->addBezierSegment (p1, p2, p3, p4);
730
 
    p1 = p4;
731
 
  }
732
 
 
733
 
  curve->setClosed (closed);
734
 
  return curve;
735
 
}
736
 
 
737
 
#include <GBezier.moc>