diff --git a/CMakeLists.txt b/CMakeLists.txt index 47dcd2d1..50e54542 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,7 @@ set(engine_SRCS # Except main.cpp. src/infill/ZigzagConnectorProcessorDisconnectedEndPieces.cpp src/infill/ZigzagConnectorProcessorEndPieces.cpp src/infill/ZigzagConnectorProcessorNoEndPieces.cpp + src/infill/subDivCube.cpp src/pathPlanning/Comb.cpp src/pathPlanning/LinePolygonsCrossings.cpp diff --git a/CPackConfig.cmake b/CPackConfig.cmake index 91c4b71d..8e4ee738 100644 --- a/CPackConfig.cmake +++ b/CPackConfig.cmake @@ -1,20 +1,82 @@ -set(CPACK_PACKAGE_VENDOR "Ultimaker") -set(CPACK_PACKAGE_CONTACT "Arjen Hiemstra ") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cura Engine") -set(CPACK_PACKAGE_VERSION "15.05.90") -set(CPACK_GENERATOR "DEB") -if(NOT DEFINED CPACK_DEBIAN_PACKAGE_ARCHITECTURE) - execute_process(COMMAND dpkg --print-architecture OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE OUTPUT_STRIP_TRAILING_WHITESPACE) +# This file will be configured to contain variables for CPack. These variables +# should be set in the CMake list file of the project before CPack module is +# included. The list of available CPACK_xxx variables and their associated +# documentation may be obtained using +# cpack --help-variable-list +# +# Some variables are common to all generators (e.g. CPACK_PACKAGE_NAME) +# and some are specific to a generator +# (e.g. CPACK_NSIS_EXTRA_INSTALL_COMMANDS). The generator specific variables +# usually begin with CPACK__xxxx. + + +SET(CPACK_BINARY_7Z "") +SET(CPACK_BINARY_BUNDLE "") +SET(CPACK_BINARY_CYGWIN "") +SET(CPACK_BINARY_DEB "") +SET(CPACK_BINARY_DRAGNDROP "") +SET(CPACK_BINARY_IFW "") +SET(CPACK_BINARY_NSIS "") +SET(CPACK_BINARY_OSXX11 "") +SET(CPACK_BINARY_PACKAGEMAKER "") +SET(CPACK_BINARY_RPM "") +SET(CPACK_BINARY_STGZ "") +SET(CPACK_BINARY_TBZ2 "") +SET(CPACK_BINARY_TGZ "") +SET(CPACK_BINARY_TXZ "") +SET(CPACK_BINARY_TZ "") +SET(CPACK_BINARY_WIX "") +SET(CPACK_BINARY_ZIP "") +SET(CPACK_CMAKE_GENERATOR "Unix Makefiles") +SET(CPACK_COMPONENT_UNSPECIFIED_HIDDEN "TRUE") +SET(CPACK_COMPONENT_UNSPECIFIED_REQUIRED "TRUE") +SET(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "") +SET(CPACK_DEBIAN_PACKAGE_DEPENDS "arcus (>= 15.05.90), protobuf (>= 3.0.0), libstdc++6 (>= 4.9.0), libgcc1 (>= 4.9.0)") +SET(CPACK_GENERATOR "DEB") +SET(CPACK_INSTALL_CMAKE_PROJECTS "/root/Data/Firm2017/release/CuraEngine;CuraEngine;ALL;/") +SET(CPACK_INSTALL_PREFIX "/usr/local") +SET(CPACK_MODULE_PATH "") +SET(CPACK_NSIS_DISPLAY_NAME "CuraEngine 15.05.90") +SET(CPACK_NSIS_INSTALLER_ICON_CODE "") +SET(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") +SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") +SET(CPACK_NSIS_PACKAGE_NAME "CuraEngine 15.05.90") +SET(CPACK_OUTPUT_CONFIG_FILE "/root/Data/Firm2017/release/CuraEngine/CPackConfig.cmake") +SET(CPACK_PACKAGE_CONTACT "Arjen Hiemstra ") +SET(CPACK_PACKAGE_DEFAULT_LOCATION "/") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "/usr/share/cmake-3.6/Templates/CPack.GenericDescription.txt") +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cura Engine") +SET(CPACK_PACKAGE_FILE_NAME "CuraEngine-15.05.90_") +SET(CPACK_PACKAGE_INSTALL_DIRECTORY "CuraEngine 15.05.90") +SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "CuraEngine 15.05.90") +SET(CPACK_PACKAGE_NAME "CuraEngine") +SET(CPACK_PACKAGE_RELOCATABLE "true") +SET(CPACK_PACKAGE_VENDOR "Ultimaker") +SET(CPACK_PACKAGE_VERSION "15.05.90") +SET(CPACK_PACKAGE_VERSION_MAJOR "0") +SET(CPACK_PACKAGE_VERSION_MINOR "1") +SET(CPACK_PACKAGE_VERSION_PATCH "1") +SET(CPACK_RESOURCE_FILE_LICENSE "/usr/share/cmake-3.6/Templates/CPack.GenericLicense.txt") +SET(CPACK_RESOURCE_FILE_README "/usr/share/cmake-3.6/Templates/CPack.GenericDescription.txt") +SET(CPACK_RESOURCE_FILE_WELCOME "/usr/share/cmake-3.6/Templates/CPack.GenericWelcome.txt") +SET(CPACK_SET_DESTDIR "OFF") +SET(CPACK_SOURCE_7Z "") +SET(CPACK_SOURCE_CYGWIN "") +SET(CPACK_SOURCE_GENERATOR "TBZ2;TGZ;TXZ;TZ") +SET(CPACK_SOURCE_OUTPUT_CONFIG_FILE "/root/Data/Firm2017/release/CuraEngine/CPackSourceConfig.cmake") +SET(CPACK_SOURCE_TBZ2 "ON") +SET(CPACK_SOURCE_TGZ "ON") +SET(CPACK_SOURCE_TXZ "ON") +SET(CPACK_SOURCE_TZ "ON") +SET(CPACK_SOURCE_ZIP "OFF") +SET(CPACK_SYSTEM_NAME "Linux") +SET(CPACK_TOPLEVEL_TAG "Linux") +SET(CPACK_WIX_SIZEOF_VOID_P "8") + +if(NOT CPACK_PROPERTIES_FILE) + set(CPACK_PROPERTIES_FILE "/root/Data/Firm2017/release/CuraEngine/CPackProperties.cmake") endif() -set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") -set(DEB_DEPENDS - "arcus (>= 15.05.90)" - "protobuf (>= 3.0.0)" - "libstdc++6 (>= 4.9.0)" - "libgcc1 (>= 4.9.0)" -) -string(REPLACE ";" ", " DEB_DEPENDS "${DEB_DEPENDS}") -set(CPACK_DEBIAN_PACKAGE_DEPENDS ${DEB_DEPENDS}) - -include(CPack) +if(EXISTS ${CPACK_PROPERTIES_FILE}) + include(${CPACK_PROPERTIES_FILE}) +endif() diff --git a/libs/clipper/clipper.hpp b/libs/clipper/clipper.hpp index 7a358ae8..9b5332db 100644 --- a/libs/clipper/clipper.hpp +++ b/libs/clipper/clipper.hpp @@ -44,7 +44,7 @@ //#define use_xyz //use_lines: Enables line clipping. Adds a very minor cost to performance. -//#define use_lines +#define use_lines //use_deprecated: Enables temporary support for the obsolete functions //#define use_deprecated diff --git a/src/FffPolygonGenerator.cpp b/src/FffPolygonGenerator.cpp index e47558fe..7e01a9f6 100644 --- a/src/FffPolygonGenerator.cpp +++ b/src/FffPolygonGenerator.cpp @@ -421,6 +421,11 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh, // create gradual infill areas SkinInfillAreaComputation::generateGradualInfill(mesh, mesh.getSettingInMicrons("gradual_infill_step_height"), mesh.getSettingAsCount("gradual_infill_steps")); + //SubDivCube Pre-compute Octree + if(mesh.getSettingAsFillMethod("infill_pattern") == EFillMethod::CUBICSUBDIV){ + SubDivCube::init(mesh); + } + // combine infill unsigned int combined_infill_layers = std::max(1U, round_divide(mesh.getSettingInMicrons("infill_sparse_thickness"), std::max(getSettingInMicrons("layer_height"), 1))); //How many infill layers to combine to obtain the requested sparse thickness. combineInfillLayers(mesh,combined_infill_layers); diff --git a/src/infill.cpp b/src/infill.cpp index 0347a642..a194e646 100644 --- a/src/infill.cpp +++ b/src/infill.cpp @@ -48,6 +48,9 @@ void Infill::generate(Polygons& result_polygons, Polygons& result_lines) case EFillMethod::ZIG_ZAG: generateZigZagInfill(result_lines, line_distance, fill_angle, connected_zigzags, use_endpieces); break; + case EFillMethod::CUBICSUBDIV: + generateCubicSubDivInfill(result_lines); + break; default: logError("Fill pattern has unknown value.\n"); break; @@ -97,6 +100,29 @@ void Infill::generateTriangleInfill(Polygons& result) generateLineInfill(result, line_distance, fill_angle + 120, 0); } +void Infill::generateCubicSubDivInfill(Polygons& result) +{ + Polygons uncropped; + baseSubDivCube->draw(z, uncropped, NULL); + addLineSegmentsInfill(result, uncropped); +} + +void Infill::addLineSegmentsInfill(Polygons& result, Polygons& input) +{ + auto addLine = [&](Point from, Point to) + { + PolygonRef p = result.newPoly(); + p.add(from); + p.add(to); + }; + ClipperLib::PolyTree goodSegsTree = in_outline.lineSegIntersection(input); + ClipperLib::Paths goodSegs; + ClipperLib::OpenPathsFromPolyTree(goodSegsTree, goodSegs); + for(uint64_t idx = 0; idx < goodSegs.size(); idx++){ + addLine(goodSegs[idx][0], goodSegs[idx][1]); + } +} + void Infill::addLineInfill(Polygons& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, const AABB boundary, std::vector>& cut_list, int64_t shift) { auto addLine = [&](Point from, Point to) diff --git a/src/infill.h b/src/infill.h index f290da04..10e4d308 100644 --- a/src/infill.h +++ b/src/infill.h @@ -12,6 +12,7 @@ #include "infill/ZigzagConnectorProcessorEndPieces.h" #include "infill/ZigzagConnectorProcessorConnectedEndPieces.h" #include "infill/ZigzagConnectorProcessorDisconnectedEndPieces.h" +#include "infill/subDivCube.h" #include "utils/intpoint.h" #include "utils/AABB.h" @@ -99,6 +100,12 @@ private: * \param result (output) The resulting lines */ void generateTriangleInfill(Polygons& result); + + /*! + * Generate a 3d pattern of subdivided cubes on their points + * \param result (output) The resulting lines + */ + void generateCubicSubDivInfill(Polygons& result); /*! * Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule @@ -112,6 +119,13 @@ private: */ void addLineInfill(Polygons& result, const PointMatrix& rotation_matrix, const int scanline_min_idx, const int line_distance, const AABB boundary, std::vector>& cut_list, int64_t total_shift); + /*! + * Crop line segments by the infill polygon using Clipper + * \param result (output) The resulting lines + * \param input The line segments to be cropped + */ + void addLineSegmentsInfill(Polygons& result, Polygons& input); + /*! * generate lines within the area of \p in_outline, at regular intervals of \p line_distance * diff --git a/src/infill/subDivCube.cpp b/src/infill/subDivCube.cpp new file mode 100644 index 00000000..b4b694f3 --- /dev/null +++ b/src/infill/subDivCube.cpp @@ -0,0 +1,226 @@ +#include "subDivCube.h" +#include "functional" +#include "../utils/polygonUtils.h" +#include "../sliceDataStorage.h" +namespace cura { +SubDivCube* baseSubDivCube; +double SubDivCube::rotCoefX; +double SubDivCube::rotCoefY; +std::vector SubDivCube::sideLen; +std::vector SubDivCube::height; +std::vector SubDivCube::maxDrawDiff; +std::vector SubDivCube::squareCutAcross; +std::vector SubDivCube::maxLineOffset; +double SubDivCube::radMult = 1; +int32_t SubDivCube::radAdd = 0; + +void SubDivCube::draw(int64_t z, Polygons& result, Polygons** dir) +{ + int epsilon = 10; + auto addLine = [&](Point from, Point to)//this simply adds a line segment to result + { + PolygonRef p = result.newPoly(); + p.add(from); + p.add(to); + }; + auto addLineAndCombine = [&](Polygons& group, Point from, Point to)//this adds a line segment to a polygon of parallel line segments and combines segments that touch within epsilon + { + for(int x = 0; x < group.size(); x++){ + if(abs(from.X-group[x][1].X)height[d]/2){//outside of cube. No drawing or subdivision needed + return; + } + if(diffdraw(z, result, dir); + } + } + if(topLevel){//take care of copying the contents of the three directional polygons into result set AND free the three directional polygons + for(int temp = 0; temp < 3; temp++){ + for(unsigned int x = 0; x < dir[temp]->size(); x++){ + addLine((*dir[temp])[x][0], (*dir[temp])[x][1]); + } + delete dir[temp]; + } + free(dir); + } +} + +SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& myCenter, int d){ + this->d = d;//d is depth of current recursion. kind of. except 0 is completely recursed... + center = myCenter; + + if(d == 0) return;//Lowest layer, no need for subdivision. + Point3 c;//c will be the centers of the new 8 cubes + int32_t nsideLen = sideLen[d-1];//the new sideLen is the sideLen for recursed one more time... + long int rad = radMult*height[d]/4+radAdd;//note:divided by four because it is half of half of the parent height. + //top + c.x=center.x; + c.y=center.y; + c.z=center.z+(height[d]/4); + if(subDiv(mesh, c, nsideLen, rad)){ + children[0] = new SubDivCube(mesh, c, d-1); + } + //top three + Point relCenter; + c.z=center.z+height[d]/12; + relCenter.X=0; + relCenter.Y=-maxLineOffset[d]; + initRot(relCenter); + for(int temp = 0; temp < 3; temp++){ + c.x = relCenter.X+center.x; + c.y = relCenter.Y+center.y; + if(subDiv(mesh, c, nsideLen, rad)){ + children[temp+1] = new SubDivCube(mesh, c, d-1); + } + if(temp < 2){ + rot120(relCenter); + } + } + //bottom + c.x=center.x; + c.y=center.y; + c.z=center.z-(height[d]/4); + if(subDiv(mesh, c, nsideLen, rad)){ + children[4] = new SubDivCube(mesh, c, d-1); + } + //botton three + c.z=center.z-height[d]/12; + relCenter.X=0; + relCenter.Y=maxLineOffset[d]; + initRot(relCenter); + for(int temp = 0; temp < 3; temp++){ + c.x = relCenter.X+center.x; + c.y = relCenter.Y+center.y; + if(subDiv(mesh, c, nsideLen, rad)){ + children[temp+5] = new SubDivCube(mesh, c, d-1); + } + if(temp < 2){ + rot120(relCenter); + } + } +} + +int SubDivCube::subDiv(SliceMeshStorage& mesh, Point3& center, int32_t sideLen, int32_t rad){//put inside of constructor as a lambda? (returns one if a described cube should be subdivided, else zero) + int32_t distance; + long int heightRad;//radius of sphere slice on target layer + int insideSomewhere = 0; + int outsideSomewhere = 0; + int inside; + double partDist; + long int layer_height = mesh.getSettingInMicrons("layer_height"); + long int bot_layer = (center.z-(rad))/layer_height; + long int top_layer = (center.z+(rad))/layer_height; + for(long int templayer = bot_layer; templayer <= top_layer; templayer+=3/*plus three as a quick speed fix... 3 layers doesn't seem like to many?*/){ + partDist = (double)(templayer*layer_height-center.z)/rad;//how far through the radius are we (0-1) + heightRad = rad*(sqrt(1-(partDist*partDist)));//radius of circumscribed sphere at this level + Point loc(center.x, center.y); + + inside = dist(mesh, templayer, loc, &distance); + if(inside == 1){//0 = outside, 1 = inside, 2 = invalid layer(outside)//FIXME LAST does the 2 option cause a speed-up? + insideSomewhere = 1; + }else{ + outsideSomewhere = 1; + } + if(outsideSomewhere && insideSomewhere){ + return 1; + } + if((inside!=2)&&abs(distance) < heightRad){ + return 1; + } + } + return 0; +} + +int SubDivCube::dist(SliceMeshStorage& mesh, long int layer_nr, Point& loc, int32_t* dist){ + if(layer_nr < 0 || layer_nr>=mesh.layers.size()){//if this layer is outside of existing layer range... + return 2; + } + Polygons collide; + mesh.layers[layer_nr].getSecondOrInnermostWalls(collide); + Point centerpoint = loc; + bool inside = collide.inside(centerpoint); + ClosestPolygonPoint rimpoint = PolygonUtils::moveInside2(collide, centerpoint); + *dist = sqrt((rimpoint.location.X-loc.X)*(rimpoint.location.X-loc.X)+(rimpoint.location.Y-loc.Y)*(rimpoint.location.Y-loc.Y)); + if(inside){ + return 1; + } + return 0; +} + +void SubDivCube::init(SliceMeshStorage& gMesh){ + radMult = 1;//gMesh.getSettingInMillimeters("sub_div_rad_mult"); + radAdd = 0;//gMesh.getSettingInMicrons("sub_div_rad_add"); + rotCoefX = cos(M_PI/4);//90 degrees hard coded in because it is for the other infills too. This prevents any of the three directions from being parallel to x or y axis + rotCoefY = sin(M_PI/4); + int maxDepth = 0; + for(int64_t maxSideLen = gMesh.getSettingInMicrons("infill_line_distance")*2; maxSideLen < 25600000; maxSideLen *= 2){//beginning at zero (most recursed) precompute values + sideLen.push_back(maxSideLen); + height.push_back(sqrt(maxSideLen*maxSideLen*3)); + squareCutAcross.push_back(sqrt(maxSideLen*maxSideLen*2)); + maxDrawDiff.push_back((1.0/sqrt(3.0))*maxSideLen); + maxLineOffset.push_back((sqrt(2.0/3.0)*maxSideLen)/2); + maxDepth++; + } + Point3 center(0, 0, 0); + baseSubDivCube = new SubDivCube(gMesh, center, maxDepth-1); +} + +void SubDivCube::initRot(Point& targ){//perform initial rotation. + int64_t x; + x = rotCoefX*targ.X-rotCoefY*targ.Y; + targ.Y = rotCoefX*targ.Y+rotCoefY*targ.X; + targ.X = x; +} + +void SubDivCube::rot120(Point& targ){//rotate 120 degrees + int64_t x; + x = (-0.5)*targ.X-(sqrt_three_fourths)*targ.Y; + targ.Y = (-0.5)*targ.Y+(sqrt_three_fourths)*targ.X; + targ.X = x; +} + +}//namespace cura diff --git a/src/infill/subDivCube.h b/src/infill/subDivCube.h new file mode 100644 index 00000000..fd4effe0 --- /dev/null +++ b/src/infill/subDivCube.h @@ -0,0 +1,34 @@ +#ifndef SUBDIVCUBE_H +#define SUBDIVCUBE_H +#include "../sliceDataStorage.h" +namespace cura +{ +class Infill; +class SubDivCube +{ +public: + static void init(SliceMeshStorage& gMesh); + void draw(int64_t z, Polygons& result, Polygons** dir); +private: + static constexpr double sqrt_three_fourths = 0.8660254037844386467637231707529361834714026269051903;//this is used for the 120 degree rotation... + SubDivCube(SliceMeshStorage& mesh, Point3& myCenter, int d); + static std::vector sideLen;//length of cube side + static std::vector height;//height of cube + static std::vector squareCutAcross;//length across face of cube + static std::vector maxDrawDiff;//maximum difference from the center level of the cube in the x axis when lines still need to be drawn. + static std::vector maxLineOffset;//maximum distance from the 2d center that subdividing lines should be drawn at + static double radMult; + static int32_t radAdd; + int d; + Point3 center;//location of cube center + SubDivCube *(children[8]) = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + static int dist(SliceMeshStorage& mesh, long int layer_nr, Point& loc, int32_t* dist);//returns 1 if inside, distance from polygon put into dist + static int subDiv(SliceMeshStorage& mesh, Point3& center, int32_t sideLen, int32_t rad); + static void rot120(Point& targ); + static void initRot(Point& targ); + static double rotCoefX; + static double rotCoefY; +}; +extern SubDivCube *baseSubDivCube;//the big cube that encompasses everything +} +#endif diff --git a/src/settings/settings.cpp b/src/settings/settings.cpp index 069e0f44..5432a66c 100644 --- a/src/settings/settings.cpp +++ b/src/settings/settings.cpp @@ -345,6 +345,8 @@ EFillMethod SettingsBaseVirtual::getSettingAsFillMethod(std::string key) const return EFillMethod::GRID; if (value == "cubic") return EFillMethod::CUBIC; + if (value == "cubicsubdiv") + return EFillMethod::CUBICSUBDIV; if (value == "tetrahedral") return EFillMethod::TETRAHEDRAL; if (value == "triangles") diff --git a/src/settings/settings.h b/src/settings/settings.h index add58fe8..45e1c0ff 100644 --- a/src/settings/settings.h +++ b/src/settings/settings.h @@ -105,6 +105,7 @@ enum class EFillMethod LINES, GRID, CUBIC, + CUBICSUBDIV, TETRAHEDRAL, TRIANGLES, CONCENTRIC, diff --git a/src/utils/polygon.h b/src/utils/polygon.h index 2766ed89..cf3f0d5a 100644 --- a/src/utils/polygon.h +++ b/src/utils/polygon.h @@ -514,6 +514,15 @@ public: clipper.Execute(ClipperLib::ctIntersection, ret.paths); return ret; } + ClipperLib::PolyTree lineSegIntersection(const Polygons& other) const + { + ClipperLib::PolyTree ret; + ClipperLib::Clipper clipper(clipper_init); + clipper.AddPaths(paths, ClipperLib::ptClip, true); + clipper.AddPaths(other.paths, ClipperLib::ptSubject, false); + clipper.Execute(ClipperLib::ctIntersection, ret); + return ret; + } Polygons xorPolygons(const Polygons& other) const { Polygons ret;