void generateInsets(SliceLayerPart* part, int offset, int insetCount) { part->combBoundery = part->outline.offset(-offset); if (insetCount == 0) { part->insets.push_back(part->outline); return; } for(int i=0; i<insetCount; i++) { part->insets.push_back(Polygons()); part->insets[i] = part->outline.offset(-offset * i - offset/2); optimizePolygons(part->insets[i]); if (part->insets[i].size() < 1) { part->insets.pop_back(); break; } } }
void SlicerLayer::makePolygons(OptimizedVolume* ov, bool keepNoneClosed, bool extensiveStitching) { for(unsigned int startSegment=0; startSegment < segmentList.size(); startSegment++) { if (segmentList[startSegment].addedToPolygon) continue; ClipperLib::Polygon poly; poly.push_back(segmentList[startSegment].start); unsigned int segmentIndex = startSegment; bool canClose; while(true) { canClose = false; segmentList[segmentIndex].addedToPolygon = true; Point p0 = segmentList[segmentIndex].end; poly.push_back(p0); int nextIndex = -1; OptimizedFace* face = &ov->faces[segmentList[segmentIndex].faceIndex]; for(unsigned int i=0;i<3;i++) { if (face->touching[i] > -1 && faceToSegmentIndex.find(face->touching[i]) != faceToSegmentIndex.end()) { Point p1 = segmentList[faceToSegmentIndex[face->touching[i]]].start; Point diff = p0 - p1; if (shorterThen(diff, 10)) { if (faceToSegmentIndex[face->touching[i]] == (int)startSegment) canClose = true; if (segmentList[faceToSegmentIndex[face->touching[i]]].addedToPolygon) continue; nextIndex = faceToSegmentIndex[face->touching[i]]; } } } if (nextIndex == -1) break; segmentIndex = nextIndex; } if (canClose) polygonList.add(poly); else openPolygonList.add(poly); } //Clear the segmentList to save memory, it is no longer needed after this point. segmentList.clear(); //Connecting polygons that are not closed yet, as models are not always perfect manifold we need to join some stuff up to get proper polygons //First link up polygon ends that are within 2 microns. for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 1) continue; for(unsigned int j=0;j<openPolygonList.size();j++) { if (openPolygonList[j].size() < 1) continue; Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][0]; int64_t distSquared = vSize2(diff); if (distSquared < 2 * 2) { if (i == j) { polygonList.add(openPolygonList[i]); openPolygonList[i].clear(); break; }else{ for(unsigned int n=0; n<openPolygonList[j].size(); n++) openPolygonList[i].push_back(openPolygonList[j][n]); openPolygonList[j].clear(); } } } } //Next link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time. while(1) { int64_t bestScore = 10000 * 10000; unsigned int bestA = -1; unsigned int bestB = -1; bool reversed = false; for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 1) continue; for(unsigned int j=0;j<openPolygonList.size();j++) { if (openPolygonList[j].size() < 1) continue; Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][0]; int64_t distSquared = vSize2(diff); if (distSquared < bestScore) { bestScore = distSquared; bestA = i; bestB = j; reversed = false; } if (i != j) { Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][openPolygonList[j].size()-1]; int64_t distSquared = vSize2(diff); if (distSquared < bestScore) { bestScore = distSquared; bestA = i; bestB = j; reversed = true; } } } } if (bestScore >= 10000 * 10000) break; if (bestA == bestB) { polygonList.add(openPolygonList[bestA]); openPolygonList[bestA].clear(); }else{ if (reversed) { for(unsigned int n=openPolygonList[bestB].size()-1; int(n)>=0; n--) openPolygonList[bestA].push_back(openPolygonList[bestB][n]); }else{ for(unsigned int n=0; n<openPolygonList[bestB].size(); n++) openPolygonList[bestA].push_back(openPolygonList[bestB][n]); } openPolygonList[bestB].clear(); } } if (extensiveStitching) { //For extensive stitching find 2 open polygons that are touching 2 closed polygons. // Then find the sortest path over this polygon that can be used to connect the open polygons, // And generate a path over this shortest bit to link up the 2 open polygons. // (If these 2 open polygons are the same polygon, then the final result is a closed polyon) while(1) { unsigned int bestA = -1; unsigned int bestB = -1; gapCloserResult bestResult; bestResult.len = LLONG_MAX; bestResult.polygonIdx = -1; bestResult.pointIdxA = -1; bestResult.pointIdxB = -1; for(unsigned int i=0; i<openPolygonList.size(); i++) { if (openPolygonList[i].size() < 1) continue; { gapCloserResult res = findPolygonGapCloser(openPolygonList[i][0], openPolygonList[i][openPolygonList[i].size()-1]); if (res.len > 0 && res.len < bestResult.len) { bestA = i; bestB = i; bestResult = res; } } for(unsigned int j=0; j<openPolygonList.size(); j++) { if (openPolygonList[j].size() < 1 || i == j) continue; gapCloserResult res = findPolygonGapCloser(openPolygonList[i][0], openPolygonList[j][openPolygonList[j].size()-1]); if (res.len > 0 && res.len < bestResult.len) { bestA = i; bestB = j; bestResult = res; } } } if (bestResult.len < LLONG_MAX) { if (bestA == bestB) { if (bestResult.pointIdxA == bestResult.pointIdxB) { polygonList.add(openPolygonList[bestA]); openPolygonList[bestA].clear(); } else if (bestResult.AtoB) { unsigned int n = polygonList.size(); polygonList.add(ClipperLib::Polygon()); for(unsigned int j = bestResult.pointIdxA; j != bestResult.pointIdxB; j = (j + 1) % polygonList[bestResult.polygonIdx].size()) polygonList[n].push_back(polygonList[bestResult.polygonIdx][j]); for(unsigned int j = openPolygonList[bestA].size() - 1; int(j) >= 0; j--) polygonList[n].push_back(openPolygonList[bestA][j]); openPolygonList[bestA].clear(); } else { unsigned int n = polygonList.size(); polygonList.add(openPolygonList[bestA]); for(unsigned int j = bestResult.pointIdxB; j != bestResult.pointIdxA; j = (j + 1) % polygonList[bestResult.polygonIdx].size()) polygonList[n].push_back(polygonList[bestResult.polygonIdx][j]); openPolygonList[bestA].clear(); } } else { if (bestResult.pointIdxA == bestResult.pointIdxB) { for(unsigned int n=0; n<openPolygonList[bestA].size(); n++) openPolygonList[bestB].push_back(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } else if (bestResult.AtoB) { ClipperLib::Polygon poly; for(unsigned int n = bestResult.pointIdxA; n != bestResult.pointIdxB; n = (n + 1) % polygonList[bestResult.polygonIdx].size()) poly.push_back(polygonList[bestResult.polygonIdx][n]); for(unsigned int n=poly.size()-1;int(n) >= 0; n--) openPolygonList[bestB].push_back(poly[n]); for(unsigned int n=0; n<openPolygonList[bestA].size(); n++) openPolygonList[bestB].push_back(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } else { for(unsigned int n = bestResult.pointIdxB; n != bestResult.pointIdxA; n = (n + 1) % polygonList[bestResult.polygonIdx].size()) openPolygonList[bestB].push_back(polygonList[bestResult.polygonIdx][n]); for(unsigned int n = openPolygonList[bestA].size() - 1; int(n) >= 0; n--) openPolygonList[bestB].push_back(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } } } else { break; } } } /* int q=0; for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 2) continue; if (!q) printf("***\n"); printf("S: %f %f\n", float(openPolygonList[i][0].X), float(openPolygonList[i][0].Y)); printf("E: %f %f\n", float(openPolygonList[i][openPolygonList[i].size()-1].X), float(openPolygonList[i][openPolygonList[i].size()-1].Y)); q = 1; } */ //if (q) exit(1); if (keepNoneClosed) { for(unsigned int n=0; n<openPolygonList.size(); n++) { if (openPolygonList[n].size() > 0) polygonList.add(openPolygonList[n]); } } //Clear the openPolygonList to save memory, the only reason to keep it after this is for debugging. //openPolygonList.clear(); //Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. int snapDistance = 1000; for(unsigned int i=0;i<polygonList.size();i++) { int length = 0; for(unsigned int n=1; n<polygonList[i].size(); n++) { length += vSize(polygonList[i][n] - polygonList[i][n-1]); if (length > snapDistance) break; } if (length < snapDistance) { polygonList.remove(i); i--; } } //Finally optimize all the polygons. Every point removed saves time in the long run. optimizePolygons(polygonList); }
void SlicerLayer::makePolygons(Mesh* mesh, bool keep_none_closed, bool extensive_stitching) { Polygons openPolygonList; for(unsigned int startSegment=0; startSegment < segmentList.size(); startSegment++) { if (segmentList[startSegment].addedToPolygon) continue; Polygon poly; poly.add(segmentList[startSegment].start); unsigned int segmentIndex = startSegment; bool canClose; while(true) { canClose = false; segmentList[segmentIndex].addedToPolygon = true; Point p0 = segmentList[segmentIndex].end; poly.add(p0); int nextIndex = -1; const MeshFace& face = mesh->faces[segmentList[segmentIndex].faceIndex]; for(unsigned int i=0;i<3;i++) { decltype(face_idx_to_segment_index.begin()) it; if (face.connected_face_index[i] > -1 && (it = face_idx_to_segment_index.find(face.connected_face_index[i])) != face_idx_to_segment_index.end()) { int index = (*it).second; Point p1 = segmentList[index].start; Point diff = p0 - p1; if (shorterThen(diff, MM2INT(0.01))) { if (index == static_cast<int>(startSegment)) canClose = true; if (segmentList[index].addedToPolygon) continue; nextIndex = index; } } } if (nextIndex == -1) break; segmentIndex = nextIndex; } if (canClose) polygonList.add(poly); else openPolygonList.add(poly); } //Clear the segmentList to save memory, it is no longer needed after this point. segmentList.clear(); //Connecting polygons that are not closed yet, as models are not always perfect manifold we need to join some stuff up to get proper polygons //First link up polygon ends that are within 2 microns. for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 1) continue; for(unsigned int j=0;j<openPolygonList.size();j++) { if (openPolygonList[j].size() < 1) continue; Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][0]; int64_t distSquared = vSize2(diff); if (distSquared < MM2INT(0.02) * MM2INT(0.02)) { if (i == j) { polygonList.add(openPolygonList[i]); openPolygonList[i].clear(); break; }else{ for(unsigned int n=0; n<openPolygonList[j].size(); n++) openPolygonList[i].add(openPolygonList[j][n]); openPolygonList[j].clear(); } } } } //Next link up all the missing ends, closing up the smallest gaps first. This is an inefficient implementation which can run in O(n*n*n) time. while(1) { int64_t bestScore = MM2INT(10.0) * MM2INT(10.0); unsigned int bestA = -1; unsigned int bestB = -1; bool reversed = false; for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() < 1) continue; for(unsigned int j=0;j<openPolygonList.size();j++) { if (openPolygonList[j].size() < 1) continue; Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][0]; int64_t distSquared = vSize2(diff); if (distSquared < bestScore) { bestScore = distSquared; bestA = i; bestB = j; reversed = false; } if (i != j) { Point diff = openPolygonList[i][openPolygonList[i].size()-1] - openPolygonList[j][openPolygonList[j].size()-1]; int64_t distSquared = vSize2(diff); if (distSquared < bestScore) { bestScore = distSquared; bestA = i; bestB = j; reversed = true; } } } } if (bestScore >= MM2INT(10.0) * MM2INT(10.0)) break; if (bestA == bestB) { polygonList.add(openPolygonList[bestA]); openPolygonList[bestA].clear(); }else{ if (reversed) { if (openPolygonList[bestA].polygonLength() > openPolygonList[bestB].polygonLength()) { for(unsigned int n=openPolygonList[bestB].size()-1; int(n)>=0; n--) openPolygonList[bestA].add(openPolygonList[bestB][n]); openPolygonList[bestB].clear(); }else{ for(unsigned int n=openPolygonList[bestA].size()-1; int(n)>=0; n--) openPolygonList[bestB].add(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } }else{ for(unsigned int n=0; n<openPolygonList[bestB].size(); n++) openPolygonList[bestA].add(openPolygonList[bestB][n]); openPolygonList[bestB].clear(); } } } if (extensive_stitching) { //For extensive stitching find 2 open polygons that are touching 2 closed polygons. // Then find the sortest path over this polygon that can be used to connect the open polygons, // And generate a path over this shortest bit to link up the 2 open polygons. // (If these 2 open polygons are the same polygon, then the final result is a closed polyon) while(1) { unsigned int bestA = -1; unsigned int bestB = -1; gapCloserResult bestResult; bestResult.len = POINT_MAX; bestResult.polygonIdx = -1; bestResult.pointIdxA = -1; bestResult.pointIdxB = -1; for(unsigned int i=0; i<openPolygonList.size(); i++) { if (openPolygonList[i].size() < 1) continue; { gapCloserResult res = findPolygonGapCloser(openPolygonList[i][0], openPolygonList[i][openPolygonList[i].size()-1]); if (res.len > 0 && res.len < bestResult.len) { bestA = i; bestB = i; bestResult = res; } } for(unsigned int j=0; j<openPolygonList.size(); j++) { if (openPolygonList[j].size() < 1 || i == j) continue; gapCloserResult res = findPolygonGapCloser(openPolygonList[i][0], openPolygonList[j][openPolygonList[j].size()-1]); if (res.len > 0 && res.len < bestResult.len) { bestA = i; bestB = j; bestResult = res; } } } if (bestResult.len < POINT_MAX) { if (bestA == bestB) { if (bestResult.pointIdxA == bestResult.pointIdxB) { polygonList.add(openPolygonList[bestA]); openPolygonList[bestA].clear(); } else if (bestResult.AtoB) { PolygonRef poly = polygonList.newPoly(); for(unsigned int j = bestResult.pointIdxA; j != bestResult.pointIdxB; j = (j + 1) % polygonList[bestResult.polygonIdx].size()) poly.add(polygonList[bestResult.polygonIdx][j]); for(unsigned int j = openPolygonList[bestA].size() - 1; int(j) >= 0; j--) poly.add(openPolygonList[bestA][j]); openPolygonList[bestA].clear(); } else { unsigned int n = polygonList.size(); polygonList.add(openPolygonList[bestA]); for(unsigned int j = bestResult.pointIdxB; j != bestResult.pointIdxA; j = (j + 1) % polygonList[bestResult.polygonIdx].size()) polygonList[n].add(polygonList[bestResult.polygonIdx][j]); openPolygonList[bestA].clear(); } } else { if (bestResult.pointIdxA == bestResult.pointIdxB) { for(unsigned int n=0; n<openPolygonList[bestA].size(); n++) openPolygonList[bestB].add(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } else if (bestResult.AtoB) { Polygon poly; for(unsigned int n = bestResult.pointIdxA; n != bestResult.pointIdxB; n = (n + 1) % polygonList[bestResult.polygonIdx].size()) poly.add(polygonList[bestResult.polygonIdx][n]); for(unsigned int n=poly.size()-1;int(n) >= 0; n--) openPolygonList[bestB].add(poly[n]); for(unsigned int n=0; n<openPolygonList[bestA].size(); n++) openPolygonList[bestB].add(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } else { for(unsigned int n = bestResult.pointIdxB; n != bestResult.pointIdxA; n = (n + 1) % polygonList[bestResult.polygonIdx].size()) openPolygonList[bestB].add(polygonList[bestResult.polygonIdx][n]); for(unsigned int n = openPolygonList[bestA].size() - 1; int(n) >= 0; n--) openPolygonList[bestB].add(openPolygonList[bestA][n]); openPolygonList[bestA].clear(); } } } else { break; } } } if (keep_none_closed) { for(unsigned int n=0; n<openPolygonList.size(); n++) { if (openPolygonList[n].size() > 0) polygonList.add(openPolygonList[n]); } } for(unsigned int i=0;i<openPolygonList.size();i++) { if (openPolygonList[i].size() > 0) openPolygons.newPoly() = openPolygonList[i]; } //Remove all the tiny polygons, or polygons that are not closed. As they do not contribute to the actual print. int snapDistance = MM2INT(1.0); for(unsigned int i=0;i<polygonList.size();i++) { int length = 0; for(unsigned int n=1; n<polygonList[i].size(); n++) { length += vSize(polygonList[i][n] - polygonList[i][n-1]); if (length > snapDistance) break; } if (length < snapDistance) { polygonList.remove(i); i--; } } //Finally optimize all the polygons. Every point removed saves time in the long run. optimizePolygons(polygonList); int xy_offset = mesh->getSettingInMicrons("xy_offset"); if (xy_offset != 0) { polygonList = polygonList.offset(xy_offset); } }