1 /*
2     This file is a part of the RepSnapper project.
3     Copyright (C) 2010  Kulitorum
4     Copyright (C) 2011  Michael Meeks <michael.meeks@novell.com>
5     Copyright (C) 2012  martin.dieringer@gmx.de
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (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 along
18     with this program; if not, write to the Free Software Foundation, Inc.,
19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21 
22 #define  MODEL_IMPLEMENTATION
23 #include <vector>
24 #include <string>
25 #include <cerrno>
26 #include <functional>
27 //#include <memory>
28 
29 // should move to platform.h with com port fun.
30 #include <sys/types.h>
31 #include <dirent.h>
32 
33 #ifdef _OPENMP
34 #include <omp.h>
35 #endif
36 
37 #include "stdafx.h"
38 #include "model.h"
39 #include "objtree.h"
40 #include "settings.h"
41 #include "ui/progress.h"
42 #include "slicer/layer.h"
43 #include "slicer/infill.h"
44 #include "slicer/clipping.h"
45 
46 
MakeRaft(GCodeState & state,double & z)47 void Model::MakeRaft(GCodeState &state, double &z)
48 {
49   if (layers.size() == 0) return;
50   vector<Poly> raftpolys =
51     Clipping::getOffset(layers[0]->GetHullPolygon(),
52 			settings.get_double("Raft","Size"), jround);
53   double layerthickness =settings.get_double("Slicing","LayerThickness");
54 
55   for (uint i = 0; i< raftpolys.size(); i++)
56     raftpolys[i].cleanup(layerthickness/4);
57 
58   vector<Layer*> raft_layers;
59 
60   double rotation = settings.get_double("Raft","Base.Rotation");
61   double basethickness =
62     layerthickness * settings.get_double("Raft","Base.Thickness");
63   double interthickness =
64     layerthickness * settings.get_double("Raft","Interface.Thickness");
65 
66   double totalthickness = settings.get_integer("Raft","Base.LayerCount") * basethickness
67     + settings.get_double("Raft","Interface.LayerCount") * interthickness;
68 
69   double raft_z = -totalthickness + basethickness
70     * settings.get_double("Slicing","FirstLayerHeight");
71 
72   for (int i = 0; i < settings.get_integer("Raft","Base.LayerCount"); i++) {
73     Layer * layer = new Layer(lastlayer,
74 			      -settings.get_integer("Raft","Interface.LayerCount")
75 			      -settings.get_integer("Raft","Base.LayerCount") + i,
76 			      basethickness, 1);
77     layer->setZ(raft_z);
78     layer->CalcRaftInfill(raftpolys,
79 			  settings.get_double("Raft","Base.MaterialDistanceRatio"),
80 			  settings.get_double("Raft","Base.Distance"), rotation);
81     raft_layers.push_back(layer);
82     lastlayer = layer;
83     rotation += settings.get_double("Raft","Base.RotationPrLayer")*M_PI/180;
84     raft_z += basethickness;
85   }
86   rotation = settings.get_double("Raft","Interface.Rotation");
87   int if_layers = settings.get_integer("Raft","Interface.LayerCount");
88   for (int i = 0; i < if_layers; i++) {
89     Layer * layer = new Layer(lastlayer,
90 			      -settings.get_integer("Raft","Base.LayerCount") + i,
91 			      interthickness, 1);
92     layer->setZ(raft_z);
93     layer->CalcRaftInfill(raftpolys,
94 			  settings.get_double("Raft","Interface.MaterialDistanceRatio"),
95 			  settings.get_double("Raft","Interface.Distance"),
96 			  rotation);
97 
98     raft_layers.push_back(layer);
99     lastlayer = layer;
100     rotation += settings.get_double("Raft","Interface.RotationPrLayer")*M_PI/180;
101     raft_z += interthickness;
102   }
103   layers.insert(layers.begin(),raft_layers.begin(),raft_layers.end());
104   z += totalthickness;
105 }
106 
107 #if 0
108 // old raft
109 void Model::MakeRaft(GCodeState &state, double &z)
110 {
111   vector<Intersection> HitsBuffer;
112 
113   double raftSize = settings.Raft.Size;
114   Vector3d raftMin =  settings.Hardware.PrintMargin + Min;
115   Vector3d raftMax =  settings.Hardware.PrintMargin + Max + 2 * raftSize;
116   Vector2d Center = Vector2d((raftMin.x + raftMax.x) / 2,
117 			     (raftMin.y + raftMax.y) / 2);
118 
119   // bbox of object
120   double Length = (std::max(raftMax.x,raftMax.y) -
121 		   std::min(raftMin.x, raftMin.y))/sqrt(2.0);
122 
123   double rot;
124   uint LayerNr = 0;
125   uint layerCount = settings.Raft.Phase[0].LayerCount +
126 		    settings.Raft.Phase[1].LayerCount;
127   Settings::RaftSettings::PhasePropertiesType *props = &settings.Raft.Phase[0];
128 
129   double thickness = props->Thickness * settings.Hardware.LayerThickness;
130   double extrusionfactor = settings.Hardware.GetExtrudeFactor(thickness)
131     * props->MaterialDistanceRatio;
132 
133 
134   while(LayerNr < layerCount)
135     {
136       // If we finished phase 0, start phase 1 of the raft...
137       if (LayerNr >= settings.Raft.Phase[0].LayerCount)
138 	props = &settings.Raft.Phase[1];
139 
140       rot = (props->Rotation+(double)LayerNr * props->RotationPrLayer)/180.0*M_PI;
141       Vector2d InfillDirX(cosf(rot), sinf(rot));
142       Vector2d InfillDirY(-InfillDirX.y, InfillDirX.x);
143 
144       Vector3d LastPosition;
145       bool reverseLines = false;
146 
147       Vector2d P1, P2;
148       double maxerr = 0.1*props->Distance;
149       for(double x = -Length ; x < Length ; x+=props->Distance)
150 	{
151 	  P1 = (InfillDirX *  Length)+(InfillDirY*x) + Center;
152 	  P2 = (InfillDirX * -Length)+(InfillDirY*x) + Center;
153 
154 	  if(reverseLines)
155 	    {
156 	      Vector2d tmp = P1;
157 	      P1 = P2;
158 	      P2 = tmp;
159 	    }
160 
161 	  //			glBegin(GL_LINES);
162 	  //			glVertex2fv(&P1.x);
163 	  //			glVertex2fv(&P2.x);
164 
165 	  // Crop lines to bbox*size
166 	  Vector3d point;
167 	  Intersection hit;
168 	  HitsBuffer.clear();
169 	  Vector2d P3(raftMin.x, raftMin.y);
170 	  Vector2d P4(raftMin.x, raftMax.y);
171 	  //			glVertex2fv(&P3.x);
172 	  //			glVertex2fv(&P4.x);
173 	  if(IntersectXY(P1,P2,P3,P4,hit,maxerr))	//Intersect edges of bbox
174 	    HitsBuffer.push_back(hit);
175 	  P3 = Vector2d(raftMax.x,raftMax.y);
176 	  //			glVertex2fv(&P3.x);
177 	  //			glVertex2fv(&P4.x);
178 	  if(IntersectXY(P1,P2,P3,P4,hit,maxerr))
179 	    HitsBuffer.push_back(hit);
180 	  P4 = Vector2d(raftMax.x,raftMin.y);
181 	  //			glVertex2fv(&P3.x);
182 	  //			glVertex2fv(&P4.x);
183 	  if(IntersectXY(P1,P2,P3,P4,hit,maxerr))
184 	    HitsBuffer.push_back(hit);
185 	  P3 = Vector2d(raftMin.x,raftMin.y);
186 	  //			glVertex2fv(&P3.x);
187 	  //			glVertex2fv(&P4.x);
188 	  if(IntersectXY(P1,P2,P3,P4,hit,maxerr))
189 	    HitsBuffer.push_back(hit);
190 	  //			glEnd();
191 
192 	  if(HitsBuffer.size() == 0)	// it can only be 2 or zero
193 	    continue;
194 	  if(HitsBuffer.size() != 2)
195 	    continue;
196 
197 	  std::sort(HitsBuffer.begin(), HitsBuffer.end());
198 
199 	  P1 = HitsBuffer[0].p;
200 	  P2 = HitsBuffer[1].p;
201 
202 	  state.MakeGCodeLine (Vector3d(P1.x,P1.y,z),
203 			       Vector3d(P2.x,P2.y,z),
204 			       Vector3d(0,0,0), 0,
205 			       settings.Hardware.MaxPrintSpeedXY * 60,
206 			       extrusionfactor, 0,
207 			       z,
208 			       settings.Slicing, settings.Hardware);
209 	  reverseLines = !reverseLines;
210 	}
211       // Set startspeed for Z-move
212       Command g;
213       g.Code = SETSPEED;
214       g.where = Vector3d(P2.x, P2.y, z);
215       g.f=settings.Hardware.MinPrintSpeedZ * 60;
216       g.comment = "Move Z";
217       g.e = 0;
218       gcode.commands.push_back(g);
219       z += thickness;
220 
221       // Move Z
222       g.Code = ZMOVE;
223       g.where = Vector3d(P2.x, P2.y, z);
224       g.f = settings.Hardware.MinPrintSpeedZ * 60;
225       g.comment = "Move Z";
226       g.e = 0;
227       gcode.commands.push_back(g);
228 
229       LayerNr++;
230     }
231 
232   // restore the E state
233   // Command gotoE;
234   // gotoE.Code = GOTO;
235   // gotoE.e = 0;
236   // gotoE.comment = _("Reset E for the remaining print");
237   // gcode.commands.push_back(gotoE);
238 }
239 #endif // 0
240 
241 // this is of not much use, too fast
CleanupLayers()242 void Model::CleanupLayers()
243 {
244   int count = (int)layers.size();
245   if (count == 0) return;
246   if(!m_progress->restart (_("Cleanup"), count)) return;
247   int progress_steps=max(1,(int)(count/100));
248   bool cont = true;
249 
250 #ifdef _OPENMP
251   #pragma omp parallel for schedule(dynamic)
252 #endif
253   for (int i=0; i < count; i++) {
254 #ifdef _OPENMP
255       #pragma omp flush (cont)
256       if (!cont) continue;
257 #else
258       if (!cont) break;
259 #endif
260       if (i%progress_steps==0) {
261 #ifdef _OPENMP
262 	#pragma omp critical(updateProgress)
263 	{
264 	    cont = m_progress->update(i);
265 	    #pragma omp flush (cont)
266 	}
267 #else
268 	cont = m_progress->update(i);
269 #endif
270       }
271       layers[i]->cleanupPolygons();
272   }
273 }
274 
275 
layersort(const Layer * l1,const Layer * l2)276 bool layersort(const Layer * l1, const Layer * l2){
277   return (l1->Z < l2->Z);
278 }
279 
Slice()280 void Model::Slice()
281 {
282   vector<Shape*> shapes;
283   vector<Matrix4d> transforms;
284 
285   if (settings.get_boolean("Slicing","SelectedOnly"))
286     objtree.get_selected_shapes(m_current_selectionpath, shapes, transforms);
287   else
288     objtree.get_all_shapes(shapes,transforms);
289 
290   if (shapes.size() == 0) return;
291 
292   assert(shapes.size() == transforms.size());
293 
294   CalcBoundingBoxAndCenter(settings.get_boolean("Slicing","SelectedOnly"));
295 
296   for (uint i = 0; i<transforms.size(); i++)
297     transforms[i] = settings.getBasicTransformation(transforms[i]);
298 
299   assert(shapes.size() == transforms.size());
300 
301   int LayerNr = 0;
302   bool varSlicing = settings.get_boolean("Slicing","Varslicing");
303 
304   uint max_skins = max(1, settings.get_integer("Slicing","Skins"));
305   double thickness = (double)settings.get_double("Slicing","LayerThickness");
306   double skin_thickness = thickness / max_skins;
307   uint skins = max_skins; // probably variable
308 
309   // - Start at z~=0, cut off everything below
310   // - Offset it a bit in Z, z = 0 gives a empty slice because no triangle crosses this Z value
311   double minZ = thickness * settings.get_double("Slicing","FirstLayerHeight");// + Min.z;
312   Vector3d volume = settings.getPrintVolume();
313   double maxZ = min(Max.z(), volume.z() - settings.getPrintMargin().z());
314 
315   double max_gradient = 0;
316   double supportangle = settings.get_double("Slicing","SupportAngle")*M_PI/180.;
317   if (!settings.get_boolean("Slicing","Support")) supportangle = -1;
318 
319   m_progress->set_terminal_output(settings.get_boolean("Display","TerminalProgress"));
320   m_progress->start (_("Slicing"), maxZ);
321   // for (vector<Layer *>::iterator pIt = layers.begin();
322   //      pIt != layers. end(); pIt++)
323   //   delete *pIt;
324   ClearLayers();
325 
326   bool flatshapes = shapes.front()->dimensions() == 2;
327   if (flatshapes) {
328     layers.resize(1);
329     layers[0] = new Layer(lastlayer, 0, thickness  , 1);
330     lastlayer = layers[0];
331     layers[0]->setZ(0); // set to real z
332     for (uint nshape= 0; nshape < shapes.size(); nshape++) {
333       layers[0]->addShape(transforms[nshape], *shapes[nshape],  0, max_gradient, -1);
334     }
335     return;
336   }
337 
338   int progress_steps=max(1,(int)(maxZ/thickness/100.));
339 
340   if ((varSlicing && skins > 1) ||
341       (settings.get_boolean("Slicing","BuildSerial") && shapes.size() > 1))
342   {
343     // have skins and/or serial build, so can't parallelise
344     uint currentshape   = 0;
345     double serialheight = maxZ; // settings.Slicing.SerialBuildHeight;
346     double z            = minZ;
347     double shape_z      = z;
348     double max_shape_z  = z + serialheight;
349     Layer * layer = new Layer(lastlayer, LayerNr, thickness, 1); // first layer no skins
350     layer->setZ(shape_z);
351     LayerNr = 1;
352     int new_polys=0;
353     bool cont = true;
354     while(cont && z < maxZ)
355       {
356         shape_z = z;
357         max_shape_z = min(shape_z + serialheight, maxZ);
358         while ( cont && currentshape < shapes.size() && shape_z <= max_shape_z ) {
359   	if (LayerNr%progress_steps==0) cont = m_progress->update(shape_z);
360   	layer->setZ(shape_z); // set to real z
361   	if (shape_z == minZ) { // the layer is on the platform
362   	  layer->LayerNo = 0;
363   	  layer->setSkins(1);
364   	  LayerNr = 1;
365   	}
366   	new_polys = layer->addShape(transforms[currentshape], *shapes[currentshape],
367   				    shape_z, max_gradient, supportangle);
368   	// cerr << "Z="<<z<<", shapez="<< shape_z << ", shape "<<currentshape
369   	//      << " of "<< shapes.size()<< " polys:" << new_polys<<endl;
370   	if (shape_z >= max_shape_z) { // next shape, reset z
371   	  currentshape++;
372   	  shape_z = z;
373   	} else {  // next z, same shape
374   	  if (varSlicing && LayerNr!=0) {
375   	    // higher gradient -> slice thinner with fewer skin divisions
376   	    skins = max_skins-(uint)(max_skins* max_gradient);
377   	    thickness = skin_thickness*skins;
378   	  }
379   	  shape_z += thickness;
380   	  max_gradient = 0;
381   	  if (new_polys > -1){
382   	    layers.push_back(layer);
383   	    lastlayer = layer;
384   	    layer = new Layer(lastlayer, LayerNr++, thickness, skins);
385   	  }
386   	}
387         }
388         //thickness = max_thickness-(max_thickness-min_thickness)*max_gradient;
389         if (currentshape < shapes.size()-1) { // reached max_shape_z, next shape
390   	currentshape++;
391         } else { // end of shapes
392   	if (new_polys > -1){
393   	  if (varSlicing) {
394   	    skins = max_skins-(uint)(max_skins* max_gradient);
395   	    thickness = skin_thickness*skins;
396   	  }
397   	  layers.push_back(layer);
398   	  lastlayer = layer;
399   	  layer = new Layer(lastlayer, LayerNr++, thickness, skins);
400   	}
401   	z = max_shape_z + thickness;
402   	currentshape = 0; // all shapes again
403         }
404         max_gradient=0;
405         //cerr << "    Z="<<z << "Max.z="<<Max.z<<endl;
406       }
407     delete layer; // have made one more than needed
408     return;
409   }
410 
411   // simple case, can do multihreading
412 
413   int num_layers = (int)ceil((maxZ - minZ) / thickness);
414   layers.resize(num_layers);
415   int nlayer;
416   bool cont = true;
417 
418 #ifdef _OPENMP
419   #pragma omp parallel for schedule(dynamic)
420 #endif
421   for (nlayer = 0; nlayer < num_layers; nlayer++) {
422     double z = minZ + thickness * nlayer;
423     if (nlayer%progress_steps==0) {
424 #ifdef _OPENMP
425 	#pragma omp critical(updateProgress)
426 	{
427 	    cont = (m_progress->update(z));
428 	    #pragma omp flush (cont)
429 	}
430 #else
431         cont = (m_progress->update(z));
432 #endif
433     }
434 #ifdef _OPENMP
435     #pragma omp flush (cont)
436     if (!cont) continue;
437 #else
438     if (!cont) break;
439 #endif
440     Layer * layer = new Layer(NULL, nlayer, thickness, nlayer>0?skins:1);
441     layer->setZ(z); // set to real z
442     for (uint nshape= 0; nshape < shapes.size(); nshape++) {
443       layer->addShape(transforms[nshape], *shapes[nshape],
444 		      z, max_gradient, supportangle);
445     }
446     layers[nlayer] = layer;
447   }
448   if (!cont)
449     ClearLayers();
450 
451 #ifdef _OPENMP
452     //std::sort(layers.begin(), layers.end(), layersort);
453 #endif
454 
455   for (uint nlayer = 1; nlayer < layers.size(); nlayer++) {
456     layers[nlayer]->setPrevious(layers[nlayer-1]);
457     assert(layers[nlayer]->Z > layers[nlayer-1]->Z);
458   }
459   if (layers.size()>0)
460 	lastlayer = layers.back();
461 
462   // shapes.clear();
463   //m_progress->stop (_("Done"));
464 }
465 
MakeFullSkins()466 void Model::MakeFullSkins()
467 {
468   // not bottom layer
469 
470   if(!m_progress->restart (_("Skins"), layers.size())) return;
471   int progress_steps=max(1,(int)(layers.size()/100));
472   int count = (int)layers.size();
473 #ifdef _OPENMP
474   omp_lock_t progress_lock;
475   omp_init_lock(&progress_lock);
476 #pragma omp parallel for schedule(dynamic) //ordered
477 #endif
478   for (int i=1; i < count; i++) {
479 #ifdef _OPENMP
480 	omp_set_lock(&progress_lock);
481 #endif
482 	if (i%progress_steps==0 && !m_progress->update(i))
483 #ifndef _OPENMP
484 	  break;
485 #else
486 	  continue;
487 	omp_unset_lock(&progress_lock);
488 #endif
489     layers[i]->makeSkinPolygons();
490   }
491   //m_progress->stop (_("Done"));
492 }
493 
494 
MakeUncoveredPolygons(bool make_decor,bool make_bridges)495 void Model::MakeUncoveredPolygons(bool make_decor, bool make_bridges)
496 {
497   int count = (int)layers.size();
498   if (count == 0 ) return;
499   if (!m_progress->restart (_("Find Uncovered"), 2*count+2)) return;
500   int progress_steps=max(1,(int)((2*count+2)/100));
501   // bottom to top: uncovered from above -> top polys
502   for (int i = 0; i < count-1; i++)
503     {
504       if (i%progress_steps==0) if(!m_progress->update(i)) return ;
505       layers[i]->addFullPolygons(GetUncoveredPolygons(layers[i],layers[i+1]), make_decor);
506     }
507   // top to bottom: uncovered from below -> bridge polys
508   for (uint i = count-1; i > 0; i--)
509     {
510       //cerr << "layer " << i << endl;
511       if (i%progress_steps==0) if(!m_progress->update(count + count - i)) return;
512       //make_bridges = false;
513       // no bridge on marked layers (serial build)
514       bool mbridge = make_bridges && (layers[i]->LayerNo != 0);
515       if (mbridge) {
516 	vector<Poly> uncovered = GetUncoveredPolygons(layers[i],layers[i-1]);
517 	layers[i]->addBridgePolygons(Clipping::getExPolys(uncovered));
518 	layers[i]->calcBridgeAngles(layers[i-1]);
519       }
520       else {
521 	const vector<Poly> &uncovered = GetUncoveredPolygons(layers[i],layers[i-1]);
522 	layers[i]->addFullPolygons(uncovered,make_decor);
523       }
524     }
525   m_progress->update(2*count+1);
526   layers.front()->addFullPolygons(layers.front()->GetFillPolygons(), make_decor);
527   m_progress->update(2*count+2);
528   layers.back()->addFullPolygons(layers.back()->GetFillPolygons(), make_decor);
529   //m_progress->stop (_("Done"));
530 }
531 
532 // find polys in subjlayer that are not covered by shell of cliplayer
GetUncoveredPolygons(const Layer * subjlayer,const Layer * cliplayer)533 vector<Poly> Model::GetUncoveredPolygons(const Layer * subjlayer,
534 					 const Layer * cliplayer)
535 {
536   Clipping clipp;
537   clipp.clear();
538   clipp.addPolys(subjlayer->GetFillPolygons(),     subject);
539   clipp.addPolys(subjlayer->GetFullFillPolygons(), subject);
540   clipp.addPolys(subjlayer->GetBridgePolygons(),   subject);
541   clipp.addPolys(subjlayer->GetDecorPolygons(),    subject);
542   //clipp.addPolys(cliplayer->GetOuterShell(),       clip); // have some overlap
543   clipp.addPolys(*(cliplayer->GetInnerShell()),       clip); // have some more overlap
544   vector<Poly> uncovered = clipp.subtractMerged();
545   return uncovered;
546 }
547 
MultiplyUncoveredPolygons()548 void Model::MultiplyUncoveredPolygons()
549 {
550   if (!settings.get_boolean("Slicing","DoInfill") &&
551       settings.get_double("Slicing","SolidThickness") == 0.0) return;
552   if (settings.get_boolean("Slicing","NoTopAndBottom")) return;
553   int shells = (int)ceil(settings.get_double("Slicing","SolidThickness")/settings.get_double("Slicing","LayerThickness"));
554   shells = max(shells, (int)settings.get_integer("Slicing","ShellCount"));
555   if (shells<1) return;
556   int count = (int)layers.size();
557 
558   int numdecor = 0;
559   // add another full layer if making decor
560   if (settings.get_boolean("Slicing","MakeDecor"))
561     numdecor = settings.get_integer("Slicing","DecorLayers");
562   shells += numdecor;
563 
564   if (!m_progress->restart (_("Uncovered Shells"), count*3)) return;
565   int progress_steps=max(1,(int)(count*3/100));
566   // bottom-up: mulitply downwards
567   int i,s;
568   for (i=0; i < count; i++)
569     {
570       if (i%progress_steps==0) if(!m_progress->update(i)) return;
571       // (brigdepolys are not multiplied downwards)
572       const vector<Poly> &fullpolys     = layers[i]->GetFullFillPolygons();
573       const vector<Poly> &skinfullpolys = layers[i]->GetSkinFullPolygons();
574       const vector<Poly> &decorpolys    = layers[i]->GetDecorPolygons();
575       for (s=1; s < shells; s++)
576 	if (i-s > 1) {
577 	  layers[i-s]->addFullPolygons (fullpolys,     false);
578 	  layers[i-s]->addFullPolygons (skinfullpolys, false);
579 	  layers[i-s]->addFullPolygons (decorpolys,    s < numdecor);
580 	}
581     }
582   // top-down: mulitply upwards
583   for (int i=count-1; i>=0; i--)
584     {
585       if (i%progress_steps==0) if (!m_progress->update(count + count -i)) return;
586       const vector<Poly>   &fullpolys     = layers[i]->GetFullFillPolygons();
587       const vector<ExPoly> &bridgepolys   = layers[i]->GetBridgePolygons();
588       const vector<Poly>   &skinfullpolys = layers[i]->GetSkinFullPolygons();
589       const vector<Poly>   &decorpolys    = layers[i]->GetDecorPolygons();
590       for (int s=1; s < shells; s++)
591 	if (i+s < count){
592 	  layers[i+s]->addFullPolygons (fullpolys,     false);
593 	  layers[i+s]->addFullPolygons (bridgepolys,   false);
594 	  layers[i+s]->addFullPolygons (skinfullpolys, false);
595 	  layers[i+s]->addFullPolygons (decorpolys,    s < numdecor);
596 	}
597     }
598 
599   m_progress->set_label(_("Merging Full Polygons"));
600   // merge results
601   bool cont = true;
602 #ifdef _OPENMP
603   omp_lock_t progress_lock;
604   omp_init_lock(&progress_lock);
605 #pragma omp parallel for schedule(dynamic)
606 #endif
607   for (i=0; i < count; i++)
608     {
609       if (i%progress_steps==0) {
610 #ifdef _OPENMP
611 	omp_set_lock(&progress_lock);
612 #endif
613 	cont = (m_progress->update(count + count +i));
614 #ifdef _OPENMP
615 	omp_unset_lock(&progress_lock);
616 #endif
617       }
618       if (!cont) continue;
619       layers[i]->mergeFullPolygons(false);
620     }
621 #ifdef _OPENMP
622   omp_destroy_lock(&progress_lock);
623 #endif  //m_progress->stop (_("Done"));
624 }
625 
626 
MakeSupportPolygons(Layer * layer,const Layer * layerabove,double widen)627 void Model::MakeSupportPolygons(Layer * layer, // lower -> will change
628 				const Layer * layerabove,  // upper
629 				double widen)
630 {
631   const double distance =
632     settings.GetExtrudedMaterialWidth(layer->thickness);
633   // vector<Poly> tosupport = Clipping::getOffset(layerabove->GetToSupportPolygons(),
634   //  					       distance/2.);
635   //vector<Poly> tosupport = Clipping::getMerged(layerabove->GetToSupportPolygons(),
636   // 					       distance);
637   vector<Poly> tosupport = layerabove->GetToSupportPolygons();
638 
639   Clipping clipp;
640   clipp.addPolys(layerabove->GetSupportPolygons(),  subject);
641   clipp.addPolys(tosupport,                         subject);
642   clipp.addPolys(layer->GetPolygons(),              clip);
643   clipp.setZ(layer->getZ());
644 
645   vector<Poly> spolys = clipp.subtract(CL::pftNonZero,CL::pftEvenOdd);
646 
647   if (widen != 0) // widen from layer to layer
648     spolys = clipp.getOffset(spolys, widen * layer->thickness);
649 
650   spolys = clipp.getMerged(spolys,distance);
651 
652   layer->setSupportPolygons(spolys);
653 }
654 
MakeSupportPolygons(double widen)655 void Model::MakeSupportPolygons(double widen)
656 {
657   int count = layers.size();
658   if (!m_progress->restart (_("Support"), count*2)) return;
659   int progress_steps=max(1,(int)(count*2/100));
660 
661   for (int i=count-1; i>0; i--)
662     {
663       if (i%progress_steps==0) if(! m_progress->update(count-i)) return;
664       if (layers[i]->LayerNo == 0) continue;
665       MakeSupportPolygons(layers[i-1], layers[i], widen);
666     }
667 
668   // // shrink a bit
669   // Clipping clipp;
670   // for (int i=0; i<count; i++)
671   //   {
672   //     const double distance =
673   // 	settings.Hardware.GetExtrudedMaterialWidth(layers[i]->thickness);
674   //     if (i%progress_steps==0) if(!m_progress->update(i+count)) return;
675   //     vector<Poly> offset =
676   // 	Clipping::getOffset(layers[i]->GetSupportPolygons(), -distance);
677   //     layers[i]->setSupportPolygons(offset);
678   //   }
679 
680   //  m_progress->stop (_("Done"));
681 }
682 
MakeSkirt()683 void Model::MakeSkirt()
684 {
685 
686   if (!settings.get_boolean("Slicing","Skirt")) return;
687   double skirtdistance  = settings.get_double("Slicing","SkirtDistance");
688 
689   Clipping clipp;
690   guint count = layers.size();
691   guint endindex = 0;
692   // find maximum of all calculated skirts
693   clipp.clear();
694   double skirtheight = settings.get_double("Slicing","SkirtHeight");
695   bool singleskirt   = settings.get_boolean("Slicing","SingleSkirt");
696   bool support       = settings.get_boolean("Slicing","Support");
697   for (guint i=0; i < count; i++)
698     {
699       if (layers[i]->getZ() > skirtheight)
700 	break;
701       layers[i]->MakeSkirt(skirtdistance, singleskirt && !support);
702       vector<Poly> sp = layers[i]->GetSkirtPolygons();
703       clipp.addPolys(sp,subject);
704       endindex = i;
705     }
706   vector<Poly> skirts = clipp.unite(CL::pftPositive,CL::pftPositive);
707   // set this skirt for all skirted layers
708   if (skirts.size()>0)
709     for (guint i=0; i<=endindex; i++) {
710       layers[i]->setSkirtPolygons(skirts);
711   }
712 }
713 
MakeShells()714 void Model::MakeShells()
715 {
716   int count = (int)layers.size();
717   if (count == 0) return;
718   if (!m_progress->restart (_("Shells"), count)) return;
719   int progress_steps=max(1,(int)(count/100));
720   bool cont = true;
721 #ifdef _OPENMP
722   omp_lock_t progress_lock;
723   omp_init_lock(&progress_lock);
724 #pragma omp parallel for schedule(dynamic)
725 #endif
726   for (int i=0;  i < count; i++)
727     {
728       if (i%progress_steps==0) {
729 #ifdef _OPENMP
730 	omp_set_lock(&progress_lock);
731 #endif
732 	cont = (m_progress->update(i));
733 #ifdef _OPENMP
734 	omp_unset_lock(&progress_lock);
735 #endif
736       }
737       if (!cont) continue;
738       layers[i]->MakeShells(settings);
739     }
740 #ifdef _OPENMP
741   omp_destroy_lock(&progress_lock);
742 #endif
743   m_progress->update(count);
744   //m_progress->stop (_("Done"));
745 }
746 
747 
CalcInfill()748 void Model::CalcInfill()
749 {
750   if (!settings.get_boolean("Slicing","DoInfill") &&
751       settings.get_double("Slicing","SolidThickness") == 0.0) return;
752 
753   int count = (int)layers.size();
754   m_progress->start (_("Infill"), count);
755   int progress_steps=max(1,(count/100));
756   bool cont = true;
757   //cerr << "make infill"<< endl;
758 #ifdef _OPENMP
759   omp_lock_t progress_lock;
760   omp_init_lock(&progress_lock);
761 #pragma omp parallel for schedule(dynamic)
762 #endif
763   for (int i=0; i < count ; i++)
764     {
765       //cerr << "thread " << omp_get_thread_num() << endl;
766       if (i%progress_steps==0){
767 #ifdef _OPENMP
768 	omp_set_lock(&progress_lock);
769 #endif
770 	cont = (m_progress->update(i));
771 #ifdef _OPENMP
772 	omp_unset_lock(&progress_lock);
773 #endif
774       }
775       if (!cont) continue;
776       layers[i]->CalcInfill(settings);
777     }
778 #ifdef _OPENMP
779   omp_destroy_lock(&progress_lock);
780 #endif
781   //m_progress->stop (_("Done"));
782 }
783 
784 
ConvertToGCode()785 void Model::ConvertToGCode()
786 {
787   if (is_calculating) {
788     return;
789   }
790   is_calculating=true;
791 
792   // default:
793   settings.SelectExtruder(0);
794 
795   Glib::TimeVal start_time;
796   start_time.assign_current_time();
797 
798   gcode.clear();
799 
800   GCodeState state(gcode);
801 
802   Infill::clearPatterns();
803 
804   Vector3d printOffset  = settings.getPrintMargin();
805   double   printOffsetZ = printOffset.z();
806 
807   // Make Layers
808   lastlayer = NULL;
809 
810 
811   Slice();
812 
813   //CleanupLayers();
814 
815   MakeShells();
816 
817   if (settings.get_boolean("Slicing","DoInfill") &&
818       !settings.get_boolean("Slicing","NoTopAndBottom") &&
819       (settings.get_double("Slicing","SolidThickness") > 0 ||
820        settings.get_integer("Slicing","ShellCount") > 0))
821     // not bridging when support
822     MakeUncoveredPolygons( settings.get_boolean("Slicing","MakeDecor"),
823 			   !settings.get_boolean("Slicing","NoBridges") &&
824 			   !settings.get_boolean("Slicing","Support") );
825 
826   if (settings.get_boolean("Slicing","Support"))
827     // easier before having multiplied uncovered bottoms
828     MakeSupportPolygons(settings.get_double("Slicing","SupportWiden"));
829 
830   MakeFullSkins(); // must before multiplied uncovered bottoms
831 
832   MultiplyUncoveredPolygons();
833 
834   if (settings.get_boolean("Slicing","Skirt"))
835     MakeSkirt();
836 
837   CalcInfill();
838 
839   if (settings.get_boolean("Raft","Enable"))
840     {
841       printOffset += Vector3d (settings.get_double("Raft","Size"), 0);
842       MakeRaft (state, printOffsetZ); // printOffsetZ will have height of raft added
843     }
844 
845   state.ResetLastWhere(Vector3d(0,0,0));
846   uint count =  layers.size();
847 
848   m_progress->start (_("Making Lines"), count+1);
849 
850   state.AppendCommand(MILLIMETERSASUNITS,  false, _("Millimeters"));
851   state.AppendCommand(ABSOLUTEPOSITIONING, false, _("Absolute Pos"));
852   if (settings.get_boolean("Slicing","RelativeEcode"))
853     state.AppendCommand(RELATIVE_ECODE, false, _("Relative E Code"));
854   else
855     state.AppendCommand(ABSOLUTE_ECODE, false, _("Absolute E Code"));
856 
857   bool cont = true;
858   vector<PLine3> plines;
859   bool farthestStart = settings.get_boolean("Slicing","FarthestLayerStart");
860   Vector3d start = state.LastPosition();
861   for (uint p=0; p<count; p++) {
862     cont = (m_progress->update(p)) ;
863     if (!cont) break;
864     // cerr << "GCode layer " << (p+1) << " of " << count
865     // 	 << " offset " << printOffsetZ
866     // 	 << " have commands: " <<commands.size()
867     // 	 << " start " << start <<  endl;;
868     // try {
869     if (farthestStart) {
870       // Vector2d randstart = layers[p]->getRandomPolygonPoint();
871       // start.set(randstart.x(), randstart.y());
872       const Vector2d fartheststart = layers[p]->getFarthestPolygonPoint(start);
873       start.set(fartheststart.x(), fartheststart.y());
874     }
875     layers[p]->MakePrintlines(start,
876 			      plines,
877 			      printOffsetZ,
878 			      settings);
879     // } catch (Glib::Error e) {
880     //   error("GCode Error:", (e.what()).c_str());
881     // }
882     // if (layers[p]->getPrevious() != NULL)
883     //   cerr << p << ": " <<layers[p]->LayerNo << " prev: "
884     // 	   << layers[p]->getPrevious()->LayerNo << endl;
885   }
886   // do antiooze retract for all lines:
887   Printlines::makeAntioozeRetract(plines, settings, m_progress);
888   vector<Command> commands;
889   //Printlines::getCommands(plines, settings, commands, m_progress);
890   Printlines::getCommands(plines, settings, state, m_progress);
891 
892   //state.AppendCommands(commands, settings.Slicing.RelativeEcode);
893 
894   string GcodeTxt;
895   if (cont)
896     gcode.MakeText (GcodeTxt, settings, m_progress);
897   else {
898     ClearLayers();
899     ClearGCode();
900     ClearPreview();
901   }
902 
903   // display whole layer if flat shapes
904   // if (shapes.back()->dimensions() == 2)
905   //   gcode.layerchanges.push_back(0);
906 
907   m_progress->stop (_("Done"));
908 
909   int h = (int)state.timeused/3600;
910   int m = ((int)state.timeused%3600)/60;
911   int s = ((int)state.timeused-3600*h-60*m);
912   std::ostringstream ostr;
913   ostr << _("Time Estimation: ") ;
914   if (h>0) ostr << h <<_("h") ;
915   ostr <<m <<_("m") <<s <<_("s") ;
916 
917   double gctime = gcode.GetTimeEstimation();
918   if (abs(state.timeused - gctime) > 10) {
919     h = (int)(gctime/3600);
920     m = ((int)gctime)%3600/60;
921     s = (int)(gctime)-3600*h-60*m;
922     ostr << _(" / GCode Estimation: ");
923     if (h>0) ostr << h <<_("h");
924     ostr<< m <<_("m") << s <<_("s") ;
925   }
926 
927   double totlength = gcode.GetTotalExtruded(settings.get_boolean("Slicing","RelativeEcode"));
928   ostr << _(" - total extruded: ") << totlength << "mm";
929   // TODO: ths assumes all extruders use the same filament diameter
930   const double diam = settings.get_double("Extruder","FilamentDiameter");
931   const double ccm = totlength * diam * diam / 4. * M_PI / 1000 ;
932   ostr << " = " << ccm << "cm^3 ";
933   ostr << "(ABS~" << ccm*1.08 << "g, PLA~" << ccm*1.25 << "g)";
934   if (statusbar)
935     statusbar->push(ostr.str());
936   else
937     cout << ostr.str() << endl;
938 
939   {
940     Glib::TimeVal now;
941     now.assign_current_time();
942     const int time_used = (int) round((now - start_time).as_double()); // seconds
943     cerr << "GCode generated in " << time_used << " seconds. " << GcodeTxt.size() << " bytes" << endl;
944   }
945 
946   is_calculating=false;
947   m_signal_gcode_changed.emit();
948 }
949 
getSVG(int single_layer_no) const950 string Model::getSVG(int single_layer_no) const
951 {
952   Vector3d printOffset  = settings.getPrintMargin();
953 
954   ostringstream ostr;
955   ostr << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" <<endl
956        << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">" << endl
957        << "<!-- Created by Repsnapper -->" << endl
958        << "<svg " << endl
959        << "\txmlns:svg=\"http://www.w3.org/2000/svg\""<< endl
960        << "\txmlns=\"http://www.w3.org/2000/svg\"" << endl
961     //<< "\tversion=\"1.1\"" << endl
962        << "\twidth=\"" << Max.x()-Min.x()+printOffset.x()
963        << "\" height=\""<< Max.y()-Min.y()+printOffset.y() << "\"" << endl
964        << ">" << endl;
965   if (single_layer_no<0) {
966     ostr << "<g id=\"" << layers.size() << "_Layers\">" << endl;
967     for (uint i = 0; i < layers.size(); i++) {
968       ostr << "\t\t" << layers[i]->SVGpath() << endl;
969     }
970   } else {
971     ostr << "<g id=\"" << "Layer_" << single_layer_no
972 	 << "_of_" <<layers.size() << "\">" << endl;
973     ostr << "\t\t" << layers[single_layer_no]->SVGpath() << endl;
974   }
975   ostr << "</g>" << endl;
976   ostr << "</svg>" << endl;
977   return ostr.str();
978 }
979 
SliceToSVG(Glib::RefPtr<Gio::File> file,bool single_layer)980 void Model::SliceToSVG(Glib::RefPtr<Gio::File> file, bool single_layer)
981 {
982   if (is_calculating) return;
983   is_calculating=true;
984 
985   lastlayer = NULL;
986   Slice();
987   m_progress->stop (_("Done"));
988   if (!single_layer) {
989     Glib::file_set_contents (file->get_path(), getSVG());
990   }
991   else {
992     uint n_layers = layers.size();
993     m_progress->start (_("Saving Files"),n_layers);
994     uint digits = log10(n_layers)+1;
995     string base = file->get_path();
996     ostringstream ostr;
997     for (uint i = 0; i < n_layers; i++) {
998       ostr.str("");
999       ostr << base;
1000       uint nzero = (uint)(digits - log10(i+1));
1001       if (i==0) nzero = digits-1;
1002       for (uint d = 0; d < nzero; d++)
1003 	ostr << "0";
1004       ostr << i
1005 	   << ".svg";
1006       if (!m_progress->update(i)) break;
1007       Glib::file_set_contents (ostr.str(), getSVG(i));
1008     }
1009     m_progress->stop (_("Done"));
1010   }
1011   string directory_path = file->get_parent()->get_path();
1012   settings.STLPath = directory_path;
1013   is_calculating = false;
1014 }
1015 
1016