Comparar commits
33 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| f660f3cd2d | |||
| 54fd9c1f5b | |||
| 72ce68ac33 | |||
| 6bed19c295 | |||
| f312f15813 | |||
| 406ea7155c | |||
| f0f23ed732 | |||
| 0a59a059f4 | |||
| 47984afb5f | |||
| 4d34cbc66b | |||
| a29af7f791 | |||
| f304c09db4 | |||
| d50f67e583 | |||
| b2d837efde | |||
| 5c680b312b | |||
| 0a683ff05e | |||
| 4e96d9cbe6 | |||
| 478bd31d02 | |||
| faab907bab | |||
| dff554863c | |||
| f2222f97fd | |||
| aa18e7bd08 | |||
| 07dc53765a | |||
| 559deb8914 | |||
| 421ff6d818 | |||
| e85a1004cd | |||
| 627848bc41 | |||
| eccc62cf1d | |||
| 58e2e1a4e1 | |||
| 4ebbceb3e3 | |||
| ace0045109 | |||
| 7a4a7fe46a | |||
| 977d02a9a2 |
@@ -42,6 +42,20 @@ if(NOT APPLE AND NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_definitions(/DNOMINMAX)
|
||||
if (MSVC)
|
||||
# Switch the runtime to use static linking on MSVC
|
||||
foreach(flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if(${flag_var} MATCHES "/MD")
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
endif(${flag_var} MATCHES "/MD")
|
||||
endforeach(flag_var)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR} libs)
|
||||
|
||||
add_library(clipper STATIC libs/clipper/clipper.cpp)
|
||||
|
||||
@@ -31,6 +31,7 @@ CMake compilation:
|
||||
4. ```$ make```
|
||||
|
||||
Project files generation:
|
||||
|
||||
1. Navigate to the CuraEngine directory and execute the following commands
|
||||
2. ```cmake . -G "CodeBlocks - Unix Makefiles"```
|
||||
3. (for a list of supported IDE's see http://www.cmake.org/Wiki/CMake_Generator_Specific_Information#Code::Blocks_Generator)
|
||||
|
||||
@@ -7,4 +7,4 @@ This is the documentation for CuraEngine, the back-end slicer of Cura.
|
||||
|
||||
[Glossary](documentation/glossary.md)
|
||||
|
||||
[Code Conventions](documentation/code_conventions.md)
|
||||
[Code Conventions](https://github.com/Ultimaker/Meta/blob/master/code_conventions.md)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <map> // multimap (ordered map allowing duplicate keys)
|
||||
|
||||
#include "utils/math.h"
|
||||
#include "utils/algorithm.h"
|
||||
#include "slicer.h"
|
||||
#include "utils/gettime.h"
|
||||
#include "utils/logoutput.h"
|
||||
@@ -115,7 +116,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
|
||||
Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper);
|
||||
|
||||
carveMultipleVolumes(slicerList);
|
||||
if (storage.getSettingBoolean("carve_multiple_volumes"))
|
||||
{
|
||||
carveMultipleVolumes(slicerList);
|
||||
}
|
||||
generateMultipleVolumesOverlap(slicerList);
|
||||
|
||||
storage.meshes.reserve(slicerList.size()); // causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated.
|
||||
@@ -256,8 +260,9 @@ void FffPolygonGenerator::slices2polygons(SliceDataStorage& storage, TimeKeeper&
|
||||
}
|
||||
*/
|
||||
|
||||
computePrintHeightStatistics(storage);
|
||||
|
||||
// handle helpers
|
||||
storage.primeTower.computePrimeTowerMax(storage);
|
||||
storage.primeTower.generatePaths(storage, print_layer_count);
|
||||
|
||||
logDebug("Processing ooze shield\n");
|
||||
@@ -492,6 +497,7 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
|
||||
{
|
||||
layer.printZ -= n_empty_first_layers * layer_height;
|
||||
}
|
||||
mesh.layer_nr_max_filled_layer -= n_empty_first_layers;
|
||||
}
|
||||
total_layers -= n_empty_first_layers;
|
||||
}
|
||||
@@ -521,6 +527,47 @@ void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, unsigned
|
||||
}
|
||||
}
|
||||
|
||||
void FffPolygonGenerator::computePrintHeightStatistics(SliceDataStorage& storage)
|
||||
{
|
||||
int extruder_count = storage.meshgroup->getExtruderCount();
|
||||
|
||||
std::vector<int>& max_print_height_per_extruder = storage.max_print_height_per_extruder;
|
||||
assert(max_print_height_per_extruder.size() == 0 && "storage.max_print_height_per_extruder shouldn't have been initialized yet!");
|
||||
max_print_height_per_extruder.resize(extruder_count, -1); // unitialize all as -1
|
||||
{ // compute max_object_height_per_extruder
|
||||
for (SliceMeshStorage& mesh : storage.meshes)
|
||||
{
|
||||
unsigned int extr_nr = mesh.getSettingAsIndex("extruder_nr");
|
||||
max_print_height_per_extruder[extr_nr] =
|
||||
std::max( max_print_height_per_extruder[extr_nr]
|
||||
, mesh.layer_nr_max_filled_layer );
|
||||
}
|
||||
int support_infill_extruder_nr = storage.getSettingAsIndex("support_infill_extruder_nr"); // TODO: support extruder should be configurable per object
|
||||
max_print_height_per_extruder[support_infill_extruder_nr] =
|
||||
std::max( max_print_height_per_extruder[support_infill_extruder_nr]
|
||||
, storage.support.layer_nr_max_filled_layer );
|
||||
int support_skin_extruder_nr = storage.getSettingAsIndex("support_interface_extruder_nr"); // TODO: support skin extruder should be configurable per object
|
||||
max_print_height_per_extruder[support_skin_extruder_nr] =
|
||||
std::max( max_print_height_per_extruder[support_skin_extruder_nr]
|
||||
, storage.support.layer_nr_max_filled_layer );
|
||||
int adhesion_extruder_nr = storage.getSettingAsIndex("adhesion_extruder_nr");
|
||||
max_print_height_per_extruder[adhesion_extruder_nr] =
|
||||
std::max(0, max_print_height_per_extruder[support_skin_extruder_nr]);
|
||||
}
|
||||
|
||||
storage.max_print_height_order = order(max_print_height_per_extruder);
|
||||
if (extruder_count >= 2)
|
||||
{
|
||||
int second_highest_extruder = storage.max_print_height_order[extruder_count - 2];
|
||||
storage.max_print_height_second_to_last_extruder = max_print_height_per_extruder[second_highest_extruder];
|
||||
}
|
||||
else
|
||||
{
|
||||
storage.max_print_height_second_to_last_extruder = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage)
|
||||
{
|
||||
if (!getSettingBoolean("ooze_shield_enabled"))
|
||||
@@ -530,7 +577,7 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage)
|
||||
|
||||
const int ooze_shield_dist = getSettingInMicrons("ooze_shield_dist");
|
||||
|
||||
for (int layer_nr = 0; layer_nr <= storage.max_object_height_second_to_last_extruder; layer_nr++)
|
||||
for (int layer_nr = 0; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++)
|
||||
{
|
||||
storage.oozeShield.push_back(storage.getLayerOutlines(layer_nr, true).offset(ooze_shield_dist, ClipperLib::jtRound));
|
||||
}
|
||||
@@ -539,18 +586,18 @@ void FffPolygonGenerator::processOozeShield(SliceDataStorage& storage)
|
||||
if (angle <= 89)
|
||||
{
|
||||
int allowed_angle_offset = tan(getSettingInAngleRadians("ooze_shield_angle")) * getSettingInMicrons("layer_height"); // Allow for a 60deg angle in the oozeShield.
|
||||
for (int layer_nr = 1; layer_nr <= storage.max_object_height_second_to_last_extruder; layer_nr++)
|
||||
for (int layer_nr = 1; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++)
|
||||
{
|
||||
storage.oozeShield[layer_nr] = storage.oozeShield[layer_nr].unionPolygons(storage.oozeShield[layer_nr - 1].offset(-allowed_angle_offset));
|
||||
}
|
||||
for (int layer_nr = storage.max_object_height_second_to_last_extruder; layer_nr > 0; layer_nr--)
|
||||
for (int layer_nr = storage.max_print_height_second_to_last_extruder; layer_nr > 0; layer_nr--)
|
||||
{
|
||||
storage.oozeShield[layer_nr - 1] = storage.oozeShield[layer_nr - 1].unionPolygons(storage.oozeShield[layer_nr].offset(-allowed_angle_offset));
|
||||
}
|
||||
}
|
||||
|
||||
const float largest_printed_area = 1.0; // TODO: make var a parameter, and perhaps even a setting?
|
||||
for (int layer_nr = 0; layer_nr <= storage.max_object_height_second_to_last_extruder; layer_nr++)
|
||||
for (int layer_nr = 0; layer_nr <= storage.max_print_height_second_to_last_extruder; layer_nr++)
|
||||
{
|
||||
storage.oozeShield[layer_nr].removeSmallAreas(largest_printed_area);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,14 @@ private:
|
||||
* \param total_layers The total number of layers
|
||||
*/
|
||||
void removeEmptyFirstLayers(SliceDataStorage& storage, const int layer_height, unsigned int& total_layers);
|
||||
|
||||
|
||||
/*!
|
||||
* Set \ref SliceDataStorage::max_print_height_per_extruder and \ref SliceDataStorage::max_print_height_order and \ref SliceDataStorage::max_print_height_second_to_last_extruder
|
||||
*
|
||||
* \param[in,out] storage Where to retrieve mesh and support etc settings from and where the print height statistics are saved.
|
||||
*/
|
||||
void computePrintHeightStatistics(SliceDataStorage& storage);
|
||||
|
||||
/*!
|
||||
* Generate the inset polygons which form the walls.
|
||||
* \param mesh Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "MeshGroup.h"
|
||||
|
||||
+4
-58
@@ -50,61 +50,6 @@ void PrimeTower::setConfigs(const MeshGroup* meshgroup, const int layer_thicknes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PrimeTower::computePrimeTowerMax(SliceDataStorage& storage)
|
||||
{ // compute storage.max_object_height_second_to_last_extruder, which is used to determine the highest point in the prime tower
|
||||
|
||||
extruder_count = storage.meshgroup->getExtruderCount();
|
||||
|
||||
int max_object_height_per_extruder[extruder_count];
|
||||
std::fill_n(max_object_height_per_extruder, extruder_count, -1); // unitialize all as -1
|
||||
{ // compute max_object_height_per_extruder
|
||||
for (SliceMeshStorage& mesh : storage.meshes)
|
||||
{
|
||||
unsigned int extr_nr = mesh.getSettingAsIndex("extruder_nr");
|
||||
max_object_height_per_extruder[extr_nr] =
|
||||
std::max( max_object_height_per_extruder[extr_nr]
|
||||
, mesh.layer_nr_max_filled_layer );
|
||||
}
|
||||
int support_infill_extruder_nr = storage.getSettingAsIndex("support_infill_extruder_nr"); // TODO: support extruder should be configurable per object
|
||||
max_object_height_per_extruder[support_infill_extruder_nr] =
|
||||
std::max( max_object_height_per_extruder[support_infill_extruder_nr]
|
||||
, storage.support.layer_nr_max_filled_layer );
|
||||
int support_skin_extruder_nr = storage.getSettingAsIndex("support_interface_extruder_nr"); // TODO: support skin extruder should be configurable per object
|
||||
max_object_height_per_extruder[support_skin_extruder_nr] =
|
||||
std::max( max_object_height_per_extruder[support_skin_extruder_nr]
|
||||
, storage.support.layer_nr_max_filled_layer );
|
||||
}
|
||||
{ // // compute max_object_height_second_to_last_extruder
|
||||
int extruder_max_object_height = 0;
|
||||
for (int extruder_nr = 1; extruder_nr < extruder_count; extruder_nr++)
|
||||
{
|
||||
if (max_object_height_per_extruder[extruder_nr] > max_object_height_per_extruder[extruder_max_object_height])
|
||||
{
|
||||
extruder_max_object_height = extruder_nr;
|
||||
}
|
||||
}
|
||||
int extruder_second_max_object_height = -1;
|
||||
for (int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
|
||||
{
|
||||
if (extruder_nr == extruder_max_object_height) { continue; }
|
||||
if (extruder_second_max_object_height == -1 || max_object_height_per_extruder[extruder_nr] > max_object_height_per_extruder[extruder_second_max_object_height])
|
||||
{
|
||||
extruder_second_max_object_height = extruder_nr;
|
||||
}
|
||||
}
|
||||
if (extruder_second_max_object_height < 0)
|
||||
{
|
||||
storage.max_object_height_second_to_last_extruder = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
storage.max_object_height_second_to_last_extruder = max_object_height_per_extruder[extruder_second_max_object_height];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
|
||||
{
|
||||
PolygonRef p = ground_poly.newPoly();
|
||||
@@ -122,7 +67,8 @@ void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
|
||||
|
||||
void PrimeTower::generatePaths(const SliceDataStorage& storage, unsigned int total_layers)
|
||||
{
|
||||
if (storage.max_object_height_second_to_last_extruder >= 0 && storage.getSettingBoolean("prime_tower_enable"))
|
||||
extruder_count = storage.meshgroup->getExtruderCount();
|
||||
if (storage.max_print_height_second_to_last_extruder >= 0 && storage.getSettingBoolean("prime_tower_enable"))
|
||||
{
|
||||
generatePaths_denseInfill(storage);
|
||||
generateWipeLocations(storage);
|
||||
@@ -160,7 +106,7 @@ void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
|
||||
|
||||
void PrimeTower::addToGcode(const SliceDataStorage& storage, GCodePlanner& gcodeLayer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, bool wipe)
|
||||
{
|
||||
if (!( storage.max_object_height_second_to_last_extruder >= 0 && storage.getSettingInMicrons("prime_tower_size") > 0) )
|
||||
if (!( storage.max_print_height_second_to_last_extruder >= 0 && storage.getSettingInMicrons("prime_tower_size") > 0) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -174,7 +120,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, GCodePlanner& gcode
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer_nr > storage.max_object_height_second_to_last_extruder + 1)
|
||||
if (layer_nr > storage.max_print_height_second_to_last_extruder + 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,13 +75,6 @@ public:
|
||||
*/
|
||||
void generatePaths(const SliceDataStorage& storage, unsigned int total_layers);
|
||||
|
||||
/*!
|
||||
* Compute the maximum layer at which a layer switch will occur and store the result in \ref SliceDataStorage::max_object_height_second_to_last_extruder
|
||||
*
|
||||
* \param[in,out] storage Where to retrieve area data and extruder settings for those areas; where to store the max_object_height_second_to_last_extruder
|
||||
*/
|
||||
void computePrimeTowerMax(SliceDataStorage& storage);
|
||||
|
||||
PrimeTower(); //!< basic constructor
|
||||
|
||||
/*!
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include <cmath> // sqrt
|
||||
#include <fstream> // debug IO
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "progress/Progress.h"
|
||||
#include "weaveDataStorage.h"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <string> // stoi
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -652,7 +652,13 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
|
||||
if (extruder_plan.prev_extruder_standby_temp)
|
||||
{ // turn off previous extruder
|
||||
constexpr bool wait = false;
|
||||
gcode.writeTemperatureCommand(prev_extruder, *extruder_plan.prev_extruder_standby_temp, wait);
|
||||
double prev_extruder_temp = *extruder_plan.prev_extruder_standby_temp;
|
||||
int prev_layer_nr = (extruder_plan_idx == 0)? layer_nr - 1 : layer_nr;
|
||||
if (prev_layer_nr == storage.max_print_height_per_extruder[prev_extruder])
|
||||
{
|
||||
prev_extruder_temp = 0; // TODO ? should there be a setting for extruder_off_temperature ?
|
||||
}
|
||||
gcode.writeTemperatureCommand(prev_extruder, prev_extruder_temp, wait);
|
||||
}
|
||||
}
|
||||
gcode.writeFanCommand(extruder_plan.getFanSpeed());
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <execinfo.h>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace cura {
|
||||
*/
|
||||
void PathOrderOptimizer::optimize()
|
||||
{
|
||||
bool picked[polygons.size()];
|
||||
bool *picked = static_cast<bool*>(alloca(sizeof(bool) * polygons.size()));
|
||||
memset(picked, false, sizeof(bool) * polygons.size());/// initialized as falses
|
||||
|
||||
for (PolygonRef poly : polygons) /// find closest point to initial starting point within each polygon +initialize picked
|
||||
@@ -154,7 +154,7 @@ void LineOrderOptimizer::optimize()
|
||||
{
|
||||
int gridSize = 5000; // the size of the cells in the hash grid. TODO
|
||||
SparsePointGridInclusive<unsigned int> line_bucket_grid(gridSize);
|
||||
bool picked[polygons.size()];
|
||||
bool *picked = static_cast<bool*>(alloca(sizeof(bool) * polygons.size()));
|
||||
memset(picked, false, sizeof(bool) * polygons.size());/// initialized as falses
|
||||
|
||||
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++) /// find closest point to initial starting point within each polygon +initialize picked
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream> // debug IO
|
||||
#ifndef WIN32
|
||||
#include <libgen.h> // dirname
|
||||
#else
|
||||
extern char *dirname(char *path);
|
||||
#endif
|
||||
#include <string>
|
||||
#include <cstring> // strtok (split string using delimiters) strcpy
|
||||
#include <fstream> // ifstream (to see if file exists)
|
||||
@@ -151,7 +155,7 @@ int SettingRegistry::loadJSONsettings(std::string filename, SettingsBase* settin
|
||||
if (err) { return err; }
|
||||
|
||||
{ // add parent folder to search paths
|
||||
char filename_cstr[filename.size()];
|
||||
char *filename_cstr = static_cast<char*>(alloca(filename.size()));
|
||||
std::strcpy(filename_cstr, filename.c_str()); // copy the string because dirname(.) changes the input string!!!
|
||||
std::string folder_name = std::string(dirname(filename_cstr));
|
||||
search_paths.emplace(folder_name);
|
||||
@@ -381,3 +385,15 @@ void SettingRegistry::_loadSettingValues(SettingConfig* config, const rapidjson:
|
||||
}
|
||||
|
||||
}//namespace cura
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
|
||||
char *dirname(char *path)
|
||||
{
|
||||
static char folder_name[MAX_PATH + 1], *p;
|
||||
GetFullPathNameA(path, _countof(folder_name), folder_name, &p);
|
||||
p[-1] = 0;
|
||||
return folder_name;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
#include <stdio.h> // for file output
|
||||
#include <sstream>
|
||||
#include <iostream> // debug IO
|
||||
#ifndef WIN32
|
||||
#include <libgen.h> // dirname
|
||||
#else
|
||||
extern char *dirname(char *path);
|
||||
#endif
|
||||
#include <string>
|
||||
#include <algorithm> // find_if
|
||||
#include <regex> // regex_search
|
||||
|
||||
@@ -180,7 +180,7 @@ bool SettingsBaseVirtual::getSettingBoolean(std::string key) const
|
||||
return true;
|
||||
if (value == "yes")
|
||||
return true;
|
||||
if (value == "true" or value == "True") //Python uses "True"
|
||||
if (value == "true" || value == "True") //Python uses "True"
|
||||
return true;
|
||||
int num = atoi(value.c_str());
|
||||
return num != 0;
|
||||
|
||||
+11
-2
@@ -162,8 +162,17 @@ void generateInfill(int layerNr, SliceMeshStorage& mesh, const int innermost_wal
|
||||
}
|
||||
}
|
||||
infill.removeSmallAreas(MIN_AREA_SIZE);
|
||||
|
||||
part.infill_area = infill.offset(infill_skin_overlap);
|
||||
|
||||
Polygons final_infill = infill.offset(infill_skin_overlap);
|
||||
|
||||
if (mesh.getSettingBoolean("infill_hollow"))
|
||||
{
|
||||
part.print_outline = part.print_outline.difference(final_infill);
|
||||
}
|
||||
else
|
||||
{
|
||||
part.infill_area = final_infill;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(mes
|
||||
raft_surface_config(PrintFeatureType::SupportInterface),
|
||||
support_config(PrintFeatureType::Support),
|
||||
support_skin_config(PrintFeatureType::SupportInterface),
|
||||
max_object_height_second_to_last_extruder(-1)
|
||||
max_print_height_second_to_last_extruder(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,10 @@ public:
|
||||
Polygons skirt_brim[MAX_EXTRUDERS]; //!< Skirt and brim polygons per extruder, ordered from inner to outer polygons.
|
||||
Polygons raftOutline; //Storage for the outline of the raft. Will be filled with lines when the GCode is generated.
|
||||
|
||||
int max_object_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder
|
||||
int max_print_height_second_to_last_extruder; //!< Used in multi-extrusion: the layer number beyond which all models are printed with the same extruder
|
||||
std::vector<int> max_print_height_per_extruder; //!< For each extruder the highest layer number at which it is used.
|
||||
std::vector<size_t> max_print_height_order; //!< Ordered indices into max_print_height_per_extruder: back() will return the extruder number with the highest print height.
|
||||
|
||||
PrimeTower primeTower;
|
||||
|
||||
std::vector<Polygons> oozeShield; //oozeShield per layer
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
|
||||
#ifndef UTILS_ALGORITHM_H
|
||||
#define UTILS_ALGORITHM_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
|
||||
// extensions to algorithm.h from the standard library
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
/*!
|
||||
* Get the order of a vector: the sorted indices of a vector
|
||||
*
|
||||
* {1.6, 1.8, 1.7} returns {1, 3, 2} meaning {in[1], in[3], in[2]} is a sorted
|
||||
* vector
|
||||
*
|
||||
* Thanks to Lukasz Wiklendt
|
||||
*
|
||||
* \param in The vector for which to get the order
|
||||
* \return An ordered vector of indices into \p in
|
||||
*/
|
||||
template<typename T>
|
||||
std::vector<size_t> order(const std::vector<T> &in)
|
||||
{
|
||||
// initialize original index locations
|
||||
std::vector<size_t> order(in.size());
|
||||
std::iota(order.begin(), order.end(), 0); // fill vector with 1, 2, 3,.. etc
|
||||
|
||||
// sort indexes based on comparing values in v
|
||||
std::sort(order.begin(), order.end(),
|
||||
[&in](size_t i1, size_t i2)
|
||||
{
|
||||
return in[i1] < in[i2];
|
||||
}
|
||||
);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // UTILS_ALGORITHM_H
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
#ifndef GETTIME_H
|
||||
#define GETTIME_H
|
||||
|
||||
#ifdef __WIN32
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#ifdef USE_CPU_TIME
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stddef.h>
|
||||
#include <cassert>
|
||||
#endif
|
||||
@@ -18,9 +18,9 @@ namespace cura
|
||||
{
|
||||
static inline double getTime()
|
||||
{
|
||||
#ifdef __WIN32
|
||||
#ifdef WIN32
|
||||
return double(GetTickCount()) / 1000.0;
|
||||
#else // not __WIN32
|
||||
#else // not WIN32
|
||||
#if USE_CPU_TIME // Use cpu usage time if available, otherwise wall clock time
|
||||
struct rusage usage;
|
||||
#ifdef DEBUG
|
||||
@@ -38,7 +38,7 @@ static inline double getTime()
|
||||
gettimeofday(&tv, nullptr);
|
||||
return double(tv.tv_sec) + double(tv.tv_usec) / 1000000.0;
|
||||
#endif // USE_CPU_TIME
|
||||
#endif // __WIN32
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
class TimeKeeper
|
||||
|
||||
@@ -119,9 +119,9 @@ unsigned int Polygons::findInside(Point p, bool border_result)
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t min_x[size()];
|
||||
int64_t *min_x = static_cast<int64_t*>(alloca(sizeof(int64_t) * size()));
|
||||
std::fill_n(min_x, size(), std::numeric_limits<int64_t>::max()); // initialize with int.max
|
||||
int crossings[size()];
|
||||
int *crossings = static_cast<int*>(alloca(sizeof(int) * size()));
|
||||
std::fill_n(crossings, size(), 0); // initialize with zeros
|
||||
|
||||
for (unsigned int poly_idx = 0; poly_idx < size(); poly_idx++)
|
||||
|
||||
+31
-5
@@ -5,6 +5,10 @@
|
||||
#include <cstdio> // sprintf
|
||||
#include <sstream> // ostringstream
|
||||
|
||||
#include <cinttypes> // PRId64
|
||||
|
||||
#include "logoutput.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
@@ -29,8 +33,19 @@ static inline int stringcasecompare(const char* a, const char* b)
|
||||
*/
|
||||
static inline void writeInt2mm(const int64_t coord, std::ostream& ss)
|
||||
{
|
||||
char buffer[24];
|
||||
int char_count = sprintf(buffer, "%ld", coord); // convert int to string
|
||||
constexpr size_t buffer_size = 24;
|
||||
char buffer[buffer_size];
|
||||
int char_count = sprintf(buffer, "%" PRId64, coord); // convert int to string
|
||||
#ifdef DEBUG
|
||||
if (char_count + 1 >= int(buffer_size)) // + 1 for the null character
|
||||
{
|
||||
logError("Cannot write %ld to buffer of size %i", coord, buffer_size);
|
||||
}
|
||||
if (char_count < 0)
|
||||
{
|
||||
logError("Encoding error while writing %ld", coord);
|
||||
}
|
||||
#endif // DEBUG
|
||||
int end_pos = char_count; // the first character not to write any more
|
||||
int trailing_zeros = 1;
|
||||
while (trailing_zeros < 4 && buffer[char_count - trailing_zeros] == '0')
|
||||
@@ -103,10 +118,21 @@ struct MMtoStream
|
||||
*/
|
||||
static inline void writeDoubleToStream(const unsigned int precision, const double coord, std::ostream& ss)
|
||||
{
|
||||
char format[5] = "%.xf"; // write a float with [x] digits after the dot
|
||||
char format[5] = "%.xF"; // write a float with [x] digits after the dot
|
||||
format[2] = '0' + precision; // set [x]
|
||||
char buffer[24];
|
||||
int char_count = snprintf(buffer, 24, format, coord);
|
||||
constexpr size_t buffer_size = 400;
|
||||
char buffer[buffer_size];
|
||||
int char_count = sprintf(buffer, format, coord);
|
||||
#ifdef DEBUG
|
||||
if (char_count + 1 >= int(buffer_size)) // + 1 for the null character
|
||||
{
|
||||
logError("Cannot write %f to buffer of size %i", coord, buffer_size);
|
||||
}
|
||||
if (char_count < 0)
|
||||
{
|
||||
logError("Encoding error while writing %f", coord);
|
||||
}
|
||||
#endif // DEBUG
|
||||
if (char_count <= 0)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
|
||||
#include "StringTest.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream> // ostringstream
|
||||
#include <../src/utils/intpoint.h>
|
||||
#include <../src/utils/string.h>
|
||||
|
||||
|
||||
namespace cura
|
||||
{
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(StringTest);
|
||||
@@ -69,13 +71,25 @@ void StringTest::writeInt2mmTest123456789()
|
||||
{
|
||||
writeInt2mmAssert(123456789);
|
||||
}
|
||||
void StringTest::writeInt2mmTestMax()
|
||||
{
|
||||
writeInt2mmAssert(std::numeric_limits<int64_t>::max() / 1001); // divide by 1001, because MM2INT first converts to int and then multiplies by 1000, which causes overflow for the highest integer.
|
||||
}
|
||||
|
||||
|
||||
void StringTest::writeInt2mmAssert(int64_t in)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
writeInt2mm(in, ss);
|
||||
|
||||
ss.flush();
|
||||
std::string str = ss.str();
|
||||
if (!ss.good())
|
||||
{
|
||||
char buffer[200];
|
||||
sprintf(buffer, "The integer %ld was printed as '%s' which was a bad string!", in, str.c_str());
|
||||
CPPUNIT_ASSERT_MESSAGE(std::string(buffer), false);
|
||||
}
|
||||
int64_t out = MM2INT(strtod(str.c_str(), nullptr));
|
||||
|
||||
char buffer[200];
|
||||
@@ -84,4 +98,102 @@ void StringTest::writeInt2mmAssert(int64_t in)
|
||||
}
|
||||
|
||||
|
||||
void StringTest::writeDoubleToStreamTest10000Negative()
|
||||
{
|
||||
writeDoubleToStreamAssert(-10.000);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest1000Negative()
|
||||
{
|
||||
writeDoubleToStreamAssert(-1.000);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest100Negative()
|
||||
{
|
||||
writeDoubleToStreamAssert(-.100);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest10Negative()
|
||||
{
|
||||
writeDoubleToStreamAssert(-.010);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest1Negative()
|
||||
{
|
||||
writeDoubleToStreamAssert(-.001);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest0()
|
||||
{
|
||||
writeDoubleToStreamAssert(0.000);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest1()
|
||||
{
|
||||
writeDoubleToStreamAssert(.001);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest10()
|
||||
{
|
||||
writeDoubleToStreamAssert(.010);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest100()
|
||||
{
|
||||
writeDoubleToStreamAssert(.100);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest1000()
|
||||
{
|
||||
writeDoubleToStreamAssert(1.000);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest10000()
|
||||
{
|
||||
writeDoubleToStreamAssert(10.000);
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTest123456789()
|
||||
{
|
||||
writeDoubleToStreamAssert(123456.789);
|
||||
}
|
||||
|
||||
|
||||
void StringTest::writeDoubleToStreamTestMin()
|
||||
{
|
||||
writeDoubleToStreamAssert(std::numeric_limits<double>::min());
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTestMax()
|
||||
{
|
||||
writeDoubleToStreamAssert(std::numeric_limits<double>::max());
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTestLowest()
|
||||
{
|
||||
writeDoubleToStreamAssert(std::numeric_limits<double>::lowest());
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTestLowestNeg()
|
||||
{
|
||||
writeDoubleToStreamAssert(-std::numeric_limits<double>::lowest());
|
||||
}
|
||||
void StringTest::writeDoubleToStreamTestLow()
|
||||
{
|
||||
writeDoubleToStreamAssert(0.00000001d);
|
||||
}
|
||||
|
||||
|
||||
void StringTest::writeDoubleToStreamAssert(double in, unsigned int precision)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
writeDoubleToStream(precision, in, ss);
|
||||
ss.flush();
|
||||
std::string str = ss.str();
|
||||
if (!ss.good())
|
||||
{
|
||||
char buffer[8000];
|
||||
sprintf(buffer, "The double %f was printed as '%s' which was a bad string!", in, str.c_str());
|
||||
CPPUNIT_ASSERT_MESSAGE(std::string(buffer), false);
|
||||
}
|
||||
double out = strtod(str.c_str(), nullptr);
|
||||
|
||||
std::ostringstream in_ss;
|
||||
in_ss << std::fixed << std::setprecision(precision) << in;
|
||||
std::string in_str = in_ss.str();
|
||||
double in_reinterpreted = strtod(in_str.c_str(), nullptr);
|
||||
|
||||
char buffer[8000];
|
||||
sprintf(buffer, "The double %f was printed as '%s' which was interpreted as %f rather than %f!", in, str.c_str(), out, in_reinterpreted);
|
||||
if (in_reinterpreted != out) std::cerr << buffer << "\n";
|
||||
CPPUNIT_ASSERT_MESSAGE(std::string(buffer), in_reinterpreted == out);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -25,6 +25,25 @@ class StringTest : public CppUnit::TestFixture
|
||||
CPPUNIT_TEST(writeInt2mmTest1000);
|
||||
CPPUNIT_TEST(writeInt2mmTest10000);
|
||||
CPPUNIT_TEST(writeInt2mmTest123456789);
|
||||
CPPUNIT_TEST(writeInt2mmTestMax);
|
||||
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest10000Negative);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest1000Negative);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest100Negative);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest10Negative);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest1Negative);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest0);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest1);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest10);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest100);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest1000);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest10000);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTest123456789);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTestMin);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTestMax);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTestLowest);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTestLowestNeg);
|
||||
CPPUNIT_TEST(writeDoubleToStreamTestLow);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -57,6 +76,25 @@ public:
|
||||
void writeInt2mmTest1000();
|
||||
void writeInt2mmTest10000();
|
||||
void writeInt2mmTest123456789();
|
||||
void writeInt2mmTestMax();
|
||||
|
||||
void writeDoubleToStreamTest10000Negative();
|
||||
void writeDoubleToStreamTest1000Negative();
|
||||
void writeDoubleToStreamTest100Negative();
|
||||
void writeDoubleToStreamTest10Negative();
|
||||
void writeDoubleToStreamTest1Negative();
|
||||
void writeDoubleToStreamTest0();
|
||||
void writeDoubleToStreamTest1();
|
||||
void writeDoubleToStreamTest10();
|
||||
void writeDoubleToStreamTest100();
|
||||
void writeDoubleToStreamTest1000();
|
||||
void writeDoubleToStreamTest10000();
|
||||
void writeDoubleToStreamTest123456789();
|
||||
void writeDoubleToStreamTestMin();
|
||||
void writeDoubleToStreamTestMax();
|
||||
void writeDoubleToStreamTestLowest();
|
||||
void writeDoubleToStreamTestLowestNeg();
|
||||
void writeDoubleToStreamTestLow();
|
||||
|
||||
private:
|
||||
|
||||
@@ -69,6 +107,17 @@ private:
|
||||
* \param in the integer to check
|
||||
*/
|
||||
void writeInt2mmAssert(int64_t in);
|
||||
|
||||
/*!
|
||||
* \brief Performs the actual assertion for the getDist2FromLineSegmentTest.
|
||||
*
|
||||
* This is essentially a parameterised version of all unit tests pertaining
|
||||
* to the writeInt2mm tests.
|
||||
*
|
||||
* \param in the double to check
|
||||
* \param precision the (maximum) number of digits after the decimal mark to print
|
||||
*/
|
||||
void writeDoubleToStreamAssert(double in, unsigned int precision = 4);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário