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