1
2
3 #include "tools/levelselection.h"
4
5 // TnzTools includes
6 #include "tools/tool.h"
7 #include "tools/toolhandle.h"
8
9 // TnzCore includes
10 #include "tfilepath.h"
11 #include "tvectorimage.h"
12 #include "tstroke.h"
13 #include "tregion.h"
14
15 // Boost includes
16 #include <boost/iterator/counting_iterator.hpp>
17 #include <boost/bind.hpp>
18
19 //*******************************************************************************
20 // Local namespace stuff
21 //*******************************************************************************
22
23 namespace {
24
tool()25 TTool *tool() { return TTool::getApplication()->getCurrentTool()->getTool(); }
26
27 //========================================================================
28
29 struct StrokeData {
30 UCHAR m_hasColor, m_hasRegion;
31 };
32
getBoundaries(TVectorImage & vi,std::vector<int> & strokes)33 void getBoundaries(TVectorImage &vi, std::vector<int> &strokes) {
34 enum { FORWARD = 0x1, BACKWARD = 0x2, INTERNAL = FORWARD | BACKWARD };
35
36 struct locals {
37 static inline bool isBoundary(const std::vector<StrokeData> &sData,
38 UINT s) {
39 return (sData[s].m_hasColor != INTERNAL);
40 }
41
42 static void markEdges(const TRegion ®ion, std::vector<StrokeData> &sData,
43 bool parentRegionHasColor) {
44 bool regionHasColor = (region.getStyle() != 0);
45
46 // Traverse region edges, marking associated strokes accordingly
47 UINT e, eCount = region.getEdgeCount();
48 for (e = 0; e != eCount; ++e) {
49 const TEdge &ed = *region.getEdge(e);
50 assert(ed.m_s);
51
52 int strokeIdx = ed.m_index;
53 if (strokeIdx >= 0) // Could be <0 in case the corresponding
54 { // stroke is a region 'closure' (autoclose)
55 assert(0 <= strokeIdx && strokeIdx < sData.size());
56
57 StrokeData &sd = sData[strokeIdx];
58
59 UCHAR side = (ed.m_w1 > ed.m_w0) ? FORWARD : BACKWARD;
60
61 sd.m_hasRegion |= side;
62 if (regionHasColor) sd.m_hasColor |= side;
63 }
64 }
65
66 if (parentRegionHasColor) {
67 // Mark non-region edge sides with color
68 for (e = 0; e != eCount; ++e) {
69 const TEdge &ed = *region.getEdge(e);
70 assert(ed.m_s);
71
72 int strokeIdx = ed.m_index;
73 if (strokeIdx >= 0) {
74 StrokeData &sd = sData[strokeIdx];
75 sd.m_hasColor |= (INTERNAL & ~sd.m_hasRegion);
76 }
77 }
78 }
79
80 // Mark recursively on sub-regions
81 UINT sr, srCount = region.getSubregionCount();
82 for (sr = 0; sr != srCount; ++sr)
83 markEdges(*region.getSubregion(sr), sData, regionHasColor);
84 }
85 }; // locals
86
87 std::vector<StrokeData> sData(vi.getStrokeCount());
88
89 // Traverse regions, mark each stroke edge with the side a COLORED region is
90 // on
91 UINT r, rCount = vi.getRegionCount();
92 for (r = 0; r != rCount; ++r)
93 locals::markEdges(*vi.getRegion(r), sData, false);
94
95 // Strokes not appearing as region edges must be checked for region inclusion
96 // separately
97 UINT s, sCount = vi.getStrokeCount();
98 for (s = 0; s != sCount; ++s) {
99 if (!sData[s].m_hasRegion) {
100 TRegion *parentRegion = vi.getRegion(vi.getStroke(s)->getPoint(0.5));
101
102 if (parentRegion && parentRegion->getStyle())
103 sData[s].m_hasColor = INTERNAL;
104 }
105 }
106
107 // Output all not internal regions
108 std::copy_if(boost::make_counting_iterator(0u),
109 boost::make_counting_iterator(vi.getStrokeCount()),
110 std::back_inserter(strokes),
111 boost::bind(locals::isBoundary, sData, _1));
112 }
113
114 } // namespace
115
116 //*******************************************************************************
117 // VectorLevelSelection implementation
118 //*******************************************************************************
119
LevelSelection()120 LevelSelection::LevelSelection() : m_framesMode(FRAMES_NONE), m_filter(EMPTY) {}
121
122 //---------------------------------------------------------------------
123
isEmpty() const124 bool LevelSelection::isEmpty() const {
125 return (m_framesMode == FRAMES_NONE || m_filter == EMPTY);
126 }
127
128 //---------------------------------------------------------------------
129
selectNone()130 void LevelSelection::selectNone() {
131 m_framesMode = FRAMES_NONE;
132 m_filter = EMPTY;
133
134 m_styles.clear();
135 }
136
137 //*******************************************************************************
138 // Related standalone functions
139 //*******************************************************************************
140
getBoundaryStrokes(TVectorImage & vi)141 std::vector<int> getBoundaryStrokes(TVectorImage &vi) {
142 std::vector<int> result;
143 getBoundaries(vi, result);
144
145 return result;
146 }
147
148 //------------------------------------------------------------------------
149
getSelectedStrokes(TVectorImage & vi,const LevelSelection & levelSelection)150 std::vector<int> getSelectedStrokes(TVectorImage &vi,
151 const LevelSelection &levelSelection) {
152 struct locals {
153 static void selectStyles(const TVectorImage &vi,
154 const std::set<int> &styles,
155 std::vector<int> &strokes) {
156 UINT s, sCount = vi.getStrokeCount();
157 for (s = 0; s != sCount; ++s) {
158 if (styles.count(vi.getStroke(s)->getStyle())) strokes.push_back(s);
159 }
160 }
161 }; // locals
162
163 std::vector<int> strokes;
164
165 switch (levelSelection.filter()) {
166 case LevelSelection::EMPTY:
167 break;
168 case LevelSelection::WHOLE:
169 strokes.assign(boost::make_counting_iterator(0u),
170 boost::make_counting_iterator(vi.getStrokeCount()));
171 break;
172 case LevelSelection::SELECTED_STYLES:
173 locals::selectStyles(vi, levelSelection.styles(), strokes);
174 break;
175 case LevelSelection::BOUNDARY_STROKES:
176 getBoundaries(vi, strokes);
177 break;
178 }
179
180 return strokes;
181 }
182