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