File indexing completed on 2024-04-28 04:32:08
0001 /* 0002 * Copyright (C) 2010-2015 by Stephen Allewell 0003 * steve.allewell@gmail.com 0004 * 0005 * This program is free software; you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation; either version 2 of the License, or 0008 * (at your option) any later version. 0009 */ 0010 0011 #include "StitchData.h" 0012 0013 #include <KLocalizedString> 0014 0015 #include "Exceptions.h" 0016 0017 FlossUsage::FlossUsage() 0018 : backstitchCount(0) 0019 , backstitchLength(0.0) 0020 { 0021 } 0022 0023 double FlossUsage::totalLength() const 0024 { 0025 return stitchLength() + backstitchLength; 0026 } 0027 0028 double FlossUsage::stitchLength() const 0029 { 0030 double total = 0; 0031 0032 foreach (double length, stitchLengths) { 0033 total += length; 0034 } 0035 0036 return total; 0037 } 0038 0039 int FlossUsage::totalStitches() const 0040 { 0041 return stitchCount() + backstitchCount; 0042 } 0043 0044 int FlossUsage::stitchCount() const 0045 { 0046 int total = 0; 0047 0048 foreach (int count, stitchCounts) { 0049 total += count; 0050 } 0051 0052 return total; 0053 } 0054 0055 StitchData::StitchData() 0056 : m_width(0) 0057 , m_height(0) 0058 { 0059 } 0060 0061 StitchData::~StitchData() 0062 { 0063 clear(); 0064 } 0065 0066 void StitchData::clear() 0067 { 0068 qDeleteAll(m_stitches); 0069 m_stitches.fill(nullptr); 0070 0071 qDeleteAll(m_backstitches); 0072 m_backstitches.clear(); 0073 0074 qDeleteAll(m_knots); 0075 m_knots.clear(); 0076 } 0077 0078 int StitchData::width() const 0079 { 0080 return m_width; 0081 } 0082 0083 int StitchData::height() const 0084 { 0085 return m_height; 0086 } 0087 0088 void StitchData::resize(int width, int height) 0089 { 0090 QVector<StitchQueue *> newVector(width * height); 0091 QRect extentsRect = extents(); 0092 0093 for (int y = extentsRect.top(); y <= extentsRect.bottom(); ++y) { 0094 for (int x = extentsRect.left(); x <= extentsRect.right(); ++x) { 0095 newVector[y * width + x] = takeStitchQueueAt(x, y); 0096 } 0097 } 0098 0099 m_stitches = newVector; 0100 m_width = width; 0101 m_height = height; 0102 } 0103 0104 void StitchData::insertColumns(int startColumn, int columns) 0105 { 0106 int originalWidth = m_width; 0107 0108 resize(originalWidth + columns, m_height); 0109 0110 for (int y = 0; y < m_height; ++y) { 0111 for (int destinationColumn = m_width - 1, sourceColumn = originalWidth - 1; sourceColumn >= startColumn; --destinationColumn, --sourceColumn) { 0112 m_stitches[index(destinationColumn, y)] = takeStitchQueueAt(sourceColumn, y); 0113 } 0114 } 0115 0116 startColumn *= 2; 0117 columns *= 2; 0118 0119 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0120 0121 while (backstitchIterator.hasNext()) { 0122 Backstitch *backstitch = backstitchIterator.next(); 0123 0124 if (backstitch->start.x() >= startColumn) { 0125 backstitch->start.setX(backstitch->start.x() + columns); 0126 } 0127 0128 if (backstitch->end.x() >= startColumn) { 0129 backstitch->end.setX(backstitch->end.x() + columns); 0130 } 0131 } 0132 0133 QListIterator<Knot *> knotIterator(m_knots); 0134 0135 while (knotIterator.hasNext()) { 0136 Knot *knot = knotIterator.next(); 0137 0138 if (knot->position.x() >= startColumn) { 0139 knot->position.setX(knot->position.x() + columns); 0140 } 0141 } 0142 } 0143 0144 void StitchData::insertRows(int startRow, int rows) 0145 { 0146 int originalHeight = m_height; 0147 0148 resize(m_width, originalHeight + rows); 0149 0150 for (int destinationRow = m_height - 1, sourceRow = originalHeight - 1; sourceRow >= startRow; --destinationRow, --sourceRow) { 0151 for (int x = 0; x < m_width; ++x) { 0152 m_stitches[index(x, destinationRow)] = takeStitchQueueAt(x, sourceRow); 0153 } 0154 } 0155 0156 startRow *= 2; 0157 rows *= 2; 0158 0159 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0160 0161 while (backstitchIterator.hasNext()) { 0162 Backstitch *backstitch = backstitchIterator.next(); 0163 0164 if (backstitch->start.y() >= startRow) { 0165 backstitch->start.setY(backstitch->start.y() + rows); 0166 } 0167 0168 if (backstitch->end.y() >= startRow) { 0169 backstitch->end.setY(backstitch->end.y() + rows); 0170 } 0171 } 0172 0173 QListIterator<Knot *> knotIterator(m_knots); 0174 0175 while (knotIterator.hasNext()) { 0176 Knot *knot = knotIterator.next(); 0177 0178 if (knot->position.y() >= startRow) { 0179 knot->position.setY(knot->position.y() + rows); 0180 } 0181 } 0182 } 0183 0184 void StitchData::removeColumns(int startColumn, int columns) 0185 { 0186 for (int y = 0; y < m_height; ++y) { 0187 for (int destinationColumn = startColumn, sourceColumn = startColumn + columns; sourceColumn < m_width; ++destinationColumn, ++sourceColumn) { 0188 m_stitches[index(destinationColumn, y)] = takeStitchQueueAt(sourceColumn, y); 0189 } 0190 } 0191 0192 int snapStartColumn = startColumn * 2; 0193 int snapColumns = columns * 2; 0194 0195 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0196 0197 while (backstitchIterator.hasNext()) { 0198 Backstitch *backstitch = backstitchIterator.next(); 0199 0200 if (backstitch->start.x() >= snapStartColumn + snapColumns) { 0201 backstitch->start.setX(backstitch->start.x() - snapColumns); 0202 } 0203 0204 if (backstitch->end.x() >= snapStartColumn + snapColumns) { 0205 backstitch->end.setX(backstitch->end.x() - snapColumns); 0206 } 0207 } 0208 0209 QListIterator<Knot *> knotIterator(m_knots); 0210 0211 while (knotIterator.hasNext()) { 0212 Knot *knot = knotIterator.next(); 0213 0214 if (knot->position.x() >= snapStartColumn + snapColumns) { 0215 knot->position.setX(knot->position.x() - snapColumns); 0216 } 0217 } 0218 0219 resize(m_width - columns, m_height); 0220 } 0221 0222 void StitchData::removeRows(int startRow, int rows) 0223 { 0224 for (int destinationRow = startRow, sourceRow = startRow + rows; sourceRow < m_height; ++destinationRow, ++sourceRow) { 0225 for (int x = 0; x < m_width; ++x) { 0226 m_stitches[index(x, destinationRow)] = takeStitchQueueAt(x, sourceRow); 0227 } 0228 } 0229 0230 int snapStartRow = startRow * 2; 0231 int snapRows = rows * 2; 0232 0233 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0234 0235 while (backstitchIterator.hasNext()) { 0236 Backstitch *backstitch = backstitchIterator.next(); 0237 0238 if (backstitch->start.y() >= snapStartRow + snapRows) { 0239 backstitch->start.setY(backstitch->start.y() - snapRows); 0240 } 0241 0242 if (backstitch->end.y() >= snapStartRow + snapRows) { 0243 backstitch->end.setY(backstitch->end.y() - snapRows); 0244 } 0245 } 0246 0247 QListIterator<Knot *> knotIterator(m_knots); 0248 0249 while (knotIterator.hasNext()) { 0250 Knot *knot = knotIterator.next(); 0251 0252 if (knot->position.y() >= snapStartRow + snapRows) { 0253 knot->position.setY(knot->position.y() - snapRows); 0254 } 0255 } 0256 0257 resize(m_width, m_height - rows); 0258 } 0259 0260 QRect StitchData::extents() const 0261 { 0262 QRect extentsRect; 0263 0264 for (int y = 0; y < m_height; ++y) { 0265 for (int x = 0; x < m_width; ++x) { 0266 if (m_stitches.at(index(x, y))) { 0267 extentsRect |= QRect(x * 2, y * 2, 2, 2); 0268 } 0269 } 0270 } 0271 0272 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0273 0274 while (backstitchIterator.hasNext()) { 0275 Backstitch *backstitch = backstitchIterator.next(); 0276 extentsRect |= QRect(backstitch->start, backstitch->end).normalized(); 0277 } 0278 0279 QListIterator<Knot *> knotIterator(m_knots); 0280 0281 while (knotIterator.hasNext()) { 0282 Knot *knot = knotIterator.next(); 0283 extentsRect |= QRect(knot->position, QSize(0, 0)); 0284 } 0285 0286 extentsRect.adjust(-(extentsRect.left() % 2), -(extentsRect.top() % 2), extentsRect.right() % 2, extentsRect.bottom() % 2); 0287 0288 if (extentsRect.isValid()) { 0289 extentsRect = QRect(extentsRect.left() / 2, extentsRect.top() / 2, extentsRect.width() / 2, extentsRect.height() / 2); 0290 } 0291 0292 return extentsRect; 0293 } 0294 0295 void StitchData::movePattern(int dx, int dy) 0296 { 0297 QRect extentsRect = extents(); 0298 0299 QVector<StitchQueue *> newVector(m_width * m_height); 0300 0301 for (int y = extentsRect.top(); y <= extentsRect.bottom(); ++y) { 0302 for (int x = extentsRect.left(); x <= extentsRect.right(); ++x) { 0303 newVector[index(x + dx, y + dy)] = takeStitchQueueAt(x, y); 0304 } 0305 } 0306 0307 m_stitches = newVector; 0308 0309 dx *= 2; 0310 dy *= 2; 0311 0312 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0313 0314 while (backstitchIterator.hasNext()) { 0315 backstitchIterator.next()->move(dx, dy); 0316 } 0317 0318 QListIterator<Knot *> knotIterator(m_knots); 0319 0320 while (knotIterator.hasNext()) { 0321 knotIterator.next()->move(dx, dy); 0322 } 0323 } 0324 0325 void StitchData::mirror(Qt::Orientation orientation) 0326 { 0327 int rows = m_height; 0328 int cols = m_width; 0329 0330 if (orientation == Qt::Vertical) { 0331 rows = rows / 2 + rows % 2; 0332 } else { 0333 cols = cols / 2 + cols % 2; 0334 } 0335 0336 for (int row = 0; row < rows; ++row) { 0337 for (int col = 0; col < cols; ++col) { 0338 QPoint srcCell(col, row); 0339 QPoint dstCell; 0340 0341 if (orientation == Qt::Vertical) { 0342 dstCell = QPoint(col, m_height - row - 1); 0343 } else { 0344 dstCell = QPoint(m_width - col - 1, row); 0345 } 0346 0347 StitchQueue *src = takeStitchQueueAt(srcCell); 0348 StitchQueue *dst = takeStitchQueueAt(dstCell); 0349 0350 if (src) { 0351 invertQueue(orientation, src); 0352 replaceStitchQueueAt(dstCell, src); 0353 } 0354 0355 if (dst) { 0356 invertQueue(orientation, dst); 0357 replaceStitchQueueAt(srcCell, dst); 0358 } 0359 } 0360 } 0361 0362 int maxXSnap = m_width * 2; 0363 int maxYSnap = m_height * 2; 0364 QListIterator<Backstitch *> bi(m_backstitches); 0365 0366 while (bi.hasNext()) { 0367 Backstitch *backstitch = bi.next(); 0368 0369 if (orientation == Qt::Horizontal) { 0370 backstitch->start.setX(maxXSnap - backstitch->start.x()); 0371 backstitch->end.setX(maxXSnap - backstitch->end.x()); 0372 } else { 0373 backstitch->start.setY(maxYSnap - backstitch->start.y()); 0374 backstitch->end.setY(maxYSnap - backstitch->end.y()); 0375 } 0376 } 0377 0378 QListIterator<Knot *> ki(m_knots); 0379 0380 while (ki.hasNext()) { 0381 Knot *knot = ki.next(); 0382 0383 if (orientation == Qt::Horizontal) { 0384 knot->position.setX(maxXSnap - knot->position.x()); 0385 } else { 0386 knot->position.setY(maxYSnap - knot->position.y()); 0387 } 0388 } 0389 } 0390 0391 void StitchData::rotate(Rotation rotation) 0392 { 0393 int rows = m_height; 0394 int cols = m_width; 0395 0396 QVector<StitchQueue *> rotatedData(m_width * m_height); 0397 0398 for (int y = 0; y < rows; ++y) { 0399 for (int x = 0; x < cols; ++x) { 0400 StitchQueue *src = takeStitchQueueAt(x, y); 0401 int index = (cols - x - 1) * rows + y; // default to Rotate90 0402 0403 switch (rotation) { 0404 case Rotate90: 0405 // index = (cols - x - 1) * rows + y; 0406 break; 0407 0408 case Rotate180: 0409 index = (rows - y - 1) * cols + (cols - x - 1); 0410 break; 0411 0412 case Rotate270: 0413 index = x * rows + (rows - y - 1); 0414 break; 0415 } 0416 0417 if (src) { 0418 rotateQueue(rotation, src); 0419 rotatedData[index] = src; 0420 } 0421 } 0422 } 0423 0424 if ((rotation == Rotate90) || (rotation == Rotate270)) { 0425 int height = m_height; 0426 m_height = m_width; 0427 m_width = height; 0428 } 0429 0430 m_stitches = rotatedData; 0431 0432 int maxXSnap = m_width * 2; 0433 int maxYSnap = m_height * 2; 0434 QListIterator<Backstitch *> bi(m_backstitches); 0435 0436 while (bi.hasNext()) { 0437 Backstitch *backstitch = bi.next(); 0438 0439 switch (rotation) { 0440 case Rotate90: 0441 backstitch->start = QPoint(backstitch->start.y(), maxXSnap - backstitch->start.x()); 0442 backstitch->end = QPoint(backstitch->end.y(), maxXSnap - backstitch->end.x()); 0443 break; 0444 0445 case Rotate180: 0446 backstitch->start = QPoint(maxXSnap - backstitch->start.x(), maxYSnap - backstitch->start.y()); 0447 backstitch->end = QPoint(maxXSnap - backstitch->end.x(), maxYSnap - backstitch->end.y()); 0448 break; 0449 0450 case Rotate270: 0451 backstitch->start = QPoint(maxYSnap - backstitch->start.y(), backstitch->start.x()); 0452 backstitch->end = QPoint(maxYSnap - backstitch->end.y(), backstitch->end.x()); 0453 break; 0454 } 0455 } 0456 0457 QListIterator<Knot *> ki(m_knots); 0458 0459 while (ki.hasNext()) { 0460 Knot *knot = ki.next(); 0461 0462 switch (rotation) { 0463 case Rotate90: 0464 knot->position = QPoint(knot->position.y(), maxXSnap - knot->position.x()); 0465 break; 0466 0467 case Rotate180: 0468 knot->position = QPoint(maxXSnap - knot->position.x(), maxYSnap - knot->position.y()); 0469 break; 0470 0471 case Rotate270: 0472 knot->position = QPoint(maxYSnap - knot->position.y(), knot->position.x()); 0473 break; 0474 } 0475 } 0476 } 0477 0478 void StitchData::invertQueue(Qt::Orientation orientation, StitchQueue *queue) 0479 { 0480 static QMap<Qt::Orientation, QMap<Stitch::Type, Stitch::Type>> mirrorMap; 0481 0482 if (mirrorMap.isEmpty()) { 0483 mirrorMap[Qt::Horizontal][Stitch::Delete] = Stitch::Delete; 0484 mirrorMap[Qt::Horizontal][Stitch::TLQtr] = Stitch::TRQtr; 0485 mirrorMap[Qt::Horizontal][Stitch::TRQtr] = Stitch::TLQtr; 0486 mirrorMap[Qt::Horizontal][Stitch::BLQtr] = Stitch::BRQtr; 0487 mirrorMap[Qt::Horizontal][Stitch::BRQtr] = Stitch::BLQtr; 0488 mirrorMap[Qt::Horizontal][Stitch::BTHalf] = Stitch::TBHalf; 0489 mirrorMap[Qt::Horizontal][Stitch::TBHalf] = Stitch::BTHalf; 0490 mirrorMap[Qt::Horizontal][Stitch::TL3Qtr] = Stitch::TR3Qtr; 0491 mirrorMap[Qt::Horizontal][Stitch::TR3Qtr] = Stitch::TL3Qtr; 0492 mirrorMap[Qt::Horizontal][Stitch::BL3Qtr] = Stitch::BR3Qtr; 0493 mirrorMap[Qt::Horizontal][Stitch::BR3Qtr] = Stitch::BL3Qtr; 0494 mirrorMap[Qt::Horizontal][Stitch::TLSmallHalf] = Stitch::TRSmallHalf; 0495 mirrorMap[Qt::Horizontal][Stitch::TRSmallHalf] = Stitch::TLSmallHalf; 0496 mirrorMap[Qt::Horizontal][Stitch::BLSmallHalf] = Stitch::BRSmallHalf; 0497 mirrorMap[Qt::Horizontal][Stitch::BRSmallHalf] = Stitch::BLSmallHalf; 0498 mirrorMap[Qt::Horizontal][Stitch::TLSmallFull] = Stitch::TRSmallFull; 0499 mirrorMap[Qt::Horizontal][Stitch::TRSmallFull] = Stitch::TLSmallFull; 0500 mirrorMap[Qt::Horizontal][Stitch::BLSmallFull] = Stitch::BRSmallFull; 0501 mirrorMap[Qt::Horizontal][Stitch::BRSmallFull] = Stitch::BLSmallFull; 0502 mirrorMap[Qt::Horizontal][Stitch::Full] = Stitch::Full; 0503 0504 mirrorMap[Qt::Vertical][Stitch::Delete] = Stitch::Delete; 0505 mirrorMap[Qt::Vertical][Stitch::TLQtr] = Stitch::BLQtr; 0506 mirrorMap[Qt::Vertical][Stitch::TRQtr] = Stitch::BRQtr; 0507 mirrorMap[Qt::Vertical][Stitch::BLQtr] = Stitch::TLQtr; 0508 mirrorMap[Qt::Vertical][Stitch::BRQtr] = Stitch::TRQtr; 0509 mirrorMap[Qt::Vertical][Stitch::BTHalf] = Stitch::TBHalf; 0510 mirrorMap[Qt::Vertical][Stitch::TBHalf] = Stitch::BTHalf; 0511 mirrorMap[Qt::Vertical][Stitch::TL3Qtr] = Stitch::BL3Qtr; 0512 mirrorMap[Qt::Vertical][Stitch::TR3Qtr] = Stitch::BR3Qtr; 0513 mirrorMap[Qt::Vertical][Stitch::BL3Qtr] = Stitch::TL3Qtr; 0514 mirrorMap[Qt::Vertical][Stitch::BR3Qtr] = Stitch::TR3Qtr; 0515 mirrorMap[Qt::Vertical][Stitch::TLSmallHalf] = Stitch::BLSmallHalf; 0516 mirrorMap[Qt::Vertical][Stitch::TRSmallHalf] = Stitch::BRSmallHalf; 0517 mirrorMap[Qt::Vertical][Stitch::BLSmallHalf] = Stitch::TLSmallHalf; 0518 mirrorMap[Qt::Vertical][Stitch::BRSmallHalf] = Stitch::TRSmallHalf; 0519 mirrorMap[Qt::Vertical][Stitch::TLSmallFull] = Stitch::BLSmallFull; 0520 mirrorMap[Qt::Vertical][Stitch::TRSmallFull] = Stitch::BRSmallFull; 0521 mirrorMap[Qt::Vertical][Stitch::BLSmallFull] = Stitch::TLSmallFull; 0522 mirrorMap[Qt::Vertical][Stitch::BRSmallFull] = Stitch::TRSmallFull; 0523 mirrorMap[Qt::Vertical][Stitch::Full] = Stitch::Full; 0524 } 0525 0526 QListIterator<Stitch *> i(*queue); 0527 0528 while (i.hasNext()) { 0529 Stitch *stitch = i.next(); 0530 stitch->type = mirrorMap[orientation][stitch->type]; 0531 } 0532 } 0533 0534 void StitchData::rotateQueue(Rotation rotation, StitchQueue *queue) 0535 { 0536 static QMap<Rotation, QMap<Stitch::Type, Stitch::Type>> rotateMap; 0537 0538 if (rotateMap.isEmpty()) { 0539 rotateMap[Rotate90][Stitch::TLQtr] = Stitch::BLQtr; 0540 rotateMap[Rotate90][Stitch::TRQtr] = Stitch::TLQtr; 0541 rotateMap[Rotate90][Stitch::BLQtr] = Stitch::BRQtr; 0542 rotateMap[Rotate90][Stitch::BRQtr] = Stitch::TRQtr; 0543 rotateMap[Rotate90][Stitch::BTHalf] = Stitch::TBHalf; 0544 rotateMap[Rotate90][Stitch::TBHalf] = Stitch::BTHalf; 0545 rotateMap[Rotate90][Stitch::TL3Qtr] = Stitch::BL3Qtr; 0546 rotateMap[Rotate90][Stitch::TR3Qtr] = Stitch::TL3Qtr; 0547 rotateMap[Rotate90][Stitch::BL3Qtr] = Stitch::BR3Qtr; 0548 rotateMap[Rotate90][Stitch::BR3Qtr] = Stitch::TR3Qtr; 0549 rotateMap[Rotate90][Stitch::TLSmallHalf] = Stitch::BLSmallHalf; 0550 rotateMap[Rotate90][Stitch::TRSmallHalf] = Stitch::TLSmallHalf; 0551 rotateMap[Rotate90][Stitch::BLSmallHalf] = Stitch::BRSmallHalf; 0552 rotateMap[Rotate90][Stitch::BRSmallHalf] = Stitch::TRSmallHalf; 0553 rotateMap[Rotate90][Stitch::TLSmallFull] = Stitch::BLSmallFull; 0554 rotateMap[Rotate90][Stitch::TRSmallFull] = Stitch::TLSmallFull; 0555 rotateMap[Rotate90][Stitch::BLSmallFull] = Stitch::BRSmallFull; 0556 rotateMap[Rotate90][Stitch::BRSmallFull] = Stitch::TRSmallFull; 0557 rotateMap[Rotate90][Stitch::Full] = Stitch::Full; 0558 0559 rotateMap[Rotate180][Stitch::TLQtr] = Stitch::BRQtr; 0560 rotateMap[Rotate180][Stitch::TRQtr] = Stitch::BLQtr; 0561 rotateMap[Rotate180][Stitch::BLQtr] = Stitch::TRQtr; 0562 rotateMap[Rotate180][Stitch::BRQtr] = Stitch::TLQtr; 0563 rotateMap[Rotate180][Stitch::BTHalf] = Stitch::BTHalf; 0564 rotateMap[Rotate180][Stitch::TBHalf] = Stitch::TBHalf; 0565 rotateMap[Rotate180][Stitch::TL3Qtr] = Stitch::BR3Qtr; 0566 rotateMap[Rotate180][Stitch::TR3Qtr] = Stitch::BL3Qtr; 0567 rotateMap[Rotate180][Stitch::BL3Qtr] = Stitch::TR3Qtr; 0568 rotateMap[Rotate180][Stitch::BR3Qtr] = Stitch::TL3Qtr; 0569 rotateMap[Rotate180][Stitch::TLSmallHalf] = Stitch::BRSmallHalf; 0570 rotateMap[Rotate180][Stitch::TRSmallHalf] = Stitch::BLSmallHalf; 0571 rotateMap[Rotate180][Stitch::BLSmallHalf] = Stitch::TRSmallHalf; 0572 rotateMap[Rotate180][Stitch::BRSmallHalf] = Stitch::TLSmallHalf; 0573 rotateMap[Rotate180][Stitch::TLSmallFull] = Stitch::BRSmallFull; 0574 rotateMap[Rotate180][Stitch::TRSmallFull] = Stitch::BLSmallFull; 0575 rotateMap[Rotate180][Stitch::BLSmallFull] = Stitch::TRSmallFull; 0576 rotateMap[Rotate180][Stitch::BRSmallFull] = Stitch::TLSmallFull; 0577 rotateMap[Rotate180][Stitch::Full] = Stitch::Full; 0578 0579 rotateMap[Rotate270][Stitch::TLQtr] = Stitch::TRQtr; 0580 rotateMap[Rotate270][Stitch::TRQtr] = Stitch::BRQtr; 0581 rotateMap[Rotate270][Stitch::BLQtr] = Stitch::TLQtr; 0582 rotateMap[Rotate270][Stitch::BRQtr] = Stitch::BLQtr; 0583 rotateMap[Rotate270][Stitch::BTHalf] = Stitch::TBHalf; 0584 rotateMap[Rotate270][Stitch::TBHalf] = Stitch::BTHalf; 0585 rotateMap[Rotate270][Stitch::TL3Qtr] = Stitch::TR3Qtr; 0586 rotateMap[Rotate270][Stitch::TR3Qtr] = Stitch::BR3Qtr; 0587 rotateMap[Rotate270][Stitch::BL3Qtr] = Stitch::TL3Qtr; 0588 rotateMap[Rotate270][Stitch::BR3Qtr] = Stitch::BL3Qtr; 0589 rotateMap[Rotate270][Stitch::TLSmallHalf] = Stitch::TRSmallHalf; 0590 rotateMap[Rotate270][Stitch::TRSmallHalf] = Stitch::BRSmallHalf; 0591 rotateMap[Rotate270][Stitch::BLSmallHalf] = Stitch::TLSmallHalf; 0592 rotateMap[Rotate270][Stitch::BRSmallHalf] = Stitch::BLSmallHalf; 0593 rotateMap[Rotate270][Stitch::TLSmallFull] = Stitch::TRSmallFull; 0594 rotateMap[Rotate270][Stitch::TRSmallFull] = Stitch::BRSmallFull; 0595 rotateMap[Rotate270][Stitch::BLSmallFull] = Stitch::TLSmallFull; 0596 rotateMap[Rotate270][Stitch::BRSmallFull] = Stitch::BLSmallFull; 0597 rotateMap[Rotate270][Stitch::Full] = Stitch::Full; 0598 } 0599 0600 QListIterator<Stitch *> i(*queue); 0601 0602 while (i.hasNext()) { 0603 Stitch *stitch = i.next(); 0604 stitch->type = rotateMap[rotation][stitch->type]; 0605 } 0606 } 0607 0608 int StitchData::index(int x, int y) const 0609 { 0610 return y * m_width + x; 0611 } 0612 0613 int StitchData::index(const QPoint &cell) const 0614 { 0615 return index(cell.x(), cell.y()); 0616 } 0617 0618 bool StitchData::isValid(int x, int y) const 0619 { 0620 return ((x >= 0) && (x < m_width) && (y >= 0) && (y < m_height)); 0621 } 0622 0623 void StitchData::addStitch(const QPoint &position, Stitch::Type type, int colorIndex) 0624 { 0625 int i = index(position); 0626 StitchQueue *stitchQueue = m_stitches.at(i); 0627 0628 if (stitchQueue == nullptr) { 0629 stitchQueue = new StitchQueue; 0630 m_stitches[i] = stitchQueue; 0631 } 0632 0633 stitchQueue->add(type, colorIndex); 0634 } 0635 0636 Stitch *StitchData::findStitch(const QPoint &cell, Stitch::Type type, int colorIndex) 0637 { 0638 StitchQueue *stitchQueue = stitchQueueAt(cell); 0639 Stitch *found = nullptr; 0640 0641 if (stitchQueue) { 0642 if (Stitch *stitch = stitchQueue->find(type, colorIndex)) { 0643 found = stitch; 0644 } 0645 } 0646 0647 return found; 0648 } 0649 0650 void StitchData::deleteStitch(const QPoint &position, Stitch::Type type, int colorIndex) 0651 { 0652 int i = index(position); 0653 StitchQueue *stitchQueue = m_stitches.at(i); 0654 0655 if (stitchQueue) { 0656 if (stitchQueue->remove(type, colorIndex) == 0) { 0657 m_stitches[i] = nullptr; 0658 delete stitchQueue; 0659 } 0660 } 0661 } 0662 0663 StitchQueue *StitchData::stitchQueueAt(int x, int y) 0664 { 0665 StitchQueue *stitchQueue = nullptr; 0666 0667 if (isValid(x, y)) { 0668 stitchQueue = m_stitches.at(index(x, y)); 0669 } 0670 0671 return stitchQueue; 0672 } 0673 0674 StitchQueue *StitchData::stitchQueueAt(const QPoint &position) 0675 { 0676 return stitchQueueAt(position.x(), position.y()); 0677 } 0678 0679 StitchQueue *StitchData::takeStitchQueueAt(int x, int y) 0680 { 0681 StitchQueue *stitchQueue = stitchQueueAt(x, y); 0682 0683 if (stitchQueue) { 0684 m_stitches[index(x, y)] = nullptr; 0685 } 0686 0687 return stitchQueue; 0688 } 0689 0690 StitchQueue *StitchData::takeStitchQueueAt(const QPoint &position) 0691 { 0692 return takeStitchQueueAt(position.x(), position.y()); 0693 } 0694 0695 StitchQueue *StitchData::replaceStitchQueueAt(int x, int y, StitchQueue *stitchQueue) 0696 { 0697 StitchQueue *originalQueue = takeStitchQueueAt(x, y); 0698 0699 if (isValid(x, y)) { 0700 m_stitches[index(x, y)] = stitchQueue; 0701 } 0702 0703 return originalQueue; 0704 } 0705 0706 StitchQueue *StitchData::replaceStitchQueueAt(const QPoint &position, StitchQueue *stitchQueue) 0707 { 0708 return replaceStitchQueueAt(position.x(), position.y(), stitchQueue); 0709 } 0710 0711 void StitchData::addBackstitch(const QPoint &start, const QPoint &end, int colorIndex) 0712 { 0713 m_backstitches.append(new Backstitch(start, end, colorIndex)); 0714 } 0715 0716 void StitchData::addBackstitch(Backstitch *backstitch) 0717 { 0718 m_backstitches.append(backstitch); 0719 } 0720 0721 Backstitch *StitchData::findBackstitch(const QPoint &start, const QPoint &end, int colorIndex) 0722 { 0723 Backstitch *found = nullptr; 0724 0725 foreach (Backstitch *backstitch, m_backstitches) { 0726 if (backstitch->contains(start) && backstitch->contains(end) && ((colorIndex == -1) || backstitch->colorIndex == colorIndex)) { 0727 found = backstitch; 0728 break; 0729 } 0730 } 0731 0732 return found; 0733 } 0734 0735 Backstitch *StitchData::takeBackstitch(const QPoint &start, const QPoint &end, int colorIndex) 0736 { 0737 Backstitch *removed = findBackstitch(start, end, colorIndex); 0738 m_backstitches.removeOne(removed); 0739 0740 return removed; 0741 } 0742 0743 Backstitch *StitchData::takeBackstitch(Backstitch *backstitch) 0744 { 0745 Backstitch *removed = nullptr; 0746 0747 if (m_backstitches.removeOne(backstitch)) { 0748 removed = backstitch; 0749 } 0750 0751 return removed; 0752 } 0753 0754 void StitchData::addFrenchKnot(const QPoint &position, int colorIndex) 0755 { 0756 m_knots.append(new Knot(position, colorIndex)); 0757 } 0758 0759 void StitchData::addFrenchKnot(Knot *knot) 0760 { 0761 m_knots.append(knot); 0762 } 0763 0764 Knot *StitchData::findKnot(const QPoint &position, int colorIndex) 0765 { 0766 Knot *found = nullptr; 0767 0768 foreach (Knot *knot, m_knots) { 0769 if ((knot->position == position) && ((colorIndex == -1) || (knot->colorIndex == colorIndex))) { 0770 found = knot; 0771 break; 0772 } 0773 } 0774 0775 return found; 0776 } 0777 0778 Knot *StitchData::takeFrenchKnot(const QPoint &position, int colorIndex) 0779 { 0780 Knot *removed = findKnot(position, colorIndex); 0781 0782 if (removed) { 0783 m_knots.removeOne(removed); 0784 } 0785 0786 return removed; 0787 } 0788 0789 Knot *StitchData::takeFrenchKnot(Knot *knot) 0790 { 0791 Knot *removed = nullptr; 0792 0793 if (m_knots.removeOne(knot)) { 0794 removed = knot; 0795 } 0796 0797 return removed; 0798 } 0799 0800 QList<Backstitch *> &StitchData::backstitches() 0801 { 0802 return m_backstitches; 0803 } 0804 0805 QList<Knot *> &StitchData::knots() 0806 { 0807 return m_knots; 0808 } 0809 0810 QListIterator<Backstitch *> StitchData::backstitchIterator() 0811 { 0812 return QListIterator<Backstitch *>(m_backstitches); 0813 } 0814 0815 QMutableListIterator<Backstitch *> StitchData::mutableBackstitchIterator() 0816 { 0817 return QMutableListIterator<Backstitch *>(m_backstitches); 0818 } 0819 0820 QListIterator<Knot *> StitchData::knotIterator() 0821 { 0822 return QListIterator<Knot *>(m_knots); 0823 } 0824 0825 QMutableListIterator<Knot *> StitchData::mutableKnotIterator() 0826 { 0827 return QMutableListIterator<Knot *>(m_knots); 0828 } 0829 0830 QMap<int, FlossUsage> StitchData::flossUsage() 0831 { 0832 QMap<int, FlossUsage> usage; 0833 static QMap<Stitch::Type, double> lengths; 0834 0835 if (!lengths.count()) { 0836 lengths.insert(Stitch::Delete, 0.0); 0837 lengths.insert(Stitch::TLQtr, 0.707107 + 0.5); 0838 lengths.insert(Stitch::TRQtr, 0.707107 + 0.5); 0839 lengths.insert(Stitch::BLQtr, 0.707107 + 0.5); 0840 lengths.insert(Stitch::BTHalf, 1.414213 + 1.0); 0841 lengths.insert(Stitch::TL3Qtr, 1.414213 + 0.707107 + 1.0 + 0.5); 0842 lengths.insert(Stitch::BRQtr, 0.707107 + 0.5); 0843 lengths.insert(Stitch::TBHalf, 1.414213 + 1.0); 0844 lengths.insert(Stitch::TR3Qtr, 1.414213 + 0.707107 + 1.0 + 0.5); 0845 lengths.insert(Stitch::BL3Qtr, 1.414213 + 0.707107 + 1.0 + 0.5); 0846 lengths.insert(Stitch::BR3Qtr, 1.414213 + 0.707107 + 1.0 + 0.5); 0847 lengths.insert(Stitch::Full, 1.414213 + 1.414213 + 1.0 + 1.0); 0848 lengths.insert(Stitch::TLSmallHalf, 0.707107 + 0.5); 0849 lengths.insert(Stitch::TRSmallHalf, 0.707107 + 0.5); 0850 lengths.insert(Stitch::BLSmallHalf, 0.707107 + 0.5); 0851 lengths.insert(Stitch::BRSmallHalf, 0.707107 + 0.5); 0852 lengths.insert(Stitch::TLSmallFull, 0.707107 + 0.5 + 0.707107 + 0.5); 0853 lengths.insert(Stitch::TRSmallFull, 0.707107 + 0.5 + 0.707107 + 0.5); 0854 lengths.insert(Stitch::BLSmallFull, 0.707107 + 0.5 + 0.707107 + 0.5); 0855 lengths.insert(Stitch::BRSmallFull, 0.707107 + 0.5 + 0.707107 + 0.5); 0856 lengths.insert(Stitch::FrenchKnot, 2.0); 0857 } 0858 0859 QVectorIterator<StitchQueue *> stitchesIterator(m_stitches); 0860 0861 while (stitchesIterator.hasNext()) { 0862 StitchQueue *stitchQueue = stitchesIterator.next(); 0863 0864 if (stitchQueue) { 0865 QListIterator<Stitch *> stitchIterator(*stitchQueue); 0866 0867 while (stitchIterator.hasNext()) { 0868 Stitch *stitch = stitchIterator.next(); 0869 usage[stitch->colorIndex].stitchCounts[stitch->type]++; 0870 usage[stitch->colorIndex].stitchLengths[stitch->type] += lengths[stitch->type]; 0871 } 0872 } 0873 } 0874 0875 QListIterator<Backstitch *> backstitchIterator(m_backstitches); 0876 0877 while (backstitchIterator.hasNext()) { 0878 Backstitch *backstitch = backstitchIterator.next(); 0879 usage[backstitch->colorIndex].backstitchCount++; 0880 usage[backstitch->colorIndex].backstitchLength += QPoint(backstitch->start - backstitch->end).manhattanLength(); 0881 } 0882 0883 QListIterator<Knot *> knotIterator(m_knots); 0884 0885 while (knotIterator.hasNext()) { 0886 Knot *knot = knotIterator.next(); 0887 usage[knot->colorIndex].stitchCounts[Stitch::FrenchKnot]++; 0888 usage[knot->colorIndex].stitchLengths[Stitch::FrenchKnot] += lengths[Stitch::FrenchKnot]; 0889 } 0890 0891 return usage; 0892 } 0893 0894 QDataStream &operator<<(QDataStream &stream, const StitchData &stitchData) 0895 { 0896 stream << qint32(stitchData.version); 0897 stream << qint32(stitchData.m_width); 0898 stream << qint32(stitchData.m_height); 0899 0900 QVectorIterator<StitchQueue *> stitchesIterator(stitchData.m_stitches); 0901 int queues = 0; 0902 0903 while (stitchesIterator.hasNext()) { 0904 if (stitchesIterator.next()) { 0905 ++queues; 0906 } 0907 } 0908 0909 stream << qint32(queues); 0910 0911 for (int row = 0; row < stitchData.m_height; ++row) { 0912 for (int column = 0; column < stitchData.m_width; ++column) { 0913 if (StitchQueue *stitchQueue = stitchData.m_stitches[stitchData.index(column, row)]) { 0914 stream << qint32(column); 0915 stream << qint32(row); 0916 stream << *stitchQueue; 0917 } 0918 } 0919 } 0920 0921 QListIterator<Backstitch *> backstitchIterator(stitchData.m_backstitches); 0922 stream << qint32(stitchData.m_backstitches.count()); 0923 0924 while (backstitchIterator.hasNext()) { 0925 stream << *(backstitchIterator.next()); 0926 0927 if (stream.status() != QDataStream::Ok) { 0928 throw FailedWriteFile(stream.status()); 0929 } 0930 } 0931 0932 QListIterator<Knot *> knotIterator(stitchData.m_knots); 0933 stream << qint32(stitchData.m_knots.count()); 0934 0935 while (knotIterator.hasNext()) { 0936 stream << *(knotIterator.next()); 0937 0938 if (stream.status() != QDataStream::Ok) { 0939 throw FailedWriteFile(stream.status()); 0940 } 0941 } 0942 0943 if (stream.status() != QDataStream::Ok) { 0944 throw FailedWriteFile(stream.status()); 0945 } 0946 0947 return stream; 0948 } 0949 0950 QDataStream &operator>>(QDataStream &stream, StitchData &stitchData) 0951 { 0952 qint32 version; 0953 qint32 width; 0954 qint32 height; 0955 qint32 layers; 0956 qint32 columns; 0957 qint32 rows; 0958 qint32 count; 0959 QHash<int, QHash<int, StitchQueue *>> stitches; 0960 0961 stitchData.clear(); 0962 0963 stream >> version; 0964 0965 switch (version) { 0966 case 103: 0967 stream >> width; 0968 stream >> height; 0969 stitchData.resize(width, height); 0970 stream >> count; 0971 0972 while (count--) { 0973 stream >> columns; 0974 stream >> rows; 0975 StitchQueue *stitchQueue = new StitchQueue; 0976 stitchData.replaceStitchQueueAt(columns, rows, stitchQueue); 0977 stream >> *stitchQueue; 0978 } 0979 0980 stream >> count; 0981 0982 while (count--) { 0983 Backstitch *backstitch = new Backstitch; 0984 stream >> *(backstitch); 0985 stitchData.addBackstitch(backstitch); 0986 } 0987 0988 stream >> count; 0989 0990 while (count--) { 0991 Knot *knot = new Knot; 0992 stream >> *knot; 0993 stitchData.addFrenchKnot(knot); 0994 } 0995 0996 break; 0997 0998 case 102: 0999 stream >> width; 1000 stream >> height; 1001 stitchData.resize(width, height); 1002 1003 stream >> columns; 1004 1005 while (columns--) { 1006 stream >> rows; 1007 1008 while (rows--) { 1009 qint32 column; 1010 qint32 row; 1011 1012 stream >> column; 1013 stream >> row; 1014 1015 StitchQueue *stitchQueue = new StitchQueue; 1016 stitches[column][row] = stitchQueue; 1017 stream >> *stitchQueue; 1018 } 1019 } 1020 1021 for (int y = 0; y < height; ++y) { 1022 for (int x = 0; x < width; ++x) { 1023 if (stitches[x][y]) { 1024 stitchData.replaceStitchQueueAt(x, y, stitches[x][y]); 1025 } 1026 } 1027 } 1028 1029 stream >> count; 1030 1031 while (count--) { 1032 Backstitch *backstitch = new Backstitch; 1033 stream >> *(backstitch); 1034 stitchData.addBackstitch(backstitch); 1035 } 1036 1037 stream >> count; 1038 1039 while (count--) { 1040 Knot *knot = new Knot; 1041 stream >> *knot; 1042 stitchData.addFrenchKnot(knot); 1043 } 1044 1045 break; 1046 1047 case 101: 1048 stream >> width; 1049 stream >> height; 1050 stitchData.resize(width, height); 1051 1052 stream >> columns; 1053 1054 while (columns--) { 1055 stream >> rows; 1056 1057 while (rows--) { 1058 qint32 column; 1059 qint32 row; 1060 1061 stream >> column; 1062 stream >> row; 1063 1064 StitchQueue *stitchQueue = new StitchQueue; 1065 stitches[column][row] = stitchQueue; 1066 stream >> *stitchQueue; 1067 } 1068 } 1069 1070 for (int y = 0; y < height; ++y) { 1071 for (int x = 0; x < width; ++x) { 1072 if (stitches[x][y]) { 1073 stitchData.replaceStitchQueueAt(x, y, stitches[x][y]); 1074 } 1075 } 1076 } 1077 1078 break; 1079 1080 case 100: 1081 stream >> width; 1082 stream >> height; 1083 stitchData.m_width = width; 1084 stitchData.m_height = height; 1085 1086 stream >> layers; 1087 1088 while (layers--) { 1089 stream >> columns; 1090 1091 while (columns--) { 1092 stream >> rows; 1093 1094 while (rows--) { 1095 qint32 layer; 1096 qint32 column; 1097 qint32 row; 1098 1099 stream >> layer; 1100 stream >> column; 1101 stream >> row; 1102 1103 StitchQueue *stitchQueue = new StitchQueue; 1104 stitches[column][row] = stitchQueue; 1105 stream >> *stitchQueue; 1106 } 1107 } 1108 } 1109 1110 for (int y = 0; y < height; ++y) { 1111 for (int x = 0; x < width; ++x) { 1112 if (stitches[x][y]) { 1113 stitchData.replaceStitchQueueAt(x, y, stitches[x][y]); 1114 } 1115 } 1116 } 1117 1118 break; 1119 1120 default: 1121 throw InvalidFileVersion(QString(i18n("Stitch data version %1", version))); 1122 break; 1123 } 1124 1125 if (stream.status() != QDataStream::Ok) { 1126 throw FailedReadFile(QString(i18n("Failed reading stitch data"))); 1127 } 1128 1129 return stream; 1130 }