src/editmodes/magicWandMode.cpp

changeset 996
9ecc878c7dea
parent 984
a7b6f987d269
equal deleted inserted replaced
995:7986584e7498 996:9ecc878c7dea
28 // Get vertex<->object data 28 // Get vertex<->object data
29 for (LDObject* obj : currentDocument()->objects()) 29 for (LDObject* obj : currentDocument()->objects())
30 { 30 {
31 // Note: this deliberately only takes vertex-objects into account. 31 // Note: this deliberately only takes vertex-objects into account.
32 // The magic wand does not process subparts. 32 // The magic wand does not process subparts.
33 for (int i = 0; i < obj->numVertices(); ++i) 33 if (obj->hasVertices())
34 m_vertices[obj->vertex (i)] << obj; 34 {
35 LDVertexObject* vo = static_cast<LDVertexObject*> (obj);
36 for (int i = 0; i < vo->numVertices(); ++i)
37 m_vertices[vo->vertex (i)] << vo;
38 }
35 } 39 }
36 } 40 }
37 41
38 EditModeType MagicWandMode::type() const 42 EditModeType MagicWandMode::type() const
39 { 43 {
40 return EditModeType::MagicWand; 44 return EditModeType::MagicWand;
41 } 45 }
42 46
43 void MagicWandMode::fillBoundaries (LDObject* obj, QVector<BoundaryType>& boundaries, QVector<LDObject*>& candidates) 47 void MagicWandMode::fillBoundaries (LDVertexObject* obj, Boundaries& boundaries, Candidates& candidates)
44 { 48 {
45 // All boundaries obviously share vertices with the object, therefore they're all in the list 49 // All boundaries obviously share vertices with the object, therefore they're all in the list
46 // of candidates. 50 // of candidates.
47 for (LDObject* candidate : candidates) 51 for (LDVertexObject* candidate : candidates)
48 { 52 {
49 if (not isOneOf (candidate->type(), OBJ_Line, OBJ_CondLine) or candidate->vertex (0) == candidate->vertex (1)) 53 if (not isOneOf (candidate->type(), OBJ_Line, OBJ_CondLine) or candidate->vertex (0) == candidate->vertex (1))
50 continue; 54 continue;
51 55
52 int matches = 0; 56 int matches = 0;
62 // conditional line, select it. 66 // conditional line, select it.
63 if (candidate->type() == OBJ_CondLine) 67 if (candidate->type() == OBJ_CondLine)
64 m_selection << candidate; 68 m_selection << candidate;
65 else 69 else
66 boundaries.append (std::make_tuple (candidate->vertex (0), candidate->vertex (1))); 70 boundaries.append (std::make_tuple (candidate->vertex (0), candidate->vertex (1)));
67
68 break; 71 break;
69 } 72 }
70 } 73 }
71 } 74 }
72 } 75 }
73 76
74 void MagicWandMode::doMagic (LDObject* obj, MagicWandMode::MagicType type) 77 void MagicWandMode::doMagic (LDObject* input, MagicType type)
75 { 78 {
76 if (obj == nullptr) 79 if (input == nullptr or not input->hasVertices())
77 { 80 {
78 if (type == Set) 81 if (type == Set)
79 { 82 {
80 currentDocument()->clearSelection(); 83 currentDocument()->clearSelection();
81 m_window->buildObjectList(); 84 m_window->buildObjectList();
82 } 85 }
83 86
84 return; 87 return;
85 } 88 }
86 89
87 int matchesneeded = 0; 90 LDVertexObject* obj = static_cast<LDVertexObject*> (input);
88 QVector<BoundaryType> boundaries; 91 int matchesneeded = (obj->numVertices() == 2) ? 1 : 2;
92 Boundaries boundaries;
89 LDObjectType objtype = obj->type(); 93 LDObjectType objtype = obj->type();
90 94
91 if (type != InternalRecursion) 95 if (type != InternalRecursion)
92 { 96 {
93 m_selection.clear(); 97 m_selection.clear();
94 m_selection.append (obj); 98 m_selection.append (obj);
95 } 99 }
96 100
97 switch (obj->type()) 101 Candidates candidates;
98 {
99 case OBJ_Line:
100 case OBJ_CondLine:
101 matchesneeded = 1;
102 break;
103
104 case OBJ_Triangle:
105 case OBJ_Quad:
106 matchesneeded = 2;
107 break;
108
109 default:
110 return;
111 }
112
113 QVector<LDObject*> candidates;
114 102
115 // Get the list of objects that touch this object, i.e. share a vertex 103 // Get the list of objects that touch this object, i.e. share a vertex
116 // with this. 104 // with this.
117 for (int i = 0; i < obj->numVertices(); ++i) 105 for (int i = 0; i < obj->numVertices(); ++i)
118 candidates += m_vertices[obj->vertex (i)]; 106 candidates += m_vertices[obj->vertex (i)];
121 109
122 // If we're dealing with surfaces, get a list of boundaries. 110 // If we're dealing with surfaces, get a list of boundaries.
123 if (matchesneeded > 1) 111 if (matchesneeded > 1)
124 fillBoundaries (obj, boundaries, candidates); 112 fillBoundaries (obj, boundaries, candidates);
125 113
126 for (LDObject* candidate : candidates) 114 for (LDVertexObject* candidate : candidates)
127 { 115 {
128 try 116 // If we're doing this on lines, we need exact type match. Surface types (quads and
129 { 117 // triangles) can be mixed. Also don't consider self a candidate, and don't consider
130 // If we're doing this on lines, we need exact type match. Surface types (quads and 118 // objects we have already processed.
131 // triangles) can be mixed. Also don't consider self a candidate, and don't consider 119 if ((candidate == obj) or
132 // objects we have already processed. 120 (candidate->color() != obj->color()) or
133 if ((candidate == obj) or 121 (m_selection.contains (candidate)) or
134 (candidate->color() != obj->color()) or 122 (matchesneeded == 1 and (candidate->type() != objtype)) or
135 (m_selection.contains (candidate)) or 123 ((candidate->numVertices() > 2) ^ (matchesneeded == 2)))
136 (matchesneeded == 1 and (candidate->type() != objtype)) or
137 ((candidate->numVertices() > 2) ^ (matchesneeded == 2)))
138 {
139 throw 0;
140 }
141
142 // Now ensure the two objects share enough vertices.
143 QVector<Vertex> matches;
144
145 for (int i = 0; i < obj->numVertices(); ++i)
146 {
147 for (int j = 0; j < candidate->numVertices(); ++j)
148 {
149 if (obj->vertex(i) == candidate->vertex(j))
150 {
151 matches << obj->vertex(i);
152 break;
153 }
154 }
155 }
156
157 if (matches.size() < matchesneeded)
158 throw 0; // Not enough matches.
159
160 // Check if a boundary gets in between the objects.
161 for (auto boundary : boundaries)
162 {
163 if (isOneOf (matches[0], std::get<0> (boundary), std::get<1> (boundary)) and
164 isOneOf (matches[1], std::get<0> (boundary), std::get<1> (boundary)))
165 {
166 throw 0;
167 }
168 }
169
170 m_selection.append (candidate);
171 doMagic (candidate, InternalRecursion);
172 }
173 catch (int&)
174 { 124 {
175 continue; 125 continue;
176 } 126 }
127
128 // Now ensure the two objects share enough vertices.
129 QSet<Vertex> matches = obj->vertexSet();
130 matches.intersect (candidate->vertexSet());
131
132 if (matches.size() < matchesneeded)
133 goto skipthis; // Not enough matches.
134
135 // Check if a boundary gets in between the objects.
136 for (const Boundary& boundary : boundaries)
137 {
138 if (matches.contains (std::get<0>(boundary)) and matches.contains (std::get<1>(boundary)))
139 goto skipthis;
140 }
141
142 m_selection.append (candidate);
143 doMagic (candidate, InternalRecursion);
144 skipthis:
145 continue;
177 } 146 }
178 147
179 switch (type) 148 switch (type)
180 { 149 {
181 case Set: 150 case Set:
210 if (data.keymods & Qt::ShiftModifier) 179 if (data.keymods & Qt::ShiftModifier)
211 wandtype = MagicWandMode::Additive; 180 wandtype = MagicWandMode::Additive;
212 else if (data.keymods & Qt::ControlModifier) 181 else if (data.keymods & Qt::ControlModifier)
213 wandtype = MagicWandMode::Subtractive; 182 wandtype = MagicWandMode::Subtractive;
214 183
215 doMagic (renderer()->pickOneObject (data.ev->x(), data.ev->y()), wandtype); 184 LDObject* obj = renderer()->pickOneObject (data.ev->x(), data.ev->y());
185 doMagic (obj, wandtype);
216 return true; 186 return true;
217 } 187 }
218 188
219 return false; 189 return false;
220 } 190 }

mercurial