1 /* BurrTools
2 *
3 * BurrTools is the legal property of its developers, whose
4 * names are listed in the COPYRIGHT file, which is included
5 * within the source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "stlexport.h"
22 #include <stdlib.h>
23
24 #include "BlockList.h"
25 #include "view3dgroup.h"
26 #include "blocklistgroup.h"
27 #include "voxelframe.h"
28 #include "buttongroup.h"
29
30 #include "../lib/puzzle.h"
31 #include "../lib/gridtype.h"
32 #include "../lib/bt_assert.h"
33 #include "../lib/voxel.h"
34
35 #include "../halfedge/volume.h"
36
37 #include "../flu/Flu_File_Chooser.h"
38
39 #include "../tools/fileexists.h"
40
41 #include <FL/Fl.H>
42 #include <FL/fl_ask.H>
43
44
45 // a simple class (structure) containing some information for each input field
46 class inputField_c
47 {
48 public:
49
50 stlExporter_c::parameterTypes type;
51 Fl_Widget * w;
52 };
53
54
cb_stlExportAbort_stub(Fl_Widget *,void * v)55 static void cb_stlExportAbort_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)(v))->cb_Abort(); }
56
cb_Abort(void)57 void stlExport_c::cb_Abort(void) {
58 hide();
59 }
60
cb_stlExportExport_stub(Fl_Widget *,void * v)61 static void cb_stlExportExport_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)(v))->cb_Export(); }
62
cb_Export(void)63 void stlExport_c::cb_Export(void) {
64
65 exportSTL(ShapeSelect->getSelection());
66
67 }
68
updateParameters(stlExporter_c * stl,const std::vector<inputField_c * > & params)69 static void updateParameters(stlExporter_c * stl, const std::vector<inputField_c *> & params)
70 {
71 for (unsigned int i = 0; i < stl->numParameters(); i++)
72 {
73 switch (params[i]->type)
74 {
75 case stlExporter_c::PAR_TYP_DOUBLE:
76 case stlExporter_c::PAR_TYP_POS_DOUBLE:
77 stl->setParameter(i, atof(((LFl_Float_Input*)(params[i]->w))->value()));
78 break;
79 case stlExporter_c::PAR_TYP_POS_INTEGER:
80 stl->setParameter(i, atoi(((LFl_Int_Input*)(params[i]->w))->value()));
81 break;
82 case stlExporter_c::PAR_TYP_SWITCH:
83 stl->setParameter(i, ((LFl_Check_Button*)(params[i]->w))->value());
84 break;
85 default:
86 bt_assert(0);
87 }
88 }
89 }
90
cb_stlExport3DUpdate_stub(Fl_Widget *,void * v)91 static void cb_stlExport3DUpdate_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)(v))->cb_Update3DView(1); }
cb_stlExport3DUpdate2_stub(Fl_Widget *,void * v)92 static void cb_stlExport3DUpdate2_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)(v))->cb_Update3DView(2); }
cb_Update3DView(int type)93 void stlExport_c::cb_Update3DView(int type)
94 {
95 updateParameters(stl, params);
96
97 if (type == 2)
98 {
99 holes.clear();
100 }
101
102 Polyhedron * p = 0;
103 try
104 {
105 p = stl->getMesh(*puzzle->getShape(ShapeSelect->getSelection()), holes);
106 }
107 catch (stlException_c e)
108 {
109 fl_message(e.comment);
110 return;
111 }
112 catch (...)
113 {
114 fl_message("The generated mesh is faulty in some way, try to tweak the parameter");
115 return;
116 }
117
118 if (p)
119 {
120 view3D->getView()->showMesh(p);
121 char txt[100];
122 snprintf(txt, 99, "Volume: %1.1f cubic-units\n", volume(*p));
123 status->copy_label(txt);
124 }
125 else
126 {
127 view3D->getView()->showNothing();
128 status->label("");
129 }
130
131 }
132
cb_stlFileChooser_stub(Fl_Widget *,void * v)133 static void cb_stlFileChooser_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)(v))->cb_FileChooser(); }
cb_FileChooser(void)134 void stlExport_c::cb_FileChooser(void)
135 {
136 char curFile[500];
137 snprintf(curFile, 500, "%s/%s", Pname->value(), Fname->value());
138
139 const char * f = flu_file_chooser("Choose STL File to write", "*.stl", curFile);
140
141 if (f)
142 {
143 const char * div = strrchr(f, '/');
144
145 if (div)
146 {
147 Fname->value(div+1);
148
149 int i = 0;
150 while (true)
151 {
152 curFile[i] = f[i];
153 i++;
154 if (f[i] == 0) break;
155 if (i >= 499) break;
156 if (div == f+i) break;
157 }
158
159 curFile[i] = 0;
160
161 Pname->value(curFile);
162 }
163
164 }
165
166
167 }
168
cb_stlExportViewUpdate_stub(Fl_Widget *,void * v)169 static void cb_stlExportViewUpdate_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)(v))->cb_Update3DViewParams(); }
cb_Update3DViewParams(void)170 void stlExport_c::cb_Update3DViewParams(void)
171 {
172 switch (mode->getSelected())
173 {
174 case 0: view3D->getView()->setInsideVisible(false); break;
175 case 1: view3D->getView()->setInsideVisible(true); break;
176 default: break;
177 }
178 }
179
cb_3dClick_stub(Fl_Widget *,void * v)180 static void cb_3dClick_stub(Fl_Widget* /*o*/, void* v) { ((stlExport_c*)v)->cb_3dClick(); }
cb_3dClick(void)181 void stlExport_c::cb_3dClick(void)
182 {
183 if (Fl::event_ctrl() || Fl::event_shift())
184 {
185 unsigned int shape, face;
186 unsigned long voxel;
187
188 if (view3D->getView()->pickShape(Fl::event_x(),
189 view3D->getView()->h()-Fl::event_y(),
190 &shape, &voxel, &face))
191 {
192 if (shape == 0)
193 {
194 if (Fl::event_ctrl())
195 {
196 holes.removeFace(voxel, face);
197 cb_Update3DView(1);
198 }
199 if (Fl::event_shift())
200 {
201 holes.addFace(voxel, face);
202 cb_Update3DView(1);
203 }
204 }
205 }
206 }
207 }
208
stlExport_c(puzzle_c * p)209 stlExport_c::stlExport_c(puzzle_c * p) : LFl_Double_Window(true), puzzle(p) {
210
211 label("Export STL");
212
213 stl = p->getGridType()->getStlExporter();
214 bt_assert(stl);
215
216 LFl_Frame *fr;
217
218 {
219 fr = new LFl_Frame(0, 0, 1, 1);
220
221 (new LFl_Box("File name", 0, 0))->stretchLeft();
222 (new LFl_Box("Path", 0, 1))->stretchLeft();
223
224 (new LFl_Box(1, 0))->setMinimumSize(5, 0);
225 (new LFl_Box(3, 0))->setMinimumSize(5, 0);
226
227 Fname = new LFl_Input(2, 0, 1, 1);
228 Fname->value("test");
229 Fname->weight(1, 0);
230 Fname->setMinimumSize(50, 0);
231 Pname = new LFl_Input(2, 1, 1, 1);
232 Pname->value(".");
233 Pname->weight(1, 0);
234 Pname->setMinimumSize(50, 0);
235
236 Fl_Button * Btn_Dir = new LFl_Button("...", 3, 0, 2, 2);
237 Btn_Dir->callback(cb_stlFileChooser_stub, this);
238
239 Binary = new LFl_Check_Button("Binary STL", 0, 2, 3, 1);
240 if (stl->getBinaryMode())
241 Binary->value(1);
242 else
243 Binary->value(0);
244
245 fr->end();
246 }
247
248 {
249 fr = new LFl_Frame(0, 1, 1, 1);
250
251 inputField_c * inp;
252
253 for (unsigned int i = 0; i < stl->numParameters(); i++)
254 {
255 inp = new inputField_c;
256
257 inp->type = stl->getParameterType(i);
258
259 switch (inp->type)
260 {
261 case stlExporter_c::PAR_TYP_DOUBLE:
262 {
263 (new LFl_Box(stl->getParameterName(i), 0, i))->stretchRight();
264 (new LFl_Box(1, i))->setMinimumSize(5, 0);
265 LFl_Float_Input * in = new LFl_Float_Input(2, i, 1, 1);
266 char val[10];
267 snprintf(val, 10, "%2.2f", stl->getParameter(i));
268 in->value(val);
269 in->weight(1, 0);
270
271 inp->w = in;
272 }
273 break;
274
275 case stlExporter_c::PAR_TYP_POS_DOUBLE:
276 {
277 (new LFl_Box(stl->getParameterName(i), 0, i))->stretchRight();
278 (new LFl_Box(1, i))->setMinimumSize(5, 0);
279 LFl_Float_Input * in = new LFl_Float_Input(2, i, 1, 1);
280
281 char val[10];
282 snprintf(val, 10, "%2.2f", stl->getParameter(i));
283 in->value(val);
284 in->weight(1, 0);
285
286 inp->w = in;
287 }
288 break;
289
290 case stlExporter_c::PAR_TYP_POS_INTEGER:
291 {
292 (new LFl_Box(stl->getParameterName(i), 0, i))->stretchRight();
293 (new LFl_Box(1, i))->setMinimumSize(5, 0);
294 LFl_Int_Input * in = new LFl_Int_Input(2, i, 1, 1);
295
296 char val[10];
297 snprintf(val, 10, "%i", (int)stl->getParameter(i));
298 in->value(val);
299 in->weight(1, 0);
300
301 inp->w = in;
302 }
303 break;
304
305 case stlExporter_c::PAR_TYP_SWITCH:
306 {
307 LFl_Check_Button * in = new LFl_Check_Button(stl->getParameterName(i), 0, i, 3, 1);
308
309 if (stl->getParameter(i))
310 in->value(1);
311 else
312 in->value(0);
313
314 in->weight(1, 0);
315
316 inp->w = in;
317 }
318 break;
319
320 default:
321 bt_assert(0);
322 }
323
324 inp->w->callback(cb_stlExport3DUpdate_stub, this);
325 inp->w->tooltip(stl->getParameterTooltip(i));
326
327 params.push_back(inp);
328 }
329
330 fr->end();
331 }
332
333 {
334 ShapeSelect = new PieceSelector(0, 0, 20, 20, puzzle);
335
336 ShapeSelect->setSelection(0);
337
338 LBlockListGroup_c * gr = new LBlockListGroup_c(0, 2, 1, 1, ShapeSelect);
339 gr->callback(cb_stlExport3DUpdate2_stub, this);
340 gr->setMinimumSize(200, 100);
341 gr->stretch();
342 gr->weight(0, 1);
343 }
344
345 {
346 fr = new LFl_Frame(0, 3, 1, 1);
347
348 layouter_c * l = new layouter_c(0, 0, 1, 1);
349 l->pitch(5);
350
351 BtnStart = new LFl_Button("Export STL", 0, 0);
352 BtnStart->callback(cb_stlExportExport_stub, this);
353
354 (new LFl_Box(0, 1))->setMinimumSize(0, 5);
355
356 BtnAbbort = new LFl_Button("Abort", 0, 2);
357 BtnAbbort->callback(cb_stlExportAbort_stub, this);
358
359 fr->end();
360 }
361
362 {
363 layouter_c * l = new layouter_c(0, 4, 2, 1);
364
365 status = new LFl_Box(0, 0, 1, 1);
366 status->box(FL_UP_BOX);
367 status->weight(1, 0);
368 status->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
369
370 mode = new ButtonGroup_c(1, 0, 1, 1);
371
372 Fl_Button * b;
373
374 b = mode->addButton();
375 b->image(pm.get(ViewModeNormal_xpm));
376 b->tooltip(" Display STL ebject normally ");
377
378 b = mode->addButton();
379 b->image(pm.get(ViewModeInsides_xpm));
380 b->tooltip(" Display the insides of the STL object ");
381
382 mode->callback(cb_stlExportViewUpdate_stub, this);
383
384 l->end();
385 }
386
387 view3D = new LView3dGroup(1, 0, 1, 4);
388 view3D->setMinimumSize(400, 400);
389 view3D->weight(1, 0);
390 view3D->callback(cb_3dClick_stub, this);
391 cb_Update3DView(1);
392
393 set_modal();
394 }
395
exportSTL(int shape)396 void stlExport_c::exportSTL(int shape)
397 {
398 char name[1000];
399
400 voxel_c *v = puzzle->getShape(shape);
401
402 updateParameters(stl, params);
403
404 stl->setBinaryMode(Binary->value() != 0);
405
406 int idx = 0;
407
408 if (Pname->value() && Pname->value()[0] && Pname->value()[strlen(Pname->value())-1] != '/') {
409 idx = snprintf(name, 1000, "%s/%s", Pname->value(), Fname->value());
410 } else {
411 idx = snprintf(name, 1000, "%s%s", Pname->value(), Fname->value());
412 }
413
414 if (fileExists(name))
415 {
416 if (fl_choice("File exists overwrite?", "Cancel", "Overwrite", 0) == 0)
417 {
418 return;
419 }
420 }
421
422 try {
423 stl->write(name, *v, holes);
424 }
425
426 catch (stlException_c e) {
427 fl_message(e.comment);
428 }
429 catch (...)
430 {
431 fl_message("The generated mesh is faulty in some way, try to tweak the parameter");
432 }
433 }
434
~stlExport_c(void)435 stlExport_c::~stlExport_c(void)
436 {
437 if (stl) delete stl;
438 for (size_t i = 0; i < params.size(); i++)
439 delete params[i];
440 }
441