1 /*
2 This file is a part of the RepSnapper project.
3 Copyright (C) 2010 Kulitorum
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <exception>
21 #include <stdexcept>
22
23 #include "stdafx.h"
24 #include "objtree.h"
25 #include "model.h"
26
27
~TreeObject()28 TreeObject::~TreeObject()
29 {
30 for (uint i = 0; i<shapes.size(); i++)
31 delete shapes[i];
32 shapes.clear();
33 }
34
35
deleteShape(uint i)36 bool TreeObject::deleteShape(uint i)
37 {
38 delete shapes[i];
39 shapes.erase (shapes.begin() + i);
40 return true;
41 }
42
43
center() const44 Vector3d TreeObject::center() const
45 {
46 Vector3d center(0.,0.,0.);
47 if (shapes.size()>0) {
48 for (uint i = 0; i<shapes.size(); i++) {
49 center += shapes[i]->Center;
50 }
51 center /= shapes.size();
52 }
53 return center;
54 }
55
addShape(Shape * shape,std::string location)56 Gtk::TreePath TreeObject::addShape(Shape *shape, std::string location)
57 {
58 Gtk::TreePath path;
59 path.push_back (0); // root
60 path.push_back (idx);
61
62 shape->filename = location;
63 if (shapes.size() > 0)
64 if (dimensions != shape->dimensions()) {
65 Gtk::MessageDialog dialog (_("Cannot add a 3-dimensional Shape to a 2-dimensional Model and vice versa"),
66 false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_CLOSE);
67 dialog.run();
68 path.push_back (shapes.size() - 1);
69 return path;
70 }
71
72 dimensions = shape->dimensions();
73 shapes.push_back(shape);
74 path.push_back (shapes.size() - 1);
75 return path;
76 }
77
78
clear()79 void ObjectsTree::clear()
80 {
81 for (vector<TreeObject*>::iterator i = Objects.begin(); i != Objects.end(); i++)
82 delete *i;
83 Objects.clear();
84 version = 0.0f;
85 m_filename = "";
86 transform3D.identity();
87 update_model();
88 }
89
90
newObject()91 void ObjectsTree::newObject()
92 {
93 Objects.push_back(new TreeObject());
94 update_model();
95 }
96
97
addShape(TreeObject * parent,Shape * shape,std::string location)98 Gtk::TreePath ObjectsTree::addShape(TreeObject *parent, Shape *shape,
99 std::string location)
100 {
101 Gtk::TreePath path = parent->addShape(shape, location);
102 update_model();
103 return path;
104 }
105
ObjectsTree()106 ObjectsTree::ObjectsTree()
107 {
108 version=0.1f;
109 m_cols = new ModelColumns();
110 m_model = Gtk::TreeStore::create (*m_cols);
111 update_model();
112 m_model->signal_row_changed().connect(sigc::mem_fun(*this, &ObjectsTree::on_row_changed));
113 }
114
~ObjectsTree()115 ObjectsTree::~ObjectsTree()
116 {
117 for (vector<TreeObject*>::iterator i = Objects.begin(); i != Objects.end(); i++)
118 delete *i;
119 Objects.clear();
120 delete m_cols;
121 }
122
on_row_changed(const Gtk::TreeModel::Path & path,const Gtk::TreeModel::iterator & iter)123 void ObjectsTree::on_row_changed(const Gtk::TreeModel::Path& path,
124 const Gtk::TreeModel::iterator& iter){
125 if (!inhibit_row_changed)
126 update_shapenames(m_model->children());
127 }
128
update_model()129 void ObjectsTree::update_model()
130 {
131 inhibit_row_changed = true;
132 // re-build the model each time for ease ...
133 m_model->clear();
134
135 size_t psep;
136 std::string root_label = m_filename;
137 if (!root_label.length())
138 root_label = _("Unsaved file");
139 else if ((psep = m_filename.find_last_of("/\\")) != string::npos)
140 root_label = m_filename.substr(psep + 1);
141
142 Gtk::TreeModel::iterator root;
143 root = m_model->append();
144 Gtk::TreeModel::Row row = *root;
145 row[m_cols->m_name] = root_label;
146 row[m_cols->m_object] = -1;
147 row[m_cols->m_shape] = -1;
148 row[m_cols->m_pickindex] = 0;
149 row[m_cols->m_material] = 0;
150
151 gint index = 1; // pick/select index. matches computation in draw()
152
153 for (guint i = 0; i < Objects.size(); i++) {
154 Objects[i]->idx = i;
155
156 Gtk::TreeModel::iterator obj = m_model->append(row.children());
157 Gtk::TreeModel::Row orow = *obj;
158 orow[m_cols->m_name] = Objects[i]->name;
159 orow[m_cols->m_object] = i;
160 orow[m_cols->m_shape] = -1;
161 orow[m_cols->m_pickindex] = index++;
162 orow[m_cols->m_material] = 0;
163
164 for (guint j = 0; j < Objects[i]->shapes.size(); j++) {
165 Objects[i]->shapes[j]->idx = j;
166 Gtk::TreeModel::iterator iter = m_model->append(orow.children());
167 row = *iter;
168 row[m_cols->m_name] = Objects[i]->shapes[j]->filename;
169 row[m_cols->m_object] = i;
170 row[m_cols->m_shape] = j;
171 row[m_cols->m_pickindex] = index++;
172 row[m_cols->m_material] = 0;
173 }
174 }
175 inhibit_row_changed = false;
176 }
177
update_shapenames(Gtk::TreeModel::Children children)178 void ObjectsTree::update_shapenames(Gtk::TreeModel::Children children)
179 {
180 Gtk::TreeModel::iterator iter = children.begin();
181 for (;iter; iter++) {
182 int nobj = (*iter)[m_cols->m_object];
183 int nshape = (*iter)[m_cols->m_shape];
184 if (nobj >= 0 && nshape >= 0) {
185 ustring name = (*iter)[m_cols->m_name];
186 if ((int)Objects.size() > nobj &&
187 (int)Objects[nobj]->shapes.size() > nshape)
188 Objects[nobj]->shapes[nshape]->filename = name;
189 }
190 else
191 update_shapenames((*iter).children());
192 }
193 }
194
195
getTransformationMatrix(int object,int shape) const196 Matrix4d ObjectsTree::getTransformationMatrix(int object, int shape) const
197 {
198 Matrix4d result = transform3D.transform;
199 // Vector3f translation = result.getTranslation();
200 // result.setTranslation(translation+PrintMargin);
201
202 if(object >= 0)
203 result *= Objects[object]->transform3D.transform;
204 if(shape >= 0)
205 result *= Objects[object]->shapes[shape]->transform3D.transform;
206 return result;
207 }
208
209
get_selected_objects(const vector<Gtk::TreeModel::Path> & path,vector<TreeObject * > & objects,vector<Shape * > & shapes) const210 void ObjectsTree::get_selected_objects(const vector<Gtk::TreeModel::Path> &path,
211 vector<TreeObject*> &objects,
212 vector<Shape*> &shapes) const
213 {
214 objects.clear();
215 shapes.clear();
216 if (path.size()==0) return;
217 for (uint p = 0; p < path.size(); p++) {
218 // cerr << "sel " << p << " -> "<< path[p].to_string ()
219 // << " - "<< path[p].size() << endl;
220 int num = path[p].size();
221 if (num == 1)
222 for (uint i=0; i<Objects.size(); i++) {
223 objects.push_back(Objects[i]);
224 }
225 else if (num == 2) {
226 objects.push_back(Objects[path[p][1]]);
227 }
228 else if (num == 3) { // have shapes
229 shapes.push_back(Objects[path[p][1]]->shapes[path[p][2]]);
230 }
231 }
232 }
get_selected_shapes(const vector<Gtk::TreeModel::Path> & path,vector<Shape * > & allshapes,vector<Matrix4d> & transforms) const233 void ObjectsTree::get_selected_shapes(const vector<Gtk::TreeModel::Path> &path,
234 vector<Shape*> &allshapes,
235 vector<Matrix4d> &transforms) const
236 {
237 allshapes.clear();
238 transforms.clear();
239 vector<Shape*> sel_shapes;
240 vector<TreeObject*> sel_objects;
241 get_selected_objects(path, sel_objects, sel_shapes);
242 // add shapes if their parent object not selected
243 for (uint s = 0; s < sel_shapes.size(); s++) {
244 bool parent_obj_selected = false;
245 for (uint o = 0; o < sel_objects.size(); o++) {
246 if (getParent(sel_shapes[s]) == Objects[o])
247 parent_obj_selected = true;
248 }
249 if (!parent_obj_selected){
250 allshapes.push_back(sel_shapes[s]);
251 transforms.push_back(transform3D.transform
252 * getParent(sel_shapes[s])->transform3D.transform);
253 }
254 }
255 // add all shapes of selected objects
256 for (uint o = 0; o < sel_objects.size(); o++) {
257 Matrix4d otrans =
258 transform3D.transform * sel_objects[o]->transform3D.transform;
259 allshapes.insert(allshapes.begin(),
260 sel_objects[o]->shapes.begin(), sel_objects[o]->shapes.end());
261 for (uint s = 0; s < sel_objects[o]->shapes.size(); s++) {
262 transforms.push_back(otrans);
263 }
264 }
265 }
266
get_all_shapes(vector<Shape * > & allshapes,vector<Matrix4d> & transforms) const267 void ObjectsTree::get_all_shapes(vector<Shape*> &allshapes,
268 vector<Matrix4d> &transforms) const
269 {
270 allshapes.clear();
271 transforms.clear();
272 for (uint o = 0; o < Objects.size(); o++) {
273 Matrix4d otrans =
274 transform3D.transform * Objects[o]->transform3D.transform;
275 allshapes.insert(allshapes.begin(),
276 Objects[o]->shapes.begin(), Objects[o]->shapes.end());
277 for (uint s = 0; s < Objects[o]->shapes.size(); s++) {
278 transforms.push_back(otrans);
279 }
280 }
281 }
282
DeleteSelected(vector<Gtk::TreeModel::Path> & path)283 void ObjectsTree::DeleteSelected(vector<Gtk::TreeModel::Path> &path)
284 {
285 if (path.size()==0) return;
286 for (int p = path.size()-1; p>=0; p--) {
287 int num = path[p].size();
288 if (num == 1)
289 Objects.clear();
290 else if (num == 2)
291 Objects.erase (Objects.begin() + path[p][1]);
292 else if (num == 3) { // have shapes
293 Objects[path[p][1]]->deleteShape(path[p][2]);
294 }
295 update_model();
296 }
297 }
298
getParent(const Shape * shape) const299 TreeObject * ObjectsTree::getParent(const Shape *shape) const
300 {
301 for (uint i=0; i<Objects.size(); i++) {
302 for (uint j=0; j<Objects[i]->shapes.size(); j++) {
303 if (Objects[i]->shapes[j] == shape)
304 return Objects[i];
305 }
306 }
307 return NULL;
308 }
309
find_stl_in_children(Gtk::TreeModel::Children children,guint pickindex)310 Gtk::TreeModel::iterator ObjectsTree::find_stl_in_children(Gtk::TreeModel::Children children,
311 guint pickindex)
312 {
313 Gtk::TreeModel::iterator iter = children.begin();
314
315 for (;iter; iter++) {
316 guint curindex = (*iter)[m_cols->m_pickindex];
317 if (curindex == pickindex)
318 return iter;
319
320 Gtk::TreeModel::iterator child_iter = find_stl_in_children((*iter).children(), pickindex);
321 if (child_iter)
322 return child_iter;
323 }
324
325 Gtk::TreeModel::iterator invalid;
326 return invalid;
327 }
328
find_stl_by_index(guint pickindex)329 Gtk::TreeModel::iterator ObjectsTree::find_stl_by_index(guint pickindex)
330 {
331 return find_stl_in_children(m_model->children(), pickindex);
332 }
333