1 /*
2     This file is a part of the RepSnapper project.
3     Copyright (C) 2010  Kulitorum
4     Copyright (C) 2012  martin.dieringer@gmx.de
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "layer.h"
22 #include "poly.h"
23 #include "shape.h"
24 #include "infill.h"
25 #include "render.h"
26 
27 // polygons will be simplified to thickness/CLEANFACTOR
28 #define CLEANFACTOR 7
29 
Layer(Layer * prevlayer,int layerno,double thick,uint skins)30 Layer::Layer(Layer * prevlayer, int layerno, double thick, uint skins)
31   : LayerNo(layerno), thickness(thick), previous(prevlayer), skins(skins)
32 {
33   normalInfill = NULL;
34   fullInfill = NULL;
35   skirtInfill = NULL;
36   supportInfill = NULL;
37   decorInfill = NULL;
38   thinInfill = NULL;
39   Min = Vector2d(G_MAXDOUBLE, G_MAXDOUBLE);
40   Max = Vector2d(G_MINDOUBLE, G_MINDOUBLE);
41 }
42 
~Layer()43 Layer::~Layer()
44 {
45   Clear();
46 }
47 
48 
Clear()49 void Layer::Clear()
50 {
51   delete normalInfill; normalInfill = NULL;
52   delete fullInfill; fullInfill = NULL;
53   delete skirtInfill; skirtInfill = NULL;
54   delete supportInfill; supportInfill = NULL;
55   delete decorInfill; decorInfill = NULL;
56   delete thinInfill; thinInfill = NULL;
57   skinFullInfills.clear();
58   clearpolys(polygons);
59   clearpolys(shellPolygons);
60   clearpolys(fillPolygons);
61   clearpolys(thinPolygons);
62   clearpolys(fullFillPolygons);
63   clearpolys(bridgePolygons);
64   clearpolys(bridgePillars);
65   bridge_angles.clear();
66   bridgeInfills.clear();
67   clearpolys(decorPolygons);
68   clearpolys(supportPolygons);
69   clearpolys(toSupportPolygons);
70   clearpolys(skinPolygons);
71   clearpolys(skinFullFillPolygons);
72   hullPolygon.clear();
73   clearpolys(skirtPolygons);
74 }
75 
76 // void Layer::setBBox(Vector2d min, Vector2d max)
77 // {
78 //   Min.x() = MIN(Min.x(),min.x());
79 //   Min.y = MIN(Min.y,min.y);
80 //   Max.x() = MAX(Max.x(),max.x());
81 //   Max.y = MAX(Max.y,max.y);
82 // }
83 // void Layer::setBBox(vector<Vector2d> minmax)
84 // {
85 //   setBBox(minmax[0],minmax[1]);
86 // }
87 // void Layer::setBBox(Vector3d min, Vector3d max)
88 // {
89 //   Min.x() = MIN(Min.x(),min.x());
90 //   Min.y = MIN(Min.y,min.y);
91 //   Max.x() = MAX(Max.x(),max.x());
92 //   Max.y = MAX(Max.y,max.y);
93 // }
94 
95 
SetPolygons(vector<Poly> & polys)96 void Layer::SetPolygons(vector<Poly> &polys) {
97   this->polygons = polys;
98   for(uint i=0;i<polygons.size();i++){
99     polygons[i].setZ(Z);
100   }
101 }
102 
103 // //not used
104 // void Layer::SetPolygons(const Matrix4d &T, const Shape &shape,
105 // 			double z) {
106 //   cerr << "Layer::SetPolygons" << endl;
107 //   double offsetZ = Z;
108 //   bool polys_ok=false;
109 //   while (!polys_ok) {
110 //     double max_grad;
111 //     polys_ok = shape.getPolygonsAtZ(T, offsetZ, polygons, max_grad);
112 //     offsetZ+=thickness/10.;
113 //   }
114 //   for(uint i=0;i<polygons.size();i++){
115 //     polygons[i].setZ(Z);
116 //   }
117 // }
118 
getRandomPolygonPoint() const119 Vector2d Layer::getRandomPolygonPoint() const
120 {
121   if (polygons.size() == 0) return Vector2d(0.,0.);
122   Poly p = polygons[rand()%polygons.size()];
123   return p.vertices[rand()%p.size()];
124 }
getFarthestPolygonPoint(const Vector2d & from) const125 Vector2d Layer::getFarthestPolygonPoint(const Vector2d &from) const
126 {
127   if (polygons.size() == 0) return from;
128   uint pindex = 0, pvindex = 0;
129   double maxdist = 0.;
130   for (uint i = 0; i<polygons.size(); i++) {
131     uint fi = polygons[i].getFarthestIndex(from);
132     double pdist = from.squared_distance(polygons[i][fi]);
133     if (pdist > maxdist) {
134       maxdist = pdist;
135       pindex = i;
136       pvindex = fi;
137     }
138   }
139   return polygons[pindex][pvindex];
140 }
141 
pointInPolygons(const Vector2d & p) const142 bool Layer::pointInPolygons(const Vector2d &p) const
143 {
144   for (uint i = 0; i<polygons.size(); i++)
145     if (!polygons[i].isHole() && polygons[i].vertexInside(p)) return true;
146   return false;
147 }
148 
149 
addShape(const Matrix4d & T,const Shape & shape,double z,double & max_gradient,double max_supportangle)150 int Layer::addShape(const Matrix4d &T, const Shape &shape, double z,
151 		    double &max_gradient, double max_supportangle)
152 {
153   double hackedZ = z;
154   bool polys_ok = false;
155   vector<Poly> polys;
156   int num_polys=-1;
157   // try to slice until polygons can be made, otherwise hack z
158   while (!polys_ok && hackedZ < z+thickness) {
159     polys.clear();
160     polys_ok = shape.getPolygonsAtZ(T, hackedZ,  // slice shape at hackedZ
161 				    polys, max_gradient,
162 				    toSupportPolygons, max_supportangle,
163 				    thickness);
164     if (polys_ok) {
165       num_polys = polys.size();
166       addPolygons(polys);
167     } else {
168       num_polys=-1;
169       hackedZ += thickness/10;
170       cerr << "hacked Z " << z << " -> " << hackedZ << endl;
171     }
172   }
173   cleanupPolygons();
174   return num_polys;
175 }
176 
cleanupPolygons()177 void Layer::cleanupPolygons()
178 {
179   double clean = thickness/CLEANFACTOR;
180   for(uint i=0; i < polygons.size(); i++){
181     polygons[i].cleanup(clean);
182   }
183 }
184 
addPolygons(vector<Poly> & polys)185 void Layer::addPolygons(vector<Poly> &polys)
186 {
187   for(uint i=0;i<polys.size();i++){
188     polys[i].setZ(Z);
189   }
190   polygons.insert(polygons.end(),polys.begin(),polys.end());
191 }
192 
193 
calcBridgeAngles(const Layer * layerbelow)194 void Layer::calcBridgeAngles(const Layer *layerbelow) {
195   bridge_angles.resize(bridgePolygons.size());
196   Clipping clipp;
197   vector<Poly> polysbelow = *(layerbelow->GetInnerShell());//clipp.getOffset(polygons,3*thickness);
198   bridgePillars.resize(bridgePolygons.size());
199   for (uint i=0; i<bridgePolygons.size(); i++)
200     {
201       // intersect bridge poly with polygons below (=pillars of bridge)
202       clipp.clear();
203       clipp.addPolys(polysbelow,subject);
204       clipp.addPolys(clipp.getOffset(bridgePolygons[i].outer,thickness),clip);
205       bridgePillars[i] = clipp.intersect();
206 
207       // TODO detect circular bridges -> rotating infill?
208 
209       // get average direction of the mutual connections of all the intersections
210       Vector2d dir(0,0);
211       for (uint p=0; p<bridgePillars[i].size(); p++){
212 	for (uint q=p+1; q<bridgePillars[i].size(); q++){
213 	  // Vector2d p1,p2;
214 	  // bridgePillars[i][q].shortestConnectionSq(bridgePillars[i][p], p1,p2);
215 	  // dir += (p2-p1);
216 	  dir += bridgePillars[i][q].center - bridgePillars[i][p].center;
217 	}
218       }
219       //cerr << pillars.size() << " - " << dir << endl;
220       bridge_angles[i] = atan2(dir.y(),dir.x());
221       if (bridge_angles[i]<0) bridge_angles[i]+=M_PI;
222     }
223 }
224 
225 // these are used for the bridge polys of the layer above
226 // NOT USED, NOT TESTED, using calcBridgeAngles
getBridgeRotations(const vector<Poly> & polys) const227 vector <double> Layer::getBridgeRotations(const vector<Poly> &polys) const{
228   cerr << "Layer::getBridgeRotations" << endl;
229   vector<double> angles; angles.resize(polys.size());
230   Clipping clipp;
231   vector<Poly> offset = polygons;//clipp.getOffset(polygons,3*thickness);
232   for (uint i=0; i<polys.size(); i++)
233     {
234       // intersect bridge poly with polygons below (=pillars of bridge)
235       clipp.clear();
236       clipp.addPolys(offset,subject);
237       clipp.addPolys(clipp.getOffset(polys[i],2*thickness),clip);
238       vector<Poly> pillars = clipp.intersect();
239       // get average direction of the connection lines of all the intersections
240       Vector2d dir(0,0);
241       for (uint p=0; p<pillars.size(); p++){
242 	for (uint q=p+1; q<pillars.size(); q++){
243 	  dir+=pillars[q].center-pillars[p].center;
244 	}
245       }
246       //cerr << pillars.size() << " - " << dir << endl;
247       angles[i] = atan2(dir.y(),dir.x());
248     }
249   return angles;
250 }
251 
252 // fills polys with raft type infill
253 // so this layer will have the raft as normal infill
CalcRaftInfill(const vector<Poly> & polys,double extrusionfactor,double infilldistance,double rotation)254 void Layer::CalcRaftInfill (const vector<Poly> &polys,
255 			    double extrusionfactor, double infilldistance,
256 			    double rotation)
257 {
258   setMinMax(polys);
259   normalInfill = new Infill(this, extrusionfactor);
260   normalInfill->setName("Raft");
261   normalInfill->addPolys(Z, polys, RaftInfill,
262 			 infilldistance, infilldistance, rotation);
263 }
264 
CalcInfill(const Settings & settings)265 void Layer::CalcInfill (const Settings &settings)
266 {
267   // inFill distances in real mm:
268   // for full polys/layers:
269   double fullInfillDistance=0;
270   double infillDistance=0; // normal fill
271   double altInfillDistance=0;
272   double altInfillPercent=settings.get_double("Slicing","InfillPercent");
273   double normalInfilldist=0;
274   bool shellOnly = !settings.get_boolean("Slicing","DoInfill");
275   fullInfillDistance = settings.GetInfillDistance(thickness, 100);
276 
277   if (settings.get_double("Slicing","InfillPercent") == 0)
278     shellOnly = true;
279   else
280     infillDistance = settings.GetInfillDistance(thickness,altInfillPercent);
281   int altinfill = settings.get_integer("Slicing","AltInfillLayers");
282   normalInfilldist = infillDistance;
283   if ( altinfill != 0  && LayerNo % altinfill == 0 && altInfillPercent != 0) {
284     altInfillDistance = settings.GetInfillDistance(thickness,
285 						   settings.get_double("Slicing","AltInfillPercent"));
286     normalInfilldist = altInfillDistance;
287   }
288   // first layers:
289   if (LayerNo < (int)settings.get_integer("Slicing","FirstLayersNum")) {
290     double first_infdist =
291       fullInfillDistance * (1.+settings.get_double("Slicing","FirstLayersInfillDist"));
292     normalInfilldist   = max(normalInfilldist,   first_infdist);
293     fullInfillDistance = max(fullInfillDistance, first_infdist);
294   }
295   // relative extrusion for skins:
296   double skinfillextrf = settings.get_double("Slicing","FullFillExtrusion")/skins/skins;
297   normalInfill = new Infill(this,settings.get_double("Slicing","NormalFillExtrusion"));
298   normalInfill->setName("normal");
299   fullInfill = new Infill(this,settings.get_double("Slicing","FullFillExtrusion"));
300   fullInfill->setName("full");
301   skirtInfill = new Infill(this,settings.get_double("Slicing","FullFillExtrusion"));
302   skirtInfill->setName("skirt");
303   skinFullInfills.clear();
304   supportInfill = new Infill(this,settings.get_double("Slicing","SupportExtrusion"));
305   supportInfill->setName("support");
306   decorInfill = new Infill(this,1.);
307   decorInfill->setName("decor");
308   thinInfill = new Infill(this, 1.);
309   thinInfill->setName("thin");
310 
311   double rot = (settings.get_double("Slicing","InfillRotation"),
312 		+ (double)LayerNo*settings.get_double("Slicing","InfillRotationPrLayer"))/180.0*M_PI;
313   if (!shellOnly)
314     normalInfill->addPolys(Z, fillPolygons, (InfillType)settings.get_integer("Slicing","NormalFilltype"),
315 			   normalInfilldist, fullInfillDistance, rot);
316 
317   if (settings.get_boolean("Slicing","FillSkirt")) {
318     vector<Poly> skirtFill;
319     Clipping clipp;
320     clipp.addPolys(skirtPolygons, subject);
321     clipp.addPolys(*GetOuterShell(), clip);
322     clipp.addPolys(supportPolygons, clip);
323     skirtFill = clipp.subtract();
324     skirtFill = Clipping::getOffset(skirtFill, -fullInfillDistance);
325     skirtInfill->addPolys(Z, skirtFill, (InfillType)settings.get_integer("Slicing","FullFilltype"),
326 			  fullInfillDistance, fullInfillDistance, rot);
327   }
328 
329   fullInfill->addPolys(Z, fullFillPolygons, (InfillType)settings.get_integer("Slicing","FullFilltype"),
330 		       fullInfillDistance, fullInfillDistance, rot);
331 
332   decorInfill->addPolys(Z, decorPolygons, (InfillType)settings.get_integer("Slicing","DecorFilltype"),
333 			settings.get_double("Slicing","DecorInfillDistance"),
334 			settings.get_double("Slicing","DecorInfillDistance"),
335 			settings.get_double("Slicing","DecorInfillRotation")/180.0*M_PI);
336 
337   assert(bridge_angles.size() >= bridgePolygons.size());
338   bridgeInfills.resize(bridgePolygons.size());
339   for (uint b=0; b < bridgePolygons.size(); b++){
340     bridgeInfills[b] = new Infill(this, settings.get_double("Slicing","BridgeExtrusion"));
341     bridgeInfills[b]->addPoly(Z, bridgePolygons[b], BridgeInfill,
342 			      fullInfillDistance, fullInfillDistance,
343 			      bridge_angles[b]+M_PI/2);
344   }
345 
346   if (skins>1) {
347     double skindistance = fullInfillDistance/skins;
348     for (uint s = 0; s<skins; s++){
349       double drot = rot + settings.get_double("Slicing","InfillRotationPrLayer")/180.0*M_PI*s;
350       double sz = Z-thickness + (s+1)*thickness/skins;
351       Infill *inf = new Infill(this, skinfillextrf);
352       inf->setName("skin");
353       inf->addPolys(sz, skinFullFillPolygons, (InfillType)settings.get_integer("Slicing","FullFilltype"),
354 		    skindistance, skindistance, drot);
355       skinFullInfills.push_back(inf);
356     }
357   }
358   supportInfill->addPolys(Z, supportPolygons,
359 			  (InfillType)settings.get_integer("Slicing","SupportFilltype"),
360 			  settings.get_double("Slicing","SupportInfillDistance"),
361 			  settings.get_double("Slicing","SupportInfillDistance"), 0);
362 
363   thinInfill->addPolys(Z, thinPolygons, ThinInfill,
364 		       fullInfillDistance, fullInfillDistance, 0);
365 }
366 
367 
368 // call before full fill areas are multiplied
makeSkinPolygons()369 void Layer::makeSkinPolygons()
370 {
371   if (skins<2) return;
372   skinFullFillPolygons = fullFillPolygons;
373   fullFillPolygons.clear();
374 }
375 
376 // add bridge polys and subtract them from normal and full fill polys
377 // each given ExPoly is a single bridge with its holes
addBridgePolygons(const vector<ExPoly> & newexpolys)378 void Layer::addBridgePolygons(const vector<ExPoly> &newexpolys)
379 {
380   // clip against normal fill and make these areas into bridges:
381   Clipping clipp;
382   uint num_bridges = newexpolys.size();
383   if (num_bridges==0) return;
384   clipp.clear();
385   bridgePolygons.clear();
386   for (uint i=0; i < num_bridges; i++){
387     vector<Poly> newpolys = Clipping::getPolys(newexpolys[i]);
388     clipp.clear();
389     clipp.addPolys(fillPolygons,subject);
390     clipp.addPolys(newpolys, clip);
391     vector<ExPoly> exbridges = clipp.ext_intersect();
392     bridgePolygons.insert(bridgePolygons.end(),exbridges.begin(),exbridges.end());
393   }
394   // subtract from normal fill
395   clipp.clear();
396   clipp.addPolys(fillPolygons,subject);
397   clipp.addPolys(newexpolys, clip);
398   setNormalFillPolygons(clipp.subtract());
399 }
400 
addFullPolygons(const vector<ExPoly> & newpolys,bool decor)401 void Layer::addFullPolygons(const vector<ExPoly> &newpolys, bool decor)
402 {
403   addFullPolygons(Clipping::getPolys(newpolys),decor);
404 }
405 
406 // add full fill and subtract them from normal fill polys
addFullPolygons(const vector<Poly> & newpolys,bool decor)407 void Layer::addFullPolygons(const vector<Poly> &newpolys, bool decor)
408 {
409   if (newpolys.size()==0) return;
410   Clipping clipp;
411   clipp.clear();
412   // full fill only where already normal fill
413   clipp.addPolys(fillPolygons,subject);
414   if (decor) clipp.addPolys(fullFillPolygons,subject);
415   clipp.addPolys(newpolys,clip);
416   clipp.setZ(Z);
417   vector<Poly> inter = clipp.intersect();
418   vector<Poly> normals = clipp.subtractMerged(thickness/2.);
419   if (decor) {//  && LayerNo != 0) // no decor on base layers
420     decorPolygons.insert(decorPolygons.end(), inter.begin(), inter.end());
421     Clipping clipp;
422     clipp.addPolys(fullFillPolygons,subject);
423     clipp.addPolys(inter,clip);
424     clipp.setZ(Z);
425     setFullFillPolygons(clipp.subtract());
426   }
427   else {
428     fullFillPolygons.insert(fullFillPolygons.end(),inter.begin(),inter.end());
429   }
430 
431   setNormalFillPolygons(normals);
432   //  mergeFullPolygons(false); // done separately
433 }
434 
cleanup(vector<Poly> & polys,double error)435 void cleanup(vector<Poly> &polys, double error)
436 {
437   for (uint i = 0; i<polys.size(); i++)
438     polys[i].cleanup(error);
439 }
440 
mergeFullPolygons(bool bridge)441 void Layer::mergeFullPolygons(bool bridge)
442 {
443   // if (bridge) {
444   //   // setBridgePolygons(Clipping::getMerged(bridgePolygons, thickness));
445   //   // clipp.addPolys(bridgePolygons,clip);
446   // } else {
447   //subtract decor from full
448   Clipping clipp;
449   // clipp.addPolys(fullFillPolygons,subject);
450   // clipp.addPolys(decorPolygons,clip);
451   // setFullFillPolygons(clipp.subtract());
452 
453   setFullFillPolygons(Clipping::getMerged(fullFillPolygons, thickness));
454   cleanup(fullFillPolygons, thickness/CLEANFACTOR);
455   //subtract from normal fills
456   clipp.clear();
457   cleanup(fillPolygons, thickness/CLEANFACTOR);
458   clipp.addPolys(fillPolygons,subject);
459   clipp.addPolys(fullFillPolygons,clip);
460   clipp.addPolys(decorPolygons,clip);
461   vector<Poly> normals = clipp.subtractMerged();
462   setNormalFillPolygons(normals);
463   // }
464 }
mergeSupportPolygons()465 void Layer::mergeSupportPolygons()
466 {
467   setSupportPolygons(Clipping::getMerged(GetSupportPolygons()));
468 }
469 
GetInnerShell() const470 const vector<Poly> * Layer::GetInnerShell() const
471 {
472   // if (fillPolygons.size()>0) return fillPolygons;
473   // // no offset
474   if (shellPolygons.size()>0) return &(shellPolygons.back());
475   // no shells:
476   if (skinPolygons.size()>0) return &skinPolygons;
477   // no skins
478   return &polygons;
479 }
GetOuterShell() const480 const vector<Poly> * Layer::GetOuterShell() const
481 {
482   if (skinPolygons.size()>0) return &skinPolygons;
483   // no skins
484   if (shellPolygons.size()>0) return &(shellPolygons.front());
485   // no shells:
486   if (fillPolygons.size()>0) return &fillPolygons;
487   // no offset
488   return &polygons;
489 }
490 
GetExPolygons() const491 vector<ExPoly> Layer::GetExPolygons() const
492 {
493   return Clipping::getExPolys(polygons,0,0);
494 }
495 
496 // circular numbering
GetShellPolygonsCirc(int number) const497 vector<Poly> Layer::GetShellPolygonsCirc(int number) const
498 {
499   number = (shellPolygons.size() +  number) % shellPolygons.size();
500   return shellPolygons[number];
501 }
502 
setNormalFillPolygons(const vector<Poly> & polys)503 void Layer::setNormalFillPolygons(const vector<Poly> &polys)
504 {
505   clearpolys(fillPolygons);
506   fillPolygons = polys;
507   for (uint i=0; i<fillPolygons.size();i++)
508     fillPolygons[i].setZ(Z);
509 }
510 
setFullFillPolygons(const vector<Poly> & polys)511 void Layer::setFullFillPolygons(const vector<Poly> &polys)
512 {
513   clearpolys(fullFillPolygons);
514   fullFillPolygons = polys;
515   for (uint i=0; i<fullFillPolygons.size();i++)
516     fullFillPolygons[i].setZ(Z);
517 }
setBridgePolygons(const vector<ExPoly> & expolys)518 void Layer::setBridgePolygons(const vector<ExPoly> &expolys)
519 {
520   uint count = expolys.size();
521   // vector<Poly> polygroups;
522   // vector<bool> done; done.resize(count);
523   // for (uint i=0; i<count;i++) done[i] = false;
524   // for (uint i=0; i<count;i++) {
525   //   if (!done[i]){
526   //     vector<Poly> group;
527   //     group.push_back(polys[i]);
528   //     done[i] = true;
529   //   }
530   //   for (uint j=i+1; j<polys.size();j++){
531   //     if (!done[j]){
532   // 	if (polys[.polyInside(polys[j]){
533   // 	    done[j] = true;
534   // 	  g
535   //   }
536   // }
537   clearpolys(bridgePolygons);
538   bridgePolygons = expolys;
539   for (uint i=0; i<count; i++) {
540     bridgePolygons[i].outer.setZ(Z);
541     for (uint h = 0; h < bridgePolygons[i].holes.size(); h++)
542       bridgePolygons[i].holes[h].setZ(Z);
543   }
544 }
setBridgeAngles(const vector<double> & angles)545 void Layer::setBridgeAngles(const vector<double> &angles)
546 {
547   bridge_angles=angles; // .insert(bridge_angles.begin(),angles.begin(),angles.end());
548 }
549 
setSupportPolygons(const vector<Poly> & polys)550 void Layer::setSupportPolygons(const vector<Poly> &polys)
551 {
552   clearpolys(supportPolygons);
553   supportPolygons = polys;
554   const double minarea = 10*thickness*thickness;
555   for (int i = supportPolygons.size()-1; i >= 0; i--) {
556     supportPolygons[i].cleanup(thickness/CLEANFACTOR);
557     if (abs(Clipping::Area(supportPolygons[i])) < minarea) {
558       supportPolygons.erase(supportPolygons.begin() + i);
559       continue;
560     }
561     vector<Vector2d> minmax = supportPolygons[i].getMinMax();
562     Min.x() = min(minmax[0].x(),Min.x());
563     Min.y() = min(minmax[0].y(),Min.y());
564     Max.x() = max(minmax[1].x(),Max.x());
565     Max.y() = max(minmax[1].y(),Max.y());
566   }
567 }
568 
setSkirtPolygons(const vector<Poly> & poly)569 void Layer::setSkirtPolygons(const vector<Poly> &poly)
570 {
571   clearpolys(skirtPolygons);
572   skirtPolygons = poly;
573   for (uint i=0; i<skirtPolygons.size(); i++) {
574     skirtPolygons[i].cleanup(thickness);
575     skirtPolygons[i].setZ(Z);
576   }
577 }
578 
579 
FindThinpolys(const vector<Poly> & polys,double extrwidth,vector<Poly> & thickpolys,vector<Poly> & thinpolys)580 void Layer::FindThinpolys(const vector<Poly> &polys, double extrwidth,
581 			  vector<Poly> &thickpolys, vector<Poly> &thinpolys)
582 {
583 #define THINPOLYS 1
584 #if THINPOLYS
585   // go in
586   thickpolys = Clipping::getOffset(polys, -0.5*extrwidth);
587   // go out again, now thin polys are gone
588   thickpolys = Clipping::getOffset(thickpolys, 0.55*extrwidth);
589   // (need overlap to really clip)
590 
591   // use bigger (longer) polys for clip to avoid overlap of thin and thick extrusion lines
592   vector <Poly> bigthick = Clipping::getOffset(thickpolys, extrwidth);
593   // difference to original are thin polys
594   Clipping clipp;
595   clipp.addPolys(polys, subject);
596   clipp.addPolys(bigthick, clip);
597   thinpolys = clipp.subtract();
598   // remove overlap
599   thickpolys = Clipping::getOffset(thickpolys, -0.05*extrwidth);
600 #else
601   thickpolys = polys;
602 #endif
603 }
604 
MakeShells(const Settings & settings)605 void Layer::MakeShells(const Settings &settings)
606 {
607   double extrudedWidth        = settings.GetExtrudedMaterialWidth(thickness);
608   double roundline_extrfactor =
609     settings.RoundedLinewidthCorrection(extrudedWidth,thickness);
610   double distance       = 0.5 * extrudedWidth;
611   double cleandist      = min(distance/CLEANFACTOR, thickness/CLEANFACTOR);
612   double shelloffset    = settings.get_double("Slicing","ShellOffset");
613   uint   shellcount     = settings.get_integer("Slicing","ShellCount");
614   double infilloverlap  = settings.get_double("Slicing","InfillOverlap");
615 
616   // first shrink with global offset
617   vector<Poly> shrinked = Clipping::getOffset(polygons, -2.0/M_PI*extrudedWidth-shelloffset);
618 
619   vector<Poly> thickPolygons;
620   FindThinpolys(shrinked, extrudedWidth, thickPolygons, thinPolygons);
621   shrinked = thickPolygons;
622 
623   for (uint i = 0; i<thinPolygons.size(); i++)
624     thinPolygons[i].cleanup(cleandist);
625 
626   // // expand shrinked to get to the outer shell again
627   // shrinked = Clipping::getOffset(shrinked, 2*distance);
628   for (uint i = 0; i<shrinked.size(); i++)
629     shrinked[i].cleanup(cleandist);
630 
631   //vector<Poly> shrinked = Clipping::getShrinkedCapped(polygons,distance);
632   // outmost shells
633   if (shellcount > 0) {
634     if (skins>1) { // either skins
635       for (uint i = 0; i<shrinked.size(); i++)  {
636 	shrinked[i].setExtrusionFactor(1./skins*roundline_extrfactor);
637       }
638       skinPolygons = shrinked;
639     } else {  // or normal shell
640       clearpolys(shellPolygons);
641       for (uint i = 0; i<shrinked.size(); i++)  {
642 	shrinked[i].setExtrusionFactor(roundline_extrfactor);
643       }
644       shellPolygons.push_back(shrinked);
645     }
646     // inner shells
647     for (uint i = 1; i<shellcount; i++) // shrink from shell to shell
648       {
649 	shrinked = Clipping::getOffset(shrinked,-extrudedWidth);
650 	vector<Poly> thinpolys;
651 	FindThinpolys(shrinked, extrudedWidth, thickPolygons, thinpolys);
652 	shrinked = thickPolygons;
653 	thinPolygons.insert(thinPolygons.end(), thinpolys.begin(),thinpolys.end());
654 	for (uint j = 0; j<shrinked.size(); j++)
655 	  shrinked[j].cleanup(cleandist);
656 	//shrinked = Clipping::getShrinkedCapped(shrinked,extrudedWidth);
657 	shellPolygons.push_back(shrinked);
658       }
659   }
660   // the filling polygon
661   if (settings.get_boolean("Slicing","DoInfill")) {
662     fillPolygons = Clipping::getOffset(shrinked,-(1.-infilloverlap)*extrudedWidth);
663     for (uint i = 0; i<fillPolygons.size(); i++)
664       fillPolygons[i].cleanup(cleandist);
665     //fillPolygons = Clipping::getShrinkedCapped(shrinked,extrudedWidth);
666     //cerr << LayerNo << " > " << fillPolygons.size()<< endl;
667   }
668 
669   calcConvexHull();
670 
671   //cerr << " .. made " << fillPolygons.size() << " offsetpolys "  << endl;
672   // for (uint i =0; i<shellPolygons.size(); i++) {
673   //   cout << "shell " << i << endl;
674   //   for (uint j =1; j<shellPolygons[i].size(); j++) {
675   //     shellPolygons[i][j].printinfo();
676   //   }
677   // }
678 }
679 
MakeSkirt(double distance,bool single)680 void Layer::MakeSkirt(double distance, bool single)
681 {
682   clearpolys(skirtPolygons);
683   vector<Poly> all;
684   if (single) { // single skirt
685     all.push_back(hullPolygon);
686     all.insert(all.end(),supportPolygons.begin(),supportPolygons.end());
687     Poly hull = convexHull2D(all);
688     vector<Poly> skp = Clipping::getOffset(hull, distance, jround);
689     if (skp.size()>0){
690       skirtPolygons.push_back(skp.front());
691       skirtPolygons[0].setZ(Z);
692       skirtPolygons[0].cleanup(thickness);
693     }
694   } else { // skirt for each shape
695     skirtPolygons = Clipping::getOffset(*GetOuterShell(), distance, jround);
696   }
697 }
698 
699 
700 // calc convex hull and Min and Max of layer
calcConvexHull()701 void Layer::calcConvexHull()
702 {
703   hullPolygon = convexHull2D(polygons); // see geometry.cpp
704   hullPolygon.setZ(Z);
705   setMinMax(hullPolygon);
706 }
707 
setMinMax(const vector<Poly> & polys)708 bool Layer::setMinMax(const vector<Poly> &polys)
709 {
710   Vector2d NewMin = Vector2d( INFTY, INFTY);
711   Vector2d NewMax = Vector2d(-INFTY, -INFTY);
712   for (uint i = 0; i< polys.size(); i++) {
713     vector<Vector2d> minmax = polys[i].getMinMax();
714     NewMin.x() = min(NewMin.x(), minmax[0].x());
715     NewMin.y() = min(NewMin.y(), minmax[0].y());
716     NewMax.x() = max(NewMax.x(), minmax[1].x());
717     NewMax.y() = max(NewMax.y(), minmax[1].y());
718   }
719   if (NewMin==Min && NewMax==Max) return false;
720   Min = NewMin;
721   Max = NewMax;
722   return true;
723 }
setMinMax(const Poly & poly)724 bool Layer::setMinMax(const Poly &poly)
725 {
726   vector<Vector2d> minmax = poly.getMinMax();
727   if (minmax[0]==Min && minmax[1]==Max) return false;
728   Min = minmax[0];
729   Max = minmax[1];
730   return true;
731 }
732 
733 
734 // Convert to GCode
MakeGCode(Vector3d & start,GCodeState & gc_state,double offsetZ,Settings & settings) const735 void Layer::MakeGCode (Vector3d &start,
736 		       GCodeState &gc_state,
737 		       double offsetZ,
738 		       Settings &settings) const
739 {
740   vector<PLine3> plines;
741   MakePrintlines(start, plines, offsetZ, settings);
742   Printlines::makeAntioozeRetract(plines, settings);
743   Printlines::getCommands(plines, settings, gc_state);
744 }
745 
746 // Convert to Printlines
MakePrintlines(Vector3d & lastPos,vector<PLine3> & lines3,double offsetZ,Settings & settings) const747 void Layer::MakePrintlines(Vector3d &lastPos, //GCodeState &state,
748 			   vector<PLine3> &lines3,
749 			   double offsetZ,
750 			   Settings &settings) const
751 {
752   const double linewidth      = settings.GetExtrudedMaterialWidth(thickness);
753   const double cornerradius   = linewidth*settings.get_double("Slicing","CornerRadius");
754 
755   const bool clipnearest      = settings.get_boolean("Slicing","MoveNearest");
756 
757   const uint supportExtruder  = settings.GetSupportExtruder();
758   const double minshelltime   = settings.get_double("Slicing","MinShelltime");
759 
760   const double maxshellspeed  = settings.get_double("Extruder","MaxShellSpeed");
761   const bool ZliftAlways      = settings.get_boolean("Extruder","ZliftAlways");
762 
763   Vector2d startPoint(lastPos.x(),lastPos.y());
764 
765   const double extr_per_mm = settings.GetExtrusionPerMM(thickness);
766 
767   //vector<PLine3> lines3;
768   Printlines printlines(this, &settings, offsetZ);
769 
770   vector<PLine2> lines;
771 
772   vector<Poly> polys; // intermediate collection
773 
774   // polys to keep line movements inside
775   //const vector<Poly> * clippolys = &polygons;
776   const vector<Poly> * clippolys = GetOuterShell();
777 
778   // 1. Skins, all but last, because they are the lowest lines, below layer Z
779   if (skins > 1) {
780     for(uint s = 0; s < skins; s++) {
781       // z offset from bottom to top:
782       double skin_z = Z - thickness + (s+1)*thickness/skins;
783       if ( skin_z < 0 ){
784 	cerr << "Skin Z<0! " << s << " -- " << Z << " -- "<<skin_z <<" -- " << thickness <<  endl;
785 	continue;
786       }
787 
788       // skin infill polys:
789       if (skinFullInfills[s])
790 	polys.insert(polys.end(),
791 		     skinFullInfills[s]->infillpolys.begin(),
792 		     skinFullInfills[s]->infillpolys.end());
793       // add skin infill to lines
794       printlines.addPolys(INFILL, polys, false);
795 
796       polys.clear();
797 
798       // make polygons at skin_z:
799       for(size_t p = 0; p < skinPolygons.size(); p++) {
800 	polys.push_back(Poly(skinPolygons[p], skin_z));
801       }
802       // add skin to lines
803       printlines.addPolys(SKIN, polys, (s==0), // displace at first skin
804 			  maxshellspeed * 60,
805 			  minshelltime);
806       if (s < skins-1) { // not on the last layer, this handle with all other lines
807 	// have to get all these separately because z changes
808 	printlines.makeLines(startPoint, lines);
809 	if (!ZliftAlways)
810 	  printlines.clipMovements(*clippolys, lines, clipnearest, linewidth);
811 	printlines.optimize(linewidth,
812 			    minshelltime, cornerradius, lines);
813 	printlines.getLines(lines, lines3, extr_per_mm);
814 	printlines.clear();
815 	lines.clear();
816       }
817       polys.clear();
818     }
819   } // last skin layer now still in lines
820   lines.clear();
821 
822   // 2. Skirt
823   printlines.addPolys(SKIRT, skirtPolygons, false,
824 		      maxshellspeed * 60,
825 		      minshelltime);
826 
827   // 3. Support
828   if (supportInfill) {
829     uint extruderbefore = settings.selectedExtruder;
830     settings.SelectExtruder(supportExtruder);
831     printlines.addPolys(SUPPORT, supportInfill->infillpolys, false);
832     settings.SelectExtruder(extruderbefore);
833   }
834   // 4. all other polygons:
835 
836   //  Shells
837   for(int p=shellPolygons.size()-1; p>=0; p--) { // inner to outer
838     //cerr << "displace " << p << endl;
839     printlines.addPolys(SHELL, shellPolygons[p],
840 			(p==(int)(shellPolygons.size())-1),
841 			maxshellspeed * 60,
842 			minshelltime);
843   }
844 
845   //  Infill
846   if (normalInfill)
847     printlines.addPolys(INFILL, normalInfill->infillpolys, false);
848   if (thinInfill)
849     printlines.addPolys(INFILL, thinInfill->infillpolys, false);
850   if (fullInfill)
851     printlines.addPolys(INFILL, fullInfill->infillpolys, false);
852   if (skirtInfill)
853     printlines.addPolys(INFILL, skirtInfill->infillpolys, false);
854   if (decorInfill)
855     printlines.addPolys(INFILL, decorInfill->infillpolys, false);
856   for (uint b=0; b < bridgeInfills.size(); b++)
857     if (bridgeInfills[b])
858       printlines.addPolys(INFILL, bridgeInfills[b]->infillpolys, false);
859 
860   double polyspeedfactor = printlines.makeLines(startPoint, lines);
861 
862   // FINISH
863 
864   Command lchange(LAYERCHANGE, LayerNo);
865   lchange.where = Vector3d(0.,0.,Z);
866   lchange.comment += info();
867   lines3.push_back(PLine3(lchange));
868 
869   if (!ZliftAlways)
870     printlines.clipMovements(*clippolys, lines, clipnearest, linewidth);
871   printlines.optimize(linewidth,
872 		      settings.get_double("Slicing","MinLayertime"),
873 		      cornerradius, lines);
874   if ((guint)LayerNo < (guint)settings.get_integer("Slicing","FirstLayersNum"))
875     printlines.setSpeedFactor(settings.get_double("Slicing","FirstLayersSpeed"), lines);
876   double slowdownfactor = printlines.getSlowdownFactor() * polyspeedfactor;
877 
878   if (settings.get_boolean("Slicing","FanControl")) {
879     int fanspeed = settings.get_integer("Slicing","MinFanSpeed");
880     if (slowdownfactor < 1 && slowdownfactor > 0) {
881       double fanfactor = 1-slowdownfactor;
882       fanspeed +=
883 	int(fanfactor * (settings.get_integer("Slicing","MaxFanSpeed")-settings.get_integer("Slicing","MinFanSpeed")));
884       fanspeed = CLAMP(fanspeed, settings.get_integer("Slicing","MinFanSpeed"),
885 		       settings.get_integer("Slicing","MaxFanSpeed"));
886       //cerr << slowdownfactor << " - " << fanfactor << " - " << fanspeed << " - " << endl;
887     }
888     Command fancommand(FANON, fanspeed);
889     lines3.push_back(PLine3(fancommand));
890   }
891 
892   printlines.getLines(lines, lines3, extr_per_mm);
893   if (lines3.size()>0)
894     lastPos = lines3.back().to;
895 }
896 
897 
area() const898 double Layer::area() const
899 {
900   return Clipping::Area(polygons);
901 }
902 
info() const903 string Layer::info() const
904 {
905   ostringstream ostr;
906   ostr <<"Layer at Z=" << Z << " No=" << LayerNo
907        <<", thickn=" << thickness
908        <<", "<<skins <<" skins"
909        <<", "<<polygons.size() <<" polys"
910        <<", "<<shellPolygons.size() <<" shells"
911        <<", "<<fullFillPolygons.size() <<" fullfill polys"
912        <<", "<<bridgePolygons.size() <<" bridge polys"
913        <<", "<<skinFullFillPolygons.size() <<" skin fullfill polys"
914        <<", "<<supportPolygons.size() <<" support polys";
915   ostr <<", infill: ";
916   if (normalInfill)
917     ostr <<" normal "<<normalInfill->size() ;
918   if (fullInfill)
919     ostr <<", full "<<fullInfill->size()  ;
920   if (bridgeInfills.size()>0)
921     ostr <<", bridges "<<bridgeInfills.size() ;
922   if (supportInfill)
923     ostr<<", support "<<supportInfill->size() ;
924   ostr <<", skinfills "<<skinFullInfills.size() ;
925 
926   if (previous != NULL)
927     ostr << " prev.No=" << previous->LayerNo;
928 
929   return ostr.str();
930 }
931 
932 
getOverhangs() const933 vector<Poly> Layer::getOverhangs() const
934 {
935   vector<Poly> overhangs;
936   if (previous!=NULL) {
937     Clipping clipp;
938     clipp.addPolys(polygons, subject);
939     vector<Poly> prevoffset = Clipping::getOffset(previous->polygons, thickness/2);
940     clipp.addPolys(prevoffset, clip);
941     clipp.setZ(Z);
942     overhangs = clipp.subtract();//CL::pftNonZero,CL::pftNonZero);
943   }
944   return overhangs;
945 }
946 
SVGpath(const Vector2d & trans) const947 string Layer::SVGpath(const Vector2d &trans) const
948 {
949   ostringstream ostr;
950   ostr << "\t<g id=\"Layer_"<< LayerNo
951        << "_z:" << getZ() << "\">" << endl;
952   for (uint i = 0; i<polygons.size(); i++) {
953     ostr << polygons[i].SVGpath(trans) << endl;
954   }
955   ostr << "\t</g>";
956   return ostr.str();
957 }
958 
959 
Draw(const Settings & settings)960 void Layer::Draw(const Settings &settings)
961 {
962 
963 #if 0
964   // test single area expolys
965   vector<ExPoly> expolys = Clipping::getExPolys(polygons);
966   draw_polys(expolys, GL_LINE_LOOP, 1, 3, RED, 1);
967   cerr << expolys.size() << endl;
968 
969   Infill exinf(this, 1.);
970   exinf.setName("infill");
971   double infilldistance = settings.GetInfillDistance(thickness,
972 						     settings.Slicing.InfillPercent);
973 
974   exinf.addPolys(Z, expolys, HexInfill,
975 		 infilldistance, infilldistance, 0.4);
976   draw_polys(exinf.infillpolys, GL_LINE_LOOP, 1, 3,
977 	     (exinf.cached?BLUEGREEN:GREEN), 1);
978   return;
979 #endif
980 
981   bool randomized = settings.get_boolean("Display","RandomizedLines");
982   bool filledpolygons = settings.get_boolean("Display","DisplayFilledAreas");
983   // glEnable(GL_LINE_SMOOTH);
984   // glHint(GL_LINE_SMOOTH_HINT,  GL_NICEST);
985   draw_polys(polygons, GL_LINE_LOOP, 1, 3, RED, 1, randomized);
986   draw_polys(polygons, GL_POINTS,    1, 3, RED, 1, randomized);
987 
988   if(settings.get_boolean("Display","DrawCPOutlineNumbers"))
989     for(size_t p=0; p<polygons.size();p++)
990       {
991 	ostringstream oss;
992 	oss << p;
993 	Vector2d center = polygons[p].getCenter();
994 	Render::draw_string(Vector3d(center.x(), center.y(), Z), oss.str());
995       }
996 
997   draw_poly(hullPolygon,    GL_LINE_LOOP, 3, 3, ORANGE,  0.5, randomized);
998   draw_polys(skirtPolygons, GL_LINE_LOOP, 3, 3, YELLOW,  1, randomized);
999   draw_polys(shellPolygons, GL_LINE_LOOP, 1, 3, YELLOW2, 1, randomized);
1000   draw_polys(thinPolygons,  GL_LINE_LOOP, 2, 3, YELLOW,  1, randomized);
1001 
1002   glColor4f(0.5,0.9,1,1);
1003   glLineWidth(1);
1004   double zs = Z;
1005   for(size_t s=0;s<skins;s++) {
1006     for(size_t p=0; p < skinPolygons.size();p++) {
1007       //cerr << s << ": " << p << " _ " << zs << endl;
1008       skinPolygons[p].draw(GL_LINE_LOOP, zs, randomized);
1009     }
1010     zs-=thickness/skins;
1011   }
1012   draw_polys(fillPolygons,         GL_LINE_LOOP, 1, 3, WHITE, 0.6, randomized);
1013   if (supportPolygons.size()>0) {
1014     if (filledpolygons)
1015       draw_polys_surface(supportPolygons,  Min, Max, Z, thickness/2., BLUE2, 0.4);
1016     draw_polys(supportPolygons,      GL_LINE_LOOP, 3, 3, BLUE2, 1,   randomized);
1017     if(settings.get_boolean("Display","DrawVertexNumbers"))
1018       for(size_t p=0; p<supportPolygons.size();p++)
1019 	supportPolygons[p].drawVertexNumbers();
1020   } // else
1021     // draw_polys(toSupportPolygons,    GL_LINE_LOOP, 1, 1, BLUE2, 1,   randomized);
1022   draw_polys(bridgePolygons,       GL_LINE_LOOP, 3, 3, RED2,  0.7, randomized);
1023   draw_polys(fullFillPolygons,     GL_LINE_LOOP, 1, 1, GREY,  0.6, randomized);
1024   draw_polys(decorPolygons,        GL_LINE_LOOP, 1, 3, WHITE, 1,   randomized);
1025   draw_polys(skinFullFillPolygons, GL_LINE_LOOP, 1, 3, GREY,  0.6, randomized);
1026   if (filledpolygons) {
1027     draw_polys_surface(fullFillPolygons,  Min, Max, Z, thickness/2., GREEN, 0.5);
1028     draw_polys_surface(decorPolygons,  Min, Max, Z, thickness/2., GREY, 0.2);
1029   }
1030   if(settings.get_boolean("Display","DisplayinFill"))
1031     {
1032       if (filledpolygons)
1033 	draw_polys_surface(fillPolygons,  Min, Max, Z, thickness/2., GREEN2, 0.25);
1034       bool DebugInfill = settings.get_boolean("Display","DisplayDebuginFill");
1035       if (normalInfill)
1036 	draw_polys(normalInfill->infillpolys, GL_LINE_LOOP, 1, 3,
1037 		   (normalInfill->cached?BLUEGREEN:GREEN), 1, randomized);
1038       if(DebugInfill && normalInfill->cached)
1039 	draw_polys(normalInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3,
1040 		   ORANGE, 0.5, randomized);
1041       if (thinInfill)
1042 	draw_polys(thinInfill->infillpolys, GL_LINE_LOOP, 1, 3,
1043 		   GREEN, 1, randomized);
1044       if (fullInfill)
1045 	draw_polys(fullInfill->infillpolys, GL_LINE_LOOP, 1, 3,
1046 		   (fullInfill->cached?BLUEGREEN:GREEN), 0.8, randomized);
1047       if (skirtInfill)
1048 	draw_polys(skirtInfill->infillpolys, GL_LINE_LOOP, 1, 3,
1049 		   YELLOW, 0.6, randomized);
1050       if(DebugInfill && fullInfill->cached)
1051 	draw_polys(fullInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3,
1052 		   ORANGE, 0.5, randomized);
1053       if (decorInfill)
1054 	draw_polys(decorInfill->infillpolys, GL_LINE_LOOP, 1, 3,
1055 		   (decorInfill->cached?BLUEGREEN:GREEN), 0.8, randomized);
1056       if(DebugInfill && decorInfill->cached)
1057 	draw_polys(decorInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3,
1058 		   ORANGE, 0.5, randomized);
1059       uint bridgecount = bridgeInfills.size();
1060       if (bridgecount>0)
1061 	for (uint i = 0; i<bridgecount; i++)
1062 	  draw_polys(bridgeInfills[i]->infillpolys, GL_LINE_LOOP, 2, 3,
1063 		     RED3,0.9, randomized);
1064       if (supportInfill)
1065 	draw_polys(supportInfill->infillpolys, GL_LINE_LOOP, 1, 3,
1066 		   (supportInfill->cached?BLUEGREEN:GREEN), 0.8, randomized);
1067       if(DebugInfill && supportInfill->cached)
1068 	draw_polys(supportInfill->getCachedPattern(Z), GL_LINE_LOOP, 1, 3,
1069 		   ORANGE, 0.5, randomized);
1070       for(size_t s=0;s<skinFullInfills.size();s++)
1071 	draw_polys(skinFullInfills[s]->infillpolys, GL_LINE_LOOP, 1, 3,
1072 		   (skinFullInfills[s]->cached?BLUEGREEN:GREEN), 0.6, randomized);
1073     }
1074   //draw_polys(GetInnerShell(), GL_LINE_LOOP, 2, 3, WHITE,  1);
1075   glLineWidth(1);
1076   if(settings.get_boolean("Display","DrawCPVertexNumbers")) // poly vertex numbers
1077     for(size_t p=0; p<polygons.size();p++)
1078       polygons[p].drawVertexNumbers();
1079       //polygons[p].drawVertexAngles();
1080 
1081   if(settings.get_boolean("Display","DrawCPLineNumbers"))  // poly line numbers
1082     for(size_t p=0; p<polygons.size();p++)
1083       polygons[p].drawLineNumbers();
1084 
1085   if(settings.get_boolean("Display","DrawVertexNumbers")) { // infill vertex numbers
1086     for(size_t p=0; p<fillPolygons.size();p++)
1087       fillPolygons[p].drawVertexNumbers();
1088     for(size_t p=0; p<fullFillPolygons.size();p++)
1089       fullFillPolygons[p].drawVertexNumbers();
1090     for(size_t p=0; p<decorPolygons.size();p++)
1091       decorPolygons[p].drawVertexNumbers();
1092     for(size_t p=0; p<shellPolygons.size();p++)
1093       for(size_t q=0; q<shellPolygons[p].size();q++)
1094 	shellPolygons[p][q].drawVertexNumbers();
1095   }
1096 
1097 
1098   if (settings.get_boolean("Display","ShowLayerOverhang")) {
1099     draw_polys(bridgePillars,        GL_LINE_LOOP, 3, 3, YELLOW,0.7, randomized);
1100     if (previous!=NULL) {
1101       vector<Poly> overhangs = getOverhangs();
1102       draw_polys(overhangs, GL_LINE_LOOP, 1, 3, VIOLET, 0.8, randomized);
1103       //draw_polys_surface(overhangs, Min, Max, Z, thickness/5, VIOLET , 0.5);
1104 
1105       Cairo::RefPtr<Cairo::ImageSurface> surface;
1106       Cairo::RefPtr<Cairo::Context>      context;
1107       if (rasterpolys(overhangs, Min, Max, thickness/5, surface, context))
1108 	if (surface) {
1109 	  glColor4f(RED[0],RED[1],RED[2], 0.5);
1110 	  glDrawCairoSurface(surface, Min, Max, Z);
1111 	  glColor4f(RED[0],RED[1],RED[2], 0.6);
1112 	  glPointSize(3);
1113  	  glBegin(GL_POINTS);
1114  	  for (double x = Min.x(); x<Max.x(); x+=thickness)
1115 	    for (double y = Min.y(); y<Max.y(); y+=thickness)
1116 	      if (getCairoSurfaceDatapoint(surface, Min, Max, Vector2d(x,y))!=0)
1117 	  	glVertex3d(x,y,Z);
1118 	  glEnd();
1119 	}
1120     }
1121   }
1122 
1123 #if 0
1124   // test point-in-polygons
1125   const vector<Poly> *polys = GetOuterShell();
1126   glColor4f(RED[0],RED[1],RED[2], 0.6);
1127   glPointSize(3);
1128   glBegin(GL_POINTS);
1129   for (double x = Min.x(); x<Max.x(); x+=thickness/1)
1130     for (double y = Min.y(); y<Max.y(); y+=thickness/1) {
1131       bool inpoly = false;
1132       for (uint i=0; i<polys->size(); i++) {
1133 	if ((*polys)[i].vertexInside(Vector2d(x,y))){
1134 	  inpoly=true; break;
1135 	}
1136       }
1137       if (inpoly)
1138 	glVertex3d(x,y,Z);
1139       // else
1140       //   glColor4f(0.3,0.3,0.3, 0.6);
1141     }
1142   glEnd();
1143 #endif
1144 
1145 }
1146 
DrawRulers(const Vector2d & point)1147 void Layer::DrawRulers(const Vector2d &point)
1148 {
1149   Vector2d x0(Min.x()-10, point.y());
1150   Vector2d x1(Max.x()+10, point.y());
1151   Vector2d y0(point.x(), Min.y()-10);
1152   Vector2d y1(point.x(), Max.y()+10);
1153 
1154   // cut axes with layer polygons
1155   vector<Intersection> xint, yint;
1156   Intersection hit;
1157   hit.p = Vector2d(Min.x(),point.y()); hit.d = 10;
1158   xint.push_back(hit);
1159   hit.p = Vector2d(Max.x(),point.y()); hit.d = Max.x()-Min.x()+10;
1160   xint.push_back(hit);
1161   hit.p = Vector2d(point.x(),Min.y()); hit.d = 10;
1162   yint.push_back(hit);
1163   hit.p = Vector2d(point.x(),Max.y()); hit.d = Max.y()-Min.y()+10;
1164   yint.push_back(hit);
1165 
1166   for(size_t p=0; p<polygons.size();p++) {
1167     vector<Intersection> lint = polygons[p].lineIntersections(x0,x1,0.1);
1168     xint.insert(xint.end(),lint.begin(),lint.end());
1169     lint = polygons[p].lineIntersections(y0,y1,0.1);
1170     yint.insert(yint.end(),lint.begin(),lint.end());
1171   }
1172   //cerr << xint.size() << " - "<< xint.size() << endl;
1173   std::sort(xint.begin(),xint.end());
1174   std::sort(yint.begin(),yint.end());
1175 
1176   glColor4f(1.,1.,1.,1.);
1177   glLineWidth(1);
1178   glBegin(GL_LINES);
1179   // draw lines
1180   glVertex3d(Min.x(), x0.y(), Z);
1181   glVertex3d(Max.x(), x1.y(), Z);
1182   glVertex3d(y0.x(), Min.y(), Z);
1183   glVertex3d(y1.x(), Max.y(), Z);
1184   // draw ticks
1185   double ticksize=2;
1186   for(guint i = 0; i<xint.size(); i++) {
1187     glVertex3d(xint[i].p.x(), xint[i].p.y()-ticksize, Z);
1188     glVertex3d(xint[i].p.x(), xint[i].p.y()+ticksize, Z);
1189   }
1190   for(guint i = 0; i<yint.size(); i++) {
1191     glVertex3d(yint[i].p.x()-ticksize, yint[i].p.y(), Z);
1192     glVertex3d(yint[i].p.x()+ticksize, yint[i].p.y(), Z);
1193   }
1194   // draw BBox
1195   glVertex3d(Min.x(), Min.y(), Z);
1196   glVertex3d(Max.x(), Min.y(), Z);
1197   glVertex3d(Max.x(), Min.y(), Z);
1198   glVertex3d(Max.x(), Max.y(), Z);
1199   glVertex3d(Max.x(), Max.y(), Z);
1200   glVertex3d(Min.x(), Max.y(), Z);
1201   glVertex3d(Min.x(), Max.y(), Z);
1202   glVertex3d(Min.x(), Min.y(), Z);
1203   glEnd();
1204   // draw numbers
1205   ostringstream val;
1206   val.precision(1);
1207   for(guint i = 1; i<xint.size(); i++) {
1208     val.str("");
1209     double v = xint[i].p.x()-xint[i-1].p.x();
1210     val << fixed << v;
1211     Render::draw_string(Vector3d((xint[i].p.x()+xint[i-1].p.x())/2.,
1212 				 xint[i].p.y()+1,Z),
1213 			val.str());
1214   }
1215   for(guint i = 1; i<yint.size(); i++) {
1216     val.str("");
1217     double v = yint[i].p.y()-yint[i-1].p.y();
1218     val << fixed << v;
1219     Render::draw_string(Vector3d(yint[i].p.x()+1,(yint[i].p.y()+yint[i-1].p.y())/2.,Z),
1220 			val.str());
1221   }
1222 
1223 }
1224