~ubuntu-branches/debian/sid/kxstitch/sid

« back to all changes in this revision

Viewing changes to kxstitch/patterncanvas.cpp

  • Committer: Bazaar Package Importer
  • Author(s): eric pareja
  • Date: 2005-02-19 12:37:22 UTC
  • Revision ID: james.westby@ubuntu.com-20050219123722-kt3ru1nqvllietee
Tags: upstream-0.6
ImportĀ upstreamĀ versionĀ 0.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2003 by Stephen Allewell                                *
 
3
 *   stephen@mirramar.fsnet.co.uk                                          *
 
4
 *                                                                         *
 
5
 *   This program is free software; you can redistribute it and/or modify  *
 
6
 *   it under the terms of the GNU General Public License as published by  *
 
7
 *   the Free Software Foundation; either version 2 of the License, or     *
 
8
 *   (at your option) any later version.                                   *
 
9
 ***************************************************************************/
 
10
 
 
11
#include <qdatastream.h>
 
12
#include <kdebug.h>
 
13
#include "patterncanvas.h"
 
14
#include "stitch.h"
 
15
 
 
16
PatternCanvas::PatternCanvas()
 
17
  : m_width(0),
 
18
    m_height(0),
 
19
    m_pCanvas(new QPtrVector<Stitch::Queue>),
 
20
    m_pKnot(new QPtrList<Knot>),
 
21
    m_pBackstitch(new QPtrList<BackStitch>)
 
22
{
 
23
  m_pCanvas->setAutoDelete(true);
 
24
  m_pKnot->setAutoDelete(true);
 
25
  m_pBackstitch->setAutoDelete(true);
 
26
}
 
27
 
 
28
PatternCanvas::~PatternCanvas()
 
29
{
 
30
  delete m_pCanvas;
 
31
  delete m_pKnot;
 
32
  delete m_pBackstitch;
 
33
}
 
34
 
 
35
void PatternCanvas::clear()
 
36
{
 
37
  m_pBackstitch->clear();
 
38
  m_pKnot->clear();
 
39
  m_pCanvas->clear();
 
40
  m_width = 0;
 
41
  m_height = 0;
 
42
}
 
43
 
 
44
bool PatternCanvas::isEmpty()
 
45
{
 
46
  if (m_pBackstitch->isEmpty() && m_pKnot->isEmpty() && m_pCanvas->isEmpty())
 
47
    return true;
 
48
  else
 
49
    return false;
 
50
}
 
51
 
 
52
void PatternCanvas::resize(int width,int height)
 
53
{
 
54
  m_pCanvas->resize(width*height);
 
55
  m_width = width;
 
56
  m_height = height;
 
57
}
 
58
 
 
59
void PatternCanvas::extendTop(int rows)
 
60
{
 
61
  int w = m_width;
 
62
  int h = m_height;
 
63
  int size = w*h;
 
64
  resize(w,h+rows);
 
65
  int newSize = m_width*m_height;
 
66
  int count = size;
 
67
  QPoint snapOffset = QPoint(0,rows*2);
 
68
  while (count--)
 
69
    m_pCanvas->insert(--newSize, m_pCanvas->take(--size));
 
70
  for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
71
    k->pos += snapOffset;
 
72
  for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
73
  {
 
74
    bs->start += snapOffset;
 
75
    bs->end += snapOffset;
 
76
  }
 
77
}
 
78
 
 
79
void PatternCanvas::extendLeft(int cols)
 
80
{
 
81
  int w = m_width;
 
82
  int h = m_height;
 
83
  int size = w*h;
 
84
  resize(m_width+cols, m_height);
 
85
  int newSize = m_width*m_height;
 
86
  QPoint snapOffset = QPoint(cols*2,0);
 
87
  while (newSize)
 
88
  {
 
89
    for (int c = w ; c ; c--)
 
90
      m_pCanvas->insert(--newSize, m_pCanvas->take(--size));
 
91
    newSize -= cols;
 
92
  }
 
93
  for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
94
    k->pos += snapOffset;
 
95
  for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
96
  {
 
97
    bs->start += snapOffset;
 
98
    bs->end += snapOffset;
 
99
  }
 
100
}
 
101
 
 
102
void PatternCanvas::extendRight(int cols)
 
103
{
 
104
  int w = m_width;
 
105
  int h = m_height;
 
106
  int size = w*h;
 
107
  resize(m_width+cols, m_height);
 
108
  int newSize = m_width*m_height;
 
109
  while (newSize)
 
110
  {
 
111
    for (int c = w ; c ; c--)
 
112
      m_pCanvas->insert((--newSize)-cols, m_pCanvas->take(--size));
 
113
    newSize -= cols;
 
114
  }
 
115
}
 
116
 
 
117
void PatternCanvas::extendBottom(int rows)
 
118
{
 
119
  resize(m_width, m_height+rows);
 
120
}
 
121
 
 
122
QRect PatternCanvas::patternBoundingRect()
 
123
{
 
124
  int canvasW = m_width;
 
125
  int canvasH = m_height;
 
126
  int canvasSize = canvasW*canvasH;
 
127
 
 
128
  QRect stitchesRect;
 
129
  if (!m_pCanvas->isEmpty())
 
130
    for (int i = 0 ; i < canvasSize ; i++)
 
131
    {
 
132
      int dx = i%canvasW;
 
133
      int dy = i/canvasW;
 
134
      if (m_pCanvas->at(i))
 
135
        stitchesRect|=QRect(dx,dy,1,1);
 
136
    }
 
137
 
 
138
  if (!m_pKnot->isEmpty())
 
139
  {
 
140
    int x1 = canvasW*2+1;
 
141
    int y1 = canvasH*2+1;
 
142
    int x2 = 0;
 
143
    int y2 = 0;
 
144
    for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
145
    {
 
146
      x1 = x1 <? k->pos.x();
 
147
      y1 = y1 <? k->pos.y();
 
148
      x2 = x2 >? k->pos.x();
 
149
      y2 = y2 >? k->pos.y();
 
150
    }
 
151
    stitchesRect|=QRect(x1/2,y1/2,(x2-x1)/2,(y2-y1)/2);
 
152
  }
 
153
 
 
154
  if (!m_pBackstitch->isEmpty())
 
155
  {
 
156
    for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
157
    {
 
158
      // create a normalised rectangle that bounds the backstitch
 
159
      QPoint s = bs->start;
 
160
      QPoint e = bs->end;
 
161
      int x1,y1,x2,y2;
 
162
      x1 = s.x() <? e.x();
 
163
      x2 = s.x() >? e.x();
 
164
      y1 = s.y() <? e.y();
 
165
      y2 = s.y() >? e.y();
 
166
      if (x1 == x2 || y1 == y2)
 
167
      {
 
168
        // special case as a QRect would show as zero m_width or m_height (ie invalid)
 
169
        // so work out were this backstitch is in relation to the canvas
 
170
        // and extend the bounding rectangle to suit.
 
171
        // worst case would be if there was only 1 vertical or horizontal backstitch and nothing else, but this is unlikely
 
172
        if (x1 == x2)
 
173
        {
 
174
          // vertical line
 
175
          if (x1/2 < canvasW/2)
 
176
          {
 
177
            // its to the left of canvas
 
178
            x2+=2; // backstitch coordinates
 
179
          }
 
180
          else if (x1/2 == canvasW/2)
 
181
          {
 
182
            // its in the middle of the canvas
 
183
            x1-=2;
 
184
            x2+=2;
 
185
          }
 
186
          else
 
187
          {
 
188
            // its to the right of canvas
 
189
            x2-=2;
 
190
          }
 
191
        }
 
192
        if (y1 == y2)
 
193
        {
 
194
          // horizontal line
 
195
          if (y1/2 < canvasH/2)
 
196
          {
 
197
            // its above the canvas center
 
198
            y2+=2;
 
199
          }
 
200
          else if (y1/2 == canvasH/2)
 
201
          {
 
202
            // its in the middle of the canvas
 
203
            y1-=2;
 
204
            y2+=2;
 
205
          }
 
206
          else
 
207
          {
 
208
            // its below the canvas center
 
209
            y1-=2;
 
210
          }
 
211
        }
 
212
      }
 
213
      stitchesRect|=QRect(x1/2,y1/2,(x2-x1)/2,(y2-y1)/2);
 
214
    }
 
215
  }
 
216
  return stitchesRect;
 
217
}
 
218
 
 
219
void PatternCanvas::centerPattern()
 
220
{
 
221
  int canvasW = m_width;
 
222
  int canvasH = m_height;
 
223
  int canvasSize = canvasW*canvasH;
 
224
 
 
225
  QRect stitchesRect = patternBoundingRect();
 
226
  // stitchesRect now bounds stitches and backstitches
 
227
  // if it is still invalid then the pattern is empty
 
228
  if (stitchesRect.isValid())
 
229
  {
 
230
    // center the rectangle in the pattern
 
231
    int patternW = stitchesRect.width();
 
232
    int patternH = stitchesRect.height();
 
233
    int destinationX = (canvasW-patternW)/2;
 
234
    int destinationY = (canvasH-patternH)/2; // destinationX,destinationY is the position of the top left of the destination rectangle
 
235
 
 
236
    int destinationOrigin = destinationY*canvasW+destinationX; // index to QVector of top left of destination rectangle
 
237
    int sourceOrigin = stitchesRect.y()*canvasW+stitchesRect.x(); // index to QVector of top left of source rectangle
 
238
    QPoint offset((destinationX-stitchesRect.x())*2,(destinationY-stitchesRect.y())*2);
 
239
    if (destinationOrigin != sourceOrigin)
 
240
    {
 
241
      if (destinationOrigin < sourceOrigin)
 
242
      {
 
243
        // moving backward
 
244
        while (sourceOrigin < canvasSize)
 
245
          m_pCanvas->insert(destinationOrigin++, m_pCanvas->take(sourceOrigin++));
 
246
      }
 
247
      else
 
248
      {
 
249
        // moving forward
 
250
        int offset = destinationOrigin-sourceOrigin;
 
251
        sourceOrigin = stitchesRect.bottom()*canvasW+stitchesRect.right();
 
252
        destinationOrigin = sourceOrigin+offset;
 
253
        while (sourceOrigin >= 0)
 
254
          m_pCanvas->insert(destinationOrigin--, m_pCanvas->take(sourceOrigin--));
 
255
      }
 
256
      // offset the knots
 
257
      for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
258
        k->pos += offset;
 
259
      // offset the backstitches
 
260
      for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
261
      {
 
262
        bs->start += offset;
 
263
        bs->end += offset;
 
264
      }
 
265
    }
 
266
    // else no move is required
 
267
  }
 
268
}
 
269
 
 
270
void PatternCanvas::cropCanvasToRect(QRect r)
 
271
{
 
272
  int rx = r.x();
 
273
  int ry = r.y();
 
274
  int rW = r.width();
 
275
  int rH = r.height();
 
276
  int destinationIndex = 0;
 
277
  for (int y = 0 ; y < rH ; y++)
 
278
    for (int x = 0 ; x < rW ; x++)
 
279
      m_pCanvas->insert(destinationIndex++, m_pCanvas->take((y+ry)*m_width+rx+x));
 
280
  resize(rW,rH);
 
281
  Knot* kn = m_pKnot->first();
 
282
  while (kn)
 
283
  {
 
284
    kn->pos -= QPoint(rx*2,ry*2);
 
285
    if (kn->pos.x() < 0 || kn->pos.y() < 0 || kn->pos.x() > rW*2 || kn->pos.y() > rH*2)
 
286
      m_pKnot->remove();
 
287
    else
 
288
      m_pKnot->next();
 
289
    kn = m_pKnot->current();
 
290
  }
 
291
  BackStitch* bs = m_pBackstitch->first();
 
292
  while (bs)
 
293
  {
 
294
    bs->start -= QPoint(rx*2,ry*2);
 
295
    bs->end -= QPoint(rx*2,ry*2);
 
296
    if (bs->start.x() < 0 || bs->start.y() < 0 || bs->end.x() < 0 || bs->end.y() < 0 || bs->start.x() > rW*2 || bs->start.y() > rH*2 || bs->end.x() > rW*2 || bs->end.y() > rH*2)
 
297
      m_pBackstitch->remove();
 
298
    else
 
299
      m_pBackstitch->next();
 
300
    bs = m_pBackstitch->current();
 
301
  }
 
302
}
 
303
 
 
304
int PatternCanvas::patternWidth()
 
305
{
 
306
  return m_width;
 
307
}
 
308
 
 
309
int PatternCanvas::patternHeight()
 
310
{
 
311
  return m_height;
 
312
}
 
313
 
 
314
uint PatternCanvas::index(QPoint c)
 
315
{
 
316
  return c.y()*m_width+c.x();
 
317
}
 
318
 
 
319
Stitch::Queue *PatternCanvas::stitchAt(QPoint cell)
 
320
{
 
321
  return (m_pCanvas && validateCell(cell))?m_pCanvas->at(index(cell)):0;
 
322
}
 
323
 
 
324
bool PatternCanvas::validateCell(QPoint c)
 
325
{
 
326
  if (c.x() < 0) return false;
 
327
  if (c.y() < 0) return false;
 
328
  if (m_width <= c.x()) return false;
 
329
  if (m_height <= c.y()) return false;
 
330
  return true;
 
331
}
 
332
 
 
333
bool PatternCanvas::validateSnap(QPoint s)
 
334
{
 
335
  if (s.x() < 0) return false;
 
336
  if (s.y() < 0) return false;
 
337
  if (m_width*2+1 <= s.x()) return false;
 
338
  if (m_height*2+1 <= s.y()) return false;
 
339
  return true;
 
340
}
 
341
 
 
342
QPtrListIterator<BackStitch> *PatternCanvas::backstitches()
 
343
{
 
344
  return new QPtrListIterator<BackStitch>(*m_pBackstitch);
 
345
}
 
346
 
 
347
QPtrListIterator<Knot> *PatternCanvas::knots()
 
348
{
 
349
  return new QPtrListIterator<Knot>(*m_pKnot);
 
350
}
 
351
 
 
352
bool PatternCanvas::deleteStitch(QPoint c,Stitch::Type t,int f)
 
353
{
 
354
  if (!validateCell(c))
 
355
    return false;
 
356
  uint id = index(c);
 
357
  if (t == Stitch::Delete && f == -1)
 
358
  {
 
359
    m_pCanvas->remove(id);
 
360
    return true;
 
361
  }
 
362
  Stitch::Queue *q = m_pCanvas->at(id);
 
363
  if (q)
 
364
  {
 
365
    int n = q->count();
 
366
    while (n--)
 
367
    {
 
368
      Stitch *s = q->dequeue();
 
369
      if (!(t == Stitch::Delete ^ s->type == t) || !(f == -1 ^ s->floss == f))
 
370
        q->enqueue(s);
 
371
      else
 
372
        delete s;
 
373
    }
 
374
    if (q->count() == 0)
 
375
      m_pCanvas->remove(id);
 
376
    return true;
 
377
  }
 
378
  return false;
 
379
}
 
380
 
 
381
bool PatternCanvas::addStitch(QPoint c, Stitch::Type t, int i)
 
382
{
 
383
  if (!validateCell(c))
 
384
    return false;
 
385
  uint id = index(c);
 
386
 
 
387
  Stitch::Queue *pStitches = m_pCanvas->at(id); // get the pointer to any existing queue of stitches for this location
 
388
  if (pStitches == 0)
 
389
  {
 
390
    /** no stitch queue currently exists for this location */
 
391
    pStitches = new Stitch::Queue();
 
392
    m_pCanvas->insert(id, pStitches);                           // insert a new stitch queue
 
393
  }
 
394
 
 
395
  uint nStitches = pStitches->count();                  // get the number of stitches in the queue (may be none)
 
396
  pStitches->enqueue(new Stitch(t, i));                 // add the new stitch to the end of the queue
 
397
 
 
398
  /** iterate the queue of existing stitches for any that have been overwritten by the new stitch */
 
399
  while (nStitches--)                                                                                   // while there are existing stitches
 
400
  {
 
401
    Stitch *pStitch = pStitches->dequeue();     // get the stitch at the head of the queue
 
402
    Stitch::Type cst = pStitch->type;                                   // and find its type
 
403
    int cfi = pStitch->floss;                                                           // and colour
 
404
    Stitch::Type interferenceMask = (Stitch::Type)(cst & t);
 
405
                                            // interferenceMask now contains a mask of which bits are affected by new stitch
 
406
    if (interferenceMask)
 
407
    {
 
408
                                            // Some parts of the current stitch are being overwritten
 
409
                                            // but a check needs to be made for illegal values
 
410
      Stitch::Type changeMask = (Stitch::Type)(cst ^ interferenceMask);
 
411
      switch (changeMask)
 
412
      {
 
413
                                            // changeMask contains what is left of the original stitch after being overwritten
 
414
                                            // it may contain illegal values, so these are checked for
 
415
        case 3:
 
416
          pStitches->enqueue(new Stitch(Stitch::TLQtr, cfi));
 
417
          pStitches->enqueue(new Stitch(Stitch::TRQtr, cfi));
 
418
          changeMask = Stitch::Delete;
 
419
          break;
 
420
        case 5:
 
421
          pStitches->enqueue(new Stitch(Stitch::TLQtr, cfi));
 
422
          pStitches->enqueue(new Stitch(Stitch::BLQtr, cfi));
 
423
          changeMask = Stitch::Delete;
 
424
          break;
 
425
        case 10:
 
426
          pStitches->enqueue(new Stitch(Stitch::TRQtr, cfi));
 
427
          pStitches->enqueue(new Stitch(Stitch::BRQtr, cfi));
 
428
          changeMask = Stitch::Delete;
 
429
          break;
 
430
        case 12:
 
431
          pStitches->enqueue(new Stitch(Stitch::BLQtr, cfi));
 
432
          pStitches->enqueue(new Stitch(Stitch::BRQtr, cfi));
 
433
          changeMask = Stitch::Delete;
 
434
          break;
 
435
        default:
 
436
          // other values are acceptable as is
 
437
          break;
 
438
      }
 
439
      if (changeMask)
 
440
      {
 
441
                                            // Check there is something left of the original stitch
 
442
        pStitch->type = changeMask;                                     // and change stitch type to the changeMask value
 
443
        pStitches->enqueue(pStitch);                            // and then add it back to the queue
 
444
      }
 
445
      else
 
446
      {
 
447
                                            // if changeMask is NULL, it does not get requeued, effectively deleting it from the pattern
 
448
        delete pStitch;                                                                                 // delete the Stitch as it is no longer required
 
449
      }
 
450
    }
 
451
    else
 
452
    {
 
453
      pStitches->enqueue(pStitch);
 
454
    }
 
455
  }
 
456
  return true;
 
457
}
 
458
 
 
459
int PatternCanvas::findColor(QPoint cell, Stitch::Type stitchType)
 
460
{
 
461
  int colorIndex = -1;
 
462
 
 
463
  if (validateCell(cell))
 
464
  {
 
465
    uint id = index(cell);
 
466
    Stitch::Queue *pStitches = m_pCanvas->at(id); // get the pointer to any existing queue of stitches for this location
 
467
    if (pStitches)
 
468
    {
 
469
      uint nStitches = pStitches->count();                      // get the number of stitches in the queue (may be none)
 
470
      /** iterate the queue of existing stitches */
 
471
      while (nStitches--)                                                                                       // while there are existing stitches
 
472
      {
 
473
        Stitch *pStitch = pStitches->dequeue(); // get the stitch at the head of the queue
 
474
        Stitch::Type cst = pStitch->type;                                       // and find its type
 
475
        int cfi = pStitch->floss;                                                               // and colour
 
476
        if (colorIndex == -1)
 
477
          colorIndex = cfi;                                                                                     // set the colorIndex to the first color found
 
478
        if (cst & stitchType)
 
479
          colorIndex = cfi;                                                                                     // change the colorIndex if the current stitch type found
 
480
        pStitches->enqueue(pStitch);                                            // put the stitch back in the queue
 
481
      }
 
482
    }
 
483
  }
 
484
  return colorIndex;
 
485
}
 
486
 
 
487
void PatternCanvas::replaceColor(int original, int replacement)
 
488
{
 
489
  int sq = m_pCanvas->size();
 
490
  for (int i = 0 ; i < sq ; i++)
 
491
  {
 
492
    Stitch::Queue *q = m_pCanvas->at(i);
 
493
    if (q)
 
494
    {
 
495
      int c = q->count();
 
496
      while (c--)
 
497
      {
 
498
        Stitch *s = q->dequeue();
 
499
        if (s)
 
500
          // shouldn't really happen, but check for it anyway
 
501
          if (s->floss == original)
 
502
            s->floss = replacement;
 
503
        q->enqueue(s);
 
504
      }
 
505
    }
 
506
  }
 
507
  for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
508
    if (bs->floss == original)
 
509
      bs->floss = replacement;
 
510
  for (Knot* k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
511
    if (k->floss == original)
 
512
      k->floss = replacement;
 
513
}
 
514
 
 
515
QValueList<int> PatternCanvas::usedColors()
 
516
{
 
517
  QValueList<int> uc;
 
518
  int sq = m_pCanvas->size();
 
519
  for (int i = 0 ; i < sq ; i++)
 
520
  {
 
521
    Stitch::Queue *pStitches = m_pCanvas->at(i);
 
522
    if (pStitches)
 
523
    {
 
524
      int c = pStitches->count();
 
525
      while (c--)
 
526
      {
 
527
        Stitch *s = pStitches->dequeue();
 
528
        if (s)
 
529
        { // shouldn't really happen, but check for it anyway
 
530
          if (!uc.contains(s->floss))
 
531
            uc << s->floss;
 
532
          pStitches->enqueue(s);
 
533
        }
 
534
      }
 
535
    }
 
536
  }
 
537
  for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
538
    if (!uc.contains(k->floss))
 
539
      uc << k->floss;
 
540
  for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
541
    if (!uc.contains(bs->floss))
 
542
      uc << bs->floss;
 
543
  return uc;
 
544
}
 
545
 
 
546
void PatternCanvas::addBackstitch(QPoint start, QPoint end, int i)
 
547
{
 
548
  if (validateSnap(start) && validateSnap(end))
 
549
    m_pBackstitch->append(new BackStitch(start, end, i));
 
550
}
 
551
 
 
552
void PatternCanvas::deleteBackstitch(BackStitch *bs)
 
553
{
 
554
  m_pBackstitch->removeRef(bs);
 
555
}
 
556
 
 
557
void PatternCanvas::addFrenchKnot(QPoint snap, int i)
 
558
{
 
559
  if (validateSnap(snap))
 
560
  {
 
561
    deleteFrenchKnot(snap,-1); // just in case there is one there already
 
562
    m_pKnot->append(new Knot(snap,i));
 
563
  }
 
564
}
 
565
 
 
566
void PatternCanvas::deleteFrenchKnot(QPoint p, int f)
 
567
{
 
568
  for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
569
    if (k->pos == p && (f == -1 ^ f == k->floss))
 
570
    {
 
571
      m_pKnot->remove(k);
 
572
      return;
 
573
    }
 
574
}
 
575
 
 
576
void PatternCanvas::writeCanvas(QDataStream &s)
 
577
{
 
578
  s << (Q_INT32)m_width;
 
579
  s << (Q_INT32)m_height;
 
580
 
 
581
  int sq = m_pCanvas->size();
 
582
  for (int i = 0 ; i < sq ; i++)
 
583
  {
 
584
    Stitch::Queue *psq = m_pCanvas->at(i);
 
585
    if (psq)
 
586
    {
 
587
      int stitches = psq->count();  // the number of stitches in the queue, may be 0
 
588
      s << (Q_INT8)stitches;
 
589
      while (stitches--)
 
590
      {
 
591
        Stitch *stitch = psq->dequeue();
 
592
        s << (Q_INT8)(stitch->type);
 
593
        s << (Q_INT16)(stitch->floss);
 
594
        psq->enqueue(stitch);
 
595
      }
 
596
    }
 
597
    else
 
598
      s << (Q_INT8)0;
 
599
  }
 
600
  sq = m_pKnot->count();
 
601
  s << (Q_INT32)sq;
 
602
  for (Knot *k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
603
    s << k->pos << (Q_INT16)(k->floss);   // QPoint, Q_INT16
 
604
  sq = m_pBackstitch->count();
 
605
  s << (Q_INT32)sq;
 
606
  for (BackStitch* bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
607
    s << bs->start << bs->end << (Q_INT16)(bs->floss);          // QPoint, QPoint, Q_INT16
 
608
}
 
609
 
 
610
bool PatternCanvas::readPCStitch5Canvas(QDataStream& s)
 
611
{
 
612
  Stitch::Type  stitchType[] = {Stitch::Delete,Stitch::Full,Stitch::TL3Qtr,Stitch::TR3Qtr,Stitch::BL3Qtr,Stitch::BR3Qtr,Stitch::TBHalf,Stitch::BTHalf,Stitch::FRKnot,Stitch::TLQtr,Stitch::TRQtr,Stitch::BLQtr,Stitch::BRQtr}; // conversion of PCStitch to KXStitch
 
613
  Q_INT32       width;
 
614
  Q_INT32       height;
 
615
  Q_INT32       cells;
 
616
  Q_INT32       backstitches;
 
617
  Q_INT32       extras;
 
618
  Q_INT32       knots;
 
619
  Q_INT16       cellCount;
 
620
  Q_INT16       x, y;
 
621
  Q_UINT8       type;
 
622
  Q_UINT8       color;
 
623
  QIODevice::Offset fileSize = s.device()->size();
 
624
  // KXStitch file format has the m_width and m_height available at this point
 
625
  // PCStitch does not, so it has been set by KXStitchDoc::openDocument()
 
626
  // and the canvas has been cleared before calling this function
 
627
  width = m_width;
 
628
  height = m_height;
 
629
  cells = width*height; // total number of cells
 
630
  for (int i = 0 ; i < cells ; i+= cellCount)
 
631
  {
 
632
    if (s.device()->at()+4 > fileSize) return false;
 
633
    s >> cellCount;
 
634
    s >> color;
 
635
    s >> type;
 
636
    if (type != 0xff)
 
637
    {
 
638
      for (int c = 0 ; c < cellCount ; c++)
 
639
      {
 
640
        int xc = (i+c)/height;
 
641
        int yc = (i+c)%height;
 
642
        addStitch(QPoint(xc,yc),stitchType[type],color-1); // color-1 because PCStitch uses 1 based array
 
643
                                                            // KXStitch uses 0 based arrays
 
644
      }
 
645
    }
 
646
  }
 
647
  // check for additional stitches
 
648
  if (s.device()->at()+4 > fileSize) return false;
 
649
  s >> extras; // assuming a 32 bit value, time will tell
 
650
  while (extras--)
 
651
  {
 
652
    if (s.device()->at()+4 > fileSize) return false;
 
653
    s >> x;
 
654
    s >> y;
 
655
    for (int dx = 0 ; dx < 4 ; dx++)
 
656
    {
 
657
      if (s.device()->at()+2 > fileSize) return false;
 
658
      s >> color;
 
659
      s >> type;
 
660
      if (type != 0xff)
 
661
        addStitch(QPoint(x-1,y-1),stitchType[type],color-1); // values -1 for same reason as above
 
662
    }
 
663
  }
 
664
  // read french knots
 
665
  if (s.device()->at()+4 > fileSize) return false;
 
666
  s >> knots;
 
667
  while (knots--)
 
668
  {
 
669
    if (s.device()->at()+5 > fileSize) return false;
 
670
    s >> x;
 
671
    s >> y;
 
672
    s >> color;
 
673
    addFrenchKnot(QPoint(x-1,y-1),color-1);
 
674
  }
 
675
  // read backstitches
 
676
  if (s.device()->at()+4 > fileSize) return false;
 
677
  s >> backstitches;
 
678
  while (backstitches--)
 
679
  {
 
680
    if (s.device()->at()+13 > fileSize) return false;
 
681
    Q_INT16 sx, sy, sp, ex, ey, ep;
 
682
    s >> sx;
 
683
    s >> sy;
 
684
    s >> sp;
 
685
    s >> ex;
 
686
    s >> ey;
 
687
    s >> ep;
 
688
    s >> color;
 
689
    m_pBackstitch->append(new BackStitch(QPoint(--sx*2+((sp-1)%3),--sy*2+((sp-1)/3)),QPoint(--ex*2+((ep-1)%3),--ey*2+((ep-1)/3)),color-1));
 
690
  }
 
691
  return true;
 
692
}
 
693
 
 
694
bool PatternCanvas::readKXStitchCanvas(QDataStream& s,int fileFormatVersion)
 
695
{
 
696
  Q_INT32     width;
 
697
  Q_INT32     height;
 
698
  Q_INT32     cells;
 
699
  Q_INT32     backstitches;
 
700
  Q_INT32     knots;
 
701
  Q_INT8      stitches;
 
702
  Q_INT8      type;
 
703
  Q_INT16     color;
 
704
  QPoint      start;
 
705
  QPoint      end;
 
706
  QIODevice*  device = s.device();
 
707
  int         fileSize = device->size();
 
708
  switch (fileFormatVersion)
 
709
  {
 
710
    case 5:
 
711
    case 4:
 
712
      if (device->at()+8 > fileSize) return false;
 
713
      s >> width >> height;
 
714
      cells = width*height;
 
715
      m_pCanvas->clear();
 
716
      resize(width, height);
 
717
      for (int i = 0 ; i < cells ; i++)
 
718
      {
 
719
        if (device->at()+1 > fileSize) return false;
 
720
        s >> stitches;
 
721
        if (stitches)
 
722
        {
 
723
          Stitch::Queue* psq = new Stitch::Queue();
 
724
          m_pCanvas->insert(i,psq);
 
725
          while (stitches--)
 
726
          {
 
727
            if (device->at()+3 > fileSize) return false;
 
728
            s >> type;
 
729
            s >> color;
 
730
            psq->enqueue(new Stitch((Stitch::Type)type, color));
 
731
          }
 
732
        }
 
733
      }
 
734
      if (device->at()+4 > fileSize) return false;
 
735
      s >> knots;
 
736
      while (knots--)
 
737
      {
 
738
        if (device->at()+10 > fileSize) return false;
 
739
        s >> start >> color;
 
740
        m_pKnot->append(new Knot(start,color));
 
741
      }
 
742
      if (device->at()+4 > fileSize) return false;
 
743
      s >> backstitches;
 
744
      while (backstitches--)
 
745
      {
 
746
      if (device->at()+17 > fileSize) return false;
 
747
        s >> start >> end >> color;
 
748
        m_pBackstitch->append(new BackStitch(start,end,color));
 
749
      }
 
750
      break;
 
751
    case 3:
 
752
    case 2:
 
753
      if (device->at()+8 > fileSize) return false;
 
754
      s >> width >> height;
 
755
      cells = width*height;
 
756
      m_pCanvas->clear();
 
757
      m_pKnot->clear();
 
758
      m_pBackstitch->clear();
 
759
      resize(width, height);
 
760
      for (int i = 0 ; i < cells ; i++)
 
761
      {
 
762
        if (device->at()+1 > fileSize) return false;
 
763
        s >> stitches;
 
764
        if (stitches)
 
765
        {
 
766
          Stitch::Queue *psq = new Stitch::Queue();
 
767
          m_pCanvas->insert(i,psq);
 
768
          while (stitches--)
 
769
          {
 
770
            if (device->at()+3 > fileSize) return false;
 
771
            s >> type;
 
772
            s >> color;
 
773
            if (type == Stitch::FRKnot)
 
774
              addFrenchKnot(QPoint((i%width)*2+1,(i/width)*2+1),color);
 
775
            else
 
776
              psq->enqueue(new Stitch((Stitch::Type)type, color));
 
777
          }
 
778
        }
 
779
      }
 
780
      if (device->at()+4 > fileSize) return false;
 
781
      s >> backstitches;
 
782
      while (backstitches--)
 
783
      {
 
784
        if (device->at()+10 > fileSize) return false;
 
785
        s >> start >> end >> color;
 
786
        m_pBackstitch->append(new BackStitch(start,end,color));
 
787
      }
 
788
      break;
 
789
  }
 
790
  return true;
 
791
}
 
792
 
 
793
UsageMap PatternCanvas::calculateUsage()
 
794
{
 
795
  // Calculate size of stitch cell relative to pattern properties
 
796
  // and calculate relative size of a half stitch and quarter stitch
 
797
  // Iterate canvas cells, iterating stitches in cell totalling the quantity of 
 
798
  // thread required
 
799
  // Required ClothCount, ClothCountUnits
 
800
  UsageMap usageMap;
 
801
  const double halfStitch = 2.4142135; // using 2.4142135 = sqrt(2)+1 representing the diagonal of a cell + 1 side, e.g.  /|/|/|/|
 
802
  const double qtrStitch = 1.4142135;  // using 1.4142135 = sqrt(2) representing corner to middle to another corner
 
803
  int sq = m_pCanvas->size();
 
804
  for (int i = 0 ; i < sq ; i++)
 
805
  {
 
806
    Stitch::Queue *q = m_pCanvas->at(i);
 
807
    if (q)
 
808
    {
 
809
      int c = q->count();
 
810
      while (c--)
 
811
      {
 
812
        Stitch *s = q->dequeue();
 
813
        if (s)
 
814
          // shouldn't really happen, but check for it anyway
 
815
        {
 
816
          switch (s->type)
 
817
          {
 
818
            case Stitch::TLQtr:
 
819
            case Stitch::TRQtr:
 
820
            case Stitch::BLQtr:
 
821
            case Stitch::BRQtr:
 
822
              usageMap[s->floss].quarter += 1;
 
823
              usageMap[s->floss].stitchLength += qtrStitch;
 
824
              break;
 
825
            case Stitch::BTHalf:
 
826
            case Stitch::TBHalf:
 
827
              usageMap[s->floss].half += 1;
 
828
              usageMap[s->floss].stitchLength += halfStitch;
 
829
              break;
 
830
            case Stitch::TL3Qtr:
 
831
            case Stitch::TR3Qtr:
 
832
            case Stitch::BL3Qtr:
 
833
            case Stitch::BR3Qtr:
 
834
              usageMap[s->floss].threeQuarter += 1;
 
835
              usageMap[s->floss].stitchLength += (halfStitch+qtrStitch);
 
836
              break;
 
837
            case Stitch::Full:
 
838
              usageMap[s->floss].full += 1;
 
839
              usageMap[s->floss].stitchLength += (halfStitch+halfStitch);
 
840
              break;
 
841
          }
 
842
          q->enqueue(s);
 
843
        }
 
844
      }
 
845
    }
 
846
  }
 
847
  for (BackStitch *bs = m_pBackstitch->first() ; bs ; bs = m_pBackstitch->next())
 
848
  {
 
849
    QPoint p = bs->end - bs->start;
 
850
    usageMap[bs->floss].backstitches += 1;
 
851
    double manhattanLength = p.manhattanLength()/2.0;
 
852
    usageMap[bs->floss].backstitchLength += manhattanLength;
 
853
  }
 
854
  for (Knot* k = m_pKnot->first() ; k ; k = m_pKnot->next())
 
855
  {
 
856
    usageMap[k->floss].knots += 1;
 
857
    usageMap[k->floss].stitchLength += halfStitch;   // estimated length of floss required for french knots
 
858
  }
 
859
  return usageMap;
 
860
}