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