bool Poly::vertexInside2(const Vector2d &point, double maxoffset) const { // Shoot a ray along +X and count the number of intersections. // If n_intersections is even, return false, else return true Vector2d EndP(point.x()+10000, point.y()); int intersectcount = 1; // we want to test if uneven double maxoffsetSq = maxoffset*maxoffset; Vector2d dummy; for(size_t i=0; i<vertices.size();i++) { const Vector2d P1 = getVertexCircular(i-1); const Vector2d P2 = vertices[i]; if (point_segment_distance_Sq(point, P1, P2, dummy) <= maxoffsetSq) return true; // Skip horizontal lines, we can't intersect with them, // because the test line is horizontal if(P1.y() == P2.y()) continue; Intersection hit; if(IntersectXY(point,EndP,P1,P2,hit,maxoffset)) intersectcount++; } return (intersectcount%2==0); }
bool CuttingPlane::VertexIsOutsideOriginalPolygon( Vector2f point, float z) { // Shoot a ray along +X and count the number of intersections. // If n_intersections is euqal, return true, else return false Vector2f EndP(point.x+10000, point.y); int intersectcount = 0; for(size_t p=0; p<polygons.size();p++) { size_t count = polygons[p].points.size(); for(size_t i=0; i<count;i++) { Vector2f P1 = Vector2f( vertices[polygons[p].points[(i-1+count)%count]] ); Vector2f P2 = Vector2f( vertices[polygons[p].points[i]]); if(P1.y == P2.y) // Skip hortisontal lines, we can't intersect with them, because the test line in horitsontal continue; InFillHit hit; if(IntersectXY(point,EndP,P1,P2,hit)) intersectcount++; } } return intersectcount%2; }
vector<InFillHit> Poly::lineIntersections(const Vector2d P1, const Vector2d P2, double maxerr) const { vector<InFillHit> HitsBuffer; Vector2d P3,P4; for(size_t i = 0; i < vertices.size(); i++) { P3 = getVertexCircular(i); P4 = getVertexCircular(i+1); InFillHit hit; if (IntersectXY (P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); } return HitsBuffer; }
uint CuttingPlane::selfIntersectAndDivideRecursive(float z, uint startPolygon, uint startVertex, vector<outline> &outlines, const Vector2f endVertex, uint &level) { level++; outline result; for(size_t p=startPolygon; p<offsetPolygons.size();p++) { size_t count = offsetPolygons[p].points.size(); for(size_t v=startVertex; v<count;v++) { for(size_t p2=0; p2<offsetPolygons.size();p2++) { size_t count2 = offsetPolygons[p2].points.size(); for(size_t v2=0; v2<count2;v2++) { if((p==p2) && (v == v2)) // Dont check a point against itself continue; Vector2f P1 = offsetVertices[offsetPolygons[p].points[v]]; Vector2f P2 = offsetVertices[offsetPolygons[p].points[(v+1)%count]]; Vector2f P3 = offsetVertices[offsetPolygons[p2].points[v2]]; Vector2f P4 = offsetVertices[offsetPolygons[p2].points[(v2+1)%count2]]; InFillHit hit; result.push_back(P1); if(P1 != P3 && P2 != P3 && P1 != P4 && P2 != P4) if(IntersectXY(P1,P2,P3,P4,hit)) { if( (hit.p-endVertex).length() < 0.01) { // outlines.push_back(result); // return (v+1)%count; } result.push_back(hit.p); // v=selfIntersectAndDivideRecursive(z, p2, (v2+1)%count2, outlines, hit.p, level); // outlines.push_back(result); // return; } } } } } outlines.push_back(result); level--; return startVertex; }
vector<Intersection> Poly::lineIntersections(const Vector2d P1, const Vector2d P2, double maxerr) const { vector<Intersection> HitsBuffer; Vector2d P3,P4; for(size_t i = 0; i < vertices.size(); i++) { P3 = getVertexCircular(i); P4 = getVertexCircular(i+1); Intersection hit; if (IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); } // std::sort(HitsBuffer.begin(),HitsBuffer.end()); // vector<Vector2d> v(HitsBuffer.size()); // for(size_t i = 0; i < v.size(); i++) // v[i] = HitsBuffer[i].p; return HitsBuffer; }
bool Poly::vertexInside(const Vector2d point, double maxoffset) const { // Shoot a ray along +X and count the number of intersections. // If n_intersections is even, return false, else return true Vector2d EndP(point.x+10000, point.y); int intersectcount = 1; // we want to test if uneven for(size_t i=0; i<vertices.size();i++) { Vector2d P1 = getVertexCircular(i-1); Vector2d P2 = vertices[i]; // Skip horizontal lines, we can't intersect with them, // because the test line is horizontal if(P1.y == P2.y) continue; Intersection hit; if(IntersectXY(point,EndP,P1,P2,hit,maxoffset)) intersectcount++; } return intersectcount%2; }
void ProcessController::MakeRaft(float &z) { vector<InFillHit> HitsBuffer; uint LayerNr = 0; float step; float size = RaftSize; Vector2f raftMin = Vector2f(Min.x - size+printOffset.x, Min.y - size+printOffset.y); Vector2f raftMax = Vector2f(Max.x + size+printOffset.x, Max.y + size+printOffset.y); Vector2f Center = (Vector2f(Max.x + size, Max.y + size)-Vector2f(Min.x + size, Min.y + size))/2+Vector2f(printOffset.x, printOffset.y); float Length = sqrtf(2)*( ((raftMax.x)>(raftMax.y)? (raftMax.x):(raftMax.y)) - ((raftMin.x)<(raftMin.y)? (raftMin.x):(raftMin.y)) )/2.0f; // bbox of object float E = 0.0f; float rot = RaftRotation/180.0f*M_PI; while(LayerNr < RaftBaseLayerCount+RaftInterfaceLayerCount) { rot = (RaftRotation+(float)LayerNr*RaftRotationPrLayer)/180.0f*M_PI; Vector2f InfillDirX(cosf(rot), sinf(rot)); Vector2f InfillDirY(-InfillDirX.y, InfillDirX.x); Vector3f LastPosition; bool reverseLines = false; if(LayerNr < RaftBaseLayerCount) step = RaftBaseDistance; else step = RaftInterfaceDistance; Vector2f P1, P2; for(float x = -Length ; x < Length ; x+=step) { P1 = (InfillDirX * Length)+(InfillDirY*x)+ Center; P2 = (InfillDirX * -Length)+(InfillDirY*x)+ Center; if(reverseLines) { Vector2f tmp = P1; P1 = P2; P2 = tmp; } // glBegin(GL_LINES); // glVertex2fv(&P1.x); // glVertex2fv(&P2.x); // Crop lines to bbox*size Vector3f point; InFillHit hit; HitsBuffer.clear(); Vector2f P3(raftMin.x, raftMin.y); Vector2f P4(raftMin.x, raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) //Intersect edges of bbox HitsBuffer.push_back(hit); P3 = Vector2f(raftMax.x,raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); P4 = Vector2f(raftMax.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); P3 = Vector2f(raftMin.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); // glEnd(); if(HitsBuffer.size() == 0) // it can only be 2 or zero continue; if(HitsBuffer.size() != 2) continue; std::sort(HitsBuffer.begin(), HitsBuffer.end(), InFillHitCompareFunc); P1 = HitsBuffer[0].p; P2 = HitsBuffer[1].p; float materialRatio; if(LayerNr < RaftBaseLayerCount) materialRatio = RaftMaterialPrDistanceRatio; // move or extrude? else materialRatio = RaftInterfaceMaterialPrDistanceRatio; // move or extrude? MakeAcceleratedGCodeLine(Vector3f(P1.x,P1.y,z), Vector3f(P2.x,P2.y,z), DistanceToReachFullSpeed, materialRatio, gcode, z, MinPrintSpeedXY, MaxPrintSpeedXY, MinPrintSpeedZ, MaxPrintSpeedZ, UseIncrementalEcode, Use3DGcode, E, EnableAcceleration); reverseLines = !reverseLines; } // Set startspeed for Z-move Command g; g.Code = SETSPEED; g.where = Vector3f(P2.x, P2.y, z); g.f=MinPrintSpeedZ; g.comment = "Move Z"; g.e = E; gcode.commands.push_back(g); if(LayerNr < RaftBaseLayerCount) z+=RaftBaseThickness*LayerThickness; else z+=RaftInterfaceThickness*LayerThickness; // Move Z g.Code = ZMOVE; g.where = Vector3f(P2.x, P2.y, z); g.f=MinPrintSpeedZ; g.comment = "Move Z"; g.e = E; gcode.commands.push_back(g); LayerNr++; } }
void CuttingPlane::recurseSelfIntersectAndDivide(float z, vector<locator> &EndPointStack, vector<outline> &outlines, vector<locator> &visited) { // pop an entry from the stack. // Trace it till it hits itself // store a outline // When finds splits, store locator on stack and recurse while(EndPointStack.size()) { locator start(EndPointStack.back().p, EndPointStack.back().v, EndPointStack.back().t); visited.push_back(start); // add to visited list EndPointStack.pop_back(); // remove from to-do stack // search for the start point outline result; for(int p = start.p; p < (int)offsetPolygons.size(); p++) { for(int v = start.v; v < (int)offsetPolygons[p].points.size(); v++) { Vector2f P1 = offsetVertices[offsetPolygons[p].points[v]]; Vector2f P2 = offsetVertices[offsetPolygons[p].points[(v+1)%offsetPolygons[p].points.size()]]; result.push_back(P1); // store this point for(int p2=0; p2 < (int)offsetPolygons.size(); p2++) { int count2 = offsetPolygons[p2].points.size(); for(int v2 = 0; v2 < count2; v2++) { if((p==p2) && (v == v2)) // Dont check a point against itself continue; Vector2f P3 = offsetVertices[offsetPolygons[p2].points[v2]]; Vector2f P4 = offsetVertices[offsetPolygons[p2].points[(v2+1)%offsetPolygons[p2].points.size()]]; InFillHit hit; if(P1 != P3 && P2 != P3 && P1 != P4 && P2 != P4) { if(IntersectXY(P1,P2,P3,P4,hit)) { bool alreadyVisited=false; size_t i; for(i=0;i<visited.size();i++) { if(visited[i].p == p && visited[i].v == v) { alreadyVisited = true; break; } } if(alreadyVisited == false) { EndPointStack.push_back(locator(p,v+1,hit.t)); // continue from here later on p=p2;v=v2; // continue along the intersection line Vector2f P1 = offsetVertices[offsetPolygons[p].points[v]]; Vector2f P2 = offsetVertices[offsetPolygons[p].points[(v+1)%offsetPolygons[p].points.size()]]; } result.push_back(hit.p); // Did we hit the starting point? if (start.p == p && start.v == v) // we have a loop { outlines.push_back(result); result.clear(); recurseSelfIntersectAndDivide(z, EndPointStack, outlines, visited); return; } glPointSize(10); glColor3f(1,1,1); glBegin(GL_POINTS); glVertex3f(hit.p.x, hit.p.y, z); glEnd(); } } } } } } } }
vector<Vector2f> *CuttingPlane::CalcInFill (uint LayerNr, float InfillDistance, float InfillRotation, float InfillRotationPrLayer, bool DisplayDebuginFill) { int c=0; vector<InFillHit> HitsBuffer; float step = InfillDistance; vector<Vector2f> *infill = new vector<Vector2f>(); bool examine = false; float Length = sqrtf(2)*( ((Max.x)>(Max.y)? (Max.x):(Max.y)) - ((Min.x)<(Min.y)? (Min.x):(Min.y)) )/2.0f; // bbox of lines to intersect the poly with float rot = InfillRotation/180.0f*M_PI; rot += (float)LayerNr*InfillRotationPrLayer/180.0f*M_PI; Vector2f InfillDirX(cosf(rot), sinf(rot)); Vector2f InfillDirY(-InfillDirX.y, InfillDirX.x); Vector2f Center = (Max+Min)/2.0f; for(float x = -Length ; x < Length ; x+=step) { bool examineThis = true; HitsBuffer.clear(); Vector2f P1 = (InfillDirX * Length)+(InfillDirY*x)+ Center; Vector2f P2 = (InfillDirX * -Length)+(InfillDirY*x) + Center; if(DisplayDebuginFill) { glBegin(GL_LINES); glColor3f(0,0.2f,0); glVertex3f(P1.x, P1.y, Z); glVertex3f(P2.x, P2.y, Z); glEnd(); } float Examine = 0.5f; if(DisplayDebuginFill && !examine && ((Examine-0.5f)*2 * Length <= x)) { examineThis = examine = true; glColor3f(1,1,1); // Draw the line glVertex3f(P1.x, P1.y, Z); glVertex3f(P2.x, P2.y, Z); } if(offsetPolygons.size() != 0) { for(size_t p=0;p<offsetPolygons.size();p++) { for(size_t i=0;i<offsetPolygons[p].points.size();i++) { Vector2f P3 = offsetVertices[offsetPolygons[p].points[i]]; Vector2f P4 = offsetVertices[offsetPolygons[p].points[(i+1)%offsetPolygons[p].points.size()]]; Vector3f point; InFillHit hit; if (IntersectXY (P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); } } } /* else if(vertices.size() != 0) { // Fallback, collide with lines rather then polygons for(size_t i=0;i<lines.size();i++) { Vector2f P3 = vertices[lines[i].start]; Vector2f P4 = vertices[lines[i].end]; Vector3f point; InFillHit hit; if(IntersectXY(P1,P2,P3,P4,hit)) { if(examineThis) int a=0; HitsBuffer.push_back(hit); } } }*/ // Sort hits // Sort the vector using predicate and std::sort std::sort (HitsBuffer.begin(), HitsBuffer.end(), InFillHitCompareFunc); if(examineThis) { glPointSize(4); glBegin(GL_POINTS); for (size_t i=0;i<HitsBuffer.size();i++) glVertex3f(HitsBuffer[0].p.x, HitsBuffer[0].p.y, Z); glEnd(); glPointSize(1); } // Verify hits intregrety // Check if hit extists in table restart_check: for (size_t i=0;i<HitsBuffer.size();i++) { bool found = false; for (size_t j=i+1;j<HitsBuffer.size();j++) { if( ABS(HitsBuffer[i].d - HitsBuffer[j].d) < 0.0001) { found = true; // Delete both points, and continue HitsBuffer.erase(HitsBuffer.begin()+j); // If we are "Going IN" to solid material, and there's // more points, keep one of the points if (i != 0 && i != HitsBuffer.size()-1) HitsBuffer.erase(HitsBuffer.begin()+i); goto restart_check; } } if (found) continue; } // Sort hits by distance and transfer to InFill Buffer if (HitsBuffer.size() != 0 && HitsBuffer.size() % 2) continue; // There's a uneven number of hits, skip this infill line (U'll live) c = 0; // Color counter while (HitsBuffer.size()) { infill->push_back(HitsBuffer[0].p); if(examineThis) { switch(c) { case 0: glColor3f(1,0,0); break; case 1: glColor3f(0,1,0); break; case 2: glColor3f(0,0,1); break; case 3: glColor3f(1,1,0); break; case 4: glColor3f(0,1,1); break; case 5: glColor3f(1,0,1); break; case 6: glColor3f(1,1,1); break; case 7: glColor3f(1,0,0); break; case 8: glColor3f(0,1,0); break; case 9: glColor3f(0,0,1); break; case 10: glColor3f(1,1,0); break; case 11: glColor3f(0,1,1); break; case 12: glColor3f(1,0,1); break; case 13: glColor3f(1,1,1); break; } c++; glPointSize(10); glBegin(GL_POINTS); glVertex3f(HitsBuffer[0].p.x, HitsBuffer[0].p.y, Z); glEnd(); glPointSize(1); } HitsBuffer.erase(HitsBuffer.begin()); } } return infill; }
void Model::MakeRaft(float &z) { vector<InFillHit> HitsBuffer; uint LayerNr = 0; float size = settings.Raft.Size; Vector2f raftMin = Vector2f(Min.x - size + printOffset.x, Min.y - size + printOffset.y); Vector2f raftMax = Vector2f(Max.x + size + printOffset.x, Max.y + size + printOffset.y); Vector2f Center = (Vector2f(Max.x + size, Max.y + size)-Vector2f(Min.x + size, Min.y + size))/2+Vector2f(printOffset.x, printOffset.y); float Length = sqrtf(2)*( ((raftMax.x)>(raftMax.y)? (raftMax.x):(raftMax.y)) - ((raftMin.x)<(raftMin.y)? (raftMin.x):(raftMin.y)) )/2.0f; // bbox of object float E = 0.0f; float rot; while(LayerNr < settings.Raft.Phase[0].LayerCount + settings.Raft.Phase[1].LayerCount) { Settings::RaftSettings::PhasePropertiesType *props; props = LayerNr < settings.Raft.Phase[0].LayerCount ? &settings.Raft.Phase[0] : &settings.Raft.Phase[1]; rot = (props->Rotation+(float)LayerNr * props->RotationPrLayer)/180.0f*M_PI; Vector2f InfillDirX(cosf(rot), sinf(rot)); Vector2f InfillDirY(-InfillDirX.y, InfillDirX.x); Vector3f LastPosition; bool reverseLines = false; Vector2f P1, P2; for(float x = -Length ; x < Length ; x+=props->Distance) { P1 = (InfillDirX * Length)+(InfillDirY*x) + Center; P2 = (InfillDirX * -Length)+(InfillDirY*x) + Center; if(reverseLines) { Vector2f tmp = P1; P1 = P2; P2 = tmp; } // glBegin(GL_LINES); // glVertex2fv(&P1.x); // glVertex2fv(&P2.x); // Crop lines to bbox*size Vector3f point; InFillHit hit; HitsBuffer.clear(); Vector2f P3(raftMin.x, raftMin.y); Vector2f P4(raftMin.x, raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) //Intersect edges of bbox HitsBuffer.push_back(hit); P3 = Vector2f(raftMax.x,raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); P4 = Vector2f(raftMax.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); P3 = Vector2f(raftMin.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit)) HitsBuffer.push_back(hit); // glEnd(); if(HitsBuffer.size() == 0) // it can only be 2 or zero continue; if(HitsBuffer.size() != 2) continue; std::sort(HitsBuffer.begin(), HitsBuffer.end(), InFillHitCompareFunc); P1 = HitsBuffer[0].p; P2 = HitsBuffer[1].p; MakeAcceleratedGCodeLine (Vector3f(P1.x,P1.y,z), Vector3f(P2.x,P2.y,z), props->MaterialDistanceRatio, gcode, E, z, settings.Slicing, settings.Hardware); reverseLines = !reverseLines; } // Set startspeed for Z-move Command g; g.Code = SETSPEED; g.where = Vector3f(P2.x, P2.y, z); g.f=settings.Hardware.MinPrintSpeedZ; g.comment = "Move Z"; g.e = E; gcode.commands.push_back(g); z += props->Thickness * settings.Hardware.LayerThickness; // Move Z g.Code = ZMOVE; g.where = Vector3f(P2.x, P2.y, z); g.f = settings.Hardware.MinPrintSpeedZ; g.comment = "Move Z"; g.e = E; gcode.commands.push_back(g); LayerNr++; } // restore the E state Command gotoE; gotoE.Code = GOTO; gotoE.e = 0; gotoE.comment = "Reset E for the remaining print"; gcode.commands.push_back(gotoE); }
// old raft void Model::MakeRaft(GCodeState &state, double &z) { vector<Intersection> HitsBuffer; double raftSize = settings.Raft.Size; Vector3d raftMin = settings.Hardware.PrintMargin + Min; Vector3d raftMax = settings.Hardware.PrintMargin + Max + 2 * raftSize; Vector2d Center = Vector2d((raftMin.x + raftMax.x) / 2, (raftMin.y + raftMax.y) / 2); // bbox of object double Length = (std::max(raftMax.x,raftMax.y) - std::min(raftMin.x, raftMin.y))/sqrt(2.0); double rot; uint LayerNr = 0; uint layerCount = settings.Raft.Phase[0].LayerCount + settings.Raft.Phase[1].LayerCount; Settings::RaftSettings::PhasePropertiesType *props = &settings.Raft.Phase[0]; double thickness = props->Thickness * settings.Hardware.LayerThickness; double extrusionfactor = settings.Hardware.GetExtrudeFactor(thickness) * props->MaterialDistanceRatio; while(LayerNr < layerCount) { // If we finished phase 0, start phase 1 of the raft... if (LayerNr >= settings.Raft.Phase[0].LayerCount) props = &settings.Raft.Phase[1]; rot = (props->Rotation+(double)LayerNr * props->RotationPrLayer)/180.0*M_PI; Vector2d InfillDirX(cosf(rot), sinf(rot)); Vector2d InfillDirY(-InfillDirX.y, InfillDirX.x); Vector3d LastPosition; bool reverseLines = false; Vector2d P1, P2; double maxerr = 0.1*props->Distance; for(double x = -Length ; x < Length ; x+=props->Distance) { P1 = (InfillDirX * Length)+(InfillDirY*x) + Center; P2 = (InfillDirX * -Length)+(InfillDirY*x) + Center; if(reverseLines) { Vector2d tmp = P1; P1 = P2; P2 = tmp; } // glBegin(GL_LINES); // glVertex2fv(&P1.x); // glVertex2fv(&P2.x); // Crop lines to bbox*size Vector3d point; Intersection hit; HitsBuffer.clear(); Vector2d P3(raftMin.x, raftMin.y); Vector2d P4(raftMin.x, raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) //Intersect edges of bbox HitsBuffer.push_back(hit); P3 = Vector2d(raftMax.x,raftMax.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); P4 = Vector2d(raftMax.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); P3 = Vector2d(raftMin.x,raftMin.y); // glVertex2fv(&P3.x); // glVertex2fv(&P4.x); if(IntersectXY(P1,P2,P3,P4,hit,maxerr)) HitsBuffer.push_back(hit); // glEnd(); if(HitsBuffer.size() == 0) // it can only be 2 or zero continue; if(HitsBuffer.size() != 2) continue; std::sort(HitsBuffer.begin(), HitsBuffer.end()); P1 = HitsBuffer[0].p; P2 = HitsBuffer[1].p; state.MakeGCodeLine (Vector3d(P1.x,P1.y,z), Vector3d(P2.x,P2.y,z), Vector3d(0,0,0), 0, settings.Hardware.MaxPrintSpeedXY * 60, extrusionfactor, 0, z, settings.Slicing, settings.Hardware); reverseLines = !reverseLines; } // Set startspeed for Z-move Command g; g.Code = SETSPEED; g.where = Vector3d(P2.x, P2.y, z); g.f=settings.Hardware.MinPrintSpeedZ * 60; g.comment = "Move Z"; g.e = 0; gcode.commands.push_back(g); z += thickness; // Move Z g.Code = ZMOVE; g.where = Vector3d(P2.x, P2.y, z); g.f = settings.Hardware.MinPrintSpeedZ * 60; g.comment = "Move Z"; g.e = 0; gcode.commands.push_back(g); LayerNr++; } // restore the E state // Command gotoE; // gotoE.Code = GOTO; // gotoE.e = 0; // gotoE.comment = _("Reset E for the remaining print"); // gcode.commands.push_back(gotoE); }