File indexing completed on 2024-04-21 04:32:12
0001 /* 0002 * Copyright (C) 2012-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 "Pattern.h" 0012 0013 #include <KLocalizedString> 0014 0015 #include "Exceptions.h" 0016 0017 Pattern::Pattern(Document *document) 0018 : m_document(document) 0019 { 0020 } 0021 0022 void Pattern::clear() 0023 { 0024 m_documentPalette = DocumentPalette(); 0025 m_stitchData.clear(); 0026 } 0027 0028 Document *Pattern::document() 0029 { 0030 return m_document; 0031 } 0032 0033 DocumentPalette &Pattern::palette() 0034 { 0035 return m_documentPalette; 0036 } 0037 0038 StitchData &Pattern::stitches() 0039 { 0040 return m_stitchData; 0041 } 0042 0043 void Pattern::constructPalette(Pattern *pattern) 0044 { 0045 pattern->palette().setSchemeName(m_documentPalette.schemeName()); 0046 QMap<int, FlossUsage> usage = pattern->stitches().flossUsage(); 0047 QMapIterator<int, FlossUsage> flossIterator(usage); 0048 0049 while (flossIterator.hasNext()) { 0050 flossIterator.next(); 0051 int index = flossIterator.key(); 0052 double length = flossIterator.value().totalLength(); 0053 0054 if (length > 0) { 0055 pattern->palette().add(index, new DocumentFloss(palette().flosses().value(index))); 0056 } 0057 } 0058 } 0059 0060 Pattern *Pattern::cut(const QRect &area, int colorMask, const QList<Stitch::Type> &stitchMask, bool excludeBackstitches, bool excludeKnots) 0061 { 0062 Pattern *pattern = new Pattern; 0063 pattern->stitches().resize(area.width(), area.height()); 0064 0065 for (int row = area.top(); row <= area.bottom(); row++) { 0066 for (int column = area.left(); column <= area.right(); ++column) { 0067 QPoint src(column, row); 0068 QPoint dst(src - area.topLeft()); 0069 StitchQueue *srcQ = stitches().takeStitchQueueAt(src); 0070 0071 if (srcQ) { 0072 StitchQueue *dstQ = new StitchQueue; 0073 // iterate the queue adding anything that matches the stitch mask or color mask to a new queue 0074 int count = srcQ->count(); 0075 0076 while (count--) { 0077 Stitch *stitch = srcQ->dequeue(); 0078 0079 if (((colorMask == -1) || (colorMask == stitch->colorIndex)) && (stitchMask.contains(stitch->type))) { 0080 dstQ->enqueue(stitch); 0081 } else { 0082 srcQ->enqueue(stitch); 0083 } 0084 } 0085 0086 if (srcQ->count()) { 0087 stitches().replaceStitchQueueAt(src, srcQ); 0088 } else { 0089 delete srcQ; 0090 } 0091 0092 if (dstQ->count()) { 0093 pattern->stitches().replaceStitchQueueAt(dst, dstQ); 0094 } else { 0095 delete dstQ; 0096 } 0097 } 0098 } 0099 } 0100 0101 QRect snapArea(area.left() * 2, area.top() * 2, area.width() * 2, area.height() * 2); 0102 0103 if (!excludeBackstitches) { 0104 QMutableListIterator<Backstitch *> mutableListIterator = stitches().mutableBackstitchIterator(); 0105 0106 while (mutableListIterator.hasNext()) { 0107 Backstitch *backstitch = mutableListIterator.next(); 0108 0109 if (((colorMask == -1) || (colorMask == backstitch->colorIndex)) && (snapArea.contains(backstitch->start) && snapArea.contains(backstitch->end))) { 0110 mutableListIterator.remove(); 0111 backstitch->start -= snapArea.topLeft(); 0112 backstitch->end -= snapArea.topLeft(); 0113 pattern->stitches().addBackstitch(backstitch); 0114 } 0115 } 0116 } 0117 0118 if (!excludeKnots) { 0119 QMutableListIterator<Knot *> mutableListIterator = stitches().mutableKnotIterator(); 0120 0121 while (mutableListIterator.hasNext()) { 0122 Knot *knot = mutableListIterator.next(); 0123 0124 if (((colorMask == -1) || (colorMask == knot->colorIndex)) && (snapArea.contains(knot->position))) { 0125 mutableListIterator.remove(); 0126 knot->position -= snapArea.topLeft(); 0127 pattern->stitches().addFrenchKnot(knot); 0128 } 0129 } 0130 } 0131 0132 constructPalette(pattern); 0133 0134 return pattern; 0135 } 0136 0137 Pattern *Pattern::copy(const QRect &area, int colorMask, const QList<Stitch::Type> &stitchMask, bool excludeBackstitches, bool excludeKnots) 0138 { 0139 Pattern *pattern = new Pattern; 0140 pattern->stitches().resize(area.width(), area.height()); 0141 0142 for (int row = area.top(); row <= area.bottom(); row++) { 0143 for (int column = area.left(); column <= area.right(); ++column) { 0144 QPoint src(column, row); 0145 QPoint dst(src - area.topLeft()); 0146 StitchQueue *srcQ = stitches().stitchQueueAt(src); 0147 0148 if (srcQ) { 0149 StitchQueue *dstQ = new StitchQueue; 0150 QListIterator<Stitch *> stitchIterator(*srcQ); 0151 0152 while (stitchIterator.hasNext()) { 0153 Stitch *stitch = stitchIterator.next(); 0154 0155 if (((colorMask == -1) || (colorMask == stitch->colorIndex)) && (stitchMask.contains(stitch->type))) { 0156 dstQ->add(stitch->type, stitch->colorIndex); 0157 } 0158 } 0159 0160 if (dstQ->count()) { 0161 pattern->stitches().replaceStitchQueueAt(dst, dstQ); 0162 } else { 0163 delete dstQ; 0164 } 0165 } 0166 } 0167 } 0168 0169 QRect snapArea(area.left() * 2, area.top() * 2, area.width() * 2, area.height() * 2); 0170 0171 if (!excludeBackstitches) { 0172 QListIterator<Backstitch *> backstitchIterator = stitches().backstitchIterator(); 0173 0174 while (backstitchIterator.hasNext()) { 0175 Backstitch *backstitch = backstitchIterator.next(); 0176 0177 if (((colorMask == -1) || (colorMask == backstitch->colorIndex)) && (snapArea.contains(backstitch->start) && snapArea.contains(backstitch->end))) { 0178 pattern->stitches().addBackstitch(backstitch->start - snapArea.topLeft(), backstitch->end - snapArea.topLeft(), backstitch->colorIndex); 0179 } 0180 } 0181 } 0182 0183 if (!excludeKnots) { 0184 QListIterator<Knot *> knotIterator = stitches().knotIterator(); 0185 0186 while (knotIterator.hasNext()) { 0187 Knot *knot = knotIterator.next(); 0188 0189 if (((colorMask == -1) || (colorMask == knot->colorIndex)) && (snapArea.contains(knot->position))) { 0190 pattern->stitches().addFrenchKnot(knot->position - snapArea.topLeft(), knot->colorIndex); 0191 } 0192 } 0193 } 0194 0195 constructPalette(pattern); 0196 0197 return pattern; 0198 } 0199 0200 void Pattern::paste(Pattern *pattern, const QPoint &cell, bool merge) 0201 { 0202 pattern->palette().setSchemeName(palette().schemeName()); 0203 0204 for (int row = 0; row < pattern->stitches().height(); ++row) { 0205 for (int col = 0; col < pattern->stitches().width(); ++col) { 0206 QPoint src(col, row); 0207 QPoint dst(cell + src); 0208 0209 StitchQueue *srcQ = pattern->stitches().stitchQueueAt(src); 0210 StitchQueue *dstQ = stitches().takeStitchQueueAt(dst); 0211 0212 if (!merge) { 0213 delete dstQ; 0214 dstQ = nullptr; 0215 } 0216 0217 if (srcQ) { 0218 if (dstQ == nullptr) { 0219 dstQ = new StitchQueue(); 0220 } 0221 0222 QListIterator<Stitch *> stitchIterator(*srcQ); 0223 0224 while (stitchIterator.hasNext()) { 0225 Stitch *stitch = stitchIterator.next(); 0226 int colorIndex = palette().add(pattern->palette().flosses().value(stitch->colorIndex)->flossColor()); 0227 dstQ->add(stitch->type, colorIndex); 0228 } 0229 } 0230 0231 stitches().replaceStitchQueueAt(dst, dstQ); 0232 } 0233 } 0234 0235 QRect snapArea(0, 0, stitches().width() * 2, stitches().height() * 2); 0236 QPoint targetOffset(cell * 2); 0237 0238 QListIterator<Backstitch *> backstitchIterator = pattern->stitches().backstitchIterator(); 0239 0240 while (backstitchIterator.hasNext()) { 0241 Backstitch *backstitch = backstitchIterator.next(); 0242 int colorIndex = palette().add(pattern->palette().flosses().value(backstitch->colorIndex)->flossColor()); 0243 0244 if (snapArea.contains(backstitch->start + targetOffset) && snapArea.contains(backstitch->end + targetOffset)) { 0245 stitches().addBackstitch(backstitch->start + targetOffset, backstitch->end + targetOffset, colorIndex); 0246 } 0247 } 0248 0249 QListIterator<Knot *> knotIterator = pattern->stitches().knotIterator(); 0250 0251 while (knotIterator.hasNext()) { 0252 Knot *knot = knotIterator.next(); 0253 int colorIndex = palette().add(pattern->palette().flosses().value(knot->colorIndex)->flossColor()); 0254 0255 if (snapArea.contains(knot->position + targetOffset)) { 0256 stitches().addFrenchKnot(knot->position + targetOffset, colorIndex); 0257 } 0258 } 0259 } 0260 0261 QDataStream &operator<<(QDataStream &stream, const Pattern &pattern) 0262 { 0263 stream << qint32(pattern.version); 0264 0265 stream << pattern.m_documentPalette; 0266 stream << pattern.m_stitchData; 0267 0268 return stream; 0269 } 0270 0271 QDataStream &operator>>(QDataStream &stream, Pattern &pattern) 0272 { 0273 qint32 version; 0274 0275 stream >> version; 0276 0277 switch (version) { 0278 case 100: 0279 stream >> pattern.m_documentPalette; 0280 stream >> pattern.m_stitchData; 0281 break; 0282 0283 default: 0284 throw InvalidFileVersion(QString(i18n("Pattern version %1", version))); 0285 break; 0286 } 0287 0288 return stream; 0289 }