1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "SmartKeyEdgeSet.h"
18 
19 #include <QStack>
20 
21 namespace VectorAnimationComplex
22 {
23 
24 /////////////////////////////////////////////////////////////////////
25 //            Single Connected Component computation               //
26 
SmartConnectedKeyEdgeSet(const KeyEdgeSet & edgeSet)27 SmartConnectedKeyEdgeSet::SmartConnectedKeyEdgeSet(const KeyEdgeSet & edgeSet):
28     edgeSet_(edgeSet),
29     path_(edgeSet),
30     loop_(edgeSet),
31     hole_(edgeSet)
32 {
33 }
34 
type() const35 SmartConnectedKeyEdgeSet::EdgeSetType SmartConnectedKeyEdgeSet::type() const
36 {
37     KeyEdge * singleEdge = edge();
38 
39     if(edgeSet_.size() == 0)
40     {
41         return EMPTY;
42     }
43     else if(singleEdge)
44     {
45         if(singleEdge->isClosed())
46         {
47             return CLOSED_EDGE;
48         }
49         else if(singleEdge->isSplittedLoop())
50         {
51             return OPEN_EDGE_LOOP;
52         }
53         else
54         {
55             return OPEN_EDGE_PATH;
56         }
57     }
58     else if(path_.isValid())
59     {
60         return SIMPLE_PATH;
61     }
62     else if(loop_.isValid())
63     {
64         return SIMPLE_LOOP;
65     }
66     else if(hole_.isValid())
67     {
68         return PATH_LOOP_DECOMPOSITION;
69     }
70     else
71     {
72         return GENERAL;
73     }
74 }
75 
edge() const76 KeyEdge * SmartConnectedKeyEdgeSet::edge() const
77 {
78     if(edgeSet_.size() == 1)
79     {
80         return *edgeSet_.begin();
81     }
82     else
83     {
84         return 0;
85     }
86 }
87 
path() const88 ProperPath SmartConnectedKeyEdgeSet::path() const
89 {
90     return path_;
91 }
92 
loop() const93 ProperCycle SmartConnectedKeyEdgeSet::loop() const
94 {
95     return loop_;
96 }
97 
hole() const98 CycleHelper SmartConnectedKeyEdgeSet::hole() const
99 {
100     return hole_;
101 }
102 
edgeSet() const103 KeyEdgeSet SmartConnectedKeyEdgeSet::edgeSet() const
104 {
105     return edgeSet_;
106 }
107 
108 
109 /////////////////////////////////////////////////////////////////////
110 //           Multiple Connected Component computation              //
111 
112 
SmartKeyEdgeSet(const KeyEdgeSet & edgeSetConst)113 SmartKeyEdgeSet::SmartKeyEdgeSet(const KeyEdgeSet & edgeSetConst) :
114     edgeSet_(edgeSetConst)
115 {
116     // ----- Compute connected components -----
117 
118     // This variable store the edges that have not yet been assigned a connected component
119     KeyEdgeSet remainingEdges = edgeSet_;
120 
121 
122     // ===== First, each closed edge is its own connected component =====
123 
124     KeyEdgeSet remainingEdgesCopy = remainingEdges;
125     foreach(KeyEdge * iedge, remainingEdgesCopy)
126     {
127         if(iedge->isClosed())
128         {
129             remainingEdges.remove(iedge);
130             KeyEdgeSet connectedEdges;
131             connectedEdges << iedge;
132             connectedComponents_ << SmartConnectedKeyEdgeSet(connectedEdges);
133         }
134     }
135 
136 
137     // ===== Define the 1-subcomplex made of the remaining vertices and open edges =====
138 
139     // Data structure for cells of the original complex
140     typedef KeyVertex Vertex;
141     typedef KeyEdge Edge;
142 
143     // Data structure for cells of the subcomplex
144     struct SubVertex;
145     struct SubEdge
146     {
147         SubEdge(Edge * edge) : edge(edge), leftSubVertex(0), rightSubVertex(0), marked(false) {}
148 
149         // Edge from SubEdge
150         Edge * edge;
151 
152         // Boundary SubVertices
153         SubVertex * leftSubVertex;
154         SubVertex * rightSubVertex;
155 
156         // Has the edge already been visited
157         bool marked;
158     };
159     struct SubVertex
160     {
161         SubVertex(Vertex * vertex) : vertex(vertex), subEdges() {}
162 
163         // Vertex from SubVertex
164         Vertex * vertex;
165 
166         // Star SubEdges
167         QSet<SubEdge*> subEdges;
168     };
169 
170     // Populate subcomplex
171     QSet<SubEdge*> subEdges;
172     QSet<SubVertex*> subVertices;
173     QMap<Vertex*, SubVertex*> vertexToSubVertex;
174     QMap<Edge*, SubEdge*> edgeToSubEdge;
175     foreach(Edge * edge, remainingEdges)
176     {
177         // create new subcomplex edge
178         SubEdge * subEdge = new SubEdge(edge);
179         subEdges << subEdge;
180         edgeToSubEdge[edge] = subEdge;
181 
182         // assign its left subcomplex vertex (create it if doesn't exist yet)
183         Vertex * startVertex = edge->startVertex(); // not NULL because edge is open
184         SubVertex * leftSubVertex = vertexToSubVertex.value(startVertex, 0); // returns 0 if not found
185         if(!leftSubVertex)
186         {
187             leftSubVertex = new SubVertex(startVertex);
188             subVertices << leftSubVertex;
189             vertexToSubVertex[startVertex] = leftSubVertex;
190         }
191         subEdge->leftSubVertex = leftSubVertex;
192         leftSubVertex->subEdges << subEdge;
193 
194         // assign its right subcomplex vertex (create it if doesn't exist yet)
195         Vertex * endVertex = edge->endVertex(); // we know it's not null since we rejected pure loops
196         SubVertex * rightSubVertex = vertexToSubVertex.value(endVertex, 0); // returns 0 if not found
197         if(!rightSubVertex)
198         {
199             rightSubVertex = new SubVertex(endVertex);
200             subVertices << rightSubVertex;
201             vertexToSubVertex[endVertex] = rightSubVertex;
202         }
203         subEdge->rightSubVertex = rightSubVertex;
204         rightSubVertex->subEdges << subEdge;
205     }
206 
207     // ===== Compute connected components of subcomplex =====
208 
209     while(!remainingEdges.isEmpty())
210     {
211         // New connected component
212         KeyEdgeSet connectedEdges;
213 
214         // get the first edge/subEdge of a new connected component
215         Edge * firstEdge = *remainingEdges.begin();
216         SubEdge * firstSubEdge =    edgeToSubEdge[firstEdge];
217 
218         // get all subEdges/edges connected to this sub/edge/edge
219         QStack<SubEdge *> toProcess;
220         toProcess.push(firstSubEdge);
221         while(!toProcess.isEmpty())
222         {
223             SubEdge * subEdge = toProcess.top();
224             toProcess.pop();
225 
226             // marked means:
227             //  - it has already been removed from remainingEdges
228             //  - it has already been added to connectedEdges
229             //  - all its neighbours have already been inserted in toProcess (possibly twice)
230 
231             if(!subEdge->marked)
232             {
233                 // Mark and remove
234                 remainingEdges.remove(subEdge->edge);
235                 connectedEdges.insert(subEdge->edge);
236                 subEdge->marked = true;
237 
238                 // Insert neighbours in stack
239                 foreach(SubEdge * neighbour, subEdge->leftSubVertex->subEdges)
240                     toProcess.push(neighbour);
241                 foreach(SubEdge * neighbour, subEdge->rightSubVertex->subEdges)
242                     toProcess.push(neighbour);
243             }
244         }
245 
246         // Process connected component
247         connectedComponents_ << SmartConnectedKeyEdgeSet(connectedEdges);
248     }
249 
250 
251     // ===== Release memory =====
252 
253     // release memory
254     foreach(SubEdge * subEdge, subEdges)
255         delete subEdge;
256     foreach(SubVertex * subVertex, subVertices)
257         delete subVertex;
258 }
259 
numConnectedComponents() const260 int SmartKeyEdgeSet::numConnectedComponents() const
261 {
262     return connectedComponents_.size();
263 }
264 
operator [](int i)265 SmartConnectedKeyEdgeSet & SmartKeyEdgeSet::operator [] (int i)
266 {
267     return connectedComponents_[i];
268 }
269 
270 
271 }
272