File indexing completed on 2024-06-09 04:21:55
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_fill_interval_map.h" 0008 #include "kis_fill_interval_map_p.h" 0009 0010 #include "kis_fill_sanity_checks.h" 0011 0012 0013 KisFillIntervalMap::KisFillIntervalMap() 0014 : m_d(new Private) 0015 { 0016 } 0017 0018 KisFillIntervalMap::~KisFillIntervalMap() 0019 { 0020 } 0021 0022 void KisFillIntervalMap::insertInterval(const KisFillInterval &interval) 0023 { 0024 Private::GlobalMap::iterator rowMap = m_d->map.find(interval.row); 0025 if (rowMap == m_d->map.end()) { 0026 rowMap = m_d->map.insert(interval.row, Private::LineIntervalMap()); 0027 } 0028 0029 rowMap->insert(interval.start, interval); 0030 } 0031 0032 void KisFillIntervalMap::cropInterval(KisFillInterval *interval) 0033 { 0034 Private::IteratorRange range; 0035 range = m_d->findFirstIntersectingInterval(*interval); 0036 0037 Private::LineIntervalMap::iterator it = range.beginIt; 0038 0039 while (interval->isValid() && it != range.endIt) { 0040 bool needsIncrement = true; 0041 0042 if (it->start <= interval->start && it->end >= interval->start) { 0043 int savedIntervalStart = interval->start; 0044 interval->start = it->end + 1; 0045 0046 /** 0047 * It might happen that we need to split a backward 0048 * interval into two pieces 0049 */ 0050 if (it->end > interval->end) { 0051 KisFillInterval newInterval(interval->end + 1, it->end, it->row); 0052 range.rowMapIt->insert(newInterval.start, newInterval); 0053 } 0054 0055 it->end = savedIntervalStart - 1; 0056 0057 /** 0058 * It might also happen that the backward interval is 0059 * fully eaten by the forward interval. This is possible 0060 * only in case the BW-interval was generated by the 0061 * strictly adjacent FW-interval, that is (it->start == 0062 * interval->start) 0063 */ 0064 if (!it->isValid()) { 0065 it = range.rowMapIt->erase(it); 0066 needsIncrement = false; 0067 } 0068 } else if (it->start <= interval->end && it->end >= interval->end) { 0069 int savedIntervalEnd = interval->end; 0070 interval->end = it->start - 1; 0071 it->start = savedIntervalEnd + 1; 0072 0073 /** 0074 * The BW-interval is eaten by the FW-interval. See a 0075 * comment above 0076 */ 0077 if (!it->isValid()) { 0078 it = range.rowMapIt->erase(it); 0079 needsIncrement = false; 0080 } 0081 } else if (it->start > interval->end) { 0082 break; 0083 } 0084 0085 #ifdef ENABLE_FILL_SANITY_CHECKS 0086 else if (it->start > interval->start && it->end < interval->end) { 0087 SANITY_ASSERT_MSG(0, "FATAL: The backward interval cannot fully reside inside the forward interval"); 0088 interval->invalidate(); 0089 it->invalidate(); 0090 it = range.rowMapIt->erase(it); 0091 needsIncrement = false; 0092 } 0093 0094 // The code above should have removed the invalidated backward interval, 0095 // just verify that 0096 KIS_SAFE_ASSERT_RECOVER((it == range.endIt || it->isValid()) && 0097 "FATAL: The backward interval cannot become " 0098 "invalid during the crop action") { 0099 it = range.rowMapIt->erase(it); 0100 needsIncrement = false; 0101 } 0102 #endif /* ENABLE_FILL_SANITY_CHECKS */ 0103 0104 if (needsIncrement) { 0105 it++; 0106 } 0107 } 0108 } 0109 0110 KisFillIntervalMap::Private::IteratorRange 0111 KisFillIntervalMap::Private::findFirstIntersectingInterval(const KisFillInterval &interval) 0112 { 0113 Private::GlobalMap::iterator rowMap = map.find(interval.row); 0114 if (rowMap == map.end()) { 0115 return IteratorRange(); 0116 } 0117 0118 LineIntervalMap::iterator it = rowMap->begin(); 0119 LineIntervalMap::iterator end = rowMap->end(); 0120 0121 while(it != end) { 0122 if (it->end < interval.start) { 0123 ++it; 0124 } else if (it->start > interval.end) { 0125 it = end; 0126 break; 0127 } else { 0128 break; 0129 } 0130 } 0131 0132 return IteratorRange(it, end, rowMap); 0133 } 0134 0135 QStack<KisFillInterval> KisFillIntervalMap::fetchAllIntervals(int rowCorrection) const 0136 { 0137 QStack<KisFillInterval> intervals; 0138 0139 Private::GlobalMap::const_iterator rowMapIt = m_d->map.constBegin(); 0140 Private::GlobalMap::const_iterator rowMapEndIt = m_d->map.constEnd(); 0141 0142 while (rowMapIt != rowMapEndIt) { 0143 Private::LineIntervalMap::const_iterator it = rowMapIt->constBegin(); 0144 Private::LineIntervalMap::const_iterator end = rowMapIt->constEnd(); 0145 0146 while(it != end) { 0147 KisFillInterval interval = *it; 0148 interval.row += rowCorrection; 0149 intervals.append(interval); 0150 ++it; 0151 } 0152 0153 ++rowMapIt; 0154 } 0155 0156 return intervals; 0157 } 0158 0159 void KisFillIntervalMap::clear() 0160 { 0161 m_d->map.clear(); 0162 }