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