// convert a model-space scaled point into G-code coordinates Pointf GCode::point_to_gcode(const Point &point) { Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset); return Pointf( unscale(point.x) + this->origin.x - extruder_offset.x, unscale(point.y) + this->origin.y - extruder_offset.y ); }
std::string SLAPrint::_SVG_path_d(const Polygon &polygon) const { const Sizef3 size = this->bb.size(); std::ostringstream d; d << "M "; for (Points::const_iterator p = polygon.points.begin(); p != polygon.points.end(); ++p) { d << unscale(p->x) - this->bb.min.x << " "; d << size.y - (unscale(p->y) - this->bb.min.y) << " "; // mirror Y coordinates as SVG uses downwards Y } d << "z"; return d.str(); }
void Renderer::getClip(Box *box) { DFBRegion clip; m_surface->GetClip(m_surface, &clip); unscale(&clip.x1); unscale(&clip.x2); unscale(&clip.y1); unscale(&clip.y2); box->x = clip.x1; box->y = clip.y1; box->w = clip.x2-clip.x1+1; box->h = clip.y2-clip.y1+1; }
/* Remove all scaling from the problem */ void __declspec(dllexport) WINAPI _unscale(lprec *lp) { if (lp != NULL) { freebuferror(); unscale(lp); } }
static void parse_status_file(const char* fn, LinuxStatus* status) { char line[256]; FILE* f; if ((f = fopen(fn, "r"))) { while (fgets(line, sizeof(line), f)) { if (strncmp(line, "State:", 6) == 0) { char* s = line+7; while (*s && isspace(*s)) ++s; switch (*s) { case 'R': status->state[S_RUNNING]++; break; case 'S': status->state[S_SLEEPING]++; break; case 'D': status->state[S_WAITING]++; break; case 'T': status->state[S_STOPPED]++; break; case 'Z': status->state[S_ZOMBIE]++; break; default: status->state[S_OTHER]++; break; } } else if (line[0] == 'V') { unsigned long value; char scale[4]; if (strncmp(line, "VmSize:", 7) == 0) { char* s = line+8; while (*s && isspace(*s)) ++s; sscanf(s, "%lu %4s", &value, scale); status->size += unscale(value, scale[0]); } else if (strncmp(line, "VmRSS:", 6) == 0) { char* s = line+7; while (*s && isspace(*s)) ++s; sscanf(s, "%lu %4s", &value, scale); status->rss += unscale(value, scale[0]); } } } fclose(f); } }
int Renderer::textWidth(const char *str) { if (!m_font) return 0; int width = m_font->width(str); unscale(&width); return width; }
// Loads an stl file, projects it to the XY plane and calculates a polygon. void BedShapePanel::load_stl() { auto dialog = new wxFileDialog(this, _(L("Choose a file to import bed shape from (STL/OBJ/AMF/3MF/PRUSA):")), "", "", file_wildcards(FT_MODEL), wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (dialog->ShowModal() != wxID_OK) { dialog->Destroy(); return; } wxArrayString input_file; dialog->GetPaths(input_file); dialog->Destroy(); std::string file_name = input_file[0].ToUTF8().data(); Model model; try { model = Model::read_from_file(file_name); } catch (std::exception &e) { auto msg = _(L("Error! ")) + file_name + " : " + e.what() + "."; show_error(this, msg); exit(1); } auto mesh = model.mesh(); auto expolygons = mesh.horizontal_projection(); if (expolygons.size() == 0) { show_error(this, _(L("The selected file contains no geometry."))); return; } if (expolygons.size() > 1) { show_error(this, _(L("The selected file contains several disjoint areas. This is not supported."))); return; } auto polygon = expolygons[0].contour; std::vector<Vec2d> points; for (auto pt : polygon.points) points.push_back(unscale(pt)); m_canvas->m_bed_shape = points; update_preview(); }
int demoImplicit(void) { # if defined ERROR # undef ERROR # endif # define ERROR() { fprintf(stderr, "Error\n"); return(1); } lprec *lp; int majorversion, minorversion, release, build; char buf[1024]; if ((lp = make_lp(0,4)) == NULL) ERROR(); lp_solve_version(&majorversion, &minorversion, &release, &build); /* let's first demonstrate the logfunc callback feature */ put_logfunc(lp, Mylogfunc, 0); sprintf(buf, "lp_solve %d.%d.%d.%d demo\n\n", majorversion, minorversion, release, build); print_str(lp, buf); solve(lp); /* just to see that a message is send via the logfunc routine ... */ /* ok, that is enough, no more callback */ put_logfunc(lp, NULL, 0); /* Now redirect all output to a file */ /* set_outputfile(lp, "result.txt"); */ /* set an abort function. Again optional */ put_abortfunc(lp, Myctrlcfunc, 0); /* set a message function. Again optional */ put_msgfunc(lp, Mymsgfunc, 0, MSG_PRESOLVE | MSG_LPFEASIBLE | MSG_LPOPTIMAL | MSG_MILPEQUAL | MSG_MILPFEASIBLE | MSG_MILPBETTER); printf("lp_solve %d.%d.%d.%d demo\n\n", majorversion, minorversion, release, build); printf("This demo will show most of the features of lp_solve %d.%d.%d.%d\n", majorversion, minorversion, release, build); press_ret(); printf("\nWe start by creating a new problem with 4 variables and 0 constraints\n"); printf("We use: lp=make_lp(0,4);\n"); press_ret(); printf("We can show the current problem with print_lp(lp)\n"); print_lp(lp); press_ret(); printf("Now we add some constraints\n"); printf("str_add_constraint(lp, \"3 2 2 1\" ,LE,4)\n"); printf("This is the string version of add_constraint. For the normal version\n"); printf("of add_constraint see the help file.\n"); if (!str_add_constraint(lp, "3 2 2 1", LE, 4)) ERROR(); print_lp(lp); press_ret(); printf("str_add_constraint(lp, \"0 4 3 1\" ,GE,3)\n"); if (!str_add_constraint(lp, "0 4 3 1", GE, 3)) ERROR(); print_lp(lp); press_ret(); printf("Set the objective function\n"); printf("str_set_obj_fn(lp, \"2 3 -2 3\")\n"); if (!str_set_obj_fn(lp, "2 3 -2 3")) ERROR(); print_lp(lp); press_ret(); printf("Now solve the problem with printf(solve(lp));\n"); printf("%d",solve(lp)); press_ret(); printf("The value is 0, this means we found an optimal solution\n"); printf("We can display this solution with print_objective(lp) and print_solution(lp)\n"); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("The dual variables of the solution are printed with\n"); printf("print_duals(lp);\n"); print_duals(lp); press_ret(); printf("We can change a single element in the matrix with\n"); printf("set_mat(lp,2,1,0.5)\n"); if (!set_mat(lp,2,1,0.5)) ERROR(); print_lp(lp); press_ret(); printf("If we want to maximize the objective function use set_maxim(lp);\n"); set_maxim(lp); print_lp(lp); press_ret(); printf("after solving this gives us:\n"); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); print_duals(lp); press_ret(); printf("Change the value of a rhs element with set_rh(lp,1,7.45)\n"); set_rh(lp,1,7.45); print_lp(lp); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("We change %s to the integer type with\n", get_col_name(lp, 4)); printf("set_int(lp, 4, TRUE)\n"); set_int(lp, 4, TRUE); print_lp(lp); printf("We set branch & bound debugging on with set_debug(lp, TRUE)\n"); set_debug(lp, TRUE); printf("and solve...\n"); press_ret(); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("We can set bounds on the variables with\n"); printf("set_lowbo(lp,2,2); & set_upbo(lp,4,5.3)\n"); set_lowbo(lp,2,2); set_upbo(lp,4,5.3); print_lp(lp); press_ret(); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("Now remove a constraint with del_constraint(lp, 1)\n"); del_constraint(lp,1); print_lp(lp); printf("Add an equality constraint\n"); if (!str_add_constraint(lp, "1 2 1 4", EQ, 8)) ERROR(); print_lp(lp); press_ret(); printf("A column can be added with:\n"); printf("str_add_column(lp,\"3 2 2\");\n"); if (!str_add_column(lp,"3 2 2")) ERROR(); print_lp(lp); press_ret(); printf("A column can be removed with:\n"); printf("del_column(lp,3);\n"); del_column(lp,3); print_lp(lp); press_ret(); printf("We can use automatic scaling with:\n"); printf("set_scaling(lp, SCALE_MEAN);\n"); set_scaling(lp, SCALE_MEAN); print_lp(lp); press_ret(); printf("The function get_mat(lprec *lp, int row, int column) returns a single\n"); printf("matrix element\n"); printf("%s get_mat(lp,2,3), get_mat(lp,1,1); gives\n","printf(\"%f %f\\n\","); printf("%f %f\n", (double)get_mat(lp,2,3), (double)get_mat(lp,1,1)); printf("Notice that get_mat returns the value of the original unscaled problem\n"); press_ret(); printf("If there are any integer type variables, then only the rows are scaled\n"); printf("set_scaling(lp, SCALE_MEAN);\n"); set_scaling(lp, SCALE_MEAN); printf("set_int(lp,3,FALSE);\n"); set_int(lp,3,FALSE); print_lp(lp); press_ret(); solve(lp); printf("print_objective, print_solution gives the solution to the original problem\n"); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("Scaling is turned off with unscale(lp);\n"); unscale(lp); print_lp(lp); press_ret(); printf("Now turn B&B debugging off and simplex tracing on with\n"); printf("set_debug(lp, FALSE), set_trace(lp, TRUE) and solve(lp)\n"); set_debug(lp, FALSE); set_trace(lp, TRUE); press_ret(); solve(lp); printf("Where possible, lp_solve will start at the last found basis\n"); printf("We can reset the problem to the initial basis with\n"); printf("default_basis(lp). Now solve it again...\n"); press_ret(); default_basis(lp); solve(lp); printf("It is possible to give variables and constraints names\n"); printf("set_row_name(lp,1,\"speed\"); & set_col_name(lp,2,\"money\")\n"); if (!set_row_name(lp,1,"speed")) ERROR(); if (!set_col_name(lp,2,"money")) ERROR(); print_lp(lp); printf("As you can see, all column and rows are assigned default names\n"); printf("If a column or constraint is deleted, the names shift place also:\n"); press_ret(); printf("del_column(lp,1);\n"); del_column(lp,1); print_lp(lp); press_ret(); delete_lp(lp); /* printf("A lp structure can be created and read from a .lp file\n"); printf("lp = read_LP(\"lp_examples/demo_lag.lp\", TRUE);\n"); printf("The verbose option is used\n"); if ((lp = read_LP("lp_examples/demo_lag.lp", TRUE, "test")) == NULL) ERROR(); press_ret(); printf("lp is now:\n"); print_lp(lp); press_ret(); printf("solution:\n"); set_debug(lp, TRUE); solve(lp); set_debug(lp, FALSE); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("You can see that branch & bound was used in this problem\n"); printf("Now remove the last constraint and use lagrangian relaxation\n"); printf("del_constraint(lp,6);\n"); printf("str_add_lag_con(lp, \"1 1 1 0 0 0\", LE, 2);\n"); del_constraint(lp,6); if (!str_add_lag_con(lp, "1 1 1 0 0 0", LE, 2)) ERROR(); print_lp(lp); */ /* printf("Lagrangian relaxation is used in some heuristics. It is now possible\n"); printf("to get a feasible integer solution without usage of branch & bound.\n"); printf("Use lag_solve(lp, 0, 30); 0 is the initial bound, 30 the maximum\n"); printf("number of iterations, the last variable turns the verbose mode on.\n"); press_ret(); set_lag_trace(lp, TRUE); printf("%d\n",lag_solve(lp, 0, 30)); printf("The returncode of lag_solve is 6 or FEAS_FOUND. this means that a feasible\n"); printf("solution has been found. For a list of other possible return values\n"); printf("see the help file. Print this solution with print_objective, print_solution\n"); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); delete_lp(lp); */ press_ret(); return(0); }
int main(void) { lprec *lp1,*lp2; FILE *input_file; printf("lp_solve 2.0 demo by Jeroen J. Dirks ([email protected])\n\n"); printf("This demo will show most of the features of lp_solve 2.0\n"); press_ret(); printf("\nWe start by creating a new problem with 4 variables and 0 constraints\n"); printf("We use: lp1=make_lp(0,4);\n"); lp1=make_lp(0,4); press_ret(); printf("We can show the current problem with print_lp(lp1)\n"); print_lp(lp1); press_ret(); printf("Now we add some constraints\n"); printf("str_add_constraint(lp1, \"3 2 2 1\" ,LE,4)\n"); printf("This is the string version of add_constraint. For the normal version\n"); printf("of add_constraint see the file lpkit.h\n"); str_add_constraint(lp1, "3 2 2 1", LE, 4); print_lp(lp1); press_ret(); printf("str_add_constraint(lp1, \"0 4 3 1\" ,GE,3)\n"); str_add_constraint(lp1, "0 4 3 1", GE, 3); print_lp(lp1); press_ret(); printf("Set the objective function\n"); printf("str_set_obj_fn(lp1, \"2 3 -2 3\")\n"); str_set_obj_fn(lp1, "2 3 -2 3"); print_lp(lp1); press_ret(); printf("Now solve the problem with printf(solve(lp1));\n"); printf("%d",solve(lp1)); press_ret(); printf("The value is 0, this means we found an optimal solution\n"); printf("We can display this solution with print_solution(lp1)\n"); print_solution(lp1); press_ret(); printf("The dual variables of the solution are printed with\n"); printf("print_duals(lp1);\n"); print_duals(lp1); press_ret(); printf("We can change a single element in the matrix with\n"); printf("set_mat(lp1,2,1,0.5)\n"); set_mat(lp1,2,1,0.5); print_lp(lp1); press_ret(); printf("It we want to maximise the objective function use set_maxim(lp1);\n"); set_maxim(lp1); print_lp(lp1); press_ret(); printf("after solving this gives us:\n"); solve(lp1); print_solution(lp1); print_duals(lp1); press_ret(); printf("Change the value of a rhs element with set_rh(lp1,1,7.45)\n"); set_rh(lp1,1,7.45); print_lp(lp1); solve(lp1); print_solution(lp1); press_ret(); printf("We change Var[4] to the integer type with\n"); printf("set_int(lp1, 4, TRUE)\n"); set_int(lp1, 4, TRUE); print_lp(lp1); printf("We set branch & bound debugging on with lp1->debug=TRUE\n"); lp1->debug=TRUE; printf("and solve...\n"); press_ret(); solve(lp1); print_solution(lp1); press_ret(); printf("We can set bounds on the variables with\n"); printf("set_lowbo(lp1,2,2); & set_upbo(lp1,4,5.3)\n"); set_lowbo(lp1,2,2); set_upbo(lp1,4,5.3); print_lp(lp1); press_ret(); solve(lp1); print_solution(lp1); press_ret(); printf("Now remove a constraint with del_constraint(lp1, 1)\n"); del_constraint(lp1,1); print_lp(lp1); printf("Add an equality constraint\n"); str_add_constraint(lp1, "1 2 1 4", EQ, 8); print_lp(lp1); press_ret(); printf("A column can be added with:\n"); printf("str_add_column(lp1,\"3 2 2\");\n"); str_add_column(lp1,"3 2 2"); print_lp(lp1); press_ret(); printf("A column can be removed with:\n"); printf("del_column(lp1,3);\n"); del_column(lp1,3); print_lp(lp1); press_ret(); printf("We can use automatic scaling with:\n"); printf("auto_scale(lp1);\n"); auto_scale(lp1); print_lp(lp1); press_ret(); printf("The function mat_elm(lprec *lp, int row, int column) returns a single\n"); printf("matrix element\n"); printf("%s mat_elm(lp1,2,3), mat_elm(lp1,1,1); gives\n","printf(\"%f %f\\n\","); printf("%f %f\n",mat_elm(lp1,2,3), mat_elm(lp1,1,1)); printf("Notice that mat_elm returns the value of the original unscaled problem\n"); press_ret(); printf("It there are any integer type variables, then only the rows are scaled\n"); printf("set_int(lp1,3,FALSE);\n"); printf("auto_scale(lp1);\n"); set_int(lp1,3,FALSE); auto_scale(lp1); print_lp(lp1); press_ret(); solve(lp1); printf("print_solution gives the solution to the original problem\n"); print_solution(lp1); press_ret(); printf("Scaling is turned off with unscale(lp1);\n"); unscale(lp1); print_lp(lp1); press_ret(); printf("Now turn B&B debugging of and simplex tracing on with\n"); printf("lp1->debug=FALSE, lp1->trace=TRUE and solve(lp1)\n"); lp1->debug=FALSE; lp1->trace=TRUE; press_ret(); solve(lp1); printf("Where possible, lp_solve will start at the last found basis\n"); printf("We can reset the problem to the initial basis with\n"); printf("reset_basis(lp1). Now solve it again...\n"); press_ret(); reset_basis(lp1); solve(lp1); press_ret(); printf("It is possible to give variables and constraints names\n"); printf("set_row_name(lp1,1,\"speed\"); & set_col_name(lp1,2,\"money\")\n"); set_row_name(lp1,1,"speed"); set_col_name(lp1,2,"money"); print_lp(lp1); printf("As you can see, all column and rows are assigned default names\n"); printf("If a column or constraint is deleted, the names shift place also:\n"); press_ret(); printf("del_column(lp1,1);\n"); del_column(lp1,1); print_lp(lp1); press_ret(); printf("A lp structure can be created and read from a .lp file\n"); printf("input_file=fopen(\"lp_examples/demo_lag.lp\",\"r\");\n"); printf("lp2 = read_lp_file(input_file, TRUE);\n"); printf("The verbose option is used\n"); input_file = fopen("lp_examples/demo_lag.lp", "r"); if (input_file == NULL) { printf("Can't find demo_lag.lp, stopping\n"); exit(EXIT_FAILURE); } lp2 = read_lp_file(input_file, TRUE, "test"); press_ret(); printf("lp2 is now:\n"); print_lp(lp2); press_ret(); printf("solution:\n"); lp2->debug=TRUE; solve(lp2); lp2->debug=FALSE; print_solution(lp2); press_ret(); printf("You can see that branch & bound was used in this problem\n"); printf("Now remove the last constraint and use lagrangian relaxation\n"); printf("del_constraint(lp2,6);\n"); printf("str_add_lag_con(lp2, \"1 1 1 0 0 0\", LE, 2);\n"); del_constraint(lp2,6); str_add_lag_con(lp2, "1 1 1 0 0 0", LE, 2); print_lp(lp2); printf("Lagrangian relaxation is used in some heuristics. It is now possible\n"); printf("to get a feasible integer soltution without usage of branch & bound.\n"); printf("Use lag_solve(lp2, 0, 40, TRUE); 0 is the initial bound, 30 the maximum\n"); printf("number of iterations, the last variable turns the verbose mode on.\n"); press_ret(); printf("%d\n",lag_solve(lp2, 0, 30, TRUE)); printf("The returncode of lag_solve is 6 or FEAS_FOUND. this means that a feasible\n"); printf("solution has been found. For a list of other possible return values\n"); printf("see \"lpkit.h\". Print this solution with print_solution\n"); print_solution(lp2); press_ret(); return(0); }
static Pointf new_unscale(const Point &p) { return Pointf(unscale(p.x), unscale(p.y)); };
static Pointf new_unscale(coord_t x, coord_t y) { return Pointf(unscale(x), unscale(y)); };
static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) { return Pointf3(unscale(x), unscale(y), unscale(z)); };
void PerimeterGenerator::process() { // other perimeters this->_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); coord_t pwidth = this->perimeter_flow.scaled_width(); coord_t pspacing = this->perimeter_flow.scaled_spacing(); // external perimeters this->_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm(); coord_t ext_pwidth = this->ext_perimeter_flow.scaled_width(); coord_t ext_pspacing = this->ext_perimeter_flow.scaled_spacing(); coord_t ext_pspacing2 = this->ext_perimeter_flow.scaled_spacing(this->perimeter_flow); // overhang perimeters this->_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm(); // solid infill coord_t ispacing = this->solid_infill_flow.scaled_spacing(); coord_t gap_area_threshold = pwidth * pwidth; // Calculate the minimum required spacing between two adjacent traces. // This should be equal to the nominal flow spacing but we experiment // with some tolerance in order to avoid triggering medial axis when // some squishing might work. Loops are still spaced by the entire // flow spacing; this only applies to collapsing parts. // For ext_min_spacing we use the ext_pspacing calculated for two adjacent // external loops (which is the correct way) instead of using ext_pspacing2 // which is the spacing between external and internal, which is not correct // and would make the collapsing (thus the details resolution) dependent on // internal flow which is unrelated. coord_t min_spacing = pspacing * (1 - INSET_OVERLAP_TOLERANCE); coord_t ext_min_spacing = ext_pspacing * (1 - INSET_OVERLAP_TOLERANCE); // prepare grown lower layer slices for overhang detection if (this->lower_slices != NULL && this->config->overhangs) { // We consider overhang any part where the entire nozzle diameter is not supported by the // lower layer, so we take lower slices and offset them by half the nozzle diameter used // in the current layer double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder-1); this->_lower_slices_p = offset(*this->lower_slices, scale_(+nozzle_diameter/2)); } // we need to process each island separately because we might have different // extra perimeters for each one for (Surfaces::const_iterator surface = this->slices->surfaces.begin(); surface != this->slices->surfaces.end(); ++surface) { // detect how many perimeters must be generated for this island signed short loop_number = this->config->perimeters + surface->extra_perimeters; loop_number--; // 0-indexed loops Polygons gaps; Polygons last = surface->expolygon.simplify_p(SCALED_RESOLUTION); if (loop_number >= 0) { // no loops = -1 std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops std::vector<PerimeterGeneratorLoops> holes(loop_number+1); // depth => loops Polylines thin_walls; // we loop one time more than needed in order to find gaps after the last perimeter was applied for (signed short i = 0; i <= loop_number+1; ++i) { // outer loop is 0 Polygons offsets; if (i == 0) { // the minimum thickness of a single loop is: // ext_width/2 + ext_spacing/2 + spacing/2 + width/2 if (this->config->thin_walls) { offsets = offset2( last, -(ext_pwidth/2 + ext_min_spacing/2 - 1), +(ext_min_spacing/2 - 1) ); } else { offsets = offset(last, -ext_pwidth/2); } // look for thin walls if (this->config->thin_walls) { Polygons diffpp = diff( last, offset(offsets, +ext_pwidth/2), true // medial axis requires non-overlapping geometry ); // the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width // (actually, something larger than that still may exist due to mitering or other causes) coord_t min_width = ext_pwidth / 2; ExPolygons expp = offset2_ex(diffpp, -min_width/2, +min_width/2); // the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop Polylines pp; for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) ex->medial_axis(ext_pwidth + ext_pspacing2, min_width, &pp); double threshold = ext_pwidth * 2; for (Polylines::const_iterator p = pp.begin(); p != pp.end(); ++p) { if (p->length() > threshold) { thin_walls.push_back(*p); } } #ifdef DEBUG printf(" %zu thin walls detected\n", thin_walls.size()); #endif /* if (false) { require "Slic3r/SVG.pm"; Slic3r::SVG::output( "medial_axis.svg", no_arrows => 1, #expolygons => \@expp, polylines => \@thin_walls, ); } */ } } else { coord_t distance = (i == 1) ? ext_pspacing2 : pspacing; if (this->config->thin_walls) { offsets = offset2( last, -(distance + min_spacing/2 - 1), +(min_spacing/2 - 1) ); } else { offsets = offset( last, -distance ); } // look for gaps if (this->config->gap_fill_speed.value > 0 && this->config->fill_density.value > 0) { // not using safety offset here would "detect" very narrow gaps // (but still long enough to escape the area threshold) that gap fill // won't be able to fill but we'd still remove from infill area ExPolygons diff_expp = diff_ex( offset(last, -0.5*distance), offset(offsets, +0.5*distance + 10) // safety offset ); for (ExPolygons::const_iterator ex = diff_expp.begin(); ex != diff_expp.end(); ++ex) { if (fabs(ex->area()) >= gap_area_threshold) { Polygons pp = *ex; gaps.insert(gaps.end(), pp.begin(), pp.end()); } } } } if (offsets.empty()) break; if (i > loop_number) break; // we were only looking for gaps this time last = offsets; for (Polygons::const_iterator polygon = offsets.begin(); polygon != offsets.end(); ++polygon) { PerimeterGeneratorLoop loop(*polygon, i); loop.is_contour = polygon->is_counter_clockwise(); if (loop.is_contour) { contours[i].push_back(loop); } else { holes[i].push_back(loop); } } } // nest loops: holes first for (signed short d = 0; d <= loop_number; ++d) { PerimeterGeneratorLoops &holes_d = holes[d]; // loop through all holes having depth == d for (signed short i = 0; i < holes_d.size(); ++i) { const PerimeterGeneratorLoop &loop = holes_d[i]; // find the hole loop that contains this one, if any for (signed short t = d+1; t <= loop_number; ++t) { for (signed short j = 0; j < holes[t].size(); ++j) { PerimeterGeneratorLoop &candidate_parent = holes[t][j]; if (candidate_parent.polygon.contains(loop.polygon.first_point())) { candidate_parent.children.push_back(loop); holes_d.erase(holes_d.begin() + i); --i; goto NEXT_LOOP; } } } // if no hole contains this hole, find the contour loop that contains it for (signed short t = loop_number; t >= 0; --t) { for (signed short j = 0; j < contours[t].size(); ++j) { PerimeterGeneratorLoop &candidate_parent = contours[t][j]; if (candidate_parent.polygon.contains(loop.polygon.first_point())) { candidate_parent.children.push_back(loop); holes_d.erase(holes_d.begin() + i); --i; goto NEXT_LOOP; } } } NEXT_LOOP: ; } } // nest contour loops for (signed short d = loop_number; d >= 1; --d) { PerimeterGeneratorLoops &contours_d = contours[d]; // loop through all contours having depth == d for (signed short i = 0; i < contours_d.size(); ++i) { const PerimeterGeneratorLoop &loop = contours_d[i]; // find the contour loop that contains it for (signed short t = d-1; t >= 0; --t) { for (signed short j = 0; j < contours[t].size(); ++j) { PerimeterGeneratorLoop &candidate_parent = contours[t][j]; if (candidate_parent.polygon.contains(loop.polygon.first_point())) { candidate_parent.children.push_back(loop); contours_d.erase(contours_d.begin() + i); --i; goto NEXT_CONTOUR; } } } NEXT_CONTOUR: ; } } // at this point, all loops should be in contours[0] ExtrusionEntityCollection entities = this->_traverse_loops(contours.front(), thin_walls); // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim // TODO: add test for perimeter order if (this->config->external_perimeters_first || (this->layer_id == 0 && this->print_config->brim_width.value > 0)) entities.reverse(); // append perimeters for this slice as a collection if (!entities.empty()) this->loops->append(entities); } // fill gaps if (!gaps.empty()) { /* if (false) { require "Slic3r/SVG.pm"; Slic3r::SVG::output( "gaps.svg", expolygons => union_ex(\@gaps), ); } */ // where $pwidth < thickness < 2*$pspacing, infill with width = 2*$pwidth // where 0.1*$pwidth < thickness < $pwidth, infill with width = 1*$pwidth std::vector<PerimeterGeneratorGapSize> gap_sizes; gap_sizes.push_back(PerimeterGeneratorGapSize(pwidth, 2*pspacing, 2*pwidth)); gap_sizes.push_back(PerimeterGeneratorGapSize(0.1*pwidth, pwidth, 1*pwidth)); for (std::vector<PerimeterGeneratorGapSize>::const_iterator gap_size = gap_sizes.begin(); gap_size != gap_sizes.end(); ++gap_size) { ExtrusionEntityCollection gap_fill = this->_fill_gaps(gap_size->min, gap_size->max, unscale(gap_size->width), gaps); this->gap_fill->append(gap_fill.entities); // Make sure we don't infill narrow parts that are already gap-filled // (we only consider this surface's gaps to reduce the diff() complexity). // Growing actual extrusions ensures that gaps not filled by medial axis // are not subtracted from fill surfaces (they might be too short gaps // that medial axis skips but infill might join with other infill regions // and use zigzag). coord_t dist = gap_size->width/2; Polygons filled; for (ExtrusionEntitiesPtr::const_iterator it = gap_fill.entities.begin(); it != gap_fill.entities.end(); ++it) { Polygons f; offset((*it)->as_polyline(), &f, dist); filled.insert(filled.end(), f.begin(), f.end()); } last = diff(last, filled); gaps = diff(gaps, filled); // prevent more gap fill here } } // create one more offset to be used as boundary for fill // we offset by half the perimeter spacing (to get to the actual infill boundary) // and then we offset back and forth by half the infill spacing to only consider the // non-collapsing regions coord_t inset = 0; if (loop_number == 0) { // one loop inset += ext_pspacing2/2; } else if (loop_number > 0) { // two or more loops inset += pspacing/2; } // only apply infill overlap if we actually have one perimeter if (inset > 0) inset -= this->config->get_abs_value("infill_overlap", inset + ispacing/2); { ExPolygons expp = union_ex(last); // simplify infill contours according to resolution Polygons pp; for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) ex->simplify_p(SCALED_RESOLUTION, &pp); // collapse too narrow infill areas coord_t min_perimeter_infill_spacing = ispacing * (1 - INSET_OVERLAP_TOLERANCE); expp = offset2_ex( pp, -inset -min_perimeter_infill_spacing/2, +min_perimeter_infill_spacing/2 ); // append infill areas to fill_surfaces for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) this->fill_surfaces->surfaces.push_back(Surface(stInternal, *ex)); // use a bogus surface type } } }
void SLAPrint::write_svg(const std::string &outputfile) const { const Sizef3 size = this->bb.size(); const double support_material_radius = sm_pillars_radius(); FILE* f = fopen(outputfile.c_str(), "w"); fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" "<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\" viewport-fill=\"black\">\n" "<!-- Generated using Slic3r %s http://slic3r.org/ -->\n" , size.x, size.y, SLIC3R_VERSION); for (size_t i = 0; i < this->layers.size(); ++i) { const Layer &layer = this->layers[i]; fprintf(f, "\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\" slic3r:slice-z=\"%0.4f\" slic3r:layer-height=\"%0.4f\">\n", i, layer.print_z, layer.slice_z, layer.print_z - ((i == 0) ? 0. : this->layers[i-1].print_z) ); if (layer.solid) { const ExPolygons &slices = layer.slices.expolygons; for (ExPolygons::const_iterator it = slices.begin(); it != slices.end(); ++it) { std::string pd = this->_SVG_path_d(*it); fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n", pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) ); } } else { // Perimeters. for (ExPolygons::const_iterator it = layer.perimeters.expolygons.begin(); it != layer.perimeters.expolygons.end(); ++it) { std::string pd = this->_SVG_path_d(*it); fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"perimeter\" />\n", pd.c_str(), "white", "black", "0" ); } // Solid infill. for (ExPolygons::const_iterator it = layer.solid_infill.expolygons.begin(); it != layer.solid_infill.expolygons.end(); ++it) { std::string pd = this->_SVG_path_d(*it); fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n", pd.c_str(), "white", "black", "0" ); } // Internal infill. for (ExtrusionEntitiesPtr::const_iterator it = layer.infill.entities.begin(); it != layer.infill.entities.end(); ++it) { const ExPolygons infill = union_ex((*it)->grow()); for (ExPolygons::const_iterator e = infill.begin(); e != infill.end(); ++e) { std::string pd = this->_SVG_path_d(*e); fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n", pd.c_str(), "white", "black", "0" ); } } } // don't print support material in raft layers if (i >= (size_t)this->config.raft_layers) { // look for support material pillars belonging to this layer for (std::vector<SupportPillar>::const_iterator it = this->sm_pillars.begin(); it != this->sm_pillars.end(); ++it) { if (!(it->top_layer >= i && it->bottom_layer <= i)) continue; // generate a conic tip float radius = fminf( support_material_radius, (it->top_layer - i + 1) * this->config.layer_height.value ); fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n", unscale(it->x) - this->bb.min.x, size.y - (unscale(it->y) - this->bb.min.y), radius ); } } fprintf(f,"\t</g>\n"); } fprintf(f,"</svg>\n"); }
void SVGExport::writeSVG(const std::string &outputfile) { // align to origin taking raft into account BoundingBoxf3 bb = this->mesh.bounding_box(); if (this->config.raft_layers > 0) { bb.min.x -= this->config.raft_offset.value; bb.min.y -= this->config.raft_offset.value; bb.max.x += this->config.raft_offset.value; bb.max.y += this->config.raft_offset.value; } this->mesh.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin bb.translate(-bb.min.x, -bb.min.y, -bb.min.z); // align to origin const Sizef3 size = bb.size(); // if we are generating a raft, first_layer_height will not affect mesh slicing const float lh = this->config.layer_height.value; const float first_lh = this->config.first_layer_height.value; // generate the list of Z coordinates for mesh slicing // (we slice each layer at half of its thickness) std::vector<float> slice_z, layer_z; { const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh; slice_z.push_back(first_slice_lh/2); layer_z.push_back(first_slice_lh); } while (layer_z.back() + lh/2 <= this->mesh.stl.stats.max.z) { slice_z.push_back(layer_z.back() + lh/2); layer_z.push_back(layer_z.back() + lh); } // perform the slicing std::vector<ExPolygons> layers; TriangleMeshSlicer(&this->mesh).slice(slice_z, &layers); // generate a solid raft if requested if (this->config.raft_layers > 0) { ExPolygons raft = offset_ex(layers.front(), scale_(this->config.raft_offset)); for (int i = this->config.raft_layers; i >= 1; --i) { layer_z.insert(layer_z.begin(), first_lh + lh * (i-1)); layers.insert(layers.begin(), raft); } // prepend total raft height to all sliced layers for (int i = this->config.raft_layers; i < layer_z.size(); ++i) layer_z[i] += first_lh + lh * (this->config.raft_layers-1); } // generate support material std::vector<Points> support_material(layers.size()); if (this->config.support_material) { // generate a grid of points according to the configured spacing, // covering the entire object bounding box Points support_material_points; for (coordf_t x = bb.min.x; x <= bb.max.x; x += this->config.support_material_spacing) { for (coordf_t y = bb.min.y; y <= bb.max.y; y += this->config.support_material_spacing) { support_material_points.push_back(Point(scale_(x), scale_(y))); } } // check overhangs, starting from the upper layer, and detect which points apply // to each layer ExPolygons overhangs; for (int i = layer_z.size()-1; i >= 0; --i) { overhangs = diff_ex(union_(overhangs, layers[i+1]), layers[i]); for (Points::const_iterator it = support_material_points.begin(); it != support_material_points.end(); ++it) { for (ExPolygons::const_iterator e = overhangs.begin(); e != overhangs.end(); ++e) { if (e->contains(*it)) { support_material[i].push_back(*it); break; } } } } } double support_material_radius = this->config.support_material_extrusion_width.get_abs_value(this->config.layer_height)/2; FILE* f = fopen(outputfile.c_str(), "w"); fprintf(f, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" "<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\" viewport-fill=\"black\">\n" "<!-- Generated using Slic3r %s http://slic3r.org/ -->\n" , size.x, size.y, SLIC3R_VERSION); for (size_t i = 0; i < layer_z.size(); ++i) { fprintf(f, "\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\">\n", i, layer_z[i]); for (ExPolygons::const_iterator it = layers[i].begin(); it != layers[i].end(); ++it) { std::string pd; Polygons pp = *it; for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp) { std::ostringstream d; d << "M "; for (Points::const_iterator p = mp->points.begin(); p != mp->points.end(); ++p) { d << unscale(p->x) << " "; d << unscale(p->y) << " "; } d << "z"; pd += d.str() + " "; } fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n", pd.c_str(), "white", "black", "0", unscale(unscale(it->area())) ); } for (Points::const_iterator it = support_material[i].begin(); it != support_material[i].end(); ++it) { fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n", unscale(it->x), unscale(it->y), support_material_radius ); } fprintf(f,"\t</g>\n"); } fprintf(f,"</svg>\n"); }
/// The LayerRegion at this point of time may contain /// surfaces of various types (internal/bridge/top/bottom/solid). /// The infills are generated on the groups of surfaces with a compatible type. /// Fills an array of ExtrusionPathCollection objects containing the infills generated now /// and the thin fills generated by generate_perimeters(). void LayerRegion::make_fill() { this->fills.clear(); const double fill_density = this->region()->config.fill_density; const Flow infill_flow = this->flow(frInfill); const Flow solid_infill_flow = this->flow(frSolidInfill); const Flow top_solid_infill_flow = this->flow(frTopSolidInfill); const coord_t perimeter_spacing = this->flow(frPerimeter).scaled_spacing(); SurfaceCollection surfaces; // merge adjacent surfaces // in case of bridge surfaces, the ones with defined angle will be attached to the ones // without any angle (shouldn't this logic be moved to process_external_surfaces()?) { Polygons polygons_bridged; polygons_bridged.reserve(this->fill_surfaces.surfaces.size()); for (Surfaces::const_iterator it = this->fill_surfaces.surfaces.begin(); it != this->fill_surfaces.surfaces.end(); ++it) if (it->is_bridge() && it->bridge_angle >= 0) append_to(polygons_bridged, (Polygons)*it); // group surfaces by distinct properties (equal surface_type, thickness, thickness_layers, bridge_angle) // group is of type SurfaceCollection // FIXME: Use some smart heuristics to merge similar surfaces to eliminate tiny regions. std::vector<SurfacesConstPtr> groups; this->fill_surfaces.group(&groups); // merge compatible solid groups (we can generate continuous infill for them) { // cache flow widths and patterns used for all solid groups // (we'll use them for comparing compatible groups) std::vector<SurfaceGroupAttrib> group_attrib(groups.size()); for (size_t i = 0; i < groups.size(); ++i) { const Surface &surface = *groups[i].front(); // we can only merge solid non-bridge surfaces, so discard // non-solid or bridge surfaces if (!surface.is_solid() || surface.is_bridge()) continue; group_attrib[i].is_solid = true; group_attrib[i].fw = (surface.is_top()) ? top_solid_infill_flow.width : solid_infill_flow.width; group_attrib[i].pattern = surface.is_top() ? this->region()->config.top_infill_pattern.value : surface.is_bottom() ? this->region()->config.bottom_infill_pattern.value : ipRectilinear; } // Loop through solid groups, find compatible groups and append them to this one. for (size_t i = 0; i < groups.size(); ++i) { if (!group_attrib[i].is_solid) continue; for (size_t j = i + 1; j < groups.size();) { if (group_attrib[i] == group_attrib[j]) { // groups are compatible, merge them append_to(groups[i], groups[j]); groups.erase(groups.begin() + j); group_attrib.erase(group_attrib.begin() + j); } else { ++j; } } } } // Give priority to oriented bridges. Process the bridges in the first round, the rest of the surfaces in the 2nd round. for (size_t round = 0; round < 2; ++ round) { for (std::vector<SurfacesConstPtr>::const_iterator it_group = groups.begin(); it_group != groups.end(); ++ it_group) { const SurfacesConstPtr &group = *it_group; const bool is_oriented_bridge = group.front()->is_bridge() && group.front()->bridge_angle >= 0; if (is_oriented_bridge != (round == 0)) continue; // Make a union of polygons defining the infiill regions of a group, use a safety offset. Polygons union_p = union_(to_polygons(group), true); // Subtract surfaces having a defined bridge_angle from any other, use a safety offset. if (!is_oriented_bridge && !polygons_bridged.empty()) union_p = diff(union_p, polygons_bridged, true); // subtract any other surface already processed //FIXME Vojtech: Because the bridge surfaces came first, they are subtracted twice! surfaces.append( diff_ex(union_p, to_polygons(surfaces), true), *group.front() // template ); } } } // we need to detect any narrow surfaces that might collapse // when adding spacing below // such narrow surfaces are often generated in sloping walls // by bridge_over_infill() and combine_infill() as a result of the // subtraction of the combinable area from the layer infill area, // which leaves small areas near the perimeters // we are going to grow such regions by overlapping them with the void (if any) // TODO: detect and investigate whether there could be narrow regions without // any void neighbors { coord_t distance_between_surfaces = std::max( std::max(infill_flow.scaled_spacing(), solid_infill_flow.scaled_spacing()), top_solid_infill_flow.scaled_spacing() ); Polygons surfaces_polygons = (Polygons)surfaces; Polygons collapsed = diff( surfaces_polygons, offset2(surfaces_polygons, -distance_between_surfaces/2, +distance_between_surfaces/2), true ); Polygons to_subtract; surfaces.filter_by_type((stInternal | stVoid), &to_subtract); append_to(to_subtract, collapsed); surfaces.append( intersection_ex( offset(collapsed, distance_between_surfaces), to_subtract, true ), (stInternal | stSolid) ); } if (false) { // require "Slic3r/SVG.pm"; // Slic3r::SVG::output("fill_" . $layerm->print_z . ".svg", // expolygons => [ map $_->expolygon, grep !$_->is_solid, @surfaces ], // red_expolygons => [ map $_->expolygon, grep $_->is_solid, @surfaces ], // ); } for (Surfaces::const_iterator surface_it = surfaces.surfaces.begin(); surface_it != surfaces.surfaces.end(); ++surface_it) { const Surface &surface = *surface_it; if (surface.surface_type == (stInternal | stVoid)) continue; InfillPattern fill_pattern = this->region()->config.fill_pattern.value; double density = fill_density; FlowRole role = (surface.is_top()) ? frTopSolidInfill : surface.is_solid() ? frSolidInfill : frInfill; const bool is_bridge = this->layer()->id() > 0 && surface.is_bridge(); if (surface.is_solid()) { density = 100.; fill_pattern = (surface.is_top()) ? this->region()->config.top_infill_pattern.value : (surface.is_bottom() && !is_bridge) ? this->region()->config.bottom_infill_pattern.value : ipRectilinear; } else if (density <= 0) continue; // get filler object #if SLIC3R_CPPVER >= 11 std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(fill_pattern)); #else std::auto_ptr<Fill> f = std::auto_ptr<Fill>(Fill::new_from_type(fill_pattern)); #endif // switch to rectilinear if this pattern doesn't support solid infill if (density > 99 && !f->can_solid()) #if SLIC3R_CPPVER >= 11 f = std::unique_ptr<Fill>(Fill::new_from_type(ipRectilinear)); #else f = std::auto_ptr<Fill>(Fill::new_from_type(ipRectilinear)); #endif f->bounding_box = this->layer()->object()->bounding_box(); // calculate the actual flow we'll be using for this infill coordf_t h = (surface.thickness == -1) ? this->layer()->height : surface.thickness; Flow flow = this->region()->flow( role, h, is_bridge || f->use_bridge_flow(), // bridge flow? this->layer()->id() == 0, // first layer? -1, // auto width *this->layer()->object() ); // calculate flow spacing for infill pattern generation bool using_internal_flow = false; if (!surface.is_solid() && !is_bridge) { // it's internal infill, so we can calculate a generic flow spacing // for all layers, for avoiding the ugly effect of // misaligned infill on first layer because of different extrusion width and // layer height Flow internal_flow = this->region()->flow( frInfill, h, // use the calculated surface thickness here for internal infill instead of the layer height to account for infill_every_layers false, // no bridge false, // no first layer -1, // auto width *this->layer()->object() ); f->min_spacing = internal_flow.spacing(); using_internal_flow = true; } else { f->min_spacing = flow.spacing(); } f->endpoints_overlap = scale_(this->region()->config.get_abs_value("infill_overlap", (unscale(perimeter_spacing) + (f->min_spacing))/2)); f->layer_id = this->layer()->id(); f->z = this->layer()->print_z; f->angle = Geometry::deg2rad(this->region()->config.fill_angle.value); // Maximum length of the perimeter segment linking two infill lines. f->link_max_length = (!is_bridge && density > 80) ? scale_(3 * f->min_spacing) : 0; // Used by the concentric infill pattern to clip the loops to create extrusion paths. f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER; // apply half spacing using this flow's own spacing and generate infill f->density = density/100; f->dont_adjust = false; /* std::cout << surface.expolygon.dump_perl() << std::endl << " layer_id: " << f->layer_id << " z: " << f->z << " angle: " << f->angle << " min-spacing: " << f->min_spacing << " endpoints_overlap: " << f->endpoints_overlap << std::endl << std::endl; */ Polylines polylines = f->fill_surface(surface); if (polylines.empty()) continue; // calculate actual flow from spacing (which might have been adjusted by the infill // pattern generator) if (using_internal_flow) { // if we used the internal flow we're not doing a solid infill // so we can safely ignore the slight variation that might have // been applied to f->spacing() } else { flow = Flow::new_from_spacing(f->spacing(), flow.nozzle_diameter, h, is_bridge || f->use_bridge_flow()); } // Save into layer. ExtrusionEntityCollection* coll = new ExtrusionEntityCollection(); coll->no_sort = f->no_sort(); this->fills.entities.push_back(coll); { ExtrusionRole role; if (is_bridge) { role = erBridgeInfill; } else if (surface.is_solid()) { role = (surface.is_top()) ? erTopSolidInfill : erSolidInfill; } else { role = erInternalInfill; } ExtrusionPath templ(role); templ.mm3_per_mm = flow.mm3_per_mm(); templ.width = flow.width; templ.height = flow.height; coll->append(STDMOVE(polylines), templ); } } // add thin fill regions // thin_fills are of C++ Slic3r::ExtrusionEntityCollection, perl type Slic3r::ExtrusionPath::Collection // Unpacks the collection, creates multiple collections per path so that they will // be individually included in the nearest neighbor search. // The path type could be ExtrusionPath, ExtrusionLoop or ExtrusionEntityCollection. for (ExtrusionEntitiesPtr::const_iterator thin_fill = this->thin_fills.entities.begin(); thin_fill != this->thin_fills.entities.end(); ++ thin_fill) { ExtrusionEntityCollection* coll = new ExtrusionEntityCollection(); this->fills.entities.push_back(coll); coll->append(**thin_fill); } }
int main ( int argv, char * argc[] ) { # if defined ERROR # undef ERROR # endif # define ERROR() { fprintf(stderr, "Error\n"); exit(1); } lprec *lp; int majorversion, minorversion, release, build; #if defined FORTIFY Fortify_EnterScope(); #endif lp_solve_version(&majorversion, &minorversion, &release, &build); printf("lp_solve %d.%d.%d.%d demo\n\n", majorversion, minorversion, release, build); printf("This demo will show most of the features of lp_solve %d.%d.%d.%d\n", majorversion, minorversion, release, build); press_ret(); printf("\nWe start by creating a new problem with 4 variables and 0 constraints\n"); printf("We use: lp=make_lp(0,4);\n"); if ((lp = make_lp(0,4)) == NULL) ERROR(); press_ret(); printf("We can show the current problem with print_lp(lp)\n"); print_lp(lp); press_ret(); printf("Now we add some constraints\n"); printf("add_constraint(lp, {0, 3, 2, 2, 1}, LE, 4)\n"); { double row[] = {0, 3, 2, 2, 1}; if (!add_constraint(lp, row, LE, 4)) ERROR(); } print_lp(lp); press_ret(); printf("add_constraintex is now used to add a row. Only the npn-zero values must be specfied with this call.\n"); printf("add_constraintex(lp, 3, {4, 3, 1}, {2, 3, 4}, GE, 3)\n"); { int colno[] = {2, 3, 4}; double row[] = {4, 3, 1}; if (!add_constraintex(lp, sizeof(colno) / sizeof(*colno), row, colno, GE, 3)) ERROR(); } print_lp(lp); press_ret(); printf("Set the objective function\n"); printf("set_obj_fn(lp, {0, 2, 3, -2, 3})\n"); { double row[] = {0, 2, 3, -2, 3}; if (!set_obj_fn(lp, row)) ERROR(); } print_lp(lp); press_ret(); printf("Now solve the problem with printf(solve(lp));\n"); printf("%d",solve(lp)); press_ret(); printf("The value is 0, this means we found an optimal solution\n"); printf("We can display this solution with print_objective(lp) and print_solution(lp)\n"); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("The dual variables of the solution are printed with\n"); printf("print_duals(lp);\n"); print_duals(lp); press_ret(); printf("We can change a single element in the matrix with\n"); printf("set_mat(lp,2,1,0.5)\n"); if (!set_mat(lp,2,1,0.5)) ERROR(); print_lp(lp); press_ret(); printf("If we want to maximize the objective function use set_maxim(lp);\n"); set_maxim(lp); print_lp(lp); press_ret(); printf("after solving this gives us:\n"); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); print_duals(lp); press_ret(); printf("Change the value of a rhs element with set_rh(lp,1,7.45)\n"); set_rh(lp,1,7.45); print_lp(lp); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("We change %s to the integer type with\n", get_col_name(lp, 4)); printf("set_int(lp, 4, TRUE)\n"); set_int(lp, 4, TRUE); print_lp(lp); printf("We set branch & bound debugging on with set_debug(lp, TRUE)\n"); set_debug(lp, TRUE); printf("and solve...\n"); press_ret(); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("We can set bounds on the variables with\n"); printf("set_lowbo(lp,2,2); & set_upbo(lp,4,5.3)\n"); set_lowbo(lp,2,2); set_upbo(lp,4,5.3); print_lp(lp); press_ret(); solve(lp); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("Now remove a constraint with del_constraint(lp, 1)\n"); del_constraint(lp,1); print_lp(lp); printf("Add an equality constraint\n"); { double row[] = {0, 1, 2, 1, 4}; if (!add_constraint(lp, row, EQ, 8)) ERROR(); } print_lp(lp); press_ret(); printf("A column can be added with:\n"); printf("add_column(lp,{3, 2, 2});\n"); { double col[] = {3, 2, 2}; if (!add_column(lp, col)) ERROR(); } print_lp(lp); press_ret(); printf("A column can be removed with:\n"); printf("del_column(lp,3);\n"); del_column(lp,3); print_lp(lp); press_ret(); printf("We can use automatic scaling with:\n"); printf("set_scaling(lp, SCALE_MEAN);\n"); set_scaling(lp, SCALE_MEAN); print_lp(lp); press_ret(); printf("The function get_mat(lprec *lp, int row, int column) returns a single\n"); printf("matrix element\n"); printf("%s get_mat(lp,2,3), get_mat(lp,1,1); gives\n","printf(\"%f %f\\n\","); printf("%f %f\n", (double)get_mat(lp,2,3), (double)get_mat(lp,1,1)); printf("Notice that get_mat returns the value of the original unscaled problem\n"); press_ret(); printf("If there are any integer type variables, then only the rows are scaled\n"); printf("set_scaling(lp, SCALE_MEAN);\n"); set_scaling(lp, SCALE_MEAN); printf("set_int(lp,3,FALSE);\n"); set_int(lp,3,FALSE); print_lp(lp); press_ret(); solve(lp); printf("print_objective, print_solution gives the solution to the original problem\n"); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); printf("Scaling is turned off with unscale(lp);\n"); unscale(lp); print_lp(lp); press_ret(); printf("Now turn B&B debugging off and simplex tracing on with\n"); printf("set_debug(lp, FALSE), set_trace(lp, TRUE) and solve(lp)\n"); set_debug(lp, FALSE); set_trace(lp, TRUE); press_ret(); solve(lp); printf("Where possible, lp_solve will start at the last found basis\n"); printf("We can reset the problem to the initial basis with\n"); printf("default_basis(lp). Now solve it again...\n"); press_ret(); default_basis(lp); solve(lp); printf("It is possible to give variables and constraints names\n"); printf("set_row_name(lp,1,\"speed\"); & set_col_name(lp,2,\"money\")\n"); if (!set_row_name(lp,1,"speed")) ERROR(); if (!set_col_name(lp,2,"money")) ERROR(); print_lp(lp); printf("As you can see, all column and rows are assigned default names\n"); printf("If a column or constraint is deleted, the names shift place also:\n"); press_ret(); printf("del_column(lp,1);\n"); del_column(lp,1); print_lp(lp); press_ret(); write_lp(lp, "lp.lp"); delete_lp(lp); printf("An lp structure can be created and read from a .lp file\n"); printf("lp = read_lp(\"lp.lp\", TRUE);\n"); printf("The verbose option is used\n"); if ((lp = read_LP("lp.lp", TRUE, "test")) == NULL) ERROR(); press_ret(); printf("lp is now:\n"); print_lp(lp); press_ret(); printf("solution:\n"); set_debug(lp, TRUE); solve(lp); set_debug(lp, FALSE); print_objective(lp); print_solution(lp, 1); print_constraints(lp, 1); press_ret(); delete_lp(lp); #if defined FORTIFY Fortify_LeaveScope(); #endif return 0; }
// Called from the constructor. // Set the initial bed shape from a list of points. // Deduce the bed shape type(rect, circle, custom) // This routine shall be smart enough if the user messes up // with the list of points in the ini file directly. void BedShapePanel::set_shape(ConfigOptionPoints* points) { auto polygon = Polygon::new_scale(points->values); // is this a rectangle ? if (points->size() == 4) { auto lines = polygon.lines(); if (lines[0].parallel_to(lines[2]) && lines[1].parallel_to(lines[3])) { // okay, it's a rectangle // find origin // the || 0 hack prevents "-0" which might confuse the user int x_min, x_max, y_min, y_max; x_max = x_min = points->values[0].x; y_max = y_min = points->values[0].y; for (auto pt : points->values){ if (x_min > pt.x) x_min = pt.x; if (x_max < pt.x) x_max = pt.x; if (y_min > pt.y) y_min = pt.y; if (y_max < pt.y) y_max = pt.y; } if (x_min < 0) x_min = 0; if (x_max < 0) x_max = 0; if (y_min < 0) y_min = 0; if (y_max < 0) y_max = 0; auto origin = new ConfigOptionPoints{ Pointf(-x_min, -y_min) }; m_shape_options_book->SetSelection(SHAPE_RECTANGULAR); auto optgroup = m_optgroups[SHAPE_RECTANGULAR]; optgroup->set_value("rect_size", new ConfigOptionPoints{ Pointf(x_max - x_min, y_max - y_min) });//[x_max - x_min, y_max - y_min]); optgroup->set_value("rect_origin", origin); update_shape(); return; } } // is this a circle ? { // Analyze the array of points.Do they reside on a circle ? auto center = polygon.bounding_box().center(); std::vector<double> vertex_distances; double avg_dist = 0; for (auto pt: polygon.points) { double distance = center.distance_to(pt); vertex_distances.push_back(distance); avg_dist += distance; } bool defined_value = true; for (auto el: vertex_distances) { if (abs(el - avg_dist) > 10 * SCALED_EPSILON) defined_value = false; break; } if (defined_value) { // all vertices are equidistant to center m_shape_options_book->SetSelection(SHAPE_CIRCULAR); auto optgroup = m_optgroups[SHAPE_CIRCULAR]; boost::any ret = wxNumberFormatter::ToString(unscale(avg_dist * 2), 0); optgroup->set_value("diameter", ret); update_shape(); return; } } if (points->size() < 3) { // Invalid polygon.Revert to default bed dimensions. m_shape_options_book->SetSelection(SHAPE_RECTANGULAR); auto optgroup = m_optgroups[SHAPE_RECTANGULAR]; optgroup->set_value("rect_size", new ConfigOptionPoints{ Pointf(200, 200) }); optgroup->set_value("rect_origin", new ConfigOptionPoints{ Pointf(0, 0) }); update_shape(); return; } // This is a custom bed shape, use the polygon provided. m_shape_options_book->SetSelection(SHAPE_CUSTOM); // Copy the polygon to the canvas, make a copy of the array. m_canvas->m_bed_shape = points->values; update_shape(); }
// caller is responsible for supplying NO lines with zero length void _3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vector<double> &widths, const std::vector<double> &heights, bool closed, double top_z, const Point ©, GLVertexArray* qverts, GLVertexArray* tverts) { /* It looks like it's faster without reserving capacity... // each segment has 4 quads, thus 16 vertices; + 2 caps qverts->reserve_more(3 * 4 * (4 * lines.size() + 2)); // two triangles for each corner tverts->reserve_more(3 * 3 * 2 * (lines.size() + 1)); */ Line prev_line; Pointf prev_b1, prev_b2; Vectorf3 prev_xy_left_normal, prev_xy_right_normal; // loop once more in case of closed loops bool first_done = false; for (size_t i = 0; i <= lines.size(); ++i) { if (i == lines.size()) i = 0; const Line &line = lines.at(i); if (i == 0 && first_done && !closed) break; double len = line.length(); double unscaled_len = unscale(len); double bottom_z = top_z - heights.at(i); double middle_z = (top_z + bottom_z) / 2; double dist = widths.at(i)/2; // scaled Vectorf v = Vectorf::new_unscale(line.vector()); v.scale(1/unscaled_len); Pointf a = Pointf::new_unscale(line.a); Pointf b = Pointf::new_unscale(line.b); Pointf a1 = a; Pointf a2 = a; a1.translate(+dist*v.y, -dist*v.x); a2.translate(-dist*v.y, +dist*v.x); Pointf b1 = b; Pointf b2 = b; b1.translate(+dist*v.y, -dist*v.x); b2.translate(-dist*v.y, +dist*v.x); // calculate new XY normals Vector n = line.normal(); Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0); xy_right_normal.scale(1/unscaled_len); Vectorf3 xy_left_normal = xy_right_normal; xy_left_normal.scale(-1); if (first_done) { // if we're making a ccw turn, draw the triangles on the right side, otherwise draw them on the left side double ccw = line.b.ccw(prev_line); if (ccw > EPSILON) { // top-right vertex triangle between previous line and this one { // use the normal going to the right calculated for the previous line tverts->push_norm(prev_xy_right_normal); tverts->push_vert(prev_b1.x, prev_b1.y, middle_z); // use the normal going to the right calculated for this line tverts->push_norm(xy_right_normal); tverts->push_vert(a1.x, a1.y, middle_z); // normal going upwards tverts->push_norm(0,0,1); tverts->push_vert(a.x, a.y, top_z); } // bottom-right vertex triangle between previous line and this one { // use the normal going to the right calculated for the previous line tverts->push_norm(prev_xy_right_normal); tverts->push_vert(prev_b1.x, prev_b1.y, middle_z); // normal going downwards tverts->push_norm(0,0,-1); tverts->push_vert(a.x, a.y, bottom_z); // use the normal going to the right calculated for this line tverts->push_norm(xy_right_normal); tverts->push_vert(a1.x, a1.y, middle_z); } } else if (ccw < -EPSILON) { // top-left vertex triangle between previous line and this one { // use the normal going to the left calculated for the previous line tverts->push_norm(prev_xy_left_normal); tverts->push_vert(prev_b2.x, prev_b2.y, middle_z); // normal going upwards tverts->push_norm(0,0,1); tverts->push_vert(a.x, a.y, top_z); // use the normal going to the right calculated for this line tverts->push_norm(xy_left_normal); tverts->push_vert(a2.x, a2.y, middle_z); } // bottom-left vertex triangle between previous line and this one { // use the normal going to the left calculated for the previous line tverts->push_norm(prev_xy_left_normal); tverts->push_vert(prev_b2.x, prev_b2.y, middle_z); // use the normal going to the right calculated for this line tverts->push_norm(xy_left_normal); tverts->push_vert(a2.x, a2.y, middle_z); // normal going downwards tverts->push_norm(0,0,-1); tverts->push_vert(a.x, a.y, bottom_z); } } } // if this was the extra iteration we were only interested in the triangles if (first_done && i == 0) break; prev_line = line; prev_b1 = b1; prev_b2 = b2; prev_xy_right_normal = xy_right_normal; prev_xy_left_normal = xy_left_normal; if (!closed) { // terminate open paths with caps if (i == 0) { // normal pointing downwards qverts->push_norm(0,0,-1); qverts->push_vert(a.x, a.y, bottom_z); // normal pointing to the right qverts->push_norm(xy_right_normal); qverts->push_vert(a1.x, a1.y, middle_z); // normal pointing upwards qverts->push_norm(0,0,1); qverts->push_vert(a.x, a.y, top_z); // normal pointing to the left qverts->push_norm(xy_left_normal); qverts->push_vert(a2.x, a2.y, middle_z); } // we don't use 'else' because both cases are true if we have only one line if (i == lines.size()-1) { // normal pointing downwards qverts->push_norm(0,0,-1); qverts->push_vert(b.x, b.y, bottom_z); // normal pointing to the left qverts->push_norm(xy_left_normal); qverts->push_vert(b2.x, b2.y, middle_z); // normal pointing upwards qverts->push_norm(0,0,1); qverts->push_vert(b.x, b.y, top_z); // normal pointing to the right qverts->push_norm(xy_right_normal); qverts->push_vert(b1.x, b1.y, middle_z); } } // bottom-right face { // normal going downwards qverts->push_norm(0,0,-1); qverts->push_norm(0,0,-1); qverts->push_vert(a.x, a.y, bottom_z); qverts->push_vert(b.x, b.y, bottom_z); qverts->push_norm(xy_right_normal); qverts->push_norm(xy_right_normal); qverts->push_vert(b1.x, b1.y, middle_z); qverts->push_vert(a1.x, a1.y, middle_z); } // top-right face { qverts->push_norm(xy_right_normal); qverts->push_norm(xy_right_normal); qverts->push_vert(a1.x, a1.y, middle_z); qverts->push_vert(b1.x, b1.y, middle_z); // normal going upwards qverts->push_norm(0,0,1); qverts->push_norm(0,0,1); qverts->push_vert(b.x, b.y, top_z); qverts->push_vert(a.x, a.y, top_z); } // top-left face { qverts->push_norm(0,0,1); qverts->push_norm(0,0,1); qverts->push_vert(a.x, a.y, top_z); qverts->push_vert(b.x, b.y, top_z); qverts->push_norm(xy_left_normal); qverts->push_norm(xy_left_normal); qverts->push_vert(b2.x, b2.y, middle_z); qverts->push_vert(a2.x, a2.y, middle_z); } // bottom-left face { qverts->push_norm(xy_left_normal); qverts->push_norm(xy_left_normal); qverts->push_vert(a2.x, a2.y, middle_z); qverts->push_vert(b2.x, b2.y, middle_z); // normal going downwards qverts->push_norm(0,0,-1); qverts->push_norm(0,0,-1); qverts->push_vert(b.x, b.y, bottom_z); qverts->push_vert(a.x, a.y, bottom_z); } first_done = true; } }
float Scale::unscaleDiffNormalized( float toValue1 , float toValue2 ) { ASSERT( doScale ); return( ( unscale( toValue1 ) - unscale( toValue2 ) ) / ( rangeFromMax - rangeFromMin ) ); }