Comparar commits

..

108 Commits

Autor SHA1 Mensagem Data
Tim Kuipers 89a8fd8b4f fix: handle the case where no texture data is provided for haft the faces (CURA-1371) 2017-01-04 17:40:52 +01:00
Tim Kuipers c73cf897ac fix: pixel inversion was 1 off (CURA-1371) 2017-01-04 16:29:02 +01:00
Tim Kuipers 43408040c7 fix: Material::getColor returns zero if no texture was ever loaded (CURA-1371) 2017-01-03 17:23:12 +01:00
Tim Kuipers 0cd3c7829b fix: make ListPolyIt conversion functions use a bool remove_duplicates parameter (CURA-1371) 2017-01-03 10:52:01 +01:00
Tim Kuipers 05c4f3da01 fix: rounding robustness for flow compensation in fuzzy walls (CURA-1371) 2017-01-03 10:30:55 +01:00
Tim Kuipers 44631f3a6f fix: use FuzzyWalls flow computation instead of WallOverlapComputation (CURA-1371) 2016-12-23 14:45:01 +01:00
Tim Kuipers 1ca622b048 refactor: make WallOverlapComputation and FuzzyWalls adhere to the same interface (CURA-1371) 2016-12-23 14:43:46 +01:00
Tim Kuipers 17e02edff7 fix: fixed fuzzy walls and handle corners (CURA-1371)
without handling corners a texture which is black everywhere would result in lower poly outer walls

this is a rewrite of fuzzy skin; a lot of other bugs have also been fixed, such as the computation of the dist_left_over when p0p1 is too short
2016-12-23 12:49:08 +01:00
Tim Kuipers 563317f47d fix: fuzzy skin dist_left_over edge case was wrong (CURA-1371) 2016-12-22 12:16:46 +01:00
Tim Kuipers 4b3a4f57a1 refactor: factor out makeSegmentFuzzy (CURA-1371) 2016-12-22 12:09:59 +01:00
Tim Kuipers 0f15b885f2 refactor: move part of fuzzy walls to constructor (CURA-1371) 2016-12-22 11:49:28 +01:00
Tim Kuipers ecceb71fdd refactor: move fuzzy skin into it's own class and process in FffGcodeWriter (CURA-1371) 2016-12-22 11:39:41 +01:00
Tim Kuipers b8d019ba4a fix: all getSetting should be const (CURA-1371) 2016-12-22 11:22:06 +01:00
Tim Kuipers 310eba6e16 fix: don't fill gaps between fuzzy wall and second wall (CURA-1371) 2016-12-22 10:47:48 +01:00
Tim Kuipers 82c8ac78a5 feat: specify which colors from the texture to use (CURA-1371) 2016-12-22 10:43:46 +01:00
Tim Kuipers 60e5b6088e fix: LinearAlg2D::getDist2FromLineSegment always set optional result even when it's a nullptr (CURA-1371) 2016-12-21 15:57:47 +01:00
Tim Kuipers f8d17c09bf fix: fuzz map used LinearAlg2D::getDist2FromLineSegment wrong (CURA-1371) 2016-12-21 15:57:13 +01:00
Tim Kuipers 72605c9d51 lil doc (CURA-1371) 2016-12-21 14:23:06 +01:00
Tim Kuipers dad342fefd fix/refactor: don't apply offset where no texture is (found) (CURA-1371)
also factors out getCornerOffset from processBumpMap and getCornerDisregard
2016-12-21 14:22:53 +01:00
Tim Kuipers 5b0c3fd4aa feat: bump map face angle correction for dual color dithering (CURA-1371) 2016-12-21 13:54:11 +01:00
Tim Kuipers 7693630f5f lil optimizition: vector.reserve(layer_count) (CURA-1371) 2016-12-21 13:53:10 +01:00
Tim Kuipers e4a23e2bef refactor: add SliceSegment faceIndex info before calling project2D (CURA-1371)
this way it passes the info to the face segment that is passed down into the bump map processor
2016-12-21 13:51:43 +01:00
Tim Kuipers f5e3cf4c91 feat: FaceNormalStorage for storing normal vector info on each face of a mesh (CURA-1371) 2016-12-21 13:12:45 +01:00
Tim Kuipers 22013f70ab feat: Point3::normal analoguous with Point::normal (CURA-1371) 2016-12-20 17:51:04 +01:00
Tim Kuipers 7cf19f06ec FIX: no_point was (0,0,0) while that was not the intent (CURA-1371)
for integer types numeric_limits::infinity evaluates to 0
2016-12-20 17:50:54 +01:00
Tim Kuipers 314ee7ab2d FIX: Point3 used int32_t instead of int64_t (CURA-1371) 2016-12-20 17:49:44 +01:00
Tim Kuipers 16d67fcd3e refactor: give TextureBumpMapProcessor access to the TexturedMesh (CURA-1371) 2016-12-20 13:54:54 +01:00
Tim Kuipers 508a093e26 fix: don't wrap texture coords (1,1) (CURA-1371) 2016-12-20 13:43:54 +01:00
Tim Kuipers 97660d4c80 refactor: move image loading into Material class (CURA-1371) 2016-12-20 12:41:04 +01:00
Tim Kuipers 1f4640e4c2 fix: transfer ownership of pointers when moving a SliceMeshStorage (CURA-1371) 2016-12-20 12:07:18 +01:00
Tim Kuipers b7b9f15063 feat: texture to fuzzy skin amplitude (CURA-1371) 2016-12-20 12:06:35 +01:00
Tim Kuipers 97432cf9f0 fix: image data was upside down (CURA-1371) 2016-12-20 11:18:58 +01:00
Tim Kuipers c081f80d26 fix: only delete image data when last copy of image is used (CURA-1371)
This could probably also have been solved by defining a move constructor which takes responsivility of the data pointed to by the old Material
and a copy constructor which actually copies the data.
2016-12-20 11:18:36 +01:00
Tim Kuipers 4307d39cc9 feat: texture processor to be used for texture_fuzz_map (CURA-1371) 2016-12-20 11:16:36 +01:00
Tim Kuipers 61f1b7d3ba fix: don't go to no-color-offset for gap closer outline segments (CURA-1371) 2016-12-19 15:10:31 +01:00
Tim Kuipers f4118da3e3 fix: texture preprocessing simplified polygons (CURA-1371)
the simplification caused some texture segments not to be found, because it was looking for a single texture segment for a polygon segment which was simplified from multiple face slice segments
2016-12-19 14:45:54 +01:00
Tim Kuipers dba466a029 lil: optimized out a call to abs() (CURA-1371) 2016-12-19 13:06:18 +01:00
Tim Kuipers 019711e24b fix: top layer of each face wasn't sliced (CURA-1371)
this bug was introduced by 1fa6298455
2016-12-19 12:50:12 +01:00
Tim Kuipers 043110db69 fix: handle bump map corner cases better (CURA-1371)
outward corners with positive offset introduce an extra point outside (similar to a miter limit)
outward corners with negative offset don't introduce bump mapping near corner, which would be removed any way.
2016-12-19 10:37:24 +01:00
Tim Kuipers b53295ffd2 fix: wrap around texture coordinates to within [0,1] (CURA-1371)
Does this mean some face textures are wrapped around the wrong way?
2016-12-16 18:52:51 +01:00
Tim Kuipers 319ce6fcfd fixes for stbi image (CURA-1371)
destroy data when done
load implementation of stb only once (Why is this neccessary?!)
without the above I couldn't include the library from two files :S
2016-12-16 18:50:31 +01:00
Tim Kuipers 9d76bb3b3a feat: for each over SparseGrid (CURA-1371) 2016-12-16 18:47:56 +01:00
Tim Kuipers 4bc944ebf6 lil: source for stb lib (CURA-1371) 2016-12-16 14:30:50 +01:00
Tim Kuipers d331687392 Merge branch 'master' into feature_textured_obj_rebased_after_refactor 2016-12-15 18:54:58 +01:00
Tim Kuipers 8a517de1d1 fix: alternate extruder by supplying two meshes in the frontend (CURA-1371)
we need to pass different settings to each extruder, and the frontend controls these settings
when supplying per object settings, derived per object settings might depend on extruder values, so we need to compute per object settings for both colors from the frontend.

alternate_carve_order doesn't do the job, because carving is done after the bump map offsets
2016-12-15 18:35:03 +01:00
Tim Kuipers bcd3347862 feat: bump map alternate with each layer (CURA-1371) 2016-12-15 17:53:18 +01:00
Tim Kuipers aa8e928f0c fix: bump map settings (CURA-1371)
bump_map_enabled, bump_map_point_dist, bump_map_amplitude, bump_map_offset
2016-12-15 17:18:39 +01:00
Tim Kuipers 4529164cdf fix: create SlicerLayer::texture_bump_map in time (CURA-1371) 2016-12-15 16:30:23 +01:00
Tim Kuipers b4140d7772 optimization: efficient material segment lookup (CURA-1371) 2016-12-15 15:54:45 +01:00
Tim Kuipers a9809f3581 refactor: encapsulate registerTextureFaceSlice() in TextureBumpMapProcessor (CURA-1371)
this way I can make segment_to_material_segment an implementation detail of the TextureBumpMapProcessor class.
It is soon te be replaced with a SparseGrid...
2016-12-15 14:59:31 +01:00
Tim Kuipers 2cc01756a0 refactor: moved getColor to MatCoord; removed TexturedMesh parameter to processBumpMap (CURA-1371)
this simplifies a lot of the texture processing
2016-12-15 14:52:33 +01:00
Tim Kuipers a5e9659676 refactor: dynamic_cast rather than virtual methods for TexturedMesh (CURA-1371) 2016-12-15 14:38:05 +01:00
Tim Kuipers 1cf75345ba refactor: move segment_to_material_segment into TextureBumpMapProcessor (CURA-1371) 2016-12-15 13:35:31 +01:00
Tim Kuipers a771600dec refactor: TextureProcessor ==> TextureBumpMapProcessor (CURA-1371) 2016-12-15 13:15:02 +01:00
Tim Kuipers 15df20fe99 REFACTOR: moved all texture related files into subfolder (CURA-1371) 2016-12-14 18:26:29 +01:00
Tim Kuipers 4179178756 lil safety: exit on failed img load; disregard more obj bs (CURA-1371) 2016-12-14 18:13:38 +01:00
Tim Kuipers a3b85c0362 fix: remove polygon complexities introduced by texture offsets (CURA-1371) 2016-12-14 18:02:21 +01:00
Tim Kuipers 0084d16c98 fix: TextureProcessor::dist_left_over wasn't computed properly if p0p1 was too short (CURA-1371)
this resulted in out-of-image texture coordinates

refactor: factor out processSegmentBumpMap out of processBumpMap (CURA-1371)

for readibility.
2016-12-14 17:17:24 +01:00
Tim Kuipers 9ede9ea524 fix: Material: round to nearest pixel (CURA-1371)
also some refactor has been done which is handy for (linear) interpolation, but I don't know whether I should even do this / give the option for it.
2016-12-14 17:06:19 +01:00
Tim Kuipers e4d2161de4 lil refactor: inlined Material::getPixelCoords (CURA-1371) 2016-12-14 15:06:37 +01:00
Tim Kuipers 0a824aac3c fix: account for snapping of slice segments for texture retrieval (CURA-1371) 2016-12-14 14:57:30 +01:00
Tim Kuipers cbcd5df2f7 feat: ColoutUsage setting enum (CURA-1371) 2016-12-14 14:55:59 +01:00
Tim Kuipers 31493500f1 debug: output image to std::cerr (CURA-1371) 2016-12-14 14:34:29 +01:00
Tim Kuipers c3689e0b58 feat: more color options in Material (CURA-1371) 2016-12-14 13:34:05 +01:00
Tim Kuipers d3e455290a fix: use image loader library instead of buggy readBMP function (CURA-1371) 2016-12-14 12:43:37 +01:00
Tim Kuipers 66ad67693e fix: obj loading ignores normals and empty lines (CURA-1371) 2016-12-13 14:21:21 +01:00
Tim Kuipers 43d4097556 refactor: process ==> processBumpMap (CURA-1371) 2016-12-13 14:20:31 +01:00
Tim Kuipers 1d030b4251 lil fix 2016-12-13 14:18:24 +01:00
Tim Kuipers d74fdf2f6c fix: added corner point handling to mesh texture offset (CURA-1371) 2016-12-13 14:18:24 +01:00
Tim Kuipers a4dc1733e8 fix: material coordinates were out of bounds (inverted) (CURA-1371) 2016-12-13 14:18:24 +01:00
Tim Kuipers a6fad000e4 fix: getFaceEdgeMatCoord converted to MM implicitly (CURA-1371) 2016-12-13 14:18:24 +01:00
Tim Kuipers 0274330a09 feat: actual texture to offset computation (still buggy) (CURA-1371)
not all material coordinates seem to be recorded
material coordinates seem always around the same value
2016-12-13 14:18:04 +01:00
Tim Kuipers 119c7e6a3d fix: ambiguous overload in FPoint (CURA-1371) 2016-12-13 13:59:53 +01:00
Tim Kuipers e74ee27256 lil (CURA-1371) 2016-12-13 13:59:53 +01:00
Tim Kuipers 4288a75d0f feat: TextureProcessor for polygons (CURA-1371) 2016-12-13 13:58:58 +01:00
Tim Kuipers ada75a04a0 fix: SlicerSegment hashing fix (CURA-1371) 2016-12-13 11:57:22 +01:00
Tim Kuipers f9ec748e91 feat: segment to material mapping (CURA-1371) 2016-12-13 11:57:22 +01:00
Tim Kuipers 3b59c79bf4 fix: obj parsing fixes and output (CURA-1371) 2016-12-13 11:50:04 +01:00
Tim Kuipers 2cb637b79b lil: SlicerSegment operator== (CURA-1371) 2016-12-13 11:50:04 +01:00
Tim Kuipers dff6595f27 refactor: registerFaceSlice result in MatSegment (CURA-1371) 2016-12-13 11:49:22 +01:00
Tim Kuipers aac3975e5d refactor: factored out child classes from TexturedMesh into MatCoord and FPoint (CURA-1371) 2016-12-13 11:39:02 +01:00
Tim Kuipers f69d070dd4 refactor: factored out child classes from TexturedMesh into MatCoord and FPoint (CURA-1371) 2016-12-13 11:37:48 +01:00
Tim Kuipers d28798ee52 fix: getFaceEdgeMatCoord should result in MatCoord (CURA-1371) 2016-12-13 11:37:48 +01:00
Tim Kuipers 1760d6b8ed fix: obj texture coordinates didn't get loaded (CURA-1371) 2016-12-13 11:37:48 +01:00
Tim Kuipers 80b3436075 refactor: moved slicer related files into slicer folder (CURA-1371) 2016-12-13 11:32:55 +01:00
Tim Kuipers 8ca0fc4cb0 refactor: moved slicer classes to separate files (CURA-1371) 2016-12-13 11:24:43 +01:00
Tim Kuipers 53c4fd28bf feat: mesh.registerFaceSlice for textured meshes (CURA-1371) 2016-12-13 10:40:07 +01:00
Tim Kuipers 56e8f8b10c refactor: send order information to project2D (slicer) (CURA-1371) 2016-12-12 19:16:37 +01:00
Tim Kuipers 1fa6298455 feat: small optimization in slicer (CURA-1371) 2016-12-12 18:53:59 +01:00
Tim Kuipers e7e0fe4050 feat: TexturedMesh.getFaceEdgeMatCoord (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers a7e0d49235 quick hack: sdfsdsgdgsda 2016-12-12 18:00:20 +01:00
Tim Kuipers 8e85c00452 refactor: material coords double ==> float; feat: TexturedMesh.getMatCoord (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 96a4fe1725 fix: lil int casting thing (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 13fe966db3 feat: retrieve color from material (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 2da5b4960a fix: use updated material in obj file (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 00d87b089b feat: load material image (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 9ec30d8168 feat: loading of mtl (obj) (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers cb21c325f6 fix: support obj relative indexing (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 35c2d018a5 fix: made obj loading robust against not having texture data (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers a9f749b4de fix: load obj file into a TexturedMesh (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 4cecf7b8e3 fix: TexturedMesh contructor (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers d661a31041 fix: delete mesh if it didn't load properly (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers f65b270d2a fix: TexturedMesh.addFace wasn't finished yet (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers de85a67f28 feat: let mesh.addFace return whether it actually inserted a face (CURA-1371) 2016-12-12 18:00:20 +01:00
Tim Kuipers 65e9da693d feat: preliminary work for textured meshes (CURA-1371)
basic file structure and functions
2016-12-12 18:00:20 +01:00
Tim Kuipers 921333a7bc refactor: meshgroup.meshes became a vector of pointers (CURA-1371)
This to support future objects inheriting from Mesh
2016-12-12 17:59:26 +01:00
Tim Kuipers bb9aa2280d feat: support basic obj files (non-textured) (CURA-1371) 2016-12-12 17:38:39 +01:00
Tim Kuipers a38d2fa31e added functionality to Mesh to load obj files 2016-12-12 17:38:39 +01:00
105 arquivos alterados com 10975 adições e 1886 exclusões
-6
Ver Arquivo
@@ -7,14 +7,8 @@
NUL
*.gcode
## Directories used for other stuff
Trash/*
output/*
callgrind/*
## Building result.
build/*
debug_build/*
*.pyc
*.exe
*.a
+15 -15
Ver Arquivo
@@ -42,16 +42,6 @@ if(NOT APPLE AND NOT WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
endif()
option (ENABLE_OPENMP
"Use OpenMP for parallel code" ON)
if (ENABLE_OPENMP)
FIND_PACKAGE( OpenMP )
if( OPENMP_FOUND )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" )
endif()
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR} libs)
add_library(clipper STATIC libs/clipper/clipper.cpp)
@@ -64,16 +54,16 @@ set(engine_SRCS # Except main.cpp.
src/FffGcodeWriter.cpp
src/FffPolygonGenerator.cpp
src/FffProcessor.cpp
src/FuzzyWalls.cpp
src/gcodeExport.cpp
src/GCodePathConfig.cpp
src/gcodePlanner.cpp
src/infill.cpp
src/layerPart.cpp
src/LayerPlan.cpp
src/WallsComputation.cpp
src/LayerPlanBuffer.cpp
src/MergeInfillLines.cpp
src/mesh.cpp
src/MeshGroup.cpp
src/multiVolumes.cpp
src/pathOrderOptimizer.cpp
src/Preheat.cpp
src/PrimeTower.cpp
@@ -81,7 +71,6 @@ set(engine_SRCS # Except main.cpp.
src/skin.cpp
src/SkirtBrim.cpp
src/sliceDataStorage.cpp
src/slicer.cpp
src/support.cpp
src/timeEstimate.cpp
src/WallsComputation.cpp
@@ -96,6 +85,18 @@ set(engine_SRCS # Except main.cpp.
src/infill/ZigzagConnectorProcessorNoEndPieces.cpp
src/infill/SubDivCube.cpp
src/slicer/LayerPart.cpp
src/slicer/MultiVolumes.cpp
src/slicer/SlicerLayer.cpp
src/slicer/Slicer.cpp
src/textureProcessing/FaceNormalStorage.cpp
src/textureProcessing/Material.cpp
src/textureProcessing/MaterialBase.cpp
src/textureProcessing/TexturedMesh.cpp
src/textureProcessing/TextureBumpMapProcessor.cpp
src/textureProcessing/TextureProximityProcessor.cpp
src/pathPlanning/Comb.cpp
src/pathPlanning/GCodePath.cpp
src/pathPlanning/LinePolygonsCrossings.cpp
@@ -105,7 +106,6 @@ set(engine_SRCS # Except main.cpp.
src/progress/Progress.cpp
src/progress/ProgressStageEstimator.cpp
src/settings/PathConfigStorage.cpp
src/settings/SettingConfig.cpp
src/settings/SettingContainer.cpp
src/settings/SettingRegistry.cpp
+5
Ver Arquivo
@@ -0,0 +1,5 @@
https://github.com/nothings/stb
Thanks to Sean T. Barrett
license: public domain
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+1 -1
Ver Arquivo
@@ -2,7 +2,7 @@
#ifndef CONICAL_OVERHANG_H
#define CONICAL_OVERHANG_H
#include "slicer.h"
#include "slicer/Slicer.h"
namespace cura {
+246 -211
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+45 -44
Ver Arquivo
@@ -12,7 +12,7 @@
#include "infill.h"
#include "bridge.h"
#include "pathOrderOptimizer.h"
#include "LayerPlan.h"
#include "gcodePlanner.h"
#include "gcodeExport.h"
#include "commandSocket.h"
#include "PrimeTower.h"
@@ -37,10 +37,10 @@ class FffGcodeWriter : public SettingsMessenger, NoCopy
{
friend class FffProcessor; // cause WireFrame2Gcode uses the member [gcode] (TODO)
private:
int max_object_height; //!< The maximal height of all previously sliced meshgroups, used to avoid collision when moving to the next meshgroup to print.
coord_t max_object_height; //!< The maximal height of all previously sliced meshgroups, used to avoid collision when moving to the next meshgroup to print.
/*
* Buffer for all layer plans (of type LayerPlan)
* Buffer for all layer plans (of type GCodePlanner)
*
* The layer plans are buffered so that we can start heating up a nozzle several layers before it needs to be used.
* Another reason is to perform Auto Temperature.
@@ -74,19 +74,18 @@ private:
std::vector<FanSpeedLayerTimeSettings> fan_speed_layer_time_settings_per_extruder; //!< The settings used relating to minimal layer time and fan speeds. Configured for each extruder.
LayerPlan::PlanningState planner_state;
Point last_position_planned; //!< The position of the head before planning the next layer
int current_extruder_planned; //!< The extruder train in use before planning the next layer
bool is_inside_mesh_layer_part; //!< Whether the last position was inside a layer part (used in combing)
public:
FffGcodeWriter(SettingsBase* settings_)
: SettingsMessenger(settings_)
, max_object_height(0)
, layer_plan_buffer(this, gcode)
, extruder_prime_is_planned {} // initialize all values in array with [false]
, planner_state{ no_point
, 0 // changed somewhere early in FffGcodeWriter::writeGCode
, false
}
, last_position_planned(no_point)
, current_extruder_planned(0) // changed somewhere early in FffGcodeWriter::writeGCode
, is_inside_mesh_layer_part(false)
{
}
@@ -173,6 +172,17 @@ private:
* \param[out] storage The data storage to which to save the configurations
*/
void setConfigRetraction(SliceDataStorage& storage);
/*!
* Initialize the GcodePathConfig config parameters which don't change over
* all layers, for each feature.
*
* The features are: skirt or brim, support and for each mesh: outer wall,
* inner walls, skin, infill (and combined infill).
*
* \param[out] storage The data storage to which to save the configurations.
*/
void initConfigs(SliceDataStorage& storage);
/*!
* Get the extruder with which to start the print.
@@ -182,7 +192,7 @@ private:
*
* \param[in] storage where to get settings from.
*/
unsigned int getStartExtruder(const SliceDataStorage& storage);
unsigned int getStartExtruder(SliceDataStorage& storage);
/*!
* Set temperatures and perform initial priming.
@@ -192,14 +202,14 @@ private:
* \param[in] storage where the slice data is stored.
* \param[in] start_extruder_nr The extruder with which to start the print.
*/
void processStartingCode(const SliceDataStorage& storage, const unsigned int start_extruder_nr);
void processStartingCode(SliceDataStorage& storage, const unsigned int start_extruder_nr);
/*!
* Move up and over the already printed meshgroups to print the next meshgroup.
*
* \param[in] storage where the slice data is stored.
*/
void processNextMeshGroupCode(const SliceDataStorage& storage);
void processNextMeshGroupCode(SliceDataStorage& storage);
/*!
* Add raft layer plans onto the FffGcodeWriter::layer_plan_buffer
@@ -207,7 +217,7 @@ private:
* \param[in,out] storage where the slice data is stored.
* \param total_layers The total number of layers.
*/
void processRaft(const SliceDataStorage& storage, unsigned int total_layers);
void processRaft(SliceDataStorage& storage, unsigned int total_layers);
/*!
* Convert the polygon data of a layer into a layer plan on the FffGcodeWriter::layer_plan_buffer
@@ -218,16 +228,15 @@ private:
* \param[in] storage where the slice data is stored.
* \param layer_nr The index of the layer to write the gcode of.
* \param total_layers The total number of layers.
* \return The layer plans
*/
LayerPlan& processLayer(const SliceDataStorage& storage, int layer_nr, unsigned int total_layers) const;
void processLayer(SliceDataStorage& storage, int layer_nr, unsigned int total_layers);
/*!
* Whether the extruders need to be primed separately just before they are used.
*
* \return whether the extruders need to be primed separately just before they are used
*/
bool getExtrudersNeedPrimeDuringFirstLayer() const;
bool getExtrudersNeedPrimeDuringFirstLayer();
/*!
* Plan priming of all used extruders which haven't been primed yet
@@ -235,7 +244,7 @@ private:
* \param layer_plan The initial planning of the g-code of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*/
void ensureAllExtrudersArePrimed(const SliceDataStorage& storage, LayerPlan& layer_plan, const int layer_nr) const;
void ensureAllExtrudersArePrimed(SliceDataStorage& storage, GCodePlanner& layer_plan, const int layer_nr);
/*!
* Add the skirt or the brim to the layer plan \p gcodeLayer.
@@ -245,7 +254,7 @@ private:
* \param extruder_nr The extruder train for which to process the skirt or
* brim.
*/
void processSkirtBrim(const SliceDataStorage& storage, LayerPlan& gcodeLayer, unsigned int extruder_nr) const;
void processSkirtBrim(SliceDataStorage& storage, GCodePlanner& gcodeLayer, unsigned int extruder_nr);
/*!
* Adds the ooze shield to the layer plan \p gcodeLayer.
@@ -254,7 +263,7 @@ private:
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*/
void processOozeShield(const SliceDataStorage& storage, LayerPlan& gcodeLayer, unsigned int layer_nr) const;
void processOozeShield(SliceDataStorage& storage, GCodePlanner& gcodeLayer, unsigned int layer_nr);
/*!
* Adds the draft protection screen to the layer plan \p gcodeLayer.
@@ -263,7 +272,7 @@ private:
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*/
void processDraftShield(const SliceDataStorage& storage, LayerPlan& gcodeLayer, unsigned int layer_nr) const;
void processDraftShield(SliceDataStorage& storage, GCodePlanner& gcodeLayer, unsigned int layer_nr);
/*!
* Calculate in which order to plan the extruders
@@ -272,7 +281,7 @@ private:
* \param current_extruder The current extruder with which we last printed
* \return A vector of pairs of extruder numbers coupled with the mesh indices ordered on print order for that extruder.
*/
std::vector<int> calculateExtruderOrder(const SliceDataStorage& storage, int current_extruder) const;
std::vector<int> calculateExtruderOrder(SliceDataStorage& storage, int current_extruder);
/*!
* Calculate in which order to plan the meshes of a specific extruder
@@ -281,95 +290,88 @@ private:
* \param extruder_nr The extruder for which to determine the order
* \return A vector of pairs of extruder numbers coupled with the mesh indices ordered on print order for that extruder.
*/
std::vector<unsigned int> calculateMeshOrder(const SliceDataStorage& storage, int extruder_nr) const;
std::vector<unsigned int> calculateMeshOrder(SliceDataStorage& storage, int extruder_nr);
/*!
* Add a single layer from a single mesh-volume to the layer plan \p gcodeLayer in mesh surface mode.
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh to add to the layer plan \p gcodeLayer.
* \param mesh_config the line config with which to print a print feature
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshLayerToGCode_meshSurfaceMode(const SliceDataStorage& storage, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcodeLayer, int layer_nr) const;
void addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcodeLayer, int layer_nr);
/*!
* Add the open polylines from a single layer from a single mesh-volume to the layer plan \p gcodeLayer for mesh the surface modes.
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param mesh_config the line config with which to print a print feature
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshOpenPolyLinesToGCode(const SliceDataStorage& storage, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer, int layer_nr) const;
void addMeshOpenPolyLinesToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add a single layer from a single mesh-volume to the layer plan \p gcode_layer.
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh to add to the layer plan \p gcode_layer.
* \param mesh_config the line config with which to print a print feature
* \param gcode_layer The initial planning of the gcode of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshLayerToGCode(const SliceDataStorage& storage, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, LayerPlan& gcode_layer, int layer_nr) const;
void addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add a single part from a given layer of a mesh-volume to the layer plan \p gcode_layer.
*
* \param[in] storage where the slice data is stored.
* \param mesh The mesh to add to the layer plan \p gcode_layer.
* \param mesh_config the line config with which to print a print feature
* \param part The part to add
* \param gcode_layer The initial planning of the gcode of the layer.
* \param layer_nr The index of the layer to write the gcode of.
*
*/
void addMeshPartToGCode(const SliceDataStorage& storage, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, LayerPlan& gcode_layer, int layer_nr) const;
void addMeshPartToGCode(SliceDataStorage& storage, SliceMeshStorage* mesh, SliceLayerPart& part, GCodePlanner& gcode_layer, int layer_nr);
/*!
* Add thicker (multiple layers) sparse infill for a given part in a layer plan.
*
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param mesh_config the line config with which to print a print feature
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \param infill_line_distance The distance between the infill lines
* \param infill_overlap The distance by which the infill overlaps with the wall insets.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processMultiLayerInfill(LayerPlan& gcodeLayer, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle) const;
void processMultiLayerInfill(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
/*!
* Add normal sparse infill for a given part in a layer.
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param mesh_config the line config with which to print a print feature
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \param infill_line_distance The distance between the infill lines
* \param infill_overlap The distance by which the infill overlaps with the wall insets.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processSingleLayerInfill(LayerPlan& gcodeLayer, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle) const;
void processSingleLayerInfill(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, int infill_line_distance, int infill_overlap, int fillAngle);
/*!
* Generate the insets for the walls of a given layer part.
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param mesh_config the line config with which to print a print feature
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \param z_seam_type dir3ective for where to start the outer paerimeter of a part
* \param z_seam_pos The location near where to start the outer inset in case \p z_seam_type is 'back'
*/
void processInsets(LayerPlan& gcodeLayer, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type, Point z_seam_pos) const;
void processInsets(GCodePlanner& gcodeLayer, SliceMeshStorage* mesh, SliceLayerPart& part, unsigned int layer_nr, EZSeamType z_seam_type, Point z_seam_pos);
/*!
@@ -380,13 +382,12 @@ private:
*
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param mesh_config the line config with which to print a print feature
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \param skin_overlap The distance by which the skin overlaps with the wall insets and the distance by which the perimeter gaps overlap with adjacent print features.
* \param fillAngle The angle in the XY plane at which the infill is generated.
*/
void processSkinAndPerimeterGaps(LayerPlan& gcode_layer, const SliceMeshStorage* mesh, const PathConfigStorage::MeshPathConfigs& mesh_config, const SliceLayerPart& part, unsigned int layer_nr, int skin_overlap, int infill_angle) const;
void processSkinAndPerimeterGaps(cura::GCodePlanner& gcode_layer, cura::SliceMeshStorage* mesh, cura::SliceLayerPart& part, unsigned int layer_nr, int skin_overlap, int infill_angle);
/*!
* Add the support to the layer plan \p gcodeLayer of the current layer for all support parts with the given \p extruder_nr.
@@ -395,7 +396,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
* \return whether any support was added to the layer plan
*/
bool addSupportToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, int layer_nr, int extruder_nr) const;
bool addSupportToGCode(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int layer_nr, int extruder_nr);
/*!
* Add the support lines/walls to the layer plan \p gcodeLayer of the current layer.
* \param[in] storage where the slice data is stored.
@@ -403,7 +404,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
* \return whether any support infill was added to the layer plan
*/
bool addSupportInfillToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, int layer_nr) const;
bool addSupportInfillToGCode(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int layer_nr);
/*!
* Add the support skins to the layer plan \p gcodeLayer of the current layer.
* \param[in] storage where the slice data is stored.
@@ -411,7 +412,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
* \return whether any support skin was added to the layer plan
*/
bool addSupportRoofsToGCode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, int layer_nr) const;
bool addSupportRoofsToGCode(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int layer_nr);
/*!
* Change to a new extruder, and add the prime tower instructions if the new extruder is different from the last.
@@ -423,7 +424,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
* \param extruder_nr The extruder to which to switch
*/
void setExtruder_addPrime(const SliceDataStorage& storage, LayerPlan& gcode_layer, int layer_nr, int extruder_nr) const;
void setExtruder_addPrime(SliceDataStorage& storage, GCodePlanner& gcode_layer, int layer_nr, int extruder_nr);
/*!
* Add the prime tower gcode for the current layer.
@@ -432,7 +433,7 @@ private:
* \param layer_nr The index of the layer to write the gcode of.
* \param prev_extruder The current extruder with which we last printed.
*/
void addPrimeTower(const SliceDataStorage& storage, LayerPlan& gcodeLayer, int layer_nr, int prev_extruder) const;
void addPrimeTower(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int layer_nr, int prev_extruder);
/*!
* Add the end gcode and set all temperatures to zero.
+44 -156
Ver Arquivo
@@ -2,17 +2,19 @@
#include <algorithm>
#include <map> // multimap (ordered map allowing duplicate keys)
#include <omp.h>
#include <functional> // function
#include "utils/math.h"
#include "slicer/Slicer.h"
#include "utils/algorithm.h"
#include "slicer.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "MeshGroup.h"
#include "support.h"
#include "multiVolumes.h"
#include "layerPart.h"
#include "slicer/MultiVolumes.h"
#include "slicer/LayerPart.h"
#include "textureProcessing/TextureBumpMapProcessor.h"
#include "textureProcessing/TextureProximityProcessor.h"
#include "WallsComputation.h"
#include "SkirtBrim.h"
#include "skin.h"
@@ -86,11 +88,28 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
return true; //This is NOT an error state!
}
storage.meshes.reserve(meshgroup->meshes.size()); // causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated.
for(unsigned int meshIdx=0; meshIdx < meshgroup->meshes.size(); meshIdx++)
{
// always make a new SliceMeshStorage, so that they have the same ordering / indexing as meshgroup.meshes
// even make a mesh for a support mesh, which doesn't introduce any parts.
storage.meshes.emplace_back(meshgroup->meshes[meshIdx], slice_layer_count); // new mesh in storage had settings from the Mes
}
// ^ needs to be set already for fuzzy wall texture map processing
std::vector<Slicer*> slicerList;
for(unsigned int mesh_idx = 0; mesh_idx < meshgroup->meshes.size(); mesh_idx++)
{
Mesh& mesh = meshgroup->meshes[mesh_idx];
Slicer* slicer = new Slicer(&mesh, initial_slice_z, layer_thickness, slice_layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
Mesh& mesh = *meshgroup->meshes[mesh_idx];
if (mesh.getSettingBoolean("fuzz_map_enabled"))
{
TextureProximityProcessor::Settings texture_proximity_processor_settings(mesh.getSettingInMicrons("wall_line_width_0"));
storage.meshes[mesh_idx].texture_proximity_processor = new TextureProximityProcessor(texture_proximity_processor_settings, slice_layer_count);
}
bool keep_open_polylines = mesh.getSettingBoolean("meshfix_keep_open_polygons");
bool extensive_stitching = mesh.getSettingBoolean("meshfix_extensive_stitching");
Slicer* slicer = new Slicer(&mesh, initial_slice_z, layer_thickness, slice_layer_count, keep_open_polylines, extensive_stitching, storage.meshes[mesh_idx].texture_proximity_processor);
slicerList.push_back(slicer);
/*
for(SlicerLayer& layer : slicer->layers)
@@ -108,7 +127,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
for(unsigned int meshIdx=0; meshIdx < slicerList.size(); meshIdx++)
{
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
if (mesh.getSettingBoolean("conical_overhang_enabled") && !mesh.getSettingBoolean("anti_overhang_mesh"))
{
ConicalOverhang::apply(slicerList[meshIdx], mesh.getSettingInAngleRadians("conical_overhang_angle"), layer_thickness);
@@ -117,6 +136,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper);
if (storage.getSettingBoolean("carve_multiple_volumes"))
{
carveMultipleVolumes(slicerList, storage.getSettingBoolean("alternate_carve_order"));
@@ -126,7 +146,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
storage.print_layer_count = 0;
for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++)
{
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
Slicer* slicer = slicerList[meshIdx];
if (!mesh.getSettingBoolean("anti_overhang_mesh") && !mesh.getSettingBoolean("infill_mesh"))
{
@@ -135,15 +155,12 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
}
storage.support.supportLayers.resize(storage.print_layer_count);
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.
for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++)
{
Slicer* slicer = slicerList[meshIdx];
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
// always make a new SliceMeshStorage, so that they have the same ordering / indexing as meshgroup.meshes
storage.meshes.emplace_back(&meshgroup->meshes[meshIdx], slicer->layers.size()); // new mesh in storage had settings from the Mesh
SliceMeshStorage& meshStorage = storage.meshes.back();
SliceMeshStorage& meshStorage = storage.meshes[meshIdx];
if (mesh.getSettingBoolean("anti_overhang_mesh"))
{
@@ -152,10 +169,6 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
SupportLayer& support_layer = storage.support.supportLayers[layer_nr];
SlicerLayer& slicer_layer = slicer->layers[layer_nr];
support_layer.anti_overhang = support_layer.anti_overhang.unionPolygons(slicer_layer.polygons);
meshStorage.layers[layer_nr].printZ =
slicer_layer.z
+ getSettingInMicrons("layer_height_0")
- initial_slice_z;
}
continue;
}
@@ -166,10 +179,6 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
SupportLayer& support_layer = storage.support.supportLayers[layer_nr];
SlicerLayer& slicer_layer = slicer->layers[layer_nr];
support_layer.support_mesh.add(slicer_layer.polygons);
meshStorage.layers[layer_nr].printZ =
slicer_layer.z
+ getSettingInMicrons("layer_height_0")
- initial_slice_z;
}
continue;
}
@@ -346,24 +355,12 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
// walls
unsigned int processed_layer_count = 0;
#pragma omp parallel for default(none) shared(mesh_layer_count, mesh, inset_skin_progress_estimate, processed_layer_count) schedule(dynamic)
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
{
logDebug("Processing insets for layer %i of %i\n", layer_number, mesh_layer_count);
processInsets(mesh, layer_number);
#ifdef _OPENMP
if (omp_get_thread_num() == 0)
#endif
{ // progress estimation is done only in one thread so that no two threads message progress at the same time
int _processed_layer_count;
#pragma omp atomic read
_processed_layer_count = processed_layer_count;
double progress = inset_skin_progress_estimate.progress(_processed_layer_count);
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
}
#pragma omp atomic
processed_layer_count++;
double progress = inset_skin_progress_estimate.progress(layer_number);
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
}
ProgressEstimatorLinear* skin_estimator = new ProgressEstimatorLinear(mesh_layer_count);
@@ -378,8 +375,8 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
SliceMeshStorage& other_mesh = storage.meshes[other_mesh_idx];
if (other_mesh.getSettingBoolean("infill_mesh"))
{
AABB3D aabb = storage.meshgroup->meshes[mesh_idx].getAABB();
AABB3D other_aabb = storage.meshgroup->meshes[other_mesh_idx].getAABB();
AABB3D aabb = storage.meshgroup->meshes[mesh_idx]->getAABB();
AABB3D other_aabb = storage.meshgroup->meshes[other_mesh_idx]->getAABB();
if (aabb.hit(other_aabb))
{
process_infill = true;
@@ -394,33 +391,16 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
{
mesh_max_bottom_layer_count = std::max(mesh_max_bottom_layer_count, mesh.getSettingAsCount("bottom_layers"));
}
processed_layer_count = 0;
#pragma omp parallel default(none) shared(mesh_layer_count, mesh, mesh_max_bottom_layer_count, process_infill, inset_skin_progress_estimate, processed_layer_count)
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
{
#pragma omp for schedule(dynamic)
for (unsigned int layer_number = 0; layer_number < mesh.layers.size(); layer_number++)
logDebug("Processing skins and infill layer %i of %i\n", layer_number, mesh_layer_count);
if (!mesh.getSettingBoolean("magic_spiralize") || static_cast<int>(layer_number) < mesh_max_bottom_layer_count) //Only generate up/downskin and infill for the first X layers when spiralize is choosen.
{
logDebug("Processing skins and infill layer %i of %i\n", layer_number, mesh_layer_count);
if (!mesh.getSettingBoolean("magic_spiralize") || static_cast<int>(layer_number) < mesh_max_bottom_layer_count) //Only generate up/downskin and infill for the first X layers when spiralize is choosen.
{
processSkinsAndInfill(mesh, layer_number, process_infill);
}
#ifdef _OPENMP
if (omp_get_thread_num() == 0)
#endif
{ // progress estimation is done only in one thread so that no two threads message progress at the same time
int _processed_layer_count;
#pragma omp atomic read
_processed_layer_count = processed_layer_count;
double progress = inset_skin_progress_estimate.progress(_processed_layer_count);
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
}
#pragma omp atomic
processed_layer_count++;
}
processSkinsAndInfill(mesh, layer_number, process_infill);
}
double progress = inset_skin_progress_estimate.progress(layer_number);
Progress::messageProgress(Progress::Stage::INSET_SKIN, progress * 100, 100);
}
}
void FffPolygonGenerator::processInfillMesh(SliceDataStorage& storage, unsigned int mesh_order_idx, std::vector<unsigned int>& mesh_order)
@@ -508,20 +488,8 @@ void FffPolygonGenerator::processDerivedWallsSkinInfill(SliceMeshStorage& mesh)
// combine infill
unsigned int combined_infill_layers = std::max(1U, round_divide(mesh.getSettingInMicrons("infill_sparse_thickness"), std::max(getSettingInMicrons("layer_height"), (coord_t)1))); //How many infill layers to combine to obtain the requested sparse thickness.
combineInfillLayers(mesh,combined_infill_layers);
// fuzzy skin
if (mesh.getSettingBoolean("magic_fuzzy_skin_enabled"))
{
processFuzzyWalls(mesh);
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* processInsets only reads and writes data for the current layer
*/
void FffPolygonGenerator::processInsets(SliceMeshStorage& mesh, unsigned int layer_nr)
{
SliceLayer* layer = &mesh.layers[layer_nr];
@@ -560,19 +528,11 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
for (SliceMeshStorage& mesh : storage.meshes)
{
SliceLayer& layer = mesh.layers[layer_idx];
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0)
if (layer.parts.size() > 0 || (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL && layer.openPolyLines.size() > 0) )
{
layer_is_empty = false;
break;
}
for (const SliceLayerPart& part : layer.parts)
{
if (part.print_outline.size() > 0)
{
layer_is_empty = false;
break;
}
}
}
if (layer_is_empty)
@@ -603,18 +563,8 @@ void FffPolygonGenerator::removeEmptyFirstLayers(SliceDataStorage& storage, cons
support_layers.erase(support_layers.begin(), support_layers.begin() + n_empty_first_layers);
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateSkins read (depend on) data from mesh.layers[*].parts[*].insets and write mesh.layers[n].parts[*].skin_parts
* generateInfill read mesh.layers[n].parts[*].{insets,skin_parts,boundingBox} and write mesh.layers[n].parts[*].infill_area
*
* processSkinsAndInfill read (depend on) mesh.layers[*].parts[*].{insets,boundingBox}.
* write mesh.layers[n].parts[*].{skin_parts,infill_area}.
*/
void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, unsigned int layer_nr, bool process_infill)
void FffPolygonGenerator::processSkinsAndInfill(SliceMeshStorage& mesh, unsigned int layer_nr, bool process_infill)
{
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)
{
@@ -768,66 +718,4 @@ void FffPolygonGenerator::processPlatformAdhesion(SliceDataStorage& storage)
}
void FffPolygonGenerator::processFuzzyWalls(SliceMeshStorage& mesh)
{
if (mesh.getSettingAsCount("wall_line_count") == 0)
{
return;
}
int64_t fuzziness = mesh.getSettingInMicrons("magic_fuzzy_skin_thickness");
int64_t avg_dist_between_points = mesh.getSettingInMicrons("magic_fuzzy_skin_point_dist");
int64_t min_dist_between_points = avg_dist_between_points * 3 / 4; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
int64_t range_random_point_dist = avg_dist_between_points / 2;
for (unsigned int layer_nr = 0; layer_nr < mesh.layers.size(); layer_nr++)
{
SliceLayer& layer = mesh.layers[layer_nr];
for (SliceLayerPart& part : layer.parts)
{
Polygons results;
Polygons& skin = (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") == ESurfaceMode::SURFACE)? part.outline : part.insets[0];
for (PolygonRef poly : skin)
{
// generate points in between p0 and p1
PolygonRef result = results.newPoly();
int64_t dist_left_over = rand() % (min_dist_between_points / 2); // the distance to be traversed on the line before making the first new point
Point* p0 = &poly.back();
for (Point& p1 : poly)
{ // 'a' is the (next) new point between p0 and p1
Point p0p1 = p1 - *p0;
int64_t p0p1_size = vSize(p0p1);
int64_t dist_last_point = dist_left_over + p0p1_size * 2; // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size
for (int64_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + rand() % range_random_point_dist)
{
int r = rand() % (fuzziness * 2) - fuzziness;
Point perp_to_p0p1 = turn90CCW(p0p1);
Point fuzz = normal(perp_to_p0p1, r);
Point pa = *p0 + normal(p0p1, p0pa_dist) + fuzz;
result.add(pa);
dist_last_point = p0pa_dist;
}
dist_left_over = p0p1_size - dist_last_point;
p0 = &p1;
}
while (result.size() < 3 )
{
unsigned int point_idx = poly.size() - 2;
result.add(poly[point_idx]);
if (point_idx == 0) { break; }
point_idx--;
}
if (result.size() < 3)
{
result.clear();
for (Point& p : poly)
result.add(p);
}
}
skin = results;
}
}
}
}//namespace cura
+3 -3
Ver Arquivo
@@ -38,7 +38,7 @@ std::string FffProcessor::getAllSettingsString(MeshGroup& meshgroup, bool first_
}
for (unsigned int mesh_idx = 0; mesh_idx < meshgroup.meshes.size(); mesh_idx++)
{
Mesh& mesh = meshgroup.meshes[mesh_idx];
Mesh& mesh = *meshgroup.meshes[mesh_idx];
sstream << " -e" << mesh.getSettingAsIndex("extruder_nr") << " -l \"" << mesh_idx << "\"" << mesh.getAllLocalSettingsString();
}
sstream << "\n";
@@ -58,9 +58,9 @@ bool FffProcessor::processMeshGroup(MeshGroup* meshgroup)
gcode_writer.setParent(meshgroup);
bool empty = true;
for (Mesh& mesh : meshgroup->meshes)
for (Mesh* mesh : meshgroup->meshes)
{
if (!mesh.getSettingBoolean("infill_mesh") && !mesh.getSettingBoolean("anti_overhang_mesh"))
if (!mesh->getSettingBoolean("infill_mesh") && !mesh->getSettingBoolean("anti_overhang_mesh"))
{
empty = false;
}
+218
Ver Arquivo
@@ -0,0 +1,218 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "FuzzyWalls.h"
#define NORMAL_LENGTH 10000
namespace cura
{
FuzzyWalls::FuzzyWalls(const SliceMeshStorage& mesh)
: settings(&mesh)
{
if (mesh.getSettingBoolean("fuzz_map_enabled"))
{
assert(mesh.texture_proximity_processor && "texture_proximity_processor should have been initialized");
getAmplitude = [&mesh, this](const unsigned int layer_nr, const Point p)
{
assert(mesh.texture_proximity_processor && "When fuzz_map_enabled there has to be a texture proximity processor!");
TextureProximityProcessor& texture_proximity_processor = *mesh.texture_proximity_processor;
float color = texture_proximity_processor.getColor(p, layer_nr, settings.color_usage, 0.0); // TODO change default 0.0
coord_t ret = color * settings.max_amplitude;
return ret;
};
}
else
{
getAmplitude = [this](const unsigned int layer_nr, const Point p)
{
return settings.max_amplitude;
};
}
}
Polygons FuzzyWalls::makeFuzzy(const SliceMeshStorage& mesh, const unsigned int layer_nr, const Polygons& in)
{
Polygons results;
if (in.size() == 0)
{
return results;
}
flows.reserve(in.size());
for (const PolygonRef poly : const_cast<Polygons&>(in))
{
assert(poly.size() >= 3);
// generate points in between p0 and p1
PolygonRef result = results.newPoly();
flows.emplace_back(); // keep flows aligned with the result
flows.back().reserve(poly.size());
Point p0 = poly[poly.size() - 2];
Point p1 = poly.back();
for (int p0_idx = poly.size() - 2; p0_idx >= 0; p0_idx--)
{ // p0 is the last point before p1 which is different from p1
p0 = poly[p0_idx];
}
CarryOver carry_over;
carry_over.dist_left_over = (settings.min_dist_between_points + rand() % settings.range_random_point_dist) / 2;
carry_over.step_size = carry_over.dist_left_over;
carry_over.offset_random = 0.0; // unused in the first iteration since carry_over.step_size = carry_over.dist_left_over; see makeCornerFuzzy
carry_over.next_offset_random = static_cast<float>(rand()) / static_cast<float>(RAND_MAX) * 2.0 - 1.0;
carry_over.p0p1_perp = turn90CCW(p1 - p0);
// 'x' is the previous location from where a randomly offsetted new point between p-1 and p0 was created
for (Point p2 : poly)
{
if (p2 == p1)
{
continue;
}
makeCornerFuzzy(layer_nr, p0, p1, p2, carry_over, result);
makeSegmentFuzzy(layer_nr, p1, p2, result, carry_over);
p0 = p1;
p1 = p2;
}
while (result.size() < 3 )
{
unsigned int point_idx = poly.size() - 2;
result.add(poly[point_idx]);
flows.back().push_back(1.0);
if (point_idx == 0)
{
break;
}
point_idx--;
}
if (result.size() > 0)
{ // compute flow of the newly introduced segment
const Point p0 = result.back();
const Point p1 = result.back();
const coord_t length = vSize(p1 - p0);
const coord_t pxpa_dist = carry_over.step_size - carry_over.dist_left_over;
const float flow_here = (length < 10 || std::abs(length - pxpa_dist) < 5)? 1.0 : std::min(1.0, INT2MM(pxpa_dist) / INT2MM(length));
flows.back().push_back(flow_here);
}
if (result.size() < 3)
{
result.clear();
flows.back().clear();
for (const Point& p : poly)
{
result.add(p);
flows.back().push_back(1.0);
}
}
assert(result.size() == flows.back().size());
}
return results;
}
void FuzzyWalls::makeCornerFuzzy(const unsigned int layer_nr, const Point p0, const Point p1, const Point p2, const CarryOver carry_over, PolygonRef result)
{
const Point p0p1_perp = carry_over.p0p1_perp;
const Point p1p2 = p2 - p1;
const Point p1p2_perp = turn90CCW(p1p2);
const Point corner_normal = normal(p0p1_perp, NORMAL_LENGTH) + normal(p1p2_perp, NORMAL_LENGTH);
// x is the last point which was offsetted
// a is the next point to be offsetted
//
// step_size
// ^^^^^^^^^^^^^^^^^^^^
// p1pa_dist
// pxp1_dist ^^^^^^^^^
// ^^^^^^^^^^
// ┬ > amplitudes
// |
// |
// ┬ |
// ┥ | > previous random offset within amplitude
// | ┥pr ┬ > corner offset computed by weighted average based on pxp0_dist, p0pa_dist and the amplitudes
// | | |
// -------x---------p1--------a-------
// | | ┥ > next random offset within amplitude
// | | ┴
// | |
// ┴ |
// |
// |
// ┴
//
// assuming all amplitudes are the same and x, p1, a are on a straight line, pr will also be on a straight line between the previous and next offsetted points
const coord_t corner_amplitude = getAmplitude(layer_nr, p1);
// randFloat = offset / amplitude
// offset weighted by relative amplitudes and distance to p0
assert(carry_over.step_size > 0);
const coord_t pxp1_dist = (carry_over.step_size - carry_over.dist_left_over);
assert(pxp1_dist >= 0);
const coord_t p1pa_dist = carry_over.dist_left_over;
const coord_t offset_contribution_0 = corner_amplitude * pxp1_dist * carry_over.offset_random;
const coord_t offset_contribution_2 = corner_amplitude * p1pa_dist * carry_over.next_offset_random;
const coord_t offset = (offset_contribution_0 + offset_contribution_2) / carry_over.step_size;
Point fuzz = normal(corner_normal, offset);
Point pr = p1 + fuzz;
if (result.size() > 0)
{ // compute flow of the newly introduced segment
const Point last = result.back();
const coord_t length = vSize(last - pr);
const float flow_here = (length < 10 || std::abs(length - pxp1_dist) < 5)? 1.0 : std::min(1.0, INT2MM(pxp1_dist) / INT2MM(length));
// limit the flow to 1.0,
// internal corners where the offset is negative could result in such a case,
// but it is then better to not cause over extrusion there
flows.back().push_back(flow_here);
}
result.add(pr);
}
void FuzzyWalls::makeSegmentFuzzy(const unsigned int layer_nr, const Point p0, const Point p1, PolygonRef result, CarryOver& carry_over)
{
// 'a' is the (next) new point between p0 and p1, offsetted from the point
// 'x', which is on the line segment p0p1
const Point p0p1 = p1 - p0;
carry_over.p0p1_perp = turn90CCW(p0p1);
const int64_t p0p1_size = vSize(p0p1);
coord_t dist_to_prev_point = carry_over.dist_left_over; // distance from the last introduced point to the newly introduced one
int64_t dist_last_point = carry_over.dist_left_over - carry_over.step_size; // so that 'carry_over.step_size - (p0p1_size - dist_last_point)' evaulates to 'dist_left_over - p0p1_size'
for (int64_t p0pa_dist = carry_over.dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += carry_over.step_size)
{
const Point px = p0 + normal(p0p1, p0pa_dist);
coord_t amplitude = getAmplitude(layer_nr, px);
if (amplitude == 0)
{
amplitude = 1;
}
carry_over.offset_random = carry_over.next_offset_random;
carry_over.next_offset_random = static_cast<float>(rand()) / static_cast<float>(RAND_MAX) * 2.0 - 1.0;
const coord_t offset = carry_over.offset_random * amplitude;
Point fuzz = normal(carry_over.p0p1_perp, offset);
Point pa = px + fuzz;
if (result.size() > 0)
{ // compute flow of the newly introduced segment
const Point last = result.back();
const coord_t length = vSize(last - pa);
const float flow_here = (length < 10 || std::abs(length - dist_to_prev_point) < 5)? 1.0 : std::min(1.0, INT2MM(dist_to_prev_point) / INT2MM(length));
flows.back().push_back(flow_here);
}
result.add(pa);
dist_last_point = p0pa_dist;
carry_over.step_size = settings.min_dist_between_points + rand() % settings.range_random_point_dist;
dist_to_prev_point = carry_over.step_size;
}
carry_over.dist_left_over = carry_over.step_size - (p0p1_size - dist_last_point);
assert(carry_over.dist_left_over >= 0);
assert(carry_over.dist_left_over < carry_over.step_size);
}
float FuzzyWalls::getFlow(const Polygons& from, unsigned int poly_idx, unsigned int from_point_idx, unsigned int to_point_idx)
{
assert(from.size() == flows.size());
assert(poly_idx < flows.size());
assert(from[poly_idx].size() == flows[poly_idx].size());
assert((from_point_idx + 1) % flows[poly_idx].size() == to_point_idx);
return flows[poly_idx][from_point_idx];
}
}//namespace cura
+52
Ver Arquivo
@@ -0,0 +1,52 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef FUZZY_WALLS_H
#define FUZZY_WALLS_H
#include "sliceDataStorage.h"
#include "PolygonFlowAdjuster.h"
namespace cura {
class FuzzyWalls : public PolygonFlowAdjuster
{
public:
struct Settings
{
coord_t max_amplitude;
coord_t avg_dist_between_points;
ColourUsage color_usage;
coord_t min_dist_between_points;
coord_t range_random_point_dist;
Settings(const SettingsBaseVirtual* settings_base)
: max_amplitude(settings_base->getSettingInMicrons("magic_fuzzy_skin_thickness"))
, avg_dist_between_points(settings_base->getSettingInMicrons("magic_fuzzy_skin_point_dist"))
, color_usage(settings_base->getSettingAsColourUsage("fuzz_map_texture_color"))
, min_dist_between_points(avg_dist_between_points * 3 / 4) // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value
, range_random_point_dist(avg_dist_between_points / 2)
{
}
};
FuzzyWalls(const SliceMeshStorage& mesh);
Polygons makeFuzzy(const SliceMeshStorage& mesh, const unsigned int layer_nr, const Polygons& in);
float getFlow(const Polygons& from, unsigned int poly_idx, unsigned int from_point_idx, unsigned int to_point_idx);
protected:
struct CarryOver
{
coord_t dist_left_over;
float offset_random; // [-1,1]
float next_offset_random; // [-1,1]
coord_t step_size;
Point p0p1_perp;
};
Settings settings;
std::function<coord_t (const unsigned int, const Point)> getAmplitude;
std::vector<std::vector<float>> flows; //!< The flow per segment per polygon in the input
void makeCornerFuzzy(const unsigned int layer_nr, const Point p0, const Point p1, const Point p2, const CarryOver carry_over, PolygonRef result);
void makeSegmentFuzzy(const unsigned int layer_nr, const Point p0, const Point p1, PolygonRef result, CarryOver& carry_over);
};
}//namespace cura
#endif//FUZZY_WALLS_H
+64 -33
Ver Arquivo
@@ -6,74 +6,105 @@
namespace cura
{
GCodePathConfig::GCodePathConfig(const GCodePathConfig& other)
: type(other.type)
, speed_derivatives(other.speed_derivatives)
, line_width(other.line_width)
, layer_thickness(other.layer_thickness)
, flow(other.flow)
, extrusion_mm3_per_mm(other.extrusion_mm3_per_mm)
GCodePathConfig::BasicConfig::BasicConfig()
: speed(0)
, acceleration(0)
, jerk(0)
, line_width(0)
, flow(100)
{
}
GCodePathConfig::GCodePathConfig(PrintFeatureType type, int line_width, int layer_height, double flow, GCodePathConfig::SpeedDerivatives speed_derivatives)
: type(type)
, speed_derivatives(speed_derivatives)
GCodePathConfig::BasicConfig::BasicConfig(double speed, double acceleration, double jerk, int line_width, double flow)
: speed(speed)
, acceleration(acceleration)
, jerk(jerk)
, line_width(line_width)
, layer_thickness(layer_height)
, flow(flow)
, extrusion_mm3_per_mm(calculateExtrusion())
{
}
void GCodePathConfig::smoothSpeed(GCodePathConfig::SpeedDerivatives first_layer_config, int layer_nr, int max_speed_layer_nr)
void GCodePathConfig::BasicConfig::set(double speed, double acceleration, double jerk, int line_width, double flow)
{
double max_speed_layer = max_speed_layer_nr;
speed_derivatives.speed = (speed_derivatives.speed * layer_nr) / max_speed_layer + (first_layer_config.speed * (max_speed_layer - layer_nr) / max_speed_layer);
speed_derivatives.acceleration = (speed_derivatives.acceleration * layer_nr) / max_speed_layer + (first_layer_config.acceleration * (max_speed_layer - layer_nr) / max_speed_layer);
speed_derivatives.jerk = (speed_derivatives.jerk * layer_nr) / max_speed_layer + (first_layer_config.jerk * (max_speed_layer - layer_nr) / max_speed_layer);
this->speed = speed;
this->acceleration = acceleration;
this->jerk = jerk;
this->line_width = line_width;
this->flow = flow;
}
double GCodePathConfig::getExtrusionMM3perMM() const
GCodePathConfig::GCodePathConfig(PrintFeatureType type)
: extrusion_mm3_per_mm(0.0)
, type(type)
{
}
void GCodePathConfig::init(double speed, double acceleration, double jerk, int line_width, double flow)
{
iconic_config.set(speed, acceleration, jerk, line_width, flow);
current_config = iconic_config;
}
void GCodePathConfig::setLayerHeight(int layer_height)
{
this->layer_thickness = layer_height;
calculateExtrusion();
}
void GCodePathConfig::smoothSpeed(GCodePathConfig::BasicConfig first_layer_config, int layer_nr, double max_speed_layer)
{
current_config.speed = (iconic_config.speed * layer_nr) / max_speed_layer + (first_layer_config.speed * (max_speed_layer - layer_nr) / max_speed_layer);
current_config.acceleration = (iconic_config.acceleration * layer_nr) / max_speed_layer + (first_layer_config.acceleration * (max_speed_layer - layer_nr) / max_speed_layer);
current_config.jerk = (iconic_config.jerk * layer_nr) / max_speed_layer + (first_layer_config.jerk * (max_speed_layer - layer_nr) / max_speed_layer);
}
void GCodePathConfig::setSpeedIconic()
{
current_config.speed = iconic_config.speed;
current_config.acceleration = iconic_config.acceleration;
current_config.jerk = iconic_config.jerk;
}
double GCodePathConfig::getExtrusionMM3perMM()
{
return extrusion_mm3_per_mm;
}
double GCodePathConfig::getSpeed() const
double GCodePathConfig::getSpeed()
{
return speed_derivatives.speed;
return current_config.speed;
}
double GCodePathConfig::getAcceleration() const
double GCodePathConfig::getAcceleration()
{
return speed_derivatives.acceleration;
return current_config.acceleration;
}
double GCodePathConfig::getJerk() const
double GCodePathConfig::getJerk()
{
return speed_derivatives.jerk;
return current_config.jerk;
}
int GCodePathConfig::getLineWidth() const
int GCodePathConfig::getLineWidth()
{
return line_width;
return current_config.line_width;
}
bool GCodePathConfig::isTravelPath() const
bool GCodePathConfig::isTravelPath()
{
return line_width == 0;
return current_config.line_width == 0;
}
double GCodePathConfig::getFlowPercentage() const
double GCodePathConfig::getFlowPercentage()
{
return flow;
return current_config.flow;
}
double GCodePathConfig::calculateExtrusion() const
void GCodePathConfig::calculateExtrusion()
{
return INT2MM(line_width) * INT2MM(layer_thickness) * double(flow) / 100.0;
extrusion_mm3_per_mm = INT2MM(current_config.line_width) * INT2MM(layer_thickness) * double(current_config.flow) / 100.0;
}
+48 -24
Ver Arquivo
@@ -13,73 +13,97 @@ namespace cura
*/
class GCodePathConfig
{
friend class LayerPlanTest;
friend class GCodePlannerTest;
public:
/*!
* A simple wrapper class for all derivatives of position which are used when printing a line
* The path config settings which may change from layer to layer
*/
struct SpeedDerivatives
struct BasicConfig
{
double speed; //!< movement speed (mm/s)
double acceleration; //!< acceleration of head movement (mm/s^2)
double jerk; //!< jerk of the head movement (around stand still) as instantaneous speed change (mm/s)
double jerk; //!< jerk of the head movement (around stand still) (mm/s^3)
int line_width; //!< width of the line extruded
double flow; //!< extrusion flow modifier in %
BasicConfig(); //!< basic contructor initializing with inaccurate values
BasicConfig(double speed, double acceleration, double jerk, int line_width, double flow); //!< basic contructor initializing all values
void set(double speed, double acceleration, double jerk, int line_width, double flow); //!< Set all config values
};
const PrintFeatureType type; //!< name of the feature type
private:
SpeedDerivatives speed_derivatives; //!< The speed settings (and acceleration and jerk) of the extruded line. May be changed when smoothSpeed is called.
const int line_width; //!< width of the line extruded
const int layer_thickness; //!< current layer height in micron
const double flow; //!< extrusion flow modifier in %
const double extrusion_mm3_per_mm;//!< current mm^3 filament moved per mm line traversed
BasicConfig iconic_config; //!< The basic path configuration iconic to this print feature type
BasicConfig current_config; //!< The current path configuration for the current layer
int layer_thickness; //!< current layer height in micron
double extrusion_mm3_per_mm;//!< current mm^3 filament moved per mm line traversed
public:
GCodePathConfig(PrintFeatureType type, int line_width, int layer_height, double flow, SpeedDerivatives speed_derivatives); // , SpeedDerivatives slowdown_speed_derivatives, int layer_nr, int max_speed_layer_nr);
const PrintFeatureType type; //!< name of the feature type
/*!
* copy constructor
* Basic constructor.
*/
GCodePathConfig(const GCodePathConfig& other);
GCodePathConfig(PrintFeatureType type);
/*!
* Initialize some of the member variables.
*
* \warning GCodePathConfig::setLayerHeight still has to be called before this object can be used.
*
* \param speed The regular speed with which to print this feature
* \param line_width The line width for this feature
* \param flow The flow modifier to apply to the extruded filament when printing this feature
*/
void init(double speed, double acceleration, double jerk, int line_width, double flow);
/*!
* Set the layer height and (re)compute the extrusion_per_mm
*/
void setLayerHeight(int layer_height);
/*!
* Set the speed to somewhere between the speed of @p first_layer_config and the iconic speed.
*
* \warning This functions should not be called with @p layer_nr > @p max_speed_layer !
*
* \warning Calling this function twice will smooth the speed more toward \p first_layer_config
*
* \param first_layer_config The speed settings at layer zero
* \param layer_nr The layer number
* \param max_speed_layer The layer number for which the speed_iconic should be used.
*/
void smoothSpeed(SpeedDerivatives first_layer_config, int layer_nr, int max_speed_layer);
void smoothSpeed(BasicConfig first_layer_config, int layer_nr, double max_speed_layer);
/*!
* Set the speed config to the iconic speed config, i.e. the normal speed of the feature type for which this is a config.
*
* Does the same for acceleration and jerk.
*/
void setSpeedIconic();
/*!
* Can only be called after the layer height has been set (which is done while writing the gcode!)
*/
double getExtrusionMM3perMM() const;
double getExtrusionMM3perMM();
/*!
* Get the movement speed in mm/s
*/
double getSpeed() const;
double getSpeed();
/*!
* Get the current acceleration of this config
*/
double getAcceleration() const;
double getAcceleration();
/*!
* Get the current jerk of this config
*/
double getJerk() const;
double getJerk();
int getLineWidth() const;
int getLineWidth();
bool isTravelPath() const;
bool isTravelPath();
double getFlowPercentage() const;
double getFlowPercentage();
private:
double calculateExtrusion() const;
void calculateExtrusion();
};
+5 -5
Ver Arquivo
@@ -17,7 +17,7 @@ void LayerPlanBuffer::flush()
}
while (!buffer.empty())
{
buffer.front()->writeGCode(gcode);
buffer.front().writeGCode(gcode);
if (CommandSocket::isInstantiated())
{
CommandSocket::getInstance()->flushGcode();
@@ -324,7 +324,7 @@ void LayerPlanBuffer::insertFinalPrintTempCommand(std::vector<ExtruderPlan*>& ex
void LayerPlanBuffer::insertTempCommands()
{
if (buffer.back()->extruder_plans.size() == 0 || (buffer.back()->extruder_plans.size() == 1 && buffer.back()->extruder_plans[0].paths.size() == 0))
if (buffer.back().extruder_plans.size() == 0 || (buffer.back().extruder_plans.size() == 1 && buffer.back().extruder_plans[0].paths.size() == 0))
{ // disregard empty layer
buffer.pop_back();
return;
@@ -332,9 +332,9 @@ void LayerPlanBuffer::insertTempCommands()
std::vector<ExtruderPlan*> extruder_plans;
extruder_plans.reserve(buffer.size() * 2);
for (LayerPlan* layer_plan : buffer)
for (GCodePlanner& layer_plan : buffer)
{
for (ExtruderPlan& extr_plan : layer_plan->extruder_plans)
for (ExtruderPlan& extr_plan : layer_plan.extruder_plans)
{
extruder_plans.push_back(&extr_plan);
}
@@ -342,7 +342,7 @@ void LayerPlanBuffer::insertTempCommands()
// insert commands for all extruder plans on this layer
LayerPlan& layer_plan = *buffer.back();
GCodePlanner& layer_plan = buffer.back();
for (unsigned int extruder_plan_idx = 0; extruder_plan_idx < layer_plan.extruder_plans.size(); extruder_plan_idx++)
{
unsigned int overall_extruder_plan_idx = extruder_plans.size() - layer_plan.extruder_plans.size() + extruder_plan_idx;
+12 -22
Ver Arquivo
@@ -8,7 +8,7 @@
#include "commandSocket.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "gcodePlanner.h"
#include "MeshGroup.h"
#include "Preheat.h"
@@ -17,7 +17,7 @@ namespace cura
{
/*!
* Class for buffering multiple layer plans (\ref LayerPlan) / extruder plans within those layer plans, so that temperature commands can be inserted in earlier layer plans.
* Class for buffering multiple layer plans (\ref GCodePlanner) / extruder plans within those layer plans, so that temperature commands can be inserted in earlier layer plans.
*
* This class handles where to insert temperature commands for:
* - initial layer temperature
@@ -42,7 +42,7 @@ class LayerPlanBuffer : SettingsMessenger
std::vector<bool> extruder_used_in_meshgroup; //!< For each extruder whether it has already been planned once in this meshgroup. This is used to see whether we should heat to the initial_print_temp or to the printing_temperature
public:
std::list<LayerPlan*> buffer; //!< The buffer containing several layer plans (LayerPlan) before writing them to gcode.
std::list<GCodePlanner> buffer; //!< The buffer containing several layer plans (GCodePlanner) before writing them to gcode.
LayerPlanBuffer(SettingsBaseVirtual* settings, GCodeExport& gcode)
: SettingsMessenger(settings)
@@ -54,43 +54,33 @@ public:
{
preheat_config.setConfig(settings);
}
/*!
* Push a new layer plan into the buffer
* Place a new layer plan (GcodePlanner) by constructing it with the given arguments.
* Pop back the oldest layer plan is it exceeds the buffer size and write it to gcode.
*/
void push(LayerPlan& layer_plan)
{
buffer.push_back(&layer_plan);
}
/*!
* Process all layers in the buffer
* This inserts the temperature commands to start warming for a given layer in earlier layers
*
* Pop out the earliest layer in the buffer if the buffer size is exceeded
* \return A nullptr or the popped gcode_layer
*/
LayerPlan* processBuffer()
template<typename... Args>
GCodePlanner& emplace_back(Args&&... constructor_args)
{
if (buffer.size() > 0)
{
insertTempCommands(); // insert preheat commands of the just completed layer plan (not the newly emplaced one)
}
buffer.emplace_back(constructor_args...);
if (buffer.size() > buffer_size)
{
LayerPlan* ret = buffer.front();
buffer.front().writeGCode(gcode);
if (CommandSocket::isInstantiated())
{
CommandSocket::getInstance()->flushGcode();
}
buffer.pop_front();
return ret;
}
return nullptr;
return buffer.back();
}
/*!
* Write all remaining layer plans (LayerPlan) to gcode and empty the buffer.
* Write all remaining layer plans (GCodePlanner) to gcode and empty the buffer.
*/
void flush();
+5 -14
Ver Arquivo
@@ -3,7 +3,7 @@
#include "utils/intpoint.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "gcodePlanner.h"
#include "GCodePathConfig.h"
namespace cura
@@ -17,7 +17,7 @@ class MergeInfillLines
std::vector<GCodePath>& paths; //!< The paths currently under consideration
ExtruderPlan& extruder_plan; //!< The extruder plan of the paths currently under consideration
const GCodePathConfig& travelConfig; //!< The travel settings used to see whether a path is a travel path or an extrusion path
GCodePathConfig& travelConfig; //!< The travel settings used to see whether a path is a travel path or an extrusion path
int64_t nozzle_size; //!< The diameter of the hole in the nozzle
bool speed_equalize_flow_enabled; //!< Should the speed be varied with extrusion width
double speed_equalize_flow_max; //!< Maximum speed when adjusting speed for flow
@@ -64,18 +64,9 @@ public:
/*!
* Simple constructor only used by MergeInfillLines::isConvertible to easily convey the environment
*/
MergeInfillLines(GCodeExport& gcode, int layer_nr, std::vector<GCodePath>& paths, ExtruderPlan& extruder_plan, const GCodePathConfig& travelConfig, int64_t nozzle_size, bool speed_equalize_flow_enabled, double speed_equalize_flow_max)
: gcode(gcode)
, layer_nr(layer_nr)
, paths(paths)
, extruder_plan(extruder_plan)
, travelConfig(travelConfig)
, nozzle_size(nozzle_size)
, speed_equalize_flow_enabled(speed_equalize_flow_enabled)
, speed_equalize_flow_max(speed_equalize_flow_max)
{
}
MergeInfillLines(GCodeExport& gcode, int layer_nr, std::vector<GCodePath>& paths, ExtruderPlan& extruder_plan, GCodePathConfig& travelConfig, int64_t nozzle_size, bool speed_equalize_flow_enabled, double speed_equalize_flow_max)
: gcode(gcode), layer_nr(layer_nr), paths(paths), extruder_plan(extruder_plan), travelConfig(travelConfig), nozzle_size(nozzle_size), speed_equalize_flow_enabled(speed_equalize_flow_enabled), speed_equalize_flow_max(speed_equalize_flow_max) { }
/*!
* Check for lots of small moves and combine them into one large line.
* Updates \p path_idx to the next path which is not combined.
+170 -22
Ver Arquivo
@@ -25,6 +25,10 @@ void* fgets_(char* ptr, size_t len, FILE* f)
*ptr = '\0';
return ptr;
}
else if (*ptr =='\0')
{
return ptr;
}
ptr++;
len--;
}
@@ -45,6 +49,10 @@ MeshGroup::~MeshGroup()
delete extruders[extruder];
}
}
for (Mesh* mesh : meshes)
{
delete mesh;
}
}
int MeshGroup::getExtruderCount() const
@@ -90,10 +98,10 @@ Point3 MeshGroup::min() const
{
return Point3(0, 0, 0);
}
Point3 ret = meshes[0].min();
for(unsigned int i=1; i<meshes.size(); i++)
Point3 ret = meshes[0]->min();
for (unsigned int i = 1; i < meshes.size(); i++)
{
Point3 v = meshes[i].min();
Point3 v = meshes[i]->min();
ret.x = std::min(ret.x, v.x);
ret.y = std::min(ret.y, v.y);
ret.z = std::min(ret.z, v.z);
@@ -107,10 +115,10 @@ Point3 MeshGroup::max() const
{
return Point3(0, 0, 0);
}
Point3 ret = meshes[0].max();
for(unsigned int i=1; i<meshes.size(); i++)
Point3 ret = meshes[0]->max();
for (unsigned int i = 1; i < meshes.size(); i++)
{
Point3 v = meshes[i].max();
Point3 v = meshes[i]->max();
ret.x = std::max(ret.x, v.x);
ret.y = std::max(ret.y, v.y);
ret.z = std::max(ret.z, v.z);
@@ -120,9 +128,9 @@ Point3 MeshGroup::max() const
void MeshGroup::clear()
{
for(Mesh& m : meshes)
for (Mesh* m : meshes)
{
m.clear();
m->clear();
}
}
@@ -140,9 +148,9 @@ void MeshGroup::finalize()
continue;
}
for (const Mesh& mesh : meshes)
for (const Mesh* mesh : meshes)
{
if (mesh.getSettingBoolean("support_enable")
if (mesh->getSettingBoolean("support_enable")
&& (
getSettingAsIndex("support_infill_extruder_nr") == extruder_nr
|| getSettingAsIndex("support_extruder_nr_layer_0") == extruder_nr
@@ -156,13 +164,13 @@ void MeshGroup::finalize()
}
}
for (const Mesh& mesh : meshes)
for (const Mesh* mesh : meshes)
{
if (!mesh.getSettingBoolean("anti_overhang_mesh")
&& !mesh.getSettingBoolean("support_mesh")
if (!mesh->getSettingBoolean("anti_overhang_mesh")
&& !mesh->getSettingBoolean("support_mesh")
)
{
getExtruderTrain(mesh.getSettingAsIndex("extruder_nr"))->setIsUsed(true);
getExtruderTrain(mesh->getSettingAsIndex("extruder_nr"))->setIsUsed(true);
}
}
@@ -175,17 +183,17 @@ void MeshGroup::finalize()
}
// If a mesh position was given, put the mesh at this position in 3D space.
for(Mesh& mesh : meshes)
for (Mesh* mesh : meshes)
{
Point3 mesh_offset(mesh.getSettingInMicrons("mesh_position_x"), mesh.getSettingInMicrons("mesh_position_y"), mesh.getSettingInMicrons("mesh_position_z"));
if (mesh.getSettingBoolean("center_object"))
Point3 mesh_offset(mesh->getSettingInMicrons("mesh_position_x"), mesh->getSettingInMicrons("mesh_position_y"), mesh->getSettingInMicrons("mesh_position_z"));
if (mesh->getSettingBoolean("center_object"))
{
Point3 object_min = mesh.min();
Point3 object_max = mesh.max();
Point3 object_min = mesh->min();
Point3 object_max = mesh->max();
Point3 object_size = object_max - object_min;
mesh_offset += Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z);
}
mesh.offset(mesh_offset + meshgroup_offset);
mesh->offset(mesh_offset + meshgroup_offset);
}
}
@@ -329,6 +337,128 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
return loadMeshSTL_binary(mesh, filename, matrix);
}
void loadMaterialBase(TexturedMesh* mesh, const char* filename)
{
FILE* f = fopen(filename, "rt");
if (f == nullptr)
{
logError("ERROR: Couldn't load MTL file %s.\n", filename);
return;
}
char buffer[1024];
char mat_name [100];
char mat_file [100];
char map_type [10];
Material* last_mat = nullptr;
while(fgets_(buffer, sizeof(buffer), f))
{
if (buffer[0] == '#')
{
continue;
}
if (sscanf(buffer, "map_%s %s", map_type, mat_file) == 2 // we don't care what type of map it specifies (currently)
|| sscanf(buffer, "bump %s", mat_file) == 1
|| sscanf(buffer, "disp %s", mat_file) == 1
|| sscanf(buffer, "decal %s", mat_file) == 1
|| sscanf(buffer, "refl %s", mat_file) == 1
)
{
std::string parent_dir = std::string(filename).substr(0, std::string(filename).find_last_of("/\\"));
std::string mtl_file = parent_dir + "/" + mat_file;
if (last_mat)
{
last_mat->loadImage(mtl_file.c_str());
}
}
else if (sscanf(buffer, "newmtl %s", mat_name) == 1)
{
last_mat = mesh->addMaterial(mat_name);
}
}
fclose(f);
}
bool loadMeshOBJ(TexturedMesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "rt");
if (f == nullptr)
{
return false;
}
char buffer[1024];
FPoint3 vertex;
int vertex_indices[3];
float texture_x;
float texture_y;
float temp;
char face_index_buffer_1 [100];
char face_index_buffer_2 [100];
char face_index_buffer_3 [100];
char str_buffer [100];
while(fgets_(buffer, sizeof(buffer), f))
{
if (buffer[0] == '#')
{
continue;
}
if (sscanf(buffer, "v %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
{
Point3 v = matrix.apply(vertex);
mesh->addVertex(v);
}
else if (sscanf(buffer, "vt %f %f", &texture_x, &texture_y) == 2)
{
mesh->addTextureCoord(texture_x, texture_y);
}
else if (sscanf(buffer, "f %s %s %s", face_index_buffer_1, face_index_buffer_2, face_index_buffer_3) == 3)
{
int normal_vector_index; // unused
int texture_indices[3]; // becomes -1 if no texture data supplied
int n_scanned_1 = sscanf(face_index_buffer_1, "%d/%d/%d", &vertex_indices[0], &texture_indices[0], &normal_vector_index);
int n_scanned_2 = sscanf(face_index_buffer_2, "%d/%d/%d", &vertex_indices[1], &texture_indices[1], &normal_vector_index);
int n_scanned_3 = sscanf(face_index_buffer_3, "%d/%d/%d", &vertex_indices[2], &texture_indices[2], &normal_vector_index);
if (n_scanned_1 >= 2 && n_scanned_2 >= 2 && n_scanned_3 >= 2)
{
mesh->addFace(vertex_indices[0] - 1, vertex_indices[1] - 1, vertex_indices[2] - 1, texture_indices[0] - 1, texture_indices[1] - 1, texture_indices[2] - 1);
// obj files count vertex indices starting from 1!
}
else if (n_scanned_1 >= 1 && n_scanned_2 >= 1 && n_scanned_3 >= 1)
{
mesh->addFace(vertex_indices[0] - 1, vertex_indices[1] - 1, vertex_indices[2] - 1);
}
}
else if (sscanf(buffer, "mtllib %s", str_buffer) == 1)
{
std::string parent_dir = std::string(filename).substr(0, std::string(filename).find_last_of("/\\"));
std::string mtl_file = parent_dir + "/" + str_buffer;
loadMaterialBase(mesh, mtl_file.c_str());
}
else if (sscanf(buffer, "usemtl %s", str_buffer) == 1)
{
mesh->setMaterial(str_buffer);
}
else if (sscanf(buffer, "vn %f %f %f", &temp, &temp, &temp) == 3)
{
// do nothing with vertex normals
}
else if (sscanf(buffer, "g %s", str_buffer) == 1)
{
// do nothing with polygon groups
}
else if (buffer[0] == '\0')
{
// empty line, do nothing
}
else
{
logError("Cannot parse line \"%s\"\n", buffer);
}
}
fclose(f);
mesh->finish();
return true;
}
bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
{
TimeKeeper load_timer;
@@ -336,14 +466,32 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMa
const char* ext = strrchr(filename, '.');
if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
{
Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
Mesh* mesh = new Mesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if (loadMeshSTL(mesh,filename,transformation)) //Load it! If successful...
{
meshgroup->meshes.push_back(mesh);
log("loading '%s' took %.3f seconds\n",filename,load_timer.restart());
return true;
}
else
{
delete mesh;
}
}
else if (ext && (strcmp(ext, ".obj") == 0 || strcmp(ext, ".OBJ") == 0))
{
TexturedMesh* mesh = new TexturedMesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if (loadMeshOBJ(mesh,filename,transformation)) //Load it! If successful...
{
meshgroup->meshes.push_back(mesh);
return true;
}
else
{
delete mesh;
}
}
return false;
}
+2 -1
Ver Arquivo
@@ -4,6 +4,7 @@
#include "utils/NoCopy.h"
#include "mesh.h"
#include "textureProcessing/TexturedMesh.h"
#include "ExtruderTrain.h"
namespace cura
@@ -35,7 +36,7 @@ public:
const ExtruderTrain* getExtruderTrain(unsigned int extruder_nr) const;
std::vector<Mesh> meshes;
std::vector<Mesh*> meshes;
Point3 min() const; //! minimal corner of bounding box
Point3 max() const; //! maximal corner of bounding box
+41
Ver Arquivo
@@ -0,0 +1,41 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef POLYGON_FLOW_ADJUSTER_H
#define POLYGON_FLOW_ADJUSTER_H
#include "utils/intpoint.h"
#include "utils/polygon.h"
namespace cura
{
/*!
* Class for computing and compensating the flow of line segments in a polygon.
*
*/
class PolygonFlowAdjuster
{
public:
/*!
* Compute the flow for a given line segment in the polygons
*
* \warning should only be called once for each line segment in a polygon!
*
* \param from the polygons from which to get the segment of a flow, which should be the same polygons as the ones which the PolygonFlowAdjuster was constructed with
* \param poly_idx Index to the polygon in which to find the line segment
* \param from_point_idx The index to the beginning of the line segment
* \param to_point_idx The index to the ending of the line segment
* \return a value between zero and one representing the reduced flow of the line segment
*/
virtual float getFlow(const Polygons& from, unsigned int poly_idx, unsigned int from_point_idx, unsigned int to_point_idx) = 0;
virtual ~PolygonFlowAdjuster()
{
}
};
}//namespace cura
#endif//POLYGON_FLOW_ADJUSTER_H
+53 -15
Ver Arquivo
@@ -5,7 +5,7 @@
#include "ExtruderTrain.h"
#include "sliceDataStorage.h"
#include "gcodeExport.h"
#include "LayerPlan.h"
#include "gcodePlanner.h"
#include "infill.h"
#include "PrintFeature.h"
@@ -15,7 +15,12 @@ namespace cura
PrimeTower::PrimeTower(const SliceDataStorage& storage)
: is_hollow(false)
, wipe_from_middle(false)
, current_pre_wipe_location_idx(0)
{
for (int extruder_nr = 0; extruder_nr < MAX_EXTRUDERS; extruder_nr++)
{
last_prime_tower_poly_printed[extruder_nr] = -1;
}
enabled = storage.getSettingBoolean("prime_tower_enable")
&& storage.getSettingInMicrons("prime_tower_wall_thickness") > 10
&& storage.getSettingInMicrons("prime_tower_size") > 10;
@@ -25,6 +30,34 @@ PrimeTower::PrimeTower(const SliceDataStorage& storage)
}
}
void PrimeTower::initConfigs(const MeshGroup* meshgroup)
{
extruder_count = meshgroup->getExtruderCount();
for (int extr = 0; extr < extruder_count; extr++)
{
config_per_extruder.emplace_back(PrintFeatureType::Support);// so that visualization in the old Cura still works (TODO)
}
for (int extr = 0; extr < extruder_count; extr++)
{
const ExtruderTrain* train = meshgroup->getExtruderTrain(extr);
config_per_extruder[extr].init(train->getSettingInMillimetersPerSecond("speed_prime_tower"), train->getSettingInMillimetersPerSecond("acceleration_prime_tower"), train->getSettingInMillimetersPerSecond("jerk_prime_tower"), train->getSettingInMicrons("prime_tower_line_width"), train->getSettingInPercentage("prime_tower_flow"));
}
}
void PrimeTower::setConfigs(const MeshGroup* meshgroup, const int layer_thickness)
{
extruder_count = meshgroup->getExtruderCount();
for (int extr = 0; extr < extruder_count; extr++)
{
GCodePathConfig& conf = config_per_extruder[extr];
conf.setLayerHeight(layer_thickness);
}
}
void PrimeTower::generateGroundpoly(const SliceDataStorage& storage)
{
extruder_count = storage.meshgroup->getExtruderCount();
@@ -94,13 +127,18 @@ void PrimeTower::generatePaths_denseInfill(const SliceDataStorage& storage)
}
void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcodeLayer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder) const
void PrimeTower::addToGcode(const SliceDataStorage& storage, GCodePlanner& gcodeLayer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder)
{
if (!enabled)
{
return;
}
if (gcodeLayer.getPrimeTowerIsPlanned())
bool prime_tower_added = false;
for (int extruder = 0; extruder < storage.meshgroup->getExtruderCount() && !prime_tower_added; extruder++)
{
prime_tower_added = last_prime_tower_poly_printed[extruder] == int(layer_nr);
}
if (prime_tower_added)
{ // don't print the prime tower if it has been printed already
return;
}
@@ -121,7 +159,7 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcodeLay
// pre-wipe:
if (pre_wipe)
{
preWipe(storage, gcodeLayer, layer_nr, new_extruder);
preWipe(storage, gcodeLayer, new_extruder);
}
addToGcode_denseInfill(gcodeLayer, layer_nr, new_extruder);
@@ -131,21 +169,21 @@ void PrimeTower::addToGcode(const SliceDataStorage& storage, LayerPlan& gcodeLay
{ //Make sure we wipe the old extruder on the prime tower.
gcodeLayer.addTravel(post_wipe_point - gcode.getExtruderOffset(prev_extruder) + gcode.getExtruderOffset(new_extruder));
}
gcodeLayer.setPrimeTowerIsPlanned();
}
void PrimeTower::addToGcode_denseInfill(LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const
void PrimeTower::addToGcode_denseInfill(GCodePlanner& gcodeLayer, const int layer_nr, const int extruder)
{
const ExtrusionMoves& pattern = patterns_per_extruder[extruder_nr][((layer_nr % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers
ExtrusionMoves& pattern = patterns_per_extruder[extruder][((layer_nr % 2) + 2) % 2]; // +2) %2 to handle negative layer numbers
const GCodePathConfig& config = gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr];
GCodePathConfig& config = config_per_extruder[extruder];
gcode_layer.addPolygonsByOptimizer(pattern.polygons, &config);
gcode_layer.addLinesByOptimizer(pattern.lines, &config, SpaceFillType::Lines);
gcodeLayer.addPolygonsByOptimizer(pattern.polygons, &config);
gcodeLayer.addLinesByOptimizer(pattern.lines, &config, SpaceFillType::Lines);
last_prime_tower_poly_printed[extruder] = layer_nr;
}
Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage) const
Point PrimeTower::getLocationBeforePrimeTower(const SliceDataStorage& storage)
{
Point ret(0, 0);
int absolute_starting_points = 0;
@@ -225,10 +263,10 @@ void PrimeTower::generateWipeLocations(const SliceDataStorage& storage)
PolygonUtils::spreadDots(segment_start, segment_end, number_of_pre_wipe_locations, pre_wipe_locations);
}
void PrimeTower::preWipe(const SliceDataStorage& storage, LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const
void PrimeTower::preWipe(const SliceDataStorage& storage, GCodePlanner& gcode_layer, const int extruder_nr)
{
int current_pre_wipe_location_idx = (pre_wipe_location_skip * layer_nr) % number_of_pre_wipe_locations;
const ClosestPolygonPoint wipe_location = pre_wipe_locations[current_pre_wipe_location_idx];
current_pre_wipe_location_idx = (current_pre_wipe_location_idx + pre_wipe_location_skip) % number_of_pre_wipe_locations;
ExtruderTrain& train = *storage.meshgroup->getExtruderTrain(extruder_nr);
const int inward_dist = train.getSettingInMicrons("machine_nozzle_size") * 3 / 2 ;
@@ -256,7 +294,7 @@ void PrimeTower::preWipe(const SliceDataStorage& storage, LayerPlan& gcode_layer
gcode_layer.addTravel(start);
}
float flow = 0.0001; // force this path being interpreted as an extrusion path, so that no Z hop will occur (TODO: really separately handle travel and extrusion moves)
gcode_layer.addExtrusionMove(end, &gcode_layer.configs_storage.prime_tower_config_per_extruder[extruder_nr], SpaceFillType::None, flow);
gcode_layer.addExtrusionMove(end, &config_per_extruder[extruder_nr], SpaceFillType::None, flow);
}
void PrimeTower::subtractFromSupport(SliceDataStorage& storage)
+28 -6
Ver Arquivo
@@ -16,7 +16,7 @@ namespace cura
class SliceDataStorage;
class LayerPlan;
class GCodePlanner;
class GCodeExport;
/*!
@@ -34,6 +34,7 @@ private:
Polygons lines;
};
int extruder_count; //!< number of extruders
std::vector<GCodePathConfig> config_per_extruder; //!< Path config for prime tower for each extruder
bool is_hollow; //!< Whether the prime tower is hollow
@@ -46,6 +47,7 @@ private:
const unsigned int pre_wipe_location_skip = 13; //!< How big the steps are when stepping through \ref PrimeTower::wipe_locations
const unsigned int number_of_pre_wipe_locations = 21; //!< The required size of \ref PrimeTower::wipe_locations
// note that the above are two consecutive numbers in the Fibonacci sequence
int current_pre_wipe_location_idx; //!< Index into \ref PrimeTower::wipe_locations of where to pre-wipe the nozzle
public:
bool enabled; //!< Whether the prime tower is enabled.
@@ -61,6 +63,21 @@ public:
*/
PrimeTower(const SliceDataStorage& storage);
/*!
* Initialize \ref PrimeTower::config_per_extruder with speed and line width settings.
*
* \param meshgroup Where to retrieve the setttings for each extruder
*/
void initConfigs(const MeshGroup* meshgroup);
/*!
* Complete the \ref PrimeTower::config_per_extruder by settings the layer height.
*
* \param meshgroup Where to retrieve the setttings for each extruder
* \param layer_thickness The current layer thickness
*/
void setConfigs(const MeshGroup* meshgroup, const int layer_thickness);
/*!
* Generate the prime tower area to be used on each layer
*
@@ -87,7 +104,7 @@ public:
* \param prev_extruder The previous extruder with which paths were planned; from which extruder a switch was made
* \param new_extruder The switched to extruder with which the prime tower paths should be generated.
*/
void addToGcode(const SliceDataStorage& storage, LayerPlan& gcode_layer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder) const;
void addToGcode(const SliceDataStorage& storage, GCodePlanner& gcode_layer, const GCodeExport& gcode, const int layer_nr, const int prev_extruder, const int new_extruder);
/*!
* \brief Subtract the prime tower from the support areas in storage.
@@ -98,6 +115,12 @@ public:
void subtractFromSupport(SliceDataStorage& storage);
private:
/*!
* Layer number of the last layer in which a prime tower has been printed per extruder train.
*
* This is recorded per extruder to account for a prime tower per extruder, instead of the mixed prime tower.
*/
int last_prime_tower_poly_printed[MAX_EXTRUDERS];
/*!
* Find an approriate representation for the point representing the location before going to the prime tower
@@ -107,7 +130,7 @@ private:
* \param storage where to get settings from
* \return that location
*/
Point getLocationBeforePrimeTower(const SliceDataStorage& storage) const;
Point getLocationBeforePrimeTower(const SliceDataStorage& storage);
/*!
* \param storage where to get settings from
@@ -136,17 +159,16 @@ private:
* \param extruder The extruder we just switched to, with which the prime
* tower paths should be drawn.
*/
void addToGcode_denseInfill(LayerPlan& gcode_layer, const int layer_nr, const int extruder) const;
void addToGcode_denseInfill(GCodePlanner& gcode_layer, const int layer_nr, const int extruder);
/*!
* Plan the moves for wiping the current nozzles oozed material before starting to print the prime tower.
*
* \param storage where to get settings from
* \param[out] gcode_layer where to add the planned paths for wiping
* \param layer_nr The layer number of the \p gcode_layer
* \param extruder_nr The current extruder
*/
void preWipe(const SliceDataStorage& storage, LayerPlan& gcode_layer, const int layer_nr, const int extruder_nr) const;
void preWipe(const SliceDataStorage& storage, GCodePlanner& gcode_layer, const int extruder_nr);
};
-4
Ver Arquivo
@@ -58,10 +58,6 @@ void SkirtBrim::getFirstLayerOutline(SliceDataStorage& storage, const unsigned i
constexpr int smallest_line_length = 200;
constexpr int largest_error_of_removed_point = 50;
first_layer_outline.simplify(smallest_line_length, largest_error_of_removed_point); // simplify for faster processing of the brim lines
if (first_layer_outline.size() == 0)
{
logError("Couldn't generate skirt / brim! No polygons on first layer.");
}
}
int SkirtBrim::generatePrimarySkirtBrimLines(SliceDataStorage& storage, int start_distance, unsigned int primary_line_count, const int primary_extruder_skirt_brim_line_width, const int64_t primary_extruder_minimal_length, const Polygons& first_layer_outline, Polygons& skirt_brim_primary_extruder)
-12
Ver Arquivo
@@ -12,12 +12,6 @@ WallsComputation::WallsComputation(int wall_0_inset, int line_width_0, int line_
{
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateInsets only reads and writes data for the current layer
*/
void WallsComputation::generateInsets(SliceLayerPart* part)
{
if (insetCount == 0)
@@ -64,12 +58,6 @@ void WallsComputation::generateInsets(SliceLayerPart* part)
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateInsets only reads and writes data for the current layer
*/
void WallsComputation::generateInsets(SliceLayer* layer)
{
for(unsigned int partNr = 0; partNr < layer->parts.size(); partNr++)
+4 -4
Ver Arquivo
@@ -23,9 +23,9 @@ void Weaver::weave(MeshGroup* meshgroup)
std::vector<cura::Slicer*> slicerList;
for(Mesh& mesh : meshgroup->meshes)
for (Mesh* mesh : meshgroup->meshes)
{
cura::Slicer* slicer = new cura::Slicer(&mesh, initial_layer_thickness, connectionHeight, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
cura::Slicer* slicer = new cura::Slicer(mesh, initial_layer_thickness, connectionHeight, layer_count, mesh->getSettingBoolean("meshfix_keep_open_polygons"), mesh->getSettingBoolean("meshfix_extensive_stitching"), nullptr);
slicerList.push_back(slicer);
}
@@ -389,7 +389,7 @@ void Weaver::chainify_polygons(Polygons& parts1, Point start_close_to, Polygons&
{
for (unsigned int prt = 0 ; prt < parts1.size(); prt++)
{
ConstPolygonRef upperPart = parts1[prt];
const PolygonRef upperPart = parts1[prt];
ClosestPolygonPoint closestInPoly = PolygonUtils::findClosest(start_close_to, upperPart);
@@ -439,7 +439,7 @@ void Weaver::connect_polygons(Polygons& supporting, int z0, Polygons& supported,
for (unsigned int prt = 0 ; prt < supported.size(); prt++)
{
ConstPolygonRef upperPart(supported[prt]);
const PolygonRef upperPart = supported[prt];
parts.emplace_back(prt);
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@
#include "settings/settings.h"
#include "MeshGroup.h"
#include "slicer.h"
#include "slicer/Slicer.h"
#include "utils/NoCopy.h"
#include "utils/polygon.h"
+1 -1
Ver Arquivo
@@ -247,7 +247,7 @@ void Wireframe2gcode::strategy_retract(WeaveLayer& layer, WeaveConnectionPart& p
retraction_config.retraction_min_travel_distance = getSettingInMicrons("retraction_min_travel");
double top_retract_pause = 2.0;
int retract_hop_dist = 1000;
coord_t retract_hop_dist = 1000;
bool after_retract_hop = false;
//bool go_horizontal_first = true;
bool lower_retract_start = true;
+17 -17
Ver Arquivo
@@ -11,7 +11,7 @@
#include "settings/settings.h"
#include "MeshGroup.h"
#include "slicer.h"
#include "slicer/Slicer.h"
#include "utils/polygon.h"
#include "Weaver.h"
@@ -29,37 +29,37 @@ private:
static const int STRATEGY_KNOT = 1;
static const int STRATEGY_RETRACT = 2;
int initial_layer_thickness;
int filament_diameter;
int line_width;
coord_t initial_layer_thickness;
coord_t filament_diameter;
coord_t line_width;
double flowConnection;
double flowFlat;
double extrusion_mm3_per_mm_connection;
double extrusion_mm3_per_mm_flat;
int nozzle_outer_diameter;
int nozzle_head_distance;
coord_t nozzle_outer_diameter;
coord_t nozzle_head_distance;
double nozzle_expansion_angle;
int nozzle_clearance;
int nozzle_top_diameter;
coord_t nozzle_clearance;
coord_t nozzle_top_diameter;
double moveSpeed;
double speedBottom;
double speedUp;
double speedDown;
double speedFlat;
int connectionHeight;
int roof_inset;
coord_t connectionHeight;
coord_t roof_inset;
double flat_delay;
double bottom_delay;
double top_delay;
int up_dist_half_speed;
int top_jump_dist;
int fall_down;
int drag_along;
coord_t up_dist_half_speed;
coord_t top_jump_dist;
coord_t fall_down;
coord_t drag_along;
int strategy;
double go_back_to_last_top;
int straight_first_when_going_down;
int roof_fall_down;
int roof_drag_along;
coord_t straight_first_when_going_down;
coord_t roof_fall_down;
coord_t roof_drag_along;
double roof_outer_delay;
RetractionConfig standard_retraction_config; //!< The standard retraction settings used for moves between parts etc.
+1 -1
Ver Arquivo
@@ -5,7 +5,7 @@
namespace cura {
int bridgeAngle(Polygons outline, const SliceLayer* prevLayer)
int bridgeAngle(Polygons outline, SliceLayer* prevLayer)
{
AABB boundaryBox(outline);
//To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer.
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@ namespace cura {
class Polygons;
class SliceLayer;
int bridgeAngle(Polygons outline, const SliceLayer* prevLayer);
int bridgeAngle(Polygons outline, SliceLayer* prevLayer);
}//namespace cura
+7 -9
Ver Arquivo
@@ -215,7 +215,7 @@ public:
/*!
* Adds closed polygon to the current path
*/
void sendPolygon(PrintFeatureType print_feature_type, ConstPolygonRef poly, int width);
void sendPolygon(PrintFeatureType print_feature_type, Polygon poly, int width);
private:
/*!
* Convert and add a point to the points buffer, each point being represented as two consecutive floats. All members adding a 2D point to the data should use this function.
@@ -346,9 +346,9 @@ void CommandSocket::connect(const std::string& ip, int port)
continue;
}
const ExtruderTrain* settings_base = meshgroup->getExtruderTrain(extruder_nr); //The extruder train that the setting should fall back to.
for (Mesh& mesh : meshgroup->meshes)
for (Mesh* mesh : meshgroup->meshes)
{
mesh.setSettingInheritBase(setting_extruder.name(), *settings_base);
mesh->setSettingInheritBase(setting_extruder.name(), *settings_base);
}
}
}
@@ -455,8 +455,8 @@ void CommandSocket::handleObjectList(cura::proto::ObjectList* list, const google
}
SettingsBase* extruder_train = meshgroup->getExtruderTrain(extruder_train_nr);
meshgroup->meshes.push_back(extruder_train); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
Mesh& mesh = meshgroup->meshes.back();
meshgroup->meshes.push_back(new Mesh(extruder_train)); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
Mesh& mesh = *meshgroup->meshes.back();
for (int i = 0; i < face_count; ++i)
{
@@ -522,7 +522,7 @@ void CommandSocket::sendPolygons(PrintFeatureType type, const Polygons& polygons
#endif
}
void CommandSocket::sendPolygon(PrintFeatureType type, ConstPolygonRef polygon, int line_width)
void CommandSocket::sendPolygon(PrintFeatureType type, Polygon& polygon, int line_width)
{
#ifdef ARCUS
if (CommandSocket::isInstantiated())
@@ -642,7 +642,6 @@ void CommandSocket::sendLayerData()
{
for (std::pair<const int, std::shared_ptr<cura::proto::Layer>> entry : data.slice_data) //Note: This is in no particular order!
{
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
private_data->socket->sendMessage(entry.second); //Send the actual layers.
}
data.sliced_objects = 0;
@@ -668,7 +667,6 @@ void CommandSocket::sendOptimizedLayerData()
{
for (std::pair<const int, std::shared_ptr<cura::proto::LayerOptimized>> entry : data.slice_data) //Note: This is in no particular order!
{
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
private_data->socket->sendMessage(entry.second); //Send the actual layers.
}
data.sliced_objects = 0;
@@ -799,7 +797,7 @@ void CommandSocket::PathCompiler::sendLineTo(PrintFeatureType print_feature_type
}
}
void CommandSocket::PathCompiler::sendPolygon(PrintFeatureType print_feature_type, ConstPolygonRef polygon, int width)
void CommandSocket::PathCompiler::sendPolygon(PrintFeatureType print_feature_type, Polygon polygon, int width)
{
if (polygon.size() < 2)
{
+1 -1
Ver Arquivo
@@ -64,7 +64,7 @@ public:
/*!
* Send a polygon to the front-end. This is used for the layerview in the GUI
*/
static void sendPolygon(cura::PrintFeatureType type, ConstPolygonRef polygon, int line_width);
static void sendPolygon(cura::PrintFeatureType type, Polygon& polygon, int line_width);
/*!
* Send a line to the front-end. This is used for the layerview in the GUI
+14 -13
Ver Arquivo
@@ -51,13 +51,13 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
extruder_count = meshgroup->getSettingAsCount("machine_extruder_count");
for (const Mesh& mesh : meshgroup->meshes)
for (const Mesh* mesh : meshgroup->meshes)
{
if (!mesh.getSettingBoolean("anti_overhang_mesh")
&& !mesh.getSettingBoolean("support_mesh")
if (!mesh->getSettingBoolean("anti_overhang_mesh")
&& !mesh->getSettingBoolean("support_mesh")
)
{
extruder_attr[mesh.getSettingAsIndex("extruder_nr")].is_used = true;
extruder_attr[mesh->getSettingAsIndex("extruder_nr")].is_used = true;
}
}
@@ -69,11 +69,11 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
{
extruder_attr[extruder_nr].is_used = true;
}
for (const Mesh& mesh : meshgroup->meshes)
for (const Mesh* mesh : meshgroup->meshes)
{
if ((mesh.getSettingBoolean("support_enable") && mesh.getSettingBoolean("support_interface_enable") && meshgroup->getSettingAsIndex("support_interface_extruder_nr") == int(extruder_nr))
|| (mesh.getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_infill_extruder_nr") == int(extruder_nr))
|| (mesh.getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_extruder_nr_layer_0") == int(extruder_nr))
if ((mesh->getSettingBoolean("support_enable") && mesh->getSettingBoolean("support_interface_enable") && meshgroup->getSettingAsIndex("support_interface_extruder_nr") == int(extruder_nr))
|| (mesh->getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_infill_extruder_nr") == int(extruder_nr))
|| (mesh->getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_extruder_nr_layer_0") == int(extruder_nr))
)
{
extruder_attr[extruder_nr].is_used = true;
@@ -270,7 +270,7 @@ void GCodeExport::setFlavor(EGCodeFlavor flavor)
}
}
EGCodeFlavor GCodeExport::getFlavor() const
EGCodeFlavor GCodeExport::getFlavor()
{
return this->flavor;
}
@@ -556,6 +556,8 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
assert((Point3(x,y,z) - currentPosition).vSize() < MM2INT(300)); // no crazy positions (this code should not be compiled for release)
#endif //ASSERT_INSANE_OUTPUT
total_bounding_box.include(Point3(x, y, z));
if (extrusion_mm3_per_mm < 0)
logWarning("Warning! Negative extrusion move!");
@@ -568,7 +570,6 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
double extrusion_per_mm = mm3ToE(extrusion_mm3_per_mm);
Point gcode_pos = getGcodePos(x,y, current_extruder);
total_bounding_box.include(Point3(gcode_pos.X, gcode_pos.Y, z));
if (extrusion_mm3_per_mm > 0.000001)
{
@@ -728,7 +729,7 @@ void GCodeExport::writeZhopStart(int hop_height)
{
isZHopped = hop_height;
*output_stream << "G1 Z" << MMtoStream{currentPosition.z + isZHopped} << new_line;
total_bounding_box.includeZ(currentPosition.z + isZHopped);
total_bounding_box.include(currentPosition + Point3(0, 0, isZHopped));
}
}
@@ -775,7 +776,7 @@ void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retra
bool force = true;
bool extruder_switch = true;
writeRetraction(retraction_config_old_extruder, force, extruder_switch);
writeRetraction(const_cast<RetractionConfig&>(retraction_config_old_extruder), force, extruder_switch);
resetExtrusionValue(); // zero the E value on the old extruder, so that the current_e_value is registered on the old extruder
@@ -922,7 +923,7 @@ void GCodeExport::finalize(const char* endCode)
{
writeFanCommand(0);
writeCode(endCode);
int64_t print_time = getTotalPrintTime();
long print_time = getTotalPrintTime();
int mat_0 = getTotalFilamentUsed(0);
log("Print time: %d\n", print_time);
log("Print time (readable): %dh %dm %ds\n", print_time / 60 / 60, (print_time / 60) % 60, print_time % 60);
+1 -1
Ver Arquivo
@@ -188,7 +188,7 @@ public:
Point getGcodePos(const int64_t x, const int64_t y, const int extruder_train) const;
void setFlavor(EGCodeFlavor flavor);
EGCodeFlavor getFlavor() const;
EGCodeFlavor getFlavor();
void setZ(int z);
+160 -57
Ver Arquivo
@@ -1,6 +1,6 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#include <cstring>
#include "LayerPlan.h"
#include "gcodePlanner.h"
#include "pathOrderOptimizer.h"
#include "sliceDataStorage.h"
#include "utils/polygonUtils.h"
@@ -10,7 +10,7 @@
namespace cura {
ExtruderPlan::ExtruderPlan(int extruder, Point start_position, int layer_nr, bool is_initial_layer, int layer_thickness, const FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, const RetractionConfig& retraction_config)
ExtruderPlan::ExtruderPlan(int extruder, Point start_position, int layer_nr, bool is_initial_layer, int layer_thickness, FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, const RetractionConfig& retraction_config)
: extruder(extruder)
, heated_pre_travel_time(0)
, initial_printing_temperature(-1)
@@ -56,7 +56,7 @@ double ExtruderPlan::getFanSpeed()
}
GCodePath* LayerPlan::getLatestPathWithConfig(const GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
GCodePath* GCodePlanner::getLatestPathWithConfig(GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
{
std::vector<GCodePath>& paths = extruder_plans.back().paths;
if (paths.size() > 0 && paths.back().config == config && !paths.back().done && paths.back().flow == flow) // spiralize can only change when a travel path is in between
@@ -74,33 +74,30 @@ GCodePath* LayerPlan::getLatestPathWithConfig(const GCodePathConfig* config, Spa
return ret;
}
void LayerPlan::forceNewPathStart()
void GCodePlanner::forceNewPathStart()
{
std::vector<GCodePath>& paths = extruder_plans.back().paths;
if (paths.size() > 0)
paths[paths.size()-1].done = true;
}
LayerPlan::LayerPlan(const SliceDataStorage& storage, int layer_nr, int z, int layer_thickness, PlanningState last_planned_state, const std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder, CombingMode combing_mode, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance)
GCodePlanner::GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int layer_thickness, Point last_position, int current_extruder, bool is_inside_mesh, std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder, CombingMode combing_mode, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance)
: storage(storage)
, configs_storage(storage, layer_nr, layer_thickness)
, layer_nr(layer_nr)
, is_initial_layer(layer_nr == 0 - Raft::getTotalExtraLayers(storage))
, z(z)
, layer_thickness(layer_thickness)
, start_position(last_planned_state.last_position)
, lastPosition(last_planned_state.last_position)
, has_prime_tower_planned(false)
, last_extruder_previous_layer(last_planned_state.current_extruder)
, last_planned_extruder_setting_base(storage.meshgroup->getExtruderTrain(last_planned_state.current_extruder))
, start_position(last_position)
, lastPosition(last_position)
, last_extruder_previous_layer(current_extruder)
, last_planned_extruder_setting_base(storage.meshgroup->getExtruderTrain(current_extruder))
, comb_boundary_inside(computeCombBoundaryInside(combing_mode))
, fan_speed_layer_time_settings_per_extruder(fan_speed_layer_time_settings_per_extruder)
{
int current_extruder = last_planned_state.current_extruder;
extruder_plans.reserve(storage.meshgroup->getExtruderCount());
extruder_plans.emplace_back(current_extruder, start_position, layer_nr, is_initial_layer, layer_thickness, fan_speed_layer_time_settings_per_extruder[current_extruder], storage.retraction_config_per_extruder[current_extruder]);
comb = nullptr;
was_inside = last_planned_state.is_inside_mesh_layer_part;
was_inside = is_inside_mesh;
is_inside = false; // assumes the next move will not be to inside a layer part (overwritten just before going into a layer part)
if (combing_mode != CombingMode::OFF)
{
@@ -110,19 +107,19 @@ LayerPlan::LayerPlan(const SliceDataStorage& storage, int layer_nr, int z, int l
comb = nullptr;
}
LayerPlan::~LayerPlan()
GCodePlanner::~GCodePlanner()
{
if (comb)
delete comb;
}
SettingsBaseVirtual* LayerPlan::getLastPlannedExtruderTrainSettings()
SettingsBaseVirtual* GCodePlanner::getLastPlannedExtruderTrainSettings()
{
return last_planned_extruder_setting_base;
}
Polygons LayerPlan::computeCombBoundaryInside(CombingMode combing_mode)
Polygons GCodePlanner::computeCombBoundaryInside(CombingMode combing_mode)
{
if (combing_mode == CombingMode::OFF)
{
@@ -142,12 +139,12 @@ Polygons LayerPlan::computeCombBoundaryInside(CombingMode combing_mode)
else
{
Polygons comb_boundary;
for (const SliceMeshStorage& mesh : storage.meshes)
for (SliceMeshStorage& mesh : storage.meshes)
{
const SliceLayer& layer = mesh.layers[layer_nr];
SliceLayer& layer = mesh.layers[layer_nr];
if (mesh.getSettingAsCombingMode("retraction_combing") == CombingMode::NO_SKIN)
{
for (const SliceLayerPart& part : layer.parts)
for (SliceLayerPart& part : layer.parts)
{
comb_boundary.add(part.infill_area);
}
@@ -165,12 +162,12 @@ Polygons LayerPlan::computeCombBoundaryInside(CombingMode combing_mode)
}
}
void LayerPlan::setIsInside(bool _is_inside)
void GCodePlanner::setIsInside(bool _is_inside)
{
is_inside = _is_inside;
}
bool LayerPlan::setExtruder(int extruder)
bool GCodePlanner::setExtruder(int extruder)
{
if (extruder == getExtruder())
{
@@ -223,7 +220,7 @@ bool LayerPlan::setExtruder(int extruder)
return true;
}
void LayerPlan::moveInsideCombBoundary(int distance)
void GCodePlanner::moveInsideCombBoundary(int distance)
{
int max_dist2 = MM2INT(2.0) * MM2INT(2.0); // if we are further than this distance, we conclude we are not inside even though we thought we were.
// this function is to be used to move from the boudary of a part to inside the part
@@ -241,15 +238,15 @@ void LayerPlan::moveInsideCombBoundary(int distance)
}
}
GCodePath& LayerPlan::addTravel(Point p)
GCodePath& GCodePlanner::addTravel(Point p)
{
GCodePath* path = nullptr;
const GCodePathConfig& travel_config = configs_storage.travel_config_per_extruder[getExtruder()];
const RetractionConfig& retraction_config = storage.retraction_config_per_extruder[getExtruder()];
GCodePathConfig& travel_config = storage.travel_config_per_extruder[getExtruder()];
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[getExtruder()];
bool combed = false;
const SettingsBaseVirtual* extr = getLastPlannedExtruderTrainSettings();
SettingsBaseVirtual* extr = getLastPlannedExtruderTrainSettings();
const bool perform_z_hops = extr->getSettingBoolean("retraction_hop_enabled");
@@ -332,18 +329,18 @@ GCodePath& LayerPlan::addTravel(Point p)
return ret;
}
GCodePath& LayerPlan::addTravel_simple(Point p, GCodePath* path)
GCodePath& GCodePlanner::addTravel_simple(Point p, GCodePath* path)
{
if (path == nullptr)
{
path = getLatestPathWithConfig(&configs_storage.travel_config_per_extruder[getExtruder()], SpaceFillType::None);
path = getLatestPathWithConfig(&storage.travel_config_per_extruder[getExtruder()], SpaceFillType::None);
}
path->points.push_back(p);
lastPosition = p;
return *path;
}
void LayerPlan::planPrime()
void GCodePlanner::planPrime()
{
forceNewPathStart();
GCodePath& prime_travel = addTravel_simple(lastPosition + Point(0, 100));
@@ -352,27 +349,31 @@ void LayerPlan::planPrime()
forceNewPathStart();
}
void LayerPlan::addExtrusionMove(Point p, const GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillType space_fill_type, float flow, bool spiralize)
{
getLatestPathWithConfig(config, space_fill_type, flow, spiralize)->points.push_back(p);
lastPosition = p;
}
void LayerPlan::addPolygon(ConstPolygonRef polygon, int start_idx, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, coord_t wall_0_wipe_dist, bool spiralize)
void GCodePlanner::addPolygon(Polygons& polygons, unsigned int poly_idx, int start_idx, GCodePathConfig* config, PolygonFlowAdjuster* wall_overlap_computation, coord_t wall_0_wipe_dist, bool spiralize)
{
Point p0 = polygon[start_idx];
PolygonRef polygon = polygons[poly_idx];
unsigned int p0_idx = start_idx;
Point p0 = polygon[p0_idx];
addTravel(p0);
for (unsigned int point_idx = 1; point_idx < polygon.size(); point_idx++)
{
Point p1 = polygon[(start_idx + point_idx) % polygon.size()];
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(p0, p1) : 1.0;
unsigned int p1_idx = (start_idx + point_idx) % polygon.size();
Point p1 = polygon[p1_idx];
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(polygons, poly_idx, p0_idx, p1_idx) : 1.0;
addExtrusionMove(p1, config, SpaceFillType::Polygons, flow, spiralize);
p0 = p1;
p0_idx = p1_idx;
}
if (polygon.size() > 2)
{
const Point& p1 = polygon[start_idx];
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(p0, p1) : 1.0;
Point& p1 = polygon[start_idx];
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(polygons, poly_idx, p0_idx, start_idx) : 1.0;
addExtrusionMove(p1, config, SpaceFillType::Polygons, flow, spiralize);
if (wall_0_wipe_dist > 0)
@@ -402,11 +403,11 @@ void LayerPlan::addPolygon(ConstPolygonRef polygon, int start_idx, const GCodePa
}
else
{
logWarning("WARNING: line added as polygon! (LayerPlan)\n");
logWarning("WARNING: line added as polygon! (gcodePlanner)\n");
}
}
void LayerPlan::addPolygonsByOptimizer(const Polygons& polygons, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation, EZSeamType z_seam_type, Point z_seam_pos, coord_t wall_0_wipe_dist, bool spiralize)
void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config, PolygonFlowAdjuster* flow_adjuster, EZSeamType z_seam_type, Point z_seam_pos, coord_t wall_0_wipe_dist, bool spiralize)
{
if (polygons.size() == 0)
{
@@ -420,10 +421,10 @@ void LayerPlan::addPolygonsByOptimizer(const Polygons& polygons, const GCodePath
orderOptimizer.optimize();
for (unsigned int poly_idx : orderOptimizer.polyOrder)
{
addPolygon(polygons[poly_idx], orderOptimizer.polyStart[poly_idx], config, wall_overlap_computation, wall_0_wipe_dist, spiralize);
addPolygon(polygons, poly_idx, orderOptimizer.polyStart[poly_idx], config, flow_adjuster, wall_0_wipe_dist, spiralize);
}
}
void LayerPlan::addLinesByOptimizer(const Polygons& polygons, const GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist)
void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist)
{
LineOrderOptimizer orderOptimizer(lastPosition);
for (unsigned int line_idx = 0; line_idx < polygons.size(); line_idx++)
@@ -433,12 +434,12 @@ void LayerPlan::addLinesByOptimizer(const Polygons& polygons, const GCodePathCon
orderOptimizer.optimize();
for (int poly_idx : orderOptimizer.polyOrder)
{
ConstPolygonRef polygon = polygons[poly_idx];
PolygonRef polygon = polygons[poly_idx];
int start = orderOptimizer.polyStart[poly_idx];
int end = 1 - start;
const Point& p0 = polygon[start];
Point& p0 = polygon[start];
addTravel(p0);
const Point& p1 = polygon[end];
Point& p1 = polygon[end];
addExtrusionMove(p1, config, space_fill_type);
if (wipe_dist != 0)
{
@@ -556,7 +557,7 @@ TimeMaterialEstimates ExtruderPlan::computeNaiveTimeEstimates()
void ExtruderPlan::processFanSpeedAndMinimalLayerTime(bool force_minimal_layer_time)
{
const FanSpeedLayerTimeSettings& fsml = fan_speed_layer_time_settings;
FanSpeedLayerTimeSettings& fsml = fan_speed_layer_time_settings;
TimeMaterialEstimates estimates = computeNaiveTimeEstimates();
totalPrintTime = estimates.getTotalTime();
if (force_minimal_layer_time)
@@ -615,7 +616,7 @@ void ExtruderPlan::processFanSpeedAndMinimalLayerTime(bool force_minimal_layer_t
}
}
TimeMaterialEstimates LayerPlan::computeNaiveTimeEstimates()
TimeMaterialEstimates GCodePlanner::computeNaiveTimeEstimates()
{
TimeMaterialEstimates ret;
for (ExtruderPlan& extruder_plan : extruder_plans)
@@ -625,7 +626,7 @@ TimeMaterialEstimates LayerPlan::computeNaiveTimeEstimates()
return ret;
}
void LayerPlan::processFanSpeedAndMinimalLayerTime()
void GCodePlanner::processFanSpeedAndMinimalLayerTime()
{
for (unsigned int extr_plan_idx = 0; extr_plan_idx < extruder_plans.size(); extr_plan_idx++)
{
@@ -637,8 +638,10 @@ void LayerPlan::processFanSpeedAndMinimalLayerTime()
void LayerPlan::writeGCode(GCodeExport& gcode)
void GCodePlanner::writeGCode(GCodeExport& gcode)
{
completeConfigs();
CommandSocket::setLayerForSend(layer_nr);
CommandSocket::setSendCurrentPosition( gcode.getPositionXY() );
gcode.setLayerNr(layer_nr);
@@ -654,7 +657,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
gcode.setZ(z);
const GCodePathConfig* last_extrusion_config = nullptr; // used to check whether we need to insert a TYPE comment in the gcode.
GCodePathConfig* last_extrusion_config = nullptr; // used to check whether we need to insert a TYPE comment in the gcode.
int extruder = gcode.getExtruderNr();
bool acceleration_enabled = storage.getSettingBoolean("acceleration_enabled");
@@ -663,7 +666,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
for(unsigned int extruder_plan_idx = 0; extruder_plan_idx < extruder_plans.size(); extruder_plan_idx++)
{
ExtruderPlan& extruder_plan = extruder_plans[extruder_plan_idx];
const RetractionConfig& retraction_config = storage.retraction_config_per_extruder[extruder_plan.extruder];
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[extruder_plan.extruder];
if (extruder != extruder_plan.extruder)
{
@@ -765,7 +768,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
else
speed *= extruder_plan.getExtrudeSpeedFactor();
if (MergeInfillLines(gcode, layer_nr, paths, extruder_plan, configs_storage.travel_config_per_extruder[extruder], nozzle_size, speed_equalize_flow_enabled, speed_equalize_flow_max).mergeInfillLines(path_idx)) // !! has effect on path_idx !!
if (MergeInfillLines(gcode, layer_nr, paths, extruder_plan, storage.travel_config_per_extruder[extruder], nozzle_size, speed_equalize_flow_enabled, speed_equalize_flow_max).mergeInfillLines(path_idx)) // !! has effect on path_idx !!
{ // !! has effect on path_idx !!
// works when path_idx is the index of the travel move BEFORE the infill lines to be merged
continue;
@@ -788,7 +791,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
bool spiralize = path.spiralize;
if (!spiralize) // normal (extrusion) move (with coasting
{
const CoastingConfig& coasting_config = storage.coasting_config[extruder];
CoastingConfig& coasting_config = storage.coasting_config[extruder];
bool coasting = coasting_config.coasting_enable;
if (coasting)
{
@@ -859,15 +862,15 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
if (train->getSettingBoolean("cool_lift_head") && extruder_plan.extraTime > 0.0)
{
gcode.writeComment("Small layer, adding delay");
const RetractionConfig& retraction_config = storage.retraction_config_per_extruder[gcode.getExtruderNr()];
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[gcode.getExtruderNr()];
gcode.writeRetraction(retraction_config);
if (extruder_plan_idx == extruder_plans.size() - 1 || !train->getSettingBoolean("machine_extruder_end_pos_abs"))
{ // only move the head if it's the last extruder plan; otherwise it's already at the switching bay area
// or do it anyway when we switch extruder in-place
gcode.setZ(gcode.getPositionZ() + MM2INT(3.0));
gcode.writeMove(gcode.getPositionXY(), configs_storage.travel_config_per_extruder[extruder].getSpeed(), 0);
gcode.writeMove(gcode.getPositionXY(), storage.travel_config_per_extruder[extruder].getSpeed(), 0);
// TODO: is this safe?! wouldn't the head move into the sides then?!
gcode.writeMove(gcode.getPositionXY() - Point(-MM2INT(20.0), 0), configs_storage.travel_config_per_extruder[extruder].getSpeed(), 0);
gcode.writeMove(gcode.getPositionXY() - Point(-MM2INT(20.0), 0), storage.travel_config_per_extruder[extruder].getSpeed(), 0);
}
gcode.writeDelay(extruder_plan.extraTime);
}
@@ -878,7 +881,7 @@ void LayerPlan::writeGCode(GCodeExport& gcode)
gcode.updateTotalPrintTime();
}
void LayerPlan::overrideFanSpeeds(double speed)
void GCodePlanner::overrideFanSpeeds(double speed)
{
for (ExtruderPlan& extruder_plan : extruder_plans)
{
@@ -887,7 +890,107 @@ void LayerPlan::overrideFanSpeeds(double speed)
}
bool LayerPlan::makeRetractSwitchRetract(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx)
void GCodePlanner::completeConfigs()
{
storage.support_config.setLayerHeight(layer_thickness);
storage.support_skin_config.setLayerHeight(layer_thickness);
for (SliceMeshStorage& mesh : storage.meshes)
{
mesh.inset0_config.setLayerHeight(layer_thickness);
mesh.insetX_config.setLayerHeight(layer_thickness);
mesh.skin_config.setLayerHeight(layer_thickness);
for(unsigned int idx=0; idx<MAX_INFILL_COMBINE; idx++)
{
mesh.infill_config[idx].setLayerHeight(layer_thickness);
}
}
storage.primeTower.setConfigs(storage.meshgroup, layer_thickness);
processInitialLayersSpeedup();
}
void GCodePlanner::processInitialLayersSpeedup()
{
int initial_speedup_layers = storage.getSettingAsCount("speed_slowdown_layers");
if (layer_nr >= 0 && layer_nr < initial_speedup_layers)
{
GCodePathConfig::BasicConfig initial_layer_speed_config;
int extruder_nr_support_infill = storage.getSettingAsIndex((layer_nr == 0)? "support_extruder_nr_layer_0" : "support_infill_extruder_nr");
initial_layer_speed_config.speed = storage.meshgroup->getExtruderTrain(extruder_nr_support_infill)->getSettingInMillimetersPerSecond("speed_print_layer_0");
initial_layer_speed_config.acceleration = storage.meshgroup->getExtruderTrain(extruder_nr_support_infill)->getSettingInMillimetersPerSecond("acceleration_print_layer_0");
initial_layer_speed_config.jerk = storage.meshgroup->getExtruderTrain(extruder_nr_support_infill)->getSettingInMillimetersPerSecond("jerk_print_layer_0");
//Support (global).
storage.support_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
//Support roof (global).
int extruder_nr_support_skin = storage.getSettingAsIndex("support_interface_extruder_nr");
initial_layer_speed_config.speed = storage.meshgroup->getExtruderTrain(extruder_nr_support_skin)->getSettingInMillimetersPerSecond("speed_print_layer_0");
initial_layer_speed_config.acceleration = storage.meshgroup->getExtruderTrain(extruder_nr_support_skin)->getSettingInMillimetersPerSecond("acceleration_print_layer_0");
initial_layer_speed_config.jerk = storage.meshgroup->getExtruderTrain(extruder_nr_support_skin)->getSettingInMillimetersPerSecond("jerk_print_layer_0");
storage.support_skin_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); ++extruder_nr)
{
const ExtruderTrain* extruder_train = storage.meshgroup->getExtruderTrain(extruder_nr);
initial_layer_speed_config.speed = extruder_train->getSettingInMillimetersPerSecond("speed_travel_layer_0");
initial_layer_speed_config.acceleration = extruder_train->getSettingInMillimetersPerSecond("acceleration_travel_layer_0");
initial_layer_speed_config.jerk = extruder_train->getSettingInMillimetersPerSecond("jerk_travel_layer_0");
//Travel speed (per extruder).
storage.travel_config_per_extruder[extruder_nr].smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
}
for (SliceMeshStorage& mesh : storage.meshes)
{
initial_layer_speed_config.speed = mesh.getSettingInMillimetersPerSecond("speed_print_layer_0");
initial_layer_speed_config.acceleration = mesh.getSettingInMillimetersPerSecond("acceleration_print_layer_0");
initial_layer_speed_config.jerk = mesh.getSettingInMillimetersPerSecond("jerk_print_layer_0");
//Outer wall speed (per mesh).
mesh.inset0_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
//Inner wall speed (per mesh).
mesh.insetX_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
//Skin speed (per mesh).
mesh.skin_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
{
//Infill speed (per combine part per mesh).
mesh.infill_config[idx].smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
}
}
}
else if (layer_nr == initial_speedup_layers) //At the topmost layer of the gradient, reset all speeds to the typical speeds.
{
storage.support_config.setSpeedIconic();
storage.support_skin_config.setSpeedIconic();
for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); ++extruder_nr)
{
storage.travel_config_per_extruder[extruder_nr].setSpeedIconic();
}
for (SliceMeshStorage& mesh : storage.meshes)
{
mesh.inset0_config.setSpeedIconic();
mesh.insetX_config.setSpeedIconic();
mesh.skin_config.setSpeedIconic();
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
{
mesh.infill_config[idx].setSpeedIconic();
}
}
}
}
bool GCodePlanner::makeRetractSwitchRetract(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx)
{
std::vector<GCodePath>& paths = extruder_plans[extruder_plan_idx].paths;
for (unsigned int path_idx2 = path_idx + 1; path_idx2 < paths.size(); path_idx2++)
@@ -913,7 +1016,7 @@ bool LayerPlan::makeRetractSwitchRetract(GCodeExport& gcode, unsigned int extrud
}
}
bool LayerPlan::writePathWithCoasting(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx, int64_t layerThickness, double coasting_volume, double coasting_speed, double coasting_min_volume)
bool GCodePlanner::writePathWithCoasting(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx, int64_t layerThickness, double coasting_volume, double coasting_speed, double coasting_min_volume)
{
if (coasting_volume <= 0)
{
+51 -76
Ver Arquivo
@@ -1,6 +1,6 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef LAYER_PLAN_H
#define LAYER_PLAN_H
#ifndef GCODE_PLANNER_H
#define GCODE_PLANNER_H
#include <vector>
@@ -11,12 +11,11 @@
#include "pathPlanning/TimeMaterialEstimates.h"
#include "utils/polygon.h"
#include "utils/logoutput.h"
#include "wallOverlap.h"
#include "PolygonFlowAdjuster.h"
#include "commandSocket.h"
#include "FanSpeedLayerTime.h"
#include "SpaceFillType.h"
#include "GCodePathConfig.h"
#include "settings/PathConfigStorage.h"
#include "utils/optional.h"
@@ -25,7 +24,7 @@ namespace cura
class SliceDataStorage;
class LayerPlan; // forward declaration so that ExtruderPlan can be a friend
class GCodePlanner; // forward declaration so that ExtruderPlan can be a friend
class LayerPlanBuffer; // forward declaration so that ExtruderPlan can be a friend
/*!
@@ -35,7 +34,7 @@ class LayerPlanBuffer; // forward declaration so that ExtruderPlan can be a frie
*/
class ExtruderPlan
{
friend class LayerPlan; // TODO: LayerPlan still does a lot which should actually be handled in this class.
friend class GCodePlanner; // TODO: GCodePlanner still does a lot which should actually be handled in this class.
friend class LayerPlanBuffer; // TODO: LayerPlanBuffer handles paths directly
protected:
std::vector<GCodePath> paths; //!< The paths planned for this extruder
@@ -58,7 +57,7 @@ public:
* \param extruder The extruder number for which this object is a plan.
* \param start_position The position the head is when this extruder plan starts
*/
ExtruderPlan(int extruder, Point start_position, int layer_nr, bool is_initial_layer, int layer_thickness, const FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, const RetractionConfig& retraction_config);
ExtruderPlan(int extruder, Point start_position, int layer_nr, bool is_initial_layer, int layer_thickness, FanSpeedLayerTimeSettings& fan_speed_layer_time_settings, const RetractionConfig& retraction_config);
/*!
* Add a new Insert, constructed with the given arguments
@@ -166,7 +165,7 @@ protected:
int layer_thickness; //!< The thickness of this layer in Z-direction
const FanSpeedLayerTimeSettings& fan_speed_layer_time_settings; //!< The fan speed and layer time settings used to limit this extruder plan
FanSpeedLayerTimeSettings& fan_speed_layer_time_settings; //!< The fan speed and layer time settings used to limit this extruder plan
const RetractionConfig& retraction_config; //!< The retraction settings for the extruder of this plan
@@ -203,38 +202,22 @@ protected:
class LayerPlanBuffer; // forward declaration to prevent circular dependency
/*!
* The LayerPlan class stores multiple moves that are planned.
* The GCodePlanner class stores multiple moves that are planned.
*
*
* It facilitates the combing to keep the head inside the print.
* It also keeps track of the print time estimate for this planning so speed adjustments can be made for the minimal-layer-time.
*
* A LayerPlan is also knows as a 'layer plan'.
* A GCodePlanner is also knows as a 'layer plan'.
*
*/
class LayerPlan : public NoCopy
class GCodePlanner : public NoCopy
{
friend class LayerPlanBuffer;
friend class LayerPlanTest;
public:
/*!
* The state which is passed along between layer plans.
* This is what a \ref LayerPlan delivers to further computation in \ref FffGcodeWriter
* This is the state which is currently planned, not which is written to gcode.
*/
struct PlanningState
{
Point last_position; //!< The position of the head before planning the next layer
int current_extruder; //!< The extruder train in use before planning the next layer
bool is_inside_mesh_layer_part; //!< Whether the last position was inside a layer part (used in combing)
};
friend class GCodePlannerTest;
private:
const SliceDataStorage& storage; //!< The polygon data obtained from FffPolygonProcessor
SliceDataStorage& storage; //!< The polygon data obtained from FffPolygonProcessor
public:
const PathConfigStorage configs_storage; //!< The line configs for this layer for each feature type
private:
int layer_nr; //!< The layer number of this layer plan
int is_initial_layer; //!< Whether this is the first layer (which might be raft)
@@ -244,9 +227,7 @@ private:
Point start_position;
Point lastPosition;
bool has_prime_tower_planned;
std::vector<ExtruderPlan> extruder_plans; //!< should always contain at least one ExtruderPlan
int last_extruder_previous_layer; //!< The last id of the extruder with which was printed in the previous layer
@@ -257,27 +238,27 @@ private:
Comb* comb;
const std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder;
std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder;
private:
/*!
* Either create a new path with the given config or return the last path if it already had that config.
* If LayerPlan::forceNewPathStart has been called a new path will always be returned.
* If GCodePlanner::forceNewPathStart has been called a new path will always be returned.
*
* \param config The config used for the path returned
* \param space_fill_type The type of space filling which this path employs
* \param flow (optional) A ratio for the extrusion speed
* \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
* \return A path with the given config which is now the last path in LayerPlan::paths
* \return A path with the given config which is now the last path in GCodePlanner::paths
*/
GCodePath* getLatestPathWithConfig(const GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
GCodePath* getLatestPathWithConfig(GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
public:
/*!
* Force LayerPlan::getLatestPathWithConfig to return a new path.
* Force GCodePlanner::getLatestPathWithConfig to return a new path.
*
* This function is introduced because in some cases
* LayerPlan::getLatestPathWithConfig is called consecutively with the same config pointer,
* GCodePlanner::getLatestPathWithConfig is called consecutively with the same config pointer,
* though the content of the config has changed.
*
* Example cases:
@@ -293,8 +274,8 @@ public:
* \param last_position The position of the head at the start of this gcode layer
* \param combing_mode Whether combing is enabled and full or within infill only.
*/
LayerPlan(const SliceDataStorage& storage, int layer_nr, int z, int layer_height, PlanningState last_planned_state, const std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder, CombingMode combing_mode, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance);
~LayerPlan();
GCodePlanner(SliceDataStorage& storage, int layer_nr, int z, int layer_height, Point last_position, int current_extruder, bool is_inside_mesh, std::vector<FanSpeedLayerTimeSettings>& fan_speed_layer_time_settings_per_extruder, CombingMode combing_mode, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance);
~GCodePlanner();
void overrideFanSpeeds(double speed);
/*!
@@ -311,21 +292,12 @@ private:
Polygons computeCombBoundaryInside(CombingMode combing_mode);
public:
int getLayerNr() const
int getLayerNr()
{
return layer_nr;
}
PlanningState getPlanningState() const
{
PlanningState ret;
ret.last_position = lastPosition;
ret.current_extruder = getExtruder();
ret.is_inside_mesh_layer_part = was_inside;
return ret;
}
Point getLastPosition() const
Point getLastPosition()
{
return lastPosition;
}
@@ -333,25 +305,14 @@ public:
/*!
* return whether the last position planned was inside the mesh (used in combing)
*/
bool getIsInsideMesh() const
bool getIsInsideMesh()
{
return was_inside;
}
bool getPrimeTowerIsPlanned() const
{
return has_prime_tower_planned;
}
void setPrimeTowerIsPlanned()
{
has_prime_tower_planned = true;
}
/*!
* send a line segment through the command socket from the previous point to the given point \p to
*/
void sendLineTo(PrintFeatureType print_feature_type, Point to, int line_width) const
void sendLineTo(PrintFeatureType print_feature_type, Point to, int line_width)
{
CommandSocket::sendLineTo(print_feature_type, to, line_width);
}
@@ -375,7 +336,7 @@ public:
/*!
* Get the last planned extruder.
*/
int getExtruder() const
int getExtruder()
{
return extruder_plans.back().extruder;
}
@@ -416,18 +377,19 @@ public:
* \param flow A modifier of the extrusion width which would follow from the \p config
* \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
*/
void addExtrusionMove(Point p, const GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
void addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillType space_fill_type, float flow = 1.0, bool spiralize = false);
/*!
* Add polygon to the gcode starting at vertex \p startIdx
* \param polygon The polygon
* \param polygon The polygons from which to get the polygon
* \param polygon The index of the polygon in \p polygons
* \param startIdx The index of the starting vertex of the \p polygon
* \param config The config with which to print the polygon lines
* \param wall_overlap_computation The wall overlap compensation calculator for each given segment (optionally nullptr)
* \param flow_adjuster Construct yielding the flow of each segment added (optionally nullptr)
* \param wall_0_wipe_dist The distance to travel along the polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over this polygon
*/
void addPolygon(ConstPolygonRef polygon, int startIdx, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, coord_t wall_0_wipe_dist = 0, bool spiralize = false);
void addPolygon(Polygons& polygons, unsigned int poly_idx, int startIdx, GCodePathConfig* config, PolygonFlowAdjuster* flow_adjuster = nullptr, coord_t wall_0_wipe_dist = 0, bool spiralize = false);
/*!
* Add polygons to the gcode with optimized order.
@@ -440,13 +402,13 @@ public:
*
* \param polygons The polygons
* \param config The config with which to print the polygon lines
* \param wall_overlap_computation The wall overlap compensation calculator for each given segment (optionally nullptr)
* \param flow_adjuster Construct yielding the flow of each segment added (optionally nullptr)
* \param z_seam_type The seam type / poly start optimizer
* \param z_seam_pos The location near where to start each part in case \p z_seam_type is 'back'
* \param wall_0_wipe_dist The distance to travel along each polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over each polygon printed
*/
void addPolygonsByOptimizer(const Polygons& polygons, const GCodePathConfig* config, WallOverlapComputation* wall_overlap_computation = nullptr, EZSeamType z_seam_type = EZSeamType::SHORTEST, Point z_seam_pos = Point(0, 0), coord_t wall_0_wipe_dist = 0, bool spiralize = false);
void addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config, PolygonFlowAdjuster* flow_adjuster = nullptr, EZSeamType z_seam_type = EZSeamType::SHORTEST, Point z_seam_pos = Point(0, 0), coord_t wall_0_wipe_dist = 0, bool spiralize = false);
/*!
* Add lines to the gcode with optimized order.
@@ -455,7 +417,7 @@ public:
* \param space_fill_type The type of space filling used to generate the line segments (should be either Lines or PolyLines!)
* \param wipe_dist (optional) the distance wiped without extruding after laying down a line.
*/
void addLinesByOptimizer(const Polygons& polygons, const GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist = 0);
void addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist = 0);
/*!
* Compute naive time estimates (without accounting for slow down at corners etc.) and naive material estimates (without accounting for MergeInfillLines)
@@ -473,7 +435,20 @@ public:
* \param gcode The gcode to write the planned paths to
*/
void writeGCode(GCodeExport& gcode);
/*!
* Complete all GcodePathConfigs by
* - altering speeds to conform to speed_print_layer_0 and
* speed_travel_layer_0
* - setting the layer_height (and thereby computing the extrusionMM3perMM)
*/
void completeConfigs();
/*!
* Interpolate between the initial layer speeds and the eventual speeds.
*/
void processInitialLayersSpeedup();
/*!
* Whether the current retracted path is to be an extruder switch retraction.
* This function is used to avoid a G10 S1 after a G10.
@@ -492,7 +467,7 @@ public:
*
* \param gcode The gcode to write the planned paths to
* \param extruder_plan_idx The index of the current extruder plan
* \param path_idx The index into LayerPlan::paths for the next path to be written to GCode.
* \param path_idx The index into GCodePlanner::paths for the next path to be written to GCode.
* \param layerThickness The height of the current layer.
* \param coasting_volume The volume otherwise leaked during a normal move.
* \param coasting_speed The speed at which to move during move-coasting.
@@ -517,4 +492,4 @@ public:
}//namespace cura
#endif // LAYER_PLAN_H
#endif//GCODE_PLANNER_H
+2 -2
Ver Arquivo
@@ -17,7 +17,7 @@ int Infill::computeScanSegmentIdx(int x, int line_width)
return x / line_width;
}
void Infill::generate(Polygons& result_polygons, Polygons& result_lines, const SliceMeshStorage* mesh)
void Infill::generate(Polygons& result_polygons, Polygons& result_lines, SliceMeshStorage* mesh)
{
if (in_outline.size() == 0) return;
if (line_distance == 0) return;
@@ -144,7 +144,7 @@ void Infill::generateTriangleInfill(Polygons& result)
generateLineInfill(result, line_distance, fill_angle + 120, 0);
}
void Infill::generateCubicSubDivInfill(Polygons& result, const SliceMeshStorage& mesh)
void Infill::generateCubicSubDivInfill(Polygons& result, SliceMeshStorage& mesh)
{
Polygons uncropped;
mesh.base_subdiv_cube->generateSubdivisionLines(z, uncropped);
+3 -3
Ver Arquivo
@@ -80,7 +80,7 @@ public:
* \param result_lines (output) The resulting line segments (from linear infill types)
* \param mesh The mesh for which to geenrate infill (should only be used for non-helper objects)
*/
void generate(Polygons& result_polygons, Polygons& result_lines, const SliceMeshStorage* mesh = nullptr);
void generate(Polygons& result_polygons, Polygons& result_lines, SliceMeshStorage* mesh = nullptr);
private:
/*!
@@ -148,8 +148,8 @@ private:
* \param[out] result The resulting lines
* \param[in] mesh Where the Cubic Subdivision Infill precomputation is stored
*/
void generateCubicSubDivInfill(Polygons& result, const SliceMeshStorage& mesh);
void generateCubicSubDivInfill(Polygons& result, SliceMeshStorage& mesh);
/*!
* Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule
* \param result (output) The resulting lines
+8 -8
Ver Arquivo
@@ -174,7 +174,7 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int dept
rel_child_centers.emplace_back(-1, -1, 1);
for (Point3 rel_child_center : rel_child_centers)
{
child_center = center + rotation_matrix.apply(rel_child_center * int32_t(cube_properties.side_length / 4));
child_center = center + rotation_matrix.apply(rel_child_center * coord_t(cube_properties.side_length / 4));
if (isValidSubdivision(mesh, child_center, radius))
{
children[child_nr] = new SubDivCube(mesh, child_center, depth - 1);
@@ -186,15 +186,15 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int dept
bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int64_t radius)
{
int64_t distance2;
coord_t sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
long int sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
bool inside_somewhere = false;
bool outside_somewhere = false;
int inside;
double part_dist;//what percentage of the radius the target layer is away from the center along the z axis. 0 - 1
const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
int bottom_layer = (center.z - radius) / layer_height;
int top_layer = (center.z + radius) / layer_height;
for (int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
const long int layer_height = mesh.getSettingInMicrons("layer_height");
long int bottom_layer = (center.z - radius) / layer_height;
long int top_layer = (center.z + radius) / layer_height;
for (long int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
{
part_dist = (double)(test_layer * layer_height - center.z) / radius;
sphere_slice_radius2 = radius * radius * (1.0 - (part_dist * part_dist));
@@ -221,9 +221,9 @@ bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int6
return false;
}
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2)
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, long int layer_nr, Point& location, int64_t* distance2)
{
if (layer_nr < 0 || (unsigned int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
if (layer_nr < 0 || (unsigned long int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
{
return 2;
}
+1 -1
Ver Arquivo
@@ -74,7 +74,7 @@ private:
* \param[out] distance2 the squared distance to the infill border
* \return Code 0: outside, 1: inside, 2: boundary does not exist at specified layer
*/
static int distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2);
static int distanceFromPointToMesh(SliceMeshStorage& mesh, long int layer_nr, Point& location, int64_t* distance2);
/*!
* Adds the defined line to the specified polygons. It assumes that the specified polygons are all parallel lines. Combines line segments with touching ends closer than epsilon.
+3 -16
Ver Arquivo
@@ -11,6 +11,7 @@
#include <stddef.h>
#include <vector>
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/string.h"
@@ -20,8 +21,6 @@
#include "settings/SettingsToGV.h"
#include <omp.h> // omp_get_num_threads
namespace cura
{
@@ -212,7 +211,7 @@ void slice(int argc, char **argv)
}
else
{
last_settings_object = &(meshgroup->meshes.back()); // pointer is valid until a new object is added, so this is OK
last_settings_object = meshgroup->meshes.back();
}
break;
case 'o':
@@ -330,19 +329,7 @@ int main(int argc, char **argv)
print_usage();
exit(1);
}
#pragma omp parallel
{
#pragma omp master
{
#ifdef _OPENMP
log("OpenMP multithreading enabled, likely number of threads to be used: %u\n", omp_get_num_threads());
#else
log("OpenMP multithreading disabled\n");
#endif
}
}
if (stringcasecompare(argv[1], "connect") == 0)
{
connect(argc, argv);
+22 -2
Ver Arquivo
@@ -19,12 +19,21 @@ Mesh::Mesh(SettingsBaseVirtual* parent)
{
}
void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
bool Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
{
int vi0 = findIndexOfVertex(v0);
int vi1 = findIndexOfVertex(v1);
int vi2 = findIndexOfVertex(v2);
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face.
return addFace(vi0, vi1, vi2);
}
bool Mesh::addFace(int vi0, int vi1, int vi2)
{
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2)
{
// the face has two vertices which get assigned the same location. Don't add the face.
return false;
}
int idx = faces.size(); // index of face to be added
faces.emplace_back();
@@ -35,6 +44,8 @@ void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
vertices[face.vertex_index[0]].connected_faces.push_back(idx);
vertices[face.vertex_index[1]].connected_faces.push_back(idx);
vertices[face.vertex_index[2]].connected_faces.push_back(idx);
return true;
}
void Mesh::clear()
@@ -81,6 +92,14 @@ void Mesh::expandXY(int64_t offset)
}
void Mesh::addVertex(const Point3& v)
{
uint32_t hash = pointHash(v);
vertex_hash_map[hash].push_back(vertices.size());
vertices.emplace_back(v);
aabb.include(v);
}
int Mesh::findIndexOfVertex(const Point3& v)
{
uint32_t hash = pointHash(v);
@@ -189,4 +208,5 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVe
return bestIdx;
}
}//namespace cura
+21 -1
Ver Arquivo
@@ -3,6 +3,7 @@
#include "settings/settings.h"
#include "utils/AABB3D.h"
#include "textureProcessing/MatSegment.h"
namespace cura
{
@@ -65,7 +66,26 @@ public:
Mesh(SettingsBaseVirtual* parent); //!< initializes the settings
void addFace(Point3& v0, Point3& v1, Point3& v2); //!< add a face to the mesh without settings it's connected_faces.
virtual ~Mesh() {} //!< Destructor
/*!
* add a face to the mesh without settings it's connected_faces.
*
* Don't add a face when the surface is zero mm^2
*
* \return whether a face has been added
*/
bool addFace(Point3& v0, Point3& v1, Point3& v2);
/*!
* add a face to the mesh without settings it's connected_faces.
*
* Don't add a face when the surface is zero mm^2
*
* \return whether a face has been added
*/
bool addFace(int vi0, int vi1, int vi2);
void addVertex(const Point3& v);
void clear(); //!< clears all data
void finish(); //!< complete the model : set the connected_face_index fields of the faces.
+10 -10
Ver Arquivo
@@ -16,7 +16,7 @@ void PathOrderOptimizer::optimize()
bool picked[polygons.size()];
memset(picked, false, sizeof(bool) * polygons.size());/// initialized as falses
for (ConstPolygonRef poly : polygons) /// find closest point to initial starting point within each polygon +initialize picked
for (PolygonRef poly : polygons) /// find closest point to initial starting point within each polygon +initialize picked
{
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
@@ -102,15 +102,15 @@ int PathOrderOptimizer::getPolyStart(Point prev_point, int poly_idx)
int PathOrderOptimizer::getClosestPointInPolygon(Point prev_point, int poly_idx)
{
ConstPolygonRef poly = polygons[poly_idx];
PolygonRef poly = polygons[poly_idx];
int best_point_idx = -1;
float best_point_score = std::numeric_limits<float>::infinity();
Point p0 = poly.back();
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
const Point& p1 = poly[point_idx];
const Point& p2 = poly[(point_idx + 1) % poly.size()];
Point& p1 = poly[point_idx];
Point& p2 = poly[(point_idx + 1) % poly.size()];
int64_t dist = vSize2(p1 - prev_point);
float is_on_inside_corner_score = -LinearAlg2D::getAngleLeft(p0, p1, p2) / M_PI * 5000 * 5000; // prefer inside corners
// this score is in the order of 5 mm
@@ -143,7 +143,7 @@ void LineOrderOptimizer::optimize()
{
int best_point_idx = -1;
float best_point_dist = std::numeric_limits<float>::infinity();
ConstPolygonRef poly = polygons[poly_idx];
PolygonRef poly = polygons[poly_idx];
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++) /// get closest point from polygon
{
float dist = vSize2f(poly[point_idx] - startPoint);
@@ -199,13 +199,13 @@ void LineOrderOptimizer::optimize()
if (best_line_idx > -1) /// should always be true; we should have been able to identify the best next polygon
{
ConstPolygonRef best_line = polygons[best_line_idx];
PolygonRef best_line = polygons[best_line_idx];
assert(best_line.size() == 2);
int line_start_point_idx = polyStart[best_line_idx];
int line_end_point_idx = line_start_point_idx * -1 + 1; /// 1 -> 0 , 0 -> 1
const Point& line_start = best_line[line_start_point_idx];
const Point& line_end = best_line[line_end_point_idx];
Point& line_start = best_line[line_start_point_idx];
Point& line_end = best_line[line_end_point_idx];
prev_point = line_end;
incoming_perpundicular_normal = turn90CCW(normal(line_end - line_start, 1000));
@@ -221,8 +221,8 @@ void LineOrderOptimizer::optimize()
inline void LineOrderOptimizer::updateBestLine(unsigned int poly_idx, int& best, float& best_score, Point prev_point, Point incoming_perpundicular_normal)
{
const Point& p0 = polygons[poly_idx][0];
const Point& p1 = polygons[poly_idx][1];
Point& p0 = polygons[poly_idx][0];
Point& p1 = polygons[poly_idx][1];
float dot_score = getAngleScore(incoming_perpundicular_normal, p0, p1);
{ /// check distance to first point on line (0)
float score = vSize2f(p0 - prev_point) + dot_score; // prefer 90 degree corners
+4 -14
Ver Arquivo
@@ -20,7 +20,7 @@ public:
EZSeamType type;
Point startPoint; //!< A location near the prefered start location
Point z_seam_pos; //!< The position near where to create the z_seam (if \ref PathOrderOptimizer::type == 'back')
std::vector<ConstPolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<PolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<int> polyStart; //!< polygons[i][polyStart[i]] = point of polygon i which is to be the starting point in printing the polygon
std::vector<int> polyOrder; //!< the optimized order as indices in #polygons
@@ -33,15 +33,10 @@ public:
void addPolygon(PolygonRef polygon)
{
this->polygons.emplace_back(polygon);
this->polygons.push_back(polygon);
}
void addPolygon(ConstPolygonRef polygon)
{
this->polygons.emplace_back(polygon);
}
void addPolygons(const Polygons& polygons)
void addPolygons(Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
this->polygons.push_back(polygons[i]);
@@ -71,7 +66,7 @@ class LineOrderOptimizer
{
public:
Point startPoint; //!< The location of the nozzle before starting to print the current layer
std::vector<ConstPolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<PolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<int> polyStart; //!< polygons[i][polyStart[i]] = point of polygon i which is to be the starting point in printing the polygon
std::vector<int> polyOrder; //!< the optimized order as indices in #polygons
@@ -85,11 +80,6 @@ public:
this->polygons.push_back(polygon);
}
void addPolygon(ConstPolygonRef polygon)
{
this->polygons.push_back(polygon);
}
void addPolygons(Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
+5 -6
Ver Arquivo
@@ -6,10 +6,9 @@
#include <unordered_set>
#include "../utils/polygonUtils.h"
#include "../utils/linearAlg2D.h"
#include "../utils/PolygonsPointIndex.h"
#include "../sliceDataStorage.h"
#include "../utils/SVG.h"
#include "../utils/linearAlg2D.h"
namespace cura {
@@ -23,7 +22,7 @@ Polygons& Comb::getBoundaryOutside()
return *boundary_outside;
}
Comb::Comb(const SliceDataStorage& storage, int layer_nr, const Polygons& comb_boundary_inside, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance)
Comb::Comb(SliceDataStorage& storage, int layer_nr, Polygons& comb_boundary_inside, int64_t comb_boundary_offset, bool travel_avoid_other_parts, int64_t travel_avoid_distance)
: storage(storage)
, layer_nr(layer_nr)
, offset_from_outlines(comb_boundary_offset) // between second wall and infill / other walls
@@ -32,7 +31,7 @@ Comb::Comb(const SliceDataStorage& storage, int layer_nr, const Polygons& comb_b
, offset_from_inside_to_outside(offset_from_outlines + offset_from_outlines_outside)
, max_crossing_dist2(offset_from_inside_to_outside * offset_from_inside_to_outside * 2) // so max_crossing_dist = offset_from_inside_to_outside * sqrt(2) =approx 1.5 to allow for slightly diagonal crossings and slightly inaccurate crossing computation
, avoid_other_parts(travel_avoid_other_parts)
, boundary_inside( comb_boundary_inside ) // copy the boundary, because the partsView_inside will reorder the polygons
, boundary_inside( comb_boundary_inside )
, partsView_inside( boundary_inside.splitIntoPartsView() ) // WARNING !! changes the order of boundary_inside !!
, inside_loc_to_line(PolygonUtils::createLocToLineGrid(boundary_inside, comb_boundary_offset))
, boundary_outside(
@@ -214,7 +213,7 @@ Comb::Crossing::Crossing(const Point& dest_point, const bool dest_is_inside, con
{
if (dest_is_inside)
{
dest_crossing_poly.emplace(boundary_inside[dest_part_boundary_crossing_poly_idx]); // initialize with most obvious poly, cause mostly a combing move will move outside the part, rather than inside a hole in the part
dest_crossing_poly = boundary_inside[dest_part_boundary_crossing_poly_idx]; // initialize with most obvious poly, cause mostly a combing move will move outside the part, rather than inside a hole in the part
}
}
@@ -333,7 +332,7 @@ bool Comb::Crossing::findOutside(const Polygons& outside, const Point close_to,
}
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> Comb::Crossing::findBestCrossing(const Polygons& outside, ConstPolygonRef from, const Point estimated_start, const Point estimated_end, Comb& comber)
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> Comb::Crossing::findBestCrossing(const Polygons& outside, const PolygonRef from, const Point estimated_start, const Point estimated_end, Comb& comber)
{
ClosestPolygonPoint* best_in = nullptr;
ClosestPolygonPoint* best_out = nullptr;
+6 -6
Ver Arquivo
@@ -48,7 +48,7 @@ private:
Point in_or_mid; //!< The point on the inside boundary, or in between the inside and outside boundary if the start/end point isn't inside the inside boudary
Point out; //!< The point on the outside boundary
PolygonsPart dest_part; //!< The assembled inside-boundary PolygonsPart in which the dest_point lies. (will only be initialized when Crossing::dest_is_inside holds)
std::optional<ConstPolygonRef> dest_crossing_poly; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon)
std::optional<PolygonRef> dest_crossing_poly; //!< The polygon of the part in which dest_point lies, which will be crossed (often will be the outside polygon)
const Polygons& boundary_inside; //!< The inside boundary as in \ref Comb::boundary_inside
const LocToLineGrid* inside_loc_to_line; //!< The loc to line grid \ref Comb::inside_loc_to_line
@@ -97,11 +97,11 @@ private:
* \param comber[in] The combing calculator which has references to the offsets and boundaries to use in combing.
* \return A pair of which the first is the crossing point on the inside boundary and the second the crossing point on the outside boundary
*/
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findBestCrossing(const Polygons& outside, ConstPolygonRef from, Point estimated_start, Point estimated_end, Comb& comber);
std::shared_ptr<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findBestCrossing(const Polygons& outside, const PolygonRef from, Point estimated_start, Point estimated_end, Comb& comber);
};
const SliceDataStorage& storage; //!< The storage from which to compute the outside boundary, when needed.
SliceDataStorage& storage; //!< The storage from which to compute the outside boundary, when needed.
const int layer_nr; //!< The layer number for the layer for which to compute the outside boundary, when needed.
const int64_t offset_from_outlines; //!< Offset from the boundary of a part to the comb path. (nozzle width / 2)
@@ -115,8 +115,8 @@ private:
const bool avoid_other_parts; //!< Whether to perform inverse combing a.k.a. avoid parts.
Polygons boundary_inside; //!< The boundary within which to comb. (Will be reordered by the partsView_inside)
const PartsView partsView_inside; //!< Structured indices onto boundary_inside which shows which polygons belong to which part.
Polygons& boundary_inside; //!< The boundary within which to comb.
PartsView partsView_inside; //!< Structured indices onto boundary_inside which shows which polygons belong to which part.
LocToLineGrid* inside_loc_to_line; //!< The SparsePointGridInclusive mapping locations to line segments of the inner boundary.
LazyInitialization<Polygons> boundary_outside; //!< The boundary outside of which to stay to avoid collision with other layer parts. This is a pointer cause we only compute it when we move outside the boundary (so not when there is only a single part in the layer)
LazyInitialization<LocToLineGrid, Comb*, const int64_t> outside_loc_to_line; //!< The SparsePointGridInclusive mapping locations to line segments of the outside boundary.
@@ -153,7 +153,7 @@ public:
* \param travel_avoid_other_parts Whether to avoid other layer parts when traveling through air.
* \param travel_avoid_distance The distance by which to avoid other layer parts when traveling through air.
*/
Comb(const SliceDataStorage& storage, int layer_nr, const Polygons& comb_boundary_inside, int64_t offset_from_outlines, bool travel_avoid_other_parts, int64_t travel_avoid_distance);
Comb(SliceDataStorage& storage, int layer_nr, Polygons& comb_boundary_inside, int64_t offset_from_outlines, bool travel_avoid_other_parts, int64_t travel_avoid_distance);
~Comb();
+1 -1
Ver Arquivo
@@ -23,7 +23,7 @@ namespace cura
class GCodePath
{
public:
const GCodePathConfig* config; //!< The configuration settings of the path.
GCodePathConfig* config; //!< The configuration settings of the path.
SpaceFillType space_fill_type; //!< The type of space filling of which this path is a part
float flow; //!< A type-independent flow configuration (used for wall overlap compensation)
bool retract; //!< Whether the path is a move path preceded by a retraction move; whether the path is a retracted move path.
-235
Ver Arquivo
@@ -1,235 +0,0 @@
/** Copyright (C) 2017 Ultimaker - Released under terms of the AGPLv3 License */
#include "PathConfigStorage.h"
#include "settings.h" // MAX_INFILL_COMBINE
#include "../sliceDataStorage.h" // SliceDataStorage
namespace cura
{
GCodePathConfig getPerimeterGapConfig(const SliceMeshStorage& mesh, int layer_thickness)
{
// The perimeter gap config follows the skin config, but has a different line width:
// wall_line_width_x divided by two because the gaps are between 0 and 1 times the wall line width
const int perimeter_gaps_line_width = mesh.getSettingInMicrons("wall_line_width_x") / 2;
double perimeter_gaps_speed = mesh.getSettingInMillimetersPerSecond("speed_topbottom");
if (mesh.getSettingBoolean("speed_equalize_flow_enabled"))
{
perimeter_gaps_speed = perimeter_gaps_speed * mesh.getSettingInMicrons("skin_line_width") / perimeter_gaps_line_width;
}
return GCodePathConfig(
PrintFeatureType::Skin
, perimeter_gaps_line_width
, layer_thickness
, mesh.getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{perimeter_gaps_speed, mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom")}
);
}
PathConfigStorage::MeshPathConfigs::MeshPathConfigs(const SliceMeshStorage& mesh, int layer_thickness)
: inset0_config(
PrintFeatureType::OuterWall
, mesh.getSettingInMicrons("wall_line_width_0")
, layer_thickness
, mesh.getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{mesh.getSettingInMillimetersPerSecond("speed_wall_0"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_0"), mesh.getSettingInMillimetersPerSecond("jerk_wall_0")}
)
, insetX_config(
PrintFeatureType::InnerWall
, mesh.getSettingInMicrons("wall_line_width_x")
, layer_thickness
, mesh.getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{mesh.getSettingInMillimetersPerSecond("speed_wall_x"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_x"), mesh.getSettingInMillimetersPerSecond("jerk_wall_x")}
)
, skin_config(
PrintFeatureType::Skin
, mesh.getSettingInMicrons("skin_line_width")
, layer_thickness
, mesh.getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{mesh.getSettingInMillimetersPerSecond("speed_topbottom"), mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom")}
)
, perimeter_gap_config(getPerimeterGapConfig(mesh, layer_thickness))
{
infill_config.reserve(MAX_INFILL_COMBINE);
for (int combine_idx = 0; combine_idx < MAX_INFILL_COMBINE; combine_idx++)
{
infill_config.emplace_back(
PrintFeatureType::Infill
, mesh.getSettingInMicrons("infill_line_width") * (combine_idx + 1)
, layer_thickness
, mesh.getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{mesh.getSettingInMillimetersPerSecond("speed_infill"), mesh.getSettingInMillimetersPerSecond("acceleration_infill"), mesh.getSettingInMillimetersPerSecond("jerk_infill")}
);
}
}
PathConfigStorage::PathConfigStorage(const SliceDataStorage& storage, int layer_nr, int layer_thickness)
: adhesion_extruder_train(storage.meshgroup->getExtruderTrain(storage.getSettingAsIndex("adhesion_extruder_nr")))
, support_infill_train(storage.meshgroup->getExtruderTrain(storage.getSettingAsIndex("support_infill_extruder_nr")))
, support_interface_train(storage.meshgroup->getExtruderTrain(storage.getSettingAsIndex("support_interface_extruder_nr")))
, raft_base_config(
PrintFeatureType::SupportInterface
, adhesion_extruder_train->getSettingInMicrons("raft_base_line_width")
, adhesion_extruder_train->getSettingInMicrons("raft_base_thickness")
, adhesion_extruder_train->getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_base_speed"), adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_base_acceleration"), adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_base_jerk")}
)
, raft_interface_config(
PrintFeatureType::Support
, adhesion_extruder_train->getSettingInMicrons("raft_interface_line_width")
, adhesion_extruder_train->getSettingInMicrons("raft_interface_thickness")
, adhesion_extruder_train->getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_interface_speed"), adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_interface_acceleration"), adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_interface_jerk")}
)
, raft_surface_config(
PrintFeatureType::SupportInterface
, adhesion_extruder_train->getSettingInMicrons("raft_surface_line_width")
, adhesion_extruder_train->getSettingInMicrons("raft_surface_thickness")
, adhesion_extruder_train->getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_surface_speed"), adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_surface_acceleration"), adhesion_extruder_train->getSettingInMillimetersPerSecond("raft_surface_jerk")}
)
, support_infill_config(
PrintFeatureType::Support
, support_infill_train->getSettingInMicrons("support_line_width")
, layer_thickness
, support_infill_train->getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{support_infill_train->getSettingInMillimetersPerSecond("speed_support_infill"), support_infill_train->getSettingInMillimetersPerSecond("acceleration_support_infill"), support_infill_train->getSettingInMillimetersPerSecond("jerk_support_infill")}
)
, support_interface_config(
PrintFeatureType::SupportInterface
, support_interface_train->getSettingInMicrons("support_interface_line_width")
, layer_thickness
, support_interface_train->getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{support_interface_train->getSettingInMillimetersPerSecond("speed_support_interface"), support_interface_train->getSettingInMillimetersPerSecond("acceleration_support_interface"), support_interface_train->getSettingInMillimetersPerSecond("jerk_support_interface")}
)
{
int extruder_count = storage.meshgroup->getExtruderCount();
travel_config_per_extruder.reserve(extruder_count);
skirt_brim_config.reserve(extruder_count);
prime_tower_config_per_extruder.reserve(extruder_count);
for (int extruder_nr = 0; extruder_nr < extruder_count; extruder_nr++)
{
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder_nr);
travel_config_per_extruder.emplace_back(
PrintFeatureType::MoveCombing
, 0
, 0
, 0.0
, GCodePathConfig::SpeedDerivatives{train->getSettingInMillimetersPerSecond("speed_travel"), train->getSettingInMillimetersPerSecond("acceleration_travel"), train->getSettingInMillimetersPerSecond("jerk_travel")}
);
skirt_brim_config.emplace_back(
PrintFeatureType::SkirtBrim
, train->getSettingInMicrons("skirt_brim_line_width")
, layer_thickness
, train->getSettingInPercentage("material_flow")
, GCodePathConfig::SpeedDerivatives{train->getSettingInMillimetersPerSecond("skirt_brim_speed"), train->getSettingInMillimetersPerSecond("acceleration_skirt_brim"), train->getSettingInMillimetersPerSecond("jerk_skirt_brim")}
);
prime_tower_config_per_extruder.emplace_back(
PrintFeatureType::SupportInfill
, train->getSettingInMicrons("prime_tower_line_width")
, layer_thickness
, train->getSettingInPercentage("prime_tower_flow")
, GCodePathConfig::SpeedDerivatives{train->getSettingInMillimetersPerSecond("speed_prime_tower"), train->getSettingInMillimetersPerSecond("acceleration_prime_tower"), train->getSettingInMillimetersPerSecond("jerk_prime_tower")}
);
}
mesh_configs.reserve(storage.meshes.size());
for (const SliceMeshStorage& mesh_storage : storage.meshes)
{
mesh_configs.emplace_back(mesh_storage, layer_thickness);
}
int initial_speedup_layer_count = storage.getSettingAsCount("speed_slowdown_layers");
if (layer_nr < initial_speedup_layer_count)
{
handleInitialLayerSpeedup(storage, layer_nr, initial_speedup_layer_count);
}
}
void cura::PathConfigStorage::handleInitialLayerSpeedup(const SliceDataStorage& storage, int layer_nr, int initial_speedup_layer_count)
{
std::vector<GCodePathConfig::SpeedDerivatives> global_first_layer_config_per_extruder;
global_first_layer_config_per_extruder.reserve(storage.meshgroup->getExtruderCount());
for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); extruder_nr++)
{
const ExtruderTrain* extruder = storage.meshgroup->getExtruderTrain(extruder_nr);
global_first_layer_config_per_extruder.emplace_back(
GCodePathConfig::SpeedDerivatives{
extruder->getSettingInMillimetersPerSecond("speed_print_layer_0")
, extruder->getSettingInMillimetersPerSecond("acceleration_print_layer_0")
, extruder->getSettingInMillimetersPerSecond("jerk_print_layer_0")
});
}
{ // support
if (layer_nr < initial_speedup_layer_count)
{
int extruder_nr_support_infill = storage.getSettingAsIndex((layer_nr <= 0)? "support_extruder_nr_layer_0" : "support_infill_extruder_nr");
GCodePathConfig::SpeedDerivatives& first_layer_config_infill = global_first_layer_config_per_extruder[extruder_nr_support_infill];
support_infill_config.smoothSpeed(first_layer_config_infill, std::max(0, layer_nr), initial_speedup_layer_count);
int extruder_nr_support_interface = storage.getSettingAsIndex("support_interface_extruder_nr");
GCodePathConfig::SpeedDerivatives& first_layer_config_interface = global_first_layer_config_per_extruder[extruder_nr_support_interface];
support_interface_config.smoothSpeed(first_layer_config_interface, std::max(0, layer_nr), initial_speedup_layer_count);
}
}
{ // extruder configs: travel, skirt/brim (= shield)
for (int extruder_nr = 0; extruder_nr < storage.meshgroup->getExtruderCount(); ++extruder_nr)
{
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder_nr);
GCodePathConfig::SpeedDerivatives initial_layer_speed_config{
train->getSettingInMillimetersPerSecond("speed_travel_layer_0")
, train->getSettingInMillimetersPerSecond("acceleration_travel_layer_0")
, train->getSettingInMillimetersPerSecond("jerk_travel_layer_0")
};
GCodePathConfig& travel = travel_config_per_extruder[extruder_nr];
travel.smoothSpeed(initial_layer_speed_config, std::max(0, layer_nr), initial_speedup_layer_count);
// don't smooth speed for the skirt/brim!
// NOTE: not smoothing skirt/brim means the speeds are also not smoothed for the draft/ooze shield
GCodePathConfig& prime_tower = prime_tower_config_per_extruder[extruder_nr];
prime_tower.smoothSpeed(initial_layer_speed_config, std::max(0, layer_nr), initial_speedup_layer_count);
}
}
{ // meshes
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
{
const SliceMeshStorage& mesh = storage.meshes[mesh_idx];
GCodePathConfig::SpeedDerivatives initial_layer_speed_config{
mesh.getSettingInMillimetersPerSecond("speed_print_layer_0")
, mesh.getSettingInMillimetersPerSecond("acceleration_print_layer_0")
, mesh.getSettingInMillimetersPerSecond("jerk_print_layer_0")
};
MeshPathConfigs& mesh_config = mesh_configs[mesh_idx];
//Outer wall speed (per mesh).
mesh_config.inset0_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layer_count);
//Inner wall speed (per mesh).
mesh_config.insetX_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layer_count);
//Skin speed (per mesh).
mesh_config.skin_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layer_count);
mesh_config.perimeter_gap_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layer_count);
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
{
//Infill speed (per combine part per mesh).
mesh_config.infill_config[idx].smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layer_count);
}
}
}
}
}//namespace cura
-63
Ver Arquivo
@@ -1,63 +0,0 @@
/** Copyright (C) 2017 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef SETTINGS_PATH_CONFIGS_H
#define SETTINGS_PATH_CONFIGS_H
#include <vector>
#include "../utils/intpoint.h" // coord_t
#include "../GCodePathConfig.h"
namespace cura
{
class SliceDataStorage; // forward decl for SliceDataStorage
class SliceMeshStorage; // forward decl for SliceDataStorage
class ExtruderTrain; // forward decl for SliceDataStorage
/*!
* A class to represent all configurations for all features types of printed lines in a meshgroup.
*/
class PathConfigStorage
{
private:
const ExtruderTrain* adhesion_extruder_train;
const ExtruderTrain* support_infill_train;
const ExtruderTrain* support_interface_train;
public:
class MeshPathConfigs
{
public:
GCodePathConfig inset0_config;
GCodePathConfig insetX_config;
GCodePathConfig skin_config;
GCodePathConfig perimeter_gap_config;
std::vector<GCodePathConfig> infill_config;
MeshPathConfigs(const SliceMeshStorage& mesh, int layer_thickness);
};
GCodePathConfig raft_base_config;
GCodePathConfig raft_interface_config;
GCodePathConfig raft_surface_config;
std::vector<GCodePathConfig> travel_config_per_extruder; //!< The config used for travel moves (only speed is set!)
std::vector<GCodePathConfig> skirt_brim_config; //!< Configuration for skirt and brim per extruder.
std::vector<GCodePathConfig> prime_tower_config_per_extruder; //!< Configuration for the prime tower per extruder.
GCodePathConfig support_infill_config; //!< The config used to print the normal support, rather than the support interface
GCodePathConfig support_interface_config; //!< The config to use to print the dense roofs and bottoms of support
std::vector<MeshPathConfigs> mesh_configs; //!< For each meash the config for all its feature types
/*!
* \warning Note that the layer_nr might be below zero for raft (filler) layers
*/
PathConfigStorage(const SliceDataStorage& storage, int layer_nr, int layer_thickness);
private:
void handleInitialLayerSpeedup(const SliceDataStorage& storage, int layer_nr, int initial_speedup_layer_count);
};
}; // namespace cura
#endif // SETTINGS_PATH_CONFIGS_H
+1 -1
Ver Arquivo
@@ -125,7 +125,7 @@ bool SettingRegistry::getDefinitionFile(const std::string machine_id, std::strin
int SettingRegistry::loadExtruderJSONsettings(unsigned int extruder_nr, SettingsBase* settings_base)
{
if (extruder_train_ids.empty())
if (extruder_train_ids.empty()) //... Tough luck, buddy.
{
logError("Couldn't find any extruder trains!\n");
return -1;
+32 -8
Ver Arquivo
@@ -93,23 +93,21 @@ void SettingsBase::setSettingInheritBase(std::string key, const SettingsBaseVirt
std::string SettingsBase::getSettingString(std::string key) const
{
auto value_it = setting_values.find(key);
if (value_it != setting_values.end())
if (setting_values.find(key) != setting_values.end())
{
return value_it->second;
return setting_values.at(key);
}
auto inherit_override_it = setting_inherit_base.find(key);
if (inherit_override_it != setting_inherit_base.end())
if (setting_inherit_base.find(key) != setting_inherit_base.end())
{
return inherit_override_it->second->getSettingString(key);
return setting_inherit_base.at(key)->getSettingString(key);
}
if (parent)
{
return parent->getSettingString(key);
}
cura::logError("Trying to retrieve unregistered setting with no value given: '%s'\n", key.c_str());
std::exit(-1);
const_cast<SettingsBase&>(*this).setting_values[key] = "";
cura::logWarning("Unregistered setting %s\n", key.c_str());
return "";
}
@@ -460,6 +458,32 @@ SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::st
return SupportDistPriority::XY_OVERRIDES_Z;
}
ColourUsage SettingsBaseVirtual::getSettingAsColourUsage(std::string key) const
{
std::string value = getSettingString(key);
if (value == "red")
{
return ColourUsage::RED;
}
if (value == "green")
{
return ColourUsage::GREEN;
}
if (value == "blue")
{
return ColourUsage::BLUE;
}
if (value == "alpha")
{
return ColourUsage::ALPHA;
}
if (value == "grey")
{
return ColourUsage::GREY;
}
return ColourUsage::GREY;
}
}//namespace cura
+13
Ver Arquivo
@@ -177,6 +177,18 @@ enum class SupportDistPriority
Z_OVERRIDES_XY
};
/*!
* Which color(s) of a texture to use
*/
enum class ColourUsage
{
RED = 0,
GREEN = 1,
BLUE = 2,
ALPHA = 3,
GREY // use red, green and blue channels
};
#define MAX_EXTRUDERS 16
//Maximum number of infill layers that can be combined into a single infill extrusion area.
@@ -253,6 +265,7 @@ public:
FillPerimeterGapMode getSettingAsFillPerimeterGapMode(std::string key) const;
CombingMode getSettingAsCombingMode(std::string key) const;
SupportDistPriority getSettingAsSupportDistPriority(std::string key) const;
ColourUsage getSettingAsColourUsage(std::string key) const;
};
class SettingRegistry;
+5 -49
Ver Arquivo
@@ -10,16 +10,7 @@
namespace cura
{
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateSkinAreas reads data from mesh.layers.parts[*].insets and writes to mesh.layers[n].parts[*].skin_parts
* generateSkinInsets only read/writes the skin_parts from the current layer.
*
* generateSkins therefore reads (depends on) data from mesh.layers[*].parts[*].insets and writes mesh.layers[n].parts[*].skin_parts
*/
void generateSkins(int layerNr, SliceMeshStorage& mesh, int downSkinCount, int upSkinCount, int wall_line_count, int innermost_wall_line_width, int insetCount, bool no_small_gaps_heuristic)
{
generateSkinAreas(layerNr, mesh, innermost_wall_line_width, downSkinCount, upSkinCount, wall_line_count, no_small_gaps_heuristic);
@@ -32,12 +23,6 @@ void generateSkins(int layerNr, SliceMeshStorage& mesh, int downSkinCount, int u
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateSkinAreas reads data from mesh.layers[*].parts[*].insets and writes to mesh.layers[n].parts[*].skin_parts
*/
void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost_wall_line_width, int downSkinCount, int upSkinCount, int wall_line_count, bool no_small_gaps_heuristic)
{
SliceLayer& layer = mesh.layers[layer_nr];
@@ -46,7 +31,7 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
return;
}
int min_infill_area = mesh.getSettingInMillimeters("min_infill_area");
for(unsigned int partNr = 0; partNr < layer.parts.size(); partNr++)
{
SliceLayerPart& part = layer.parts[partNr];
@@ -78,22 +63,12 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
if (static_cast<int>(layer_nr - downSkinCount) >= 0)
{
Polygons not_air = getInsidePolygons(mesh.layers[layer_nr - downSkinCount]);
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
downskin = downskin.difference(not_air); // skin overlaps with the walls
downskin = downskin.difference(getInsidePolygons(mesh.layers[layer_nr - downSkinCount])); // skin overlaps with the walls
}
if (static_cast<int>(layer_nr + upSkinCount) < static_cast<int>(mesh.layers.size()))
{
Polygons not_air = getInsidePolygons(mesh.layers[layer_nr + upSkinCount]);
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
upskin = upskin.difference(not_air); // skin overlaps with the walls
upskin = upskin.difference(getInsidePolygons(mesh.layers[layer_nr + upSkinCount])); // skin overlaps with the walls
}
}
else
@@ -105,10 +80,6 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
not_air = not_air.intersection(getInsidePolygons(mesh.layers[downskin_layer_nr]));
}
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
downskin = downskin.difference(not_air); // skin overlaps with the walls
}
@@ -119,10 +90,6 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
{
not_air = not_air.intersection(getInsidePolygons(mesh.layers[upskin_layer_nr]));
}
if (min_infill_area > 0)
{
not_air.removeSmallAreas(min_infill_area);
}
upskin = upskin.difference(not_air); // skin overlaps with the walls
}
}
@@ -139,12 +106,7 @@ void generateSkinAreas(int layer_nr, SliceMeshStorage& mesh, const int innermost
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateSkinInsets only read/writes the skin_parts from the current layer.
*/
void generateSkinInsets(SliceLayerPart* part, const int wall_line_width, int insetCount)
{
if (insetCount == 0)
@@ -177,12 +139,6 @@ void generateSkinInsets(SliceLayerPart* part, const int wall_line_width, int ins
}
}
/*
* This function is executed in a parallel region based on layer_nr.
* When modifying make sure any changes does not introduce data races.
*
* generateInfill read mesh.layers[n].parts[*].{insets,skin_parts,boundingBox} and write mesh.layers[n].parts[*].infill_area
*/
void generateInfill(int layerNr, SliceMeshStorage& mesh, const int innermost_wall_line_width, int infill_skin_overlap, int wall_line_count)
{
SliceLayer& layer = mesh.layers[layerNr];
+71 -5
Ver Arquivo
@@ -35,7 +35,7 @@ void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const
{
if (external_polys_only)
{
result.add(part.outline.outerPolygon());
result.add(const_cast<SliceLayerPart&>(part).outline.outerPolygon()); // TODO: make a const version of outerPolygon()
}
else
{
@@ -57,12 +57,12 @@ void SliceLayer::getSecondOrInnermostWalls(Polygons& layer_walls) const
{
// we want the 2nd inner walls
if (part.insets.size() >= 2) {
layer_walls.add(part.insets[1]);
layer_walls.add(const_cast<SliceLayerPart&>(part).insets[1]); // TODO const cast!
continue;
}
// but we'll also take the inner wall if the 2nd doesn't exist
if (part.insets.size() == 1) {
layer_walls.add(part.insets[0]);
layer_walls.add(const_cast<SliceLayerPart&>(part).insets[0]); // TODO const cast!
continue;
}
// offset_from_outlines was so large that it completely destroyed our isle,
@@ -72,12 +72,46 @@ void SliceLayer::getSecondOrInnermostWalls(Polygons& layer_walls) const
}
}
SliceMeshStorage::SliceMeshStorage(SettingsBaseVirtual* settings, unsigned int slice_layer_count)
: SettingsMessenger(settings)
, layer_nr_max_filled_layer(0)
, inset0_config(PrintFeatureType::OuterWall)
, insetX_config(PrintFeatureType::InnerWall)
, skin_config(PrintFeatureType::Skin)
, base_subdiv_cube(nullptr)
, texture_proximity_processor(nullptr)
{
layers.resize(slice_layer_count);
infill_config.reserve(MAX_INFILL_COMBINE);
for(int n=0; n<MAX_INFILL_COMBINE; n++)
infill_config.emplace_back(PrintFeatureType::Infill);
}
SliceMeshStorage::SliceMeshStorage(SliceMeshStorage&& old)
: SettingsMessenger(SettingsBaseVirtual::parent)
, layers(old.layers)
, layer_nr_max_filled_layer(old.layer_nr_max_filled_layer)
, inset0_config(old.inset0_config)
, insetX_config(old.insetX_config)
, skin_config(old.skin_config)
, base_subdiv_cube(old.base_subdiv_cube)
, texture_proximity_processor(old.texture_proximity_processor)
{
old.base_subdiv_cube = nullptr;
old.texture_proximity_processor = nullptr;
}
SliceMeshStorage::~SliceMeshStorage()
{
if (base_subdiv_cube)
{
delete base_subdiv_cube;
}
if (texture_proximity_processor)
{
delete texture_proximity_processor;
}
}
std::vector<RetractionConfig> SliceDataStorage::initializeRetractionConfigs()
@@ -87,16 +121,48 @@ std::vector<RetractionConfig> SliceDataStorage::initializeRetractionConfigs()
return ret;
}
std::vector<GCodePathConfig> SliceDataStorage::initializeTravelConfigs()
{
std::vector<GCodePathConfig> ret;
for (int extruder = 0; extruder < meshgroup->getExtruderCount(); extruder++)
{
travel_config_per_extruder.emplace_back(PrintFeatureType::MoveCombing);
}
return ret;
}
std::vector<GCodePathConfig> SliceDataStorage::initializeSkirtBrimConfigs()
{
std::vector<GCodePathConfig> ret;
for (int extruder = 0; extruder < meshgroup->getExtruderCount(); extruder++)
{
skirt_brim_config.emplace_back(PrintFeatureType::SkirtBrim);
}
return ret;
}
SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(meshgroup),
meshgroup(meshgroup != nullptr ? meshgroup : new MeshGroup(FffProcessor::getInstance())), //If no mesh group is provided, we roll our own.
print_layer_count(0),
retraction_config_per_extruder(initializeRetractionConfigs()),
extruder_switch_retraction_config_per_extruder(initializeRetractionConfigs()),
travel_config_per_extruder(initializeTravelConfigs()),
skirt_brim_config(initializeSkirtBrimConfigs()),
raft_base_config(PrintFeatureType::SupportInterface),
raft_interface_config(PrintFeatureType::Support),
raft_surface_config(PrintFeatureType::SupportInterface),
support_config(PrintFeatureType::Support),
support_skin_config(PrintFeatureType::SupportInterface),
max_print_height_second_to_last_extruder(-1),
primeTower(*this)
{
}
SliceDataStorage::~SliceDataStorage()
{
}
Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_parts, bool external_polys_only) const
{
if (layer_nr < 0 && layer_nr < -Raft::getFillerLayerCount(*this))
@@ -136,7 +202,7 @@ Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_pa
}
const SliceLayer& layer = mesh.layers[layer_nr];
layer.getOutlines(total, external_polys_only);
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
if (const_cast<SliceMeshStorage&>(mesh).getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // TODO: make all getSetting functions const??
{
total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
}
@@ -180,7 +246,7 @@ Polygons SliceDataStorage::getLayerSecondOrInnermostWalls(int layer_nr, bool inc
{
const SliceLayer& layer = mesh.layers[layer_nr];
layer.getSecondOrInnermostWalls(total);
if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
if (const_cast<SliceMeshStorage&>(mesh).getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL) // TODO: make getSetting const? make settings.setting_values mapping mutable??
{
total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
}
+50 -23
Ver Arquivo
@@ -8,9 +8,11 @@
#include "utils/NoCopy.h"
#include "utils/AABB.h"
#include "mesh.h"
#include "gcodePlanner.h"
#include "MeshGroup.h"
#include "PrimeTower.h"
#include "gcodeExport.h" // CoastingConfig
#include "GCodePathConfig.h"
#include "textureProcessing/TextureProximityProcessor.h"
namespace cura
{
@@ -137,33 +139,41 @@ public:
std::vector<SupportLayer> supportLayers;
SupportStorage()
: generated(false)
, layer_nr_max_filled_layer(-1)
{
}
SupportStorage() : generated(false), layer_nr_max_filled_layer(-1) { }
~SupportStorage(){ supportLayers.clear(); }
};
/******************/
class SubDivCube; // forward declaration to prevent dependency loop
class SliceMeshStorage : public SettingsMessenger // passes on settings from a Mesh object
/*!
*
* passes on settings from a Mesh object
*
* Cannot be copied due to \ref SliceMeshStorage::texture_proximity_processor being governed by this object alone
*/
class SliceMeshStorage : public SettingsMessenger, public NoCopy
{
public:
std::vector<SliceLayer> layers;
int layer_nr_max_filled_layer; //!< the layer number of the uppermost layer with content (modified while infill meshes are processed)
GCodePathConfig inset0_config;
GCodePathConfig insetX_config;
GCodePathConfig skin_config;
std::vector<GCodePathConfig> infill_config;
SubDivCube* base_subdiv_cube;
SliceMeshStorage(SettingsBaseVirtual* settings, unsigned int slice_layer_count)
: SettingsMessenger(settings)
, layer_nr_max_filled_layer(0)
, base_subdiv_cube(nullptr)
{
layers.resize(slice_layer_count);
}
TextureProximityProcessor* texture_proximity_processor; //!< TextureProximityProcessor per layer per mesh (if that mesh needs a proximity processor)
SliceMeshStorage(SettingsBaseVirtual* settings, unsigned int slice_layer_count);
/*!
* Move constructor
*/
SliceMeshStorage(SliceMeshStorage&& old);
virtual ~SliceMeshStorage();
};
@@ -181,8 +191,18 @@ public:
std::vector<RetractionConfig> retraction_config_per_extruder; //!< Retraction config per extruder.
std::vector<RetractionConfig> extruder_switch_retraction_config_per_extruder; //!< Retraction config per extruder for when performing an extruder switch
std::vector<GCodePathConfig> travel_config_per_extruder; //!< The config used for travel moves (only speed is set!)
std::vector<GCodePathConfig> skirt_brim_config; //!< Configuration for skirt and brim per extruder.
std::vector<CoastingConfig> coasting_config; //!< coasting config per extruder
GCodePathConfig raft_base_config;
GCodePathConfig raft_interface_config;
GCodePathConfig raft_surface_config;
GCodePathConfig support_config;
GCodePathConfig support_skin_config; //!< The config to use to print the dense roofs and bottoms of support
SupportStorage support;
Polygons skirt_brim[MAX_EXTRUDERS]; //!< Skirt and brim polygons per extruder, ordered from inner to outer polygons.
@@ -197,6 +217,21 @@ public:
std::vector<Polygons> oozeShield; //oozeShield per layer
Polygons draft_protection_shield; //!< The polygons for a heightened skirt which protects from warping by gusts of wind and acts as a heated chamber.
/*!
* Construct the initial retraction_config_per_extruder
*/
std::vector<RetractionConfig> initializeRetractionConfigs();
/*!
* Construct the initial travel_config_per_extruder
*/
std::vector<GCodePathConfig> initializeTravelConfigs();
/*!
* Construct the initial skirt & brim configurations for each extruder.
*/
std::vector<GCodePathConfig> initializeSkirtBrimConfigs();
/*!
* \brief Creates a new slice data storage that stores the slice data of the
* specified mesh group.
@@ -209,9 +244,7 @@ public:
*/
SliceDataStorage(MeshGroup* meshgroup);
~SliceDataStorage()
{
}
~SliceDataStorage();
/*!
* Get all outlines within a given layer.
@@ -246,12 +279,6 @@ public:
* \return a vector of bools indicating whether the extruder with corresponding index is used in this layer.
*/
std::vector<bool> getExtrudersUsed(int layer_nr) const;
private:
/*!
* Construct the retraction_config_per_extruder
*/
std::vector<RetractionConfig> initializeRetractionConfigs();
};
}//namespace cura
+21
Ver Arquivo
@@ -0,0 +1,21 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_CLOSE_POLYGON_RESULT_H
#define SLICER_CLOSE_POLYGON_RESULT_H
#include "../utils/intpoint.h"
namespace cura
{
class ClosePolygonResult
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
//The line on which the point lays is between pointIdx-1 and pointIdx
public:
Point intersectionPoint;
int polygonIdx = -1;
unsigned int pointIdx = -1;
};
} // namespace cura
#endif // SLICER_CLOSE_POLYGON_RESULT_H
+22
Ver Arquivo
@@ -0,0 +1,22 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_GAP_CLOSER_RESULT_H
#define SLICER_GAP_CLOSER_RESULT_H
#include "../utils/intpoint.h"
namespace cura
{
class GapCloserResult
{
public:
int64_t len = -1;
int polygonIdx = -1;
unsigned int pointIdxA = -1;
unsigned int pointIdxB = -1;
bool AtoB = false;
};
} // namespace cura
#endif // SLICER_GAP_CLOSER_RESULT_H
+5 -8
Ver Arquivo
@@ -1,10 +1,10 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "layerPart.h"
#include "settings/settings.h"
#include "progress/Progress.h"
#include "LayerPart.h"
#include "../settings/settings.h"
#include "../progress/Progress.h"
#include "utils/SVG.h" // debug output
#include "../utils/SVG.h" // debug output
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
@@ -44,10 +44,7 @@ void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, bool uni
}
void createLayerParts(SliceMeshStorage& mesh, Slicer* slicer, bool union_layers, bool union_all_remove_holes)
{
const auto total_layers = slicer->layers.size();
assert(mesh.layers.size() == total_layers);
#pragma omp parallel for default(none) shared(mesh,slicer) firstprivate(union_layers,union_all_remove_holes) schedule(dynamic)
for(unsigned int layer_nr = 0; layer_nr < total_layers; layer_nr++)
for(unsigned int layer_nr = 0; layer_nr < slicer->layers.size(); layer_nr++)
{
mesh.layers[layer_nr].sliceZ = slicer->layers[layer_nr].z;
mesh.layers[layer_nr].printZ = slicer->layers[layer_nr].z;
+6 -6
Ver Arquivo
@@ -1,10 +1,10 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef LAYERPART_H
#define LAYERPART_H
#ifndef SLICER_LAYERPART_H
#define SLICER_LAYERPART_H
#include "sliceDataStorage.h"
#include "slicer.h"
#include "commandSocket.h"
#include "../sliceDataStorage.h"
#include "Slicer.h"
#include "../commandSocket.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
@@ -28,4 +28,4 @@ void layerparts2HTML(SliceDataStorage& mesh, const char* filename, bool all_laye
}//namespace cura
#endif//LAYERPART_H
#endif//SLICER_LAYERPART_H
@@ -1,4 +1,4 @@
#include "multiVolumes.h"
#include "MultiVolumes.h"
namespace cura
{
@@ -1,8 +1,8 @@
#ifndef MULTIVOLUMES_H
#define MULTIVOLUMES_H
#ifndef SLICER_MULTIVOLUMES_H
#define SLICER_MULTIVOLUMES_H
#include "sliceDataStorage.h"
#include "slicer.h"
#include "../sliceDataStorage.h"
#include "Slicer.h"
/* This file contains code to help fixing up and changing layers that are build from multiple volumes. */
namespace cura {
@@ -21,4 +21,4 @@ void generateMultipleVolumesOverlap(std::vector<Slicer*> &meshes);
}//namespace cura
#endif//MULTIVOLUMES_H
#endif//SLICER_MULTIVOLUMES_H
+180
Ver Arquivo
@@ -0,0 +1,180 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include "../utils/gettime.h"
#include "../utils/logoutput.h"
#include "../textureProcessing/MatCoord.h"
#include "../textureProcessing/FaceNormalStorage.h"
#include "Slicer.h"
namespace cura {
void Slicer::project2D(unsigned int face_idx, const Point3 p[3], unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, int32_t layer_nr, SlicerSegment& seg)
{
const Point3& p0 = p[idx_shared];
const Point3& p1 = p[idx_first];
const Point3& p2 = p[idx_second];
seg.start.X = interpolate(z, p0.z, p1.z, p0.x, p1.x);
seg.start.Y = interpolate(z, p0.z, p1.z, p0.y, p1.y);
seg.end .X = interpolate(z, p0.z, p2.z, p0.x, p2.x);
seg.end .Y = interpolate(z, p0.z, p2.z, p0.y, p2.y);
if (textured_mesh)
{
MatSegment mat_segment;
bool got_texture_coords = textured_mesh->sliceFaceTexture(face_idx, idx_shared, idx_first, idx_second, z, seg.start, seg.end, mat_segment);
SlicerLayer& layer = layers[layer_nr];
if (got_texture_coords)
{
if (layer.texture_bump_map)
{
layer.texture_bump_map->registerTexturedFaceSlice(seg, mat_segment);
}
if (texture_proximity_processor)
{
texture_proximity_processor->registerTexturedFaceSlice(seg, mat_segment, layer_nr);
}
}
}
}
Slicer::Slicer(Mesh* mesh, int initial, int thickness, unsigned int slice_layer_count, bool keep_none_closed, bool extensive_stitching, TextureProximityProcessor* texture_proximity_processor)
: mesh(mesh)
, textured_mesh(dynamic_cast<TexturedMesh*>(mesh))
, texture_proximity_processor(texture_proximity_processor)
{
assert((int) slice_layer_count > 0);
TimeKeeper slice_timer;
std::optional<TextureBumpMapProcessor::Settings> bump_map_settings;
FaceNormalStorage* face_normal_storage = nullptr;
if (mesh->getSettingBoolean("bump_map_enabled"))
{
bump_map_settings.emplace(mesh);
if (mesh->getSettingAsRatio("bump_map_face_angle_correction") != 0.0)
{
face_normal_storage = new FaceNormalStorage(mesh);
}
}
layers.reserve(slice_layer_count);
for (uint32_t layer_nr = 0; layer_nr < slice_layer_count; layer_nr++)
{ // initialize all layers
layers.emplace_back(layer_nr, mesh, bump_map_settings, face_normal_storage);
assert(&layers.back() == &layers[layer_nr] && "We should just have emplaced the last layer!");
layers[layer_nr].z = initial + thickness * layer_nr;
}
bool bump_map_alternate = mesh->getSettingBoolean("bump_map_alternate");
int extruder_nr = mesh->getSettingAsIndex("extruder_nr");
for(unsigned int face_idx = 0; face_idx < mesh->faces.size(); face_idx++)
{
const MeshFace& face = mesh->faces[face_idx];
const MeshVertex& v0 = mesh->vertices[face.vertex_index[0]];
const MeshVertex& v1 = mesh->vertices[face.vertex_index[1]];
const MeshVertex& v2 = mesh->vertices[face.vertex_index[2]];
Point3 p[3] =
{ mesh->vertices[face.vertex_index[0]].p
, mesh->vertices[face.vertex_index[1]].p
, mesh->vertices[face.vertex_index[2]].p };
Point3& p0 = p[0];
Point3& p1 = p[1];
Point3& p2 = p[2];
int32_t minZ = p0.z;
int32_t maxZ = p0.z;
if (p1.z < minZ) minZ = p1.z;
if (p2.z < minZ) minZ = p2.z;
if (p1.z > maxZ) maxZ = p1.z;
if (p2.z > maxZ) maxZ = p2.z;
int32_t layer_max = (maxZ - initial) / thickness;
int32_t layer_min = (minZ - initial + thickness - 1) / thickness; // + thickness - 1 to get the first layer above or at minZ
for (int32_t layer_nr = layer_min; layer_nr <= layer_max; layer_nr++)
{
if (bump_map_alternate && layer_nr % 2 == extruder_nr) // TODO only works for the first two extruders!
{
continue;
}
int32_t z = layer_nr * thickness + initial;
if (z < minZ) continue;
if (layer_nr < 0) continue;
SlicerSegment s;
s.endVertex = nullptr;
s.faceIndex = face_idx;
assert(face_idx >= 0);
s.addedToPolygon = false;
if (p0.z < z && p1.z >= z && p2.z >= z)
{
s.endOtherFaceIdx = face.connected_face_index[0];
if (p1.z == z)
{
s.endVertex = &v1;
}
project2D(face_idx, p, 0, 2, 1, z, layer_nr, s);
}
else if (p0.z > z && p1.z < z && p2.z < z)
{
s.endOtherFaceIdx = face.connected_face_index[2];
project2D(face_idx, p, 0, 1, 2, z, layer_nr, s);
}
else if (p1.z < z && p0.z >= z && p2.z >= z)
{
s.endOtherFaceIdx = face.connected_face_index[1];
if (p2.z == z)
{
s.endVertex = &v2;
}
project2D(face_idx, p, 1, 0, 2, z, layer_nr, s);
}
else if (p1.z > z && p0.z < z && p2.z < z)
{
s.endOtherFaceIdx = face.connected_face_index[0];
project2D(face_idx, p, 1, 2, 0, z, layer_nr, s);
}
else if (p2.z < z && p1.z >= z && p0.z >= z)
{
s.endOtherFaceIdx = face.connected_face_index[2];
if (p0.z == z)
{
s.endVertex = &v0;
}
project2D(face_idx, p, 2, 1, 0, z, layer_nr, s);
}
else if (p2.z > z && p1.z < z && p0.z < z)
{
s.endOtherFaceIdx = face.connected_face_index[1];
project2D(face_idx, p, 2, 0, 1, z, layer_nr, s);
}
else
{
//Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
// on the slice would create two segments
continue;
}
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(face_idx, layers[layer_nr].segments.size()));
layers[layer_nr].segments.push_back(s);
}
}
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
{
layers[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
}
mesh->expandXY(mesh->getSettingInMicrons("xy_offset"));
log("slice make polygons took %.3f seconds\n",slice_timer.restart());
if (face_normal_storage)
{
delete face_normal_storage;
}
}
}//namespace cura
+75
Ver Arquivo
@@ -0,0 +1,75 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_H
#define SLICER_SLICER_H
#include <queue>
#include "../mesh.h"
#include "../utils/polygon.h"
#include "SlicerSegment.h"
#include "ClosePolygonResult.h"
#include "SlicerLayer.h"
#include "../textureProcessing/MatSegment.h"
#include "../textureProcessing/TextureProximityProcessor.h"
/*
The Slicer creates layers of polygons from an optimized 3D model.
The result of the Slicer is a list of polygons without any order or structure.
*/
namespace cura {
class Slicer
{
public:
std::vector<SlicerLayer> layers;
const Mesh* mesh = nullptr; //!< The sliced mesh
const TexturedMesh* textured_mesh; //!< Pointer to the textured mesh if \ref Slicer::mesh is a TexturedMesh
TextureProximityProcessor* texture_proximity_processor; //!< Containers for each layer for fast lookup of textures being defined in the proximity of the lookup point
/*!
*
* \param texture_proximity_processors (optional) A TextureProximityProcessor for all layers in the mesh
*/
Slicer(Mesh* mesh, int initial, int thickness, unsigned int slice_layer_count, bool keepNoneClosed, bool extensiveStitching, TextureProximityProcessor* texture_proximity_processors);
/*!
* Linear interpolation
*
* Get the Y of a point with X \p x in the line through (\p x0, \p y0) and (\p x1, \p y1)
*
* \param p The face vertice locations in the order the vertices are given in the face
*/
int64_t interpolate(int64_t x, int64_t x0, int64_t x1, int64_t y0, int64_t y1) const
{
int64_t dx_01 = x1 - x0;
int64_t num = (y1 - y0) * (x - x0);
num += num > 0 ? dx_01/2 : -dx_01/2; // add in offset to round result
int64_t y = y0 + num / dx_01;
return y;
}
/*!
*
* \warning this function requires result.faceIndex to be correctly set already
*
* \p result where to store the start and end of the sliced segment
*/
void project2D(unsigned int face_idx, const Point3 p[3], unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, int32_t layer_nr, SlicerSegment& result);
void dumpSegmentsToHTML(const char* filename);
};
}//namespace cura
#endif//SLICER_SLICER_H
+28 -128
Ver Arquivo
@@ -1,21 +1,29 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include <algorithm> // remove_if
#include "SlicerLayer.h"
#include "../textureProcessing/TextureBumpMapProcessor.h"
#include "../utils/SparsePointGridInclusive.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/SparsePointGridInclusive.h"
#include "slicer.h"
namespace cura {
namespace cura
{
int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance between two line segments regarded as connected
int largest_neglected_gap_second_phase = MM2INT(0.02); //!< distance between two line segments regarded as connected
int max_stitch1 = MM2INT(10.0); //!< maximal distance stitched between open polylines to form polygons
SlicerLayer::SlicerLayer(unsigned int layer_nr, Mesh* mesh, std::optional<TextureBumpMapProcessor::Settings> bump_map_settings, FaceNormalStorage* face_normal_storage)
: layer_nr(layer_nr)
{
if (bump_map_settings)
{
TexturedMesh* textured_mesh = dynamic_cast<TexturedMesh*>(mesh);
assert(textured_mesh && "we should only have bump map settings when there is a texture");
texture_bump_map.emplace(textured_mesh, *bump_map_settings, face_normal_storage);
}
}
void SlicerLayer::makeBasicPolygonLoops(const Mesh* mesh, Polygons& open_polylines)
{
for(unsigned int start_segment_idx = 0; start_segment_idx < segments.size(); start_segment_idx++)
@@ -216,7 +224,7 @@ SlicerLayer::findPossibleStitches(
// insert the starts of the polylines).
for(unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++)
{
ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx];
const PolygonRef polyline_0 = open_polylines[polyline_0_idx];
if (polyline_0.size() < 1) continue;
@@ -231,7 +239,7 @@ SlicerLayer::findPossibleStitches(
{
for(unsigned int polyline_0_idx = 0; polyline_0_idx < open_polylines.size(); polyline_0_idx++)
{
ConstPolygonRef polyline_0 = open_polylines[polyline_0_idx];
const PolygonRef polyline_0 = open_polylines[polyline_0_idx];
if (polyline_0.size() < 1) continue;
@@ -245,7 +253,7 @@ SlicerLayer::findPossibleStitches(
// search for nearby end points
for(unsigned int polyline_1_idx = 0; polyline_1_idx < open_polylines.size(); polyline_1_idx++)
{
ConstPolygonRef polyline_1 = open_polylines[polyline_1_idx];
const PolygonRef polyline_1 = open_polylines[polyline_1_idx];
if (polyline_1.size() < 1) continue;
@@ -774,6 +782,11 @@ void SlicerLayer::makePolygons(const Mesh* mesh, bool keep_none_closed, bool ext
auto it = std::remove_if(polygons.begin(), polygons.end(), [snapDistance](PolygonRef poly) { return poly.shorterThan(snapDistance); });
polygons.erase(it, polygons.end());
if (texture_bump_map)
{
texture_bump_map->processBumpMap(polygons, layer_nr);
}
//Finally optimize all the polygons. Every point removed saves time in the long run.
polygons.simplify();
@@ -786,117 +799,4 @@ void SlicerLayer::makePolygons(const Mesh* mesh, bool keep_none_closed, bool ext
}
}
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keep_none_closed, bool extensive_stitching)
: mesh(mesh)
{
assert(slice_layer_count > 0);
TimeKeeper slice_timer;
layers.resize(slice_layer_count);
for(int32_t layer_nr = 0; layer_nr < slice_layer_count; layer_nr++)
{
layers[layer_nr].z = initial + thickness * layer_nr;
}
for(unsigned int mesh_idx = 0; mesh_idx < mesh->faces.size(); mesh_idx++)
{
const MeshFace& face = mesh->faces[mesh_idx];
const MeshVertex& v0 = mesh->vertices[face.vertex_index[0]];
const MeshVertex& v1 = mesh->vertices[face.vertex_index[1]];
const MeshVertex& v2 = mesh->vertices[face.vertex_index[2]];
Point3 p0 = v0.p;
Point3 p1 = v1.p;
Point3 p2 = v2.p;
int32_t minZ = p0.z;
int32_t maxZ = p0.z;
if (p1.z < minZ) minZ = p1.z;
if (p2.z < minZ) minZ = p2.z;
if (p1.z > maxZ) maxZ = p1.z;
if (p2.z > maxZ) maxZ = p2.z;
int32_t layer_max = (maxZ - initial) / thickness;
for(int32_t layer_nr = (minZ - initial) / thickness; layer_nr <= layer_max; layer_nr++)
{
int32_t z = layer_nr * thickness + initial;
if (z < minZ) continue;
if (layer_nr < 0) continue;
SlicerSegment s;
s.endVertex = nullptr;
int end_edge_idx = -1;
if (p0.z < z && p1.z >= z && p2.z >= z)
{
s = project2D(p0, p2, p1, z);
end_edge_idx = 0;
if (p1.z == z)
{
s.endVertex = &v1;
}
}
else if (p0.z > z && p1.z < z && p2.z < z)
{
s = project2D(p0, p1, p2, z);
end_edge_idx = 2;
}
else if (p1.z < z && p0.z >= z && p2.z >= z)
{
s = project2D(p1, p0, p2, z);
end_edge_idx = 1;
if (p2.z == z)
{
s.endVertex = &v2;
}
}
else if (p1.z > z && p0.z < z && p2.z < z)
{
s = project2D(p1, p2, p0, z);
end_edge_idx = 0;
}
else if (p2.z < z && p1.z >= z && p0.z >= z)
{
s = project2D(p2, p1, p0, z);
end_edge_idx = 2;
if (p0.z == z)
{
s.endVertex = &v0;
}
}
else if (p2.z > z && p1.z < z && p0.z < z)
{
s = project2D(p2, p0, p1, z);
end_edge_idx = 1;
}
else
{
//Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
// on the slice would create two segments
continue;
}
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(mesh_idx, layers[layer_nr].segments.size()));
s.faceIndex = mesh_idx;
s.endOtherFaceIdx = face.connected_face_index[end_edge_idx];
s.addedToPolygon = false;
layers[layer_nr].segments.push_back(s);
}
}
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
std::vector<SlicerLayer>& layers_ref = layers; // force layers not to be copied into the threads
#pragma omp parallel for default(none) shared(mesh,layers_ref) firstprivate(keep_none_closed, extensive_stitching)
for(unsigned int layer_nr=0; layer_nr<layers_ref.size(); layer_nr++)
{
layers_ref[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
}
mesh->expandXY(mesh->getSettingInMicrons("xy_offset"));
log("slice make polygons took %.3f seconds\n",slice_timer.restart());
}
}//namespace cura
} // namespace cura
+30 -80
Ver Arquivo
@@ -1,58 +1,46 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_H
#define SLICER_H
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_LAYER_H
#define SLICER_SLICER_LAYER_H
#include <queue>
#include <unordered_map>
#include "mesh.h"
#include "utils/polygon.h"
/*
The Slicer creates layers of polygons from an optimized 3D model.
The result of the Slicer is a list of polygons without any order or structure.
*/
namespace cura {
#include "../utils/optional.h"
#include "../mesh.h"
#include "../utils/intpoint.h"
#include "../utils/polygon.h"
class SlicerSegment
#include "SlicerSegment.h"
#include "GapCloserResult.h"
#include "ClosePolygonResult.h"
#include "../textureProcessing/MatSegment.h"
#include "../textureProcessing/TextureBumpMapProcessor.h"
#include "../textureProcessing/FaceNormalStorage.h"
namespace cura
{
public:
Point start, end;
int faceIndex = -1;
// The index of the other face connected via the edge that created end
int endOtherFaceIdx = -1;
// If end corresponds to a vertex of the mesh, then this is populated
// with the vertex that it ended on.
const MeshVertex *endVertex = nullptr;
bool addedToPolygon = false;
};
class ClosePolygonResult
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
//The line on which the point lays is between pointIdx-1 and pointIdx
public:
Point intersectionPoint;
int polygonIdx = -1;
unsigned int pointIdx = -1;
};
class GapCloserResult
{
public:
int64_t len = -1;
int polygonIdx = -1;
unsigned int pointIdxA = -1;
unsigned int pointIdxB = -1;
bool AtoB = false;
};
class SlicerLayer
{
public:
/*!
* \param mesh For which mesh this layer is sliced
* \param bump_map_settings The settings with which to create a TextureBumpMapProcessor - if provided
* \param face_normal_storage The face normal statistics to be used in the \p bump_map_settings - if provided
*/
SlicerLayer(unsigned int layer_nr, Mesh* mesh, std::optional<TextureBumpMapProcessor::Settings> bump_map_settings, FaceNormalStorage* face_normal_storage);
std::vector<SlicerSegment> segments;
std::unordered_map<int, int> face_idx_to_segment_idx; // topology
int z = -1;
unsigned int layer_nr;
Polygons polygons;
Polygons openPolylines;
std::optional<TextureBumpMapProcessor> texture_bump_map; //!< the bump map to apply to the outlines - if any
/*!
* Connect the segments into polygons for this layer of this \p mesh
*
@@ -483,44 +471,6 @@ private:
bool allow_reverse);
};
class Slicer
{
public:
std::vector<SlicerLayer> layers;
} // namespace cura
const Mesh* mesh = nullptr; //!< The sliced mesh
Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keepNoneClosed, bool extensiveStitching);
/*!
* Linear interpolation
*
* Get the Y of a point with X \p x in the line through (\p x0, \p y0) and (\p x1, \p y1)
*/
int64_t interpolate(int64_t x, int64_t x0, int64_t x1, int64_t y0, int64_t y1) const
{
int64_t dx_01 = x1 - x0;
int64_t num = (y1 - y0) * (x - x0);
num += num > 0 ? dx_01/2 : -dx_01/2; // add in offset to round result
int64_t y = y0 + num / dx_01;
return y;
}
SlicerSegment project2D(Point3& p0, Point3& p1, Point3& p2, int32_t z) const
{
SlicerSegment seg;
seg.start.X = interpolate(z, p0.z, p1.z, p0.x, p1.x);
seg.start.Y = interpolate(z, p0.z, p1.z, p0.y, p1.y);
seg.end .X = interpolate(z, p0.z, p2.z, p0.x, p2.x);
seg.end .Y = interpolate(z, p0.z, p2.z, p0.y, p2.y);
return seg;
}
void dumpSegmentsToHTML(const char* filename);
};
}//namespace cura
#endif//SLICER_H
#endif // SLICER_SLICER_LAYER_H
+59
Ver Arquivo
@@ -0,0 +1,59 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_SEGMENT_H
#define SLICER_SLICER_SEGMENT_H
#include <functional>
#include "../utils/intpoint.h"
#include "../mesh.h"
namespace cura
{
class SlicerSegment
{
public:
Point start, end;
int faceIndex = -1;
// The index of the other face connected via the edge that created end
int endOtherFaceIdx = -1;
// If end corresponds to a vertex of the mesh, then this is populated
// with the vertex that it ended on.
const MeshVertex *endVertex = nullptr;
bool addedToPolygon = false;
SlicerSegment() //!< non-initializing constructor
{}
SlicerSegment(Point start, Point end) //!< partially initializing constructor
: start(start)
, end(end)
{}
/*!
* equivalence testing irrespective of start/end order
*/
bool operator==(const SlicerSegment& b) const
{
return (start == b.start && end == b.end) || (start == b.end && end == b.start);
}
};
} // namespace cura
namespace std
{
/*!
* hash function irrespective of start/end order
*/
template<> struct hash<cura::SlicerSegment>
{
typedef std::size_t result_type;
result_type operator()(cura::SlicerSegment const& s) const
{
return std::hash<cura::Point>()(cura::operator+(s.start, s.end));
}
};
} // namespace std
#endif // SLICER_SLICER_SEGMENT_H
+49 -59
Ver Arquivo
@@ -90,7 +90,6 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
storage.support.supportLayers.resize(layer_count);
}
// generate support areas
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
{
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
@@ -101,33 +100,25 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
std::vector<Polygons> supportAreas;
supportAreas.resize(layer_count, Polygons());
generateSupportAreas(storage, mesh_idx, layer_count, supportAreas);
for (unsigned int layer_idx = 0; layer_idx < layer_count; layer_idx++)
if (mesh.getSettingBoolean("support_interface_enable"))
{
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[layer_idx]);
generateSupportInterface(storage, mesh, supportAreas, layer_count);
}
else
{
for (unsigned int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
{
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[layer_idx]);
}
}
}
for (unsigned int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
{
Polygons& support_areas = storage.support.supportLayers[layer_idx].supportAreas;
support_areas = support_areas.unionPolygons();
}
// handle support interface
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
{
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
if (mesh.getSettingBoolean("infill_mesh") || mesh.getSettingBoolean("anti_overhang_mesh"))
{
continue;
}
if (mesh.getSettingBoolean("support_interface_enable"))
{
generateSupportInterface(storage, mesh, layer_count);
}
}
}
/*
@@ -165,7 +156,6 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
const int supportTowerDiameter = mesh.getSettingInMicrons("support_tower_diameter");
const int supportMinAreaSqrt = mesh.getSettingInMicrons("support_minimal_diameter");
const double supportTowerRoofAngle = mesh.getSettingInAngleRadians("support_tower_roof_angle");
const bool use_towers = mesh.getSettingBoolean("support_use_towers") && supportMinAreaSqrt > 0;
const int layerThickness = storage.getSettingInMicrons("layer_height");
const int supportXYDistance = mesh.getSettingInMicrons("support_xy_distance");
@@ -235,10 +225,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
std::vector<std::pair<int, std::vector<Polygons>>> overhang_points; // stores overhang_points along with the layer index at which the overhang point occurs
if (use_towers)
{
AreaSupport::detectOverhangPoints(storage, mesh, overhang_points, layer_count, supportMinAreaSqrt);
}
AreaSupport::detectOverhangPoints(storage, mesh, overhang_points, layer_count, supportMinAreaSqrt);
std::deque<std::pair<Polygons, Polygons>> basic_and_full_overhang_above;
for (unsigned int layer_idx = support_layer_count - 1; layer_idx != support_layer_count - 1 - layerZdistanceTop ; layer_idx--)
@@ -268,7 +255,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
supportLayer_this = supportLayer_this.offset(extension_offset);
}
if (use_towers)
if (supportMinAreaSqrt > 0)
{
// handle straight walls
AreaSupport::handleWallStruts(supportLayer_this, supportMinAreaSqrt, supportTowerDiameter);
@@ -355,14 +342,14 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
}
//Enforce top Z distance.
if (layerZdistanceTop > 1)
if (layerZdistanceTop > 0)
{
// this is performed after the main support generation loop above, because it affects the joining of polygons
// if this would be performed in the main loop then some support would not have been generated under the overhangs and consequently no support is generated for that,
// meaning almost no support would be generated in some cases which definitely need support.
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - (layerZdistanceTop - 1); layer_idx++)
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - layerZdistanceTop; layer_idx++)
{
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop - 1, false));
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop, false));
}
}
@@ -572,7 +559,7 @@ void AreaSupport::handleWallStruts(
}
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, const unsigned int layer_count)
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count)
{
const unsigned int roof_layer_count = round_divide(mesh.getSettingInMicrons("support_roof_height"), storage.getSettingInMicrons("layer_height"));
const unsigned int bottom_layer_count = round_divide(mesh.getSettingInMicrons("support_bottom_height"), storage.getSettingInMicrons("layer_height"));
@@ -589,41 +576,44 @@ void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const Slic
const unsigned int top_layer_idx_above = layer_idx + roof_layer_count + z_distance_top;
const unsigned int bottom_layer_idx_below = std::max(0, int(layer_idx) - int(bottom_layer_count) - int(z_distance_bottom));
if (top_layer_idx_above >= supportLayers.size())
if (top_layer_idx_above < supportLayers.size())
{
continue;
}
Polygons roofs;
if (roof_layer_count > 0)
{
Polygons model;
const unsigned int n_scans = std::max(1u, (roof_layer_count - 1) / skip_layer_count);
const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(n_scans));
for (float layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip)
Polygons roofs;
if (roof_layer_count > 0)
{
const Polygons outlines_above = mesh.layers[std::round(layer_idx_above)].getOutlines();
model = model.unionPolygons(outlines_above);
Polygons model;
const unsigned int n_scans = std::max(1u, (roof_layer_count - 1) / skip_layer_count);
const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(n_scans));
for (float layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip)
{
const Polygons outlines_above = mesh.layers[std::round(layer_idx_above)].getOutlines();
model = model.unionPolygons(outlines_above);
}
roofs = support_areas[layer_idx].intersection(model);
}
roofs = layer.supportAreas.intersection(model);
}
Polygons bottoms;
if (bottom_layer_count > 0)
{
Polygons model;
const unsigned int n_scans = std::max(1u, (bottom_layer_count - 1) / skip_layer_count);
const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(n_scans));
for (float layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip)
Polygons bottoms;
if (bottom_layer_count > 0)
{
const Polygons outlines_below = mesh.layers[std::round(layer_idx_below)].getOutlines();
model = model.unionPolygons(outlines_below);
Polygons model;
const unsigned int n_scans = std::max(1u, (bottom_layer_count - 1) / skip_layer_count);
const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(n_scans));
for (float layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip)
{
const Polygons outlines_below = mesh.layers[std::round(layer_idx_below)].getOutlines();
model = model.unionPolygons(outlines_below);
}
bottoms = support_areas[layer_idx].intersection(model);
}
bottoms = layer.supportAreas.intersection(model);
// expand skin a bit so that we're sure it's not too thin to be printed.
Polygons skin = roofs.unionPolygons(bottoms).offset(interface_line_width).intersection(support_areas[layer_idx]);
skin.removeSmallAreas(1.0);
layer.skin.add(skin);
layer.supportAreas.add(support_areas[layer_idx].difference(layer.skin));
}
else
{
layer.skin.add(support_areas[layer_idx]);
}
// expand skin a bit so that we're sure it's not too thin to be printed.
Polygons skin = roofs.unionPolygons(bottoms).offset(interface_line_width).intersection(layer.supportAreas);
skin.removeSmallAreas(1.0);
layer.skin.add(skin);
layer.supportAreas = layer.supportAreas.difference(layer.skin);
}
}
+2 -1
Ver Arquivo
@@ -36,9 +36,10 @@ private:
*
* \param storage Output storage: support area + support skin area output
* \param mesh The mesh to generate support skins for.
* \param support_areas The basic support areas for the current mesh
* \param layer_count The number of layers in this mesh group.
*/
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, const unsigned int layer_count);
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count);
/*!
* Join current support layer with the support of the layer above, (make support conical) and perform smoothing etc operations.
+59
Ver Arquivo
@@ -0,0 +1,59 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#include <limits> // numeric_limits
#include <cmath> // isnan
#include "FaceNormalStorage.h"
#include <math.h> // debug
#define NORMAL_LENGTH 10000
namespace cura
{
FaceNormalStorage::FaceNormalStorage(Mesh* mesh)
{
face_normal_vertical_component.reserve(mesh->faces.size());
for (MeshFace& face : mesh->faces)
{
Point3 p0 = mesh->vertices[face.vertex_index[0]].p;
Point3 p1 = mesh->vertices[face.vertex_index[1]].p;
Point3 p2 = mesh->vertices[face.vertex_index[2]].p;
face_normal_vertical_component.emplace_back(computeFaceTanAngle(p0, p1, p2));
}
}
float FaceNormalStorage::computeFaceTanAngle(const Point3 p0, const Point3 p1, const Point3 p2) const
{
Point3 v01 = p1 - p0;
Point3 v01_n = v01.normal(NORMAL_LENGTH);
Point3 v02 = p2 - p0;
Point3 v02_n = v02.normal(NORMAL_LENGTH);
Point3 normal_dir = v01_n.cross(v02_n);
coord_t z_component = normal_dir.z;
coord_t xy_component = vSize(Point(normal_dir.x, normal_dir.y));
if (xy_component > -2 && xy_component < 2)
{
if (z_component > 0)
{
return std::numeric_limits<float>::infinity();
}
else
{
return -1 * std::numeric_limits<float>::infinity();
}
}
float ret = (float) z_component / (float) xy_component;
assert(!std::isnan(ret));
assert(!std::isnan(-ret));
return ret;
}
float FaceNormalStorage::getFaceTanAngle(unsigned int face_idx)
{
return face_normal_vertical_component[face_idx];
}
} // namespace cura
+42
Ver Arquivo
@@ -0,0 +1,42 @@
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_FACE_NORMAL_STORAGE_H
#define TEXTURE_PROCESSING_FACE_NORMAL_STORAGE_H
#include "../mesh.h"
#include "../utils/NoCopy.h"
namespace cura
{
/*!
* helper class for storing mesh face data to be used by each TextureBumpMapProcessor of one mesh
*/
class FaceNormalStorage : NoCopy
{
public:
/*!
* Constructor to compute the tan angle for all faces in the model.
*/
FaceNormalStorage(Mesh* mesh);
/*!
* Get the horizontal component of the face normal
*
* returns a negative amount for faces angling downward
* (TODO verify above sentence)
* \return the ratio between the vertical and the horizontal aspect of the normal of the face with index \p face_index (in the list of faes in the \ref Mesh)
*/
float getFaceTanAngle(unsigned int face_idx);
protected:
/*!
* compute the tan angle of one face
* \p p0, \p p1 and \p p2 should be in CCW order
*/
float computeFaceTanAngle(const Point3 p0, const Point3 p1, const Point3 p2) const;
std::vector<float> face_normal_vertical_component; //!< for each face the horizontal component of the normal angle
};
} // namespace cura
#endif // TEXTURE_PROCESSING_FACE_NORMAL_STORAGE_H
+44
Ver Arquivo
@@ -0,0 +1,44 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_MAT_COORD_H
#define TEXTURE_PROCESSING_MAT_COORD_H
#include "../utils/FPoint.h"
#include "Material.h"
namespace cura
{
/*!
* Coordinates in a specific texture bitmap
*/
struct MatCoord
{
FPoint coords;
const Material* mat; //!< Material id
MatCoord() //!< non-initializing constructor
{}
MatCoord(FPoint coords, const Material& mat) //!< constructor
: coords(coords)
, mat(&mat)
{}
/*!
* Get the color of the material to which this coordinate is pointing
*/
float getColor(ColourUsage color) const
{
if (mat)
{
return mat->getColor(coords.x, coords.y, color);
}
else
{
return 0.0f;
}
}
};
} // namespace cura
#endif // TEXTURE_PROCESSING_MAT_COORD_H
+27
Ver Arquivo
@@ -0,0 +1,27 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_MAT_SEGMENT_H
#define TEXTURE_PROCESSING_MAT_SEGMENT_H
#include "MatCoord.h"
namespace cura
{
/*!
* Coordinates in a specific texture bitmap
*/
struct MatSegment
{
MatCoord start;
MatCoord end;
MatSegment() //!< non-initializing constructor
{}
MatSegment(MatCoord start, MatCoord end)
: start(start)
, end(end)
{}
};
} // namespace cura
#endif // TEXTURE_PROCESSING_MAT_SEGMENT_H
+178
Ver Arquivo
@@ -0,0 +1,178 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include <limits> // numeric limits
#include <algorithm> // min max
#include <iostream>
#include <cassert>
#include "Material.h"
#define STBI_FAILURE_USERMSG // enable user friendly bug messages for STB lib
#define STB_IMAGE_IMPLEMENTATION // needed in order to enable the implementation of libs/std_image.h
#include "stb/stb_image.h"
namespace cura
{
/*!
* custom destructor for the data to be used by the shared_pointer
*/
struct ArrayDeleter
{
void operator ()(unsigned char* p)
{
stbi_image_free(p);
}
};
Material::Material()
: data(nullptr, ArrayDeleter())
, width(0)
, height(0)
, depth(0)
{
}
Material::~Material()
{
}
void Material::loadImage(const char* filename)
{
int w, h, d;
// in RGBA order
int desired_channel_count = 0; // keep original amount of channels
unsigned char* data = stbi_load(filename, &w, &h, &d, desired_channel_count);
if (data)
{
width = w;
height = h;
depth = d;
this->data = std::shared_ptr<unsigned char>(data);
}
else
{
const char* reason = "[unknown reason]";
if (stbi_failure_reason())
{
reason = stbi_failure_reason();
}
logError("Cannot load image %s: '%s'.\n", filename, reason);
std::exit(-1);
}
}
float Material::getColor(float x, float y, ColourUsage color) const
{
if (!data)
{
return 0.0;
}
assert(x >= 0.0f && x <= 1.0f);
assert(y >= 0.0f && y <= 1.0f);
switch (color)
{
case ColourUsage::RED:
case ColourUsage::GREEN:
case ColourUsage::BLUE:
case ColourUsage::ALPHA:
{
assert((int)color >= 0 && (unsigned int)color < depth && "Z out of bounds!");
return getColorData(x, y, (unsigned int) color);
}
case ColourUsage::GREY:
default:
{
float r = getColorData(x, y, (unsigned int) ColourUsage::RED);
float g = getColorData(x, y, (unsigned int) ColourUsage::GREEN);
float b = getColorData(x, y, (unsigned int) ColourUsage::BLUE);
return (r + g + b) / 3.0;
}
}
}
float Material::getColorData(float x, float y, unsigned int z) const
{
unsigned int x_idx = (unsigned int) (x * (width - 1) + 0.5);
assert(x_idx >= 0 && x_idx < width && "requested X is out of bounds!");
unsigned int y_idx = (unsigned int) (y * (height - 1) + 0.5);
assert(y_idx >= 0 && y_idx < height && "requested Y is out of bounds!");
unsigned char col = data.get()[((height - y_idx - 1) * width + x_idx) * depth + z];
return (float) col / std::numeric_limits<unsigned char>::max();
}
void Material::debugOutput(bool dw) const
{
std::cerr << "\nImage size: " << width << " x " << height << " (" << depth << "channels)\n";
std::cerr << '+';
for (unsigned int i = 0; i < width; i++)
{
std::cerr << ((dw)? "--" : "-");
}
std::cerr << "+\n";
for (unsigned int y = 0; y < height; y++)
{
std::cerr << "|";
for (unsigned int x = 0; x < width; x++)
{
int val = (data.get()[((height - y) * width + x) * depth] * 10 / 256);
switch (val)
{
case 0:
std::cerr << ((dw)? " " : " ");
break;
case 1:
std::cerr << ((dw)? ".." : ".");
break;
case 2:
std::cerr << ((dw)? ",," : ",");
break;
case 3:
std::cerr << ((dw)? "::" : ":");
break;
case 4:
std::cerr << ((dw)? ";;" : ";");
break;
case 5:
std::cerr << ((dw)? "++" : "+");
break;
case 6:
std::cerr << ((dw)? "░░" : "");
break;
case 7:
std::cerr << ((dw)? "▒▒" : "");
break;
case 8:
std::cerr << ((dw)? "▓▓" : "");
break;
default:
if (val > 8)
{
std::cerr << ((dw)? "██" : "");
}
else
{
std::cerr << ((dw)? " " : " ");
}
}
}
std::cerr << "|\n";
}
std::cerr << '+';
for (unsigned int i = 0; i < width; i++)
{
std::cerr << ((dw)? "--" : "-");
}
std::cerr << "+\n";
}
} // namespace cura
+71
Ver Arquivo
@@ -0,0 +1,71 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_MATERIAL_H
#define TEXTURE_PROCESSING_MATERIAL_H
#include <memory> // shared_ptr
#include "../settings/settings.h" // ColourUsage
namespace cura
{
/*!
* The material used in a texture.
*
* This class just holds the image data and has some nice utility functions.
*/
class Material
{
public:
/*!
* non-initializing constructor
*/
Material();
/*!
* Destructor
*
* deletes the image data
*/
~Material();
/*!
* Load an image from file.
*
* Crash if this doesn't work. (unsupported file type, IO exception, etc.)
*/
void loadImage(const char* filename);
/*!
* get the color value at a particular place in the image
*
* \param x place in the horizontal direction left to right (value between zero and one)
* \param y place in the vertical direction top to bottom (value between zero and one)
* \param color The color channel to check
* \return a value between zero and one
*/
float getColor(float x, float y, ColourUsage color) const;
/*!
* print out something which looks like the picture through std::cerr
* \param double_width Whether to double each character being written, so that the width is visually similar to the height of each pixel.
*/
void debugOutput(bool double_width = true) const;
protected:
std::shared_ptr<unsigned char> data; //!< pixel data in rgb-row-first (or bgr-row first ?)
unsigned int width, height, depth; //!< image dimensions
/*!
* Get a color value from the data
* \param x place in the horizontal direction left to right (value between zero and one)
* \param y place in the vertical direction top to bottom (value between zero and one)
* \return the color data (0-256)
*/
float getColorData(float x, float y, unsigned int z) const;
};
} // namespace cura
#endif // TEXTURE_PROCESSING_MATERIAL_H
+42
Ver Arquivo
@@ -0,0 +1,42 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "MaterialBase.h"
namespace cura
{
Material* MaterialBase::add(std::string name)
{
name_to_mat_idx[name] = materials.size();
materials.emplace_back();
return &materials.back();
}
const Material* MaterialBase::getMat(unsigned int id) const
{
if (id < materials.size())
{
return &materials[id];
}
else
{
return nullptr;
}
}
int MaterialBase::getMatId(std::string name) const
{
auto it = name_to_mat_idx.find(name);
if (it == name_to_mat_idx.end())
{
return -1;
}
else
{
return it->second;
}
}
} // namespace cura
+27
Ver Arquivo
@@ -0,0 +1,27 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_MATERIAL_BASE_H
#define TEXTURE_PROCESSING_MATERIAL_BASE_H
#include <unordered_map>
#include <string>
#include <vector>
#include "Material.h"
namespace cura
{
class MaterialBase
{
public:
int getMatId(std::string name) const;
Material* add(std::string name);
const Material* getMat(unsigned int id) const;
protected:
std::unordered_map<std::string, int> name_to_mat_idx;
std::vector<Material> materials;
};
} // namespace cura
#endif // TEXTURE_PROCESSING_MATERIAL_BASE_H
@@ -0,0 +1,289 @@
#include "TextureBumpMapProcessor.h"
#include <algorithm> // swap
#include <cmath> // fabs
#include "../utils/optional.h"
#include "../utils/linearAlg2D.h"
#include "../slicer/SlicerSegment.h"
namespace cura
{
#define SLICE_SEGMENT_SNAP_GAP 20
TextureBumpMapProcessor::TextureBumpMapProcessor(TexturedMesh* mesh, const TextureBumpMapProcessor::Settings settings, FaceNormalStorage* face_normal_storage)
: mesh(mesh)
, settings(settings)
, face_normal_storage(face_normal_storage)
, loc_to_slice(SLICE_SEGMENT_SNAP_GAP)
{
}
void TextureBumpMapProcessor::registerTexturedFaceSlice(SlicerSegment face_segment, MatSegment texture_segment)
{
assert(face_segment.faceIndex >= 0);
TexturedFaceSlice slice{face_segment, texture_segment};
loc_to_slice.insert(face_segment.start, slice);
loc_to_slice.insert(face_segment.end, slice);
}
std::optional<TextureBumpMapProcessor::TexturedFaceSlice> TextureBumpMapProcessor::getTexturedFaceSlice(Point p0, Point p1)
{
std::vector<TexturedFaceSlice> nearby_slices = loc_to_slice.getNearby(p0, SLICE_SEGMENT_SNAP_GAP);
std::optional<TexturedFaceSlice> best;
coord_t best_dist_score = std::numeric_limits<coord_t>::max();
for (TexturedFaceSlice& slice : nearby_slices)
{
coord_t dist_score = std::min(
vSize2(slice.face_segment.start - p0) + vSize2(slice.face_segment.end - p1)
, vSize2(slice.face_segment.end - p0) + vSize2(slice.face_segment.start - p1)
);
if (dist_score < best_dist_score)
{
best = slice;
best_dist_score = dist_score;
}
}
if (best_dist_score > SLICE_SEGMENT_SNAP_GAP * SLICE_SEGMENT_SNAP_GAP * 4) // TODO: this condition doesn't follow exactly from using SLICE_SEGMENT_SNAP_GAP and the quadratic dist score
{
return std::optional<TextureBumpMapProcessor::TexturedFaceSlice>();
}
if (vSize2(best->face_segment.start - p0) > vSize2(best->face_segment.start - p1))
{
std::swap(best->face_segment.start, best->face_segment.end);
}
assert(best->face_segment.faceIndex >= 0);
return best;
}
coord_t TextureBumpMapProcessor::getOffset(const float color, const int face_idx)
{
coord_t extra_offset = 0;
if (face_normal_storage)
{
assert(face_idx >= 0 && "we must know for which face we are getting the color");
float tan_angle = face_normal_storage->getFaceTanAngle(face_idx);
float abs_tan_angle = std::fabs(tan_angle);
abs_tan_angle = std::min(abs_tan_angle, settings.max_tan_correction_angle);
extra_offset = settings.face_angle_correction * (color - 0.5) * abs_tan_angle * settings.layer_height;
// (color - 0.5) so that the color causes either an outset or an inset which is
// within the range [-0.5, 0.5] so that when at max it will coincide with the min on the previous layer:
//
// for a black mesh
// bridged gap = 4 applied offset = 2 and -2
// ^^^^ ^^
// ____ ______^^
// :_______ :_____
// : : : will become : : :
}
return color * (settings.amplitude * 2) - settings.amplitude + settings.offset + extra_offset;
}
coord_t TextureBumpMapProcessor::getCornerOffset(std::optional<TextureBumpMapProcessor::TexturedFaceSlice>& textured_face_slice, std::optional<TextureBumpMapProcessor::TexturedFaceSlice>& next_textured_face_slice)
{
coord_t offset0 = 0; // where no texture is present, no offset is applied
coord_t offset1 = 0;
if (textured_face_slice)
{
const float color0 = textured_face_slice->mat_segment.end.getColor(settings.color_usage);
const int face_0_idx = textured_face_slice->face_segment.faceIndex;
offset0 = getOffset(color0, face_0_idx);
}
if (next_textured_face_slice)
{
const float color1 = next_textured_face_slice->mat_segment.start.getColor(settings.color_usage);
const int face_1_idx = next_textured_face_slice->face_segment.faceIndex;
offset1 = getOffset(color1, face_1_idx);
}
coord_t offset = (offset0 + offset1) / 2;
return offset;
}
coord_t TextureBumpMapProcessor::getCornerDisregard(Point p0, Point p1, Point p2, std::optional<TextureBumpMapProcessor::TexturedFaceSlice>& textured_face_slice, std::optional<TextureBumpMapProcessor::TexturedFaceSlice>& next_textured_face_slice)
{
coord_t offset = getCornerOffset(textured_face_slice, next_textured_face_slice);
if ((LinearAlg2D::pointIsLeftOfLine(p1, p0, p2) < 0) == (offset > 0))
{
return 0;
}
Point v01 = p1 - p0;
Point v12 = p2 - p1;
assert(p0 != p1 && "Code below depends on v01 not being of zer o size");
assert(p1 != p2 && "This function assumes the three points are different");
Point n01 = normal(turn90CCW(v01), -1000);
Point n12 = normal(turn90CCW(v12), -1000);
Point corner_normal = n01 + n12;
coord_t corner_normal_size2 = vSize2(corner_normal);
coord_t normal_aspect = dot(corner_normal, v01) / vSize(v01); // The aspect of the corner normal along v01 (might be negative)
coord_t dist_aspect = sqrt(std::max((coord_t)1, corner_normal_size2 - normal_aspect * normal_aspect)); // The distance of the end of the normal vector to v01 or v12
// ^ due to rounding errors 'corner_normal_size2 - normal_aspect^2' may be smaller than zero; because of division on line below should be at least 1
coord_t disregard = std::abs(offset * normal_aspect) / dist_aspect;
assert(disregard >= 0);
return disregard;
}
void TextureBumpMapProcessor::processSegmentBumpMap(unsigned int layer_nr, const SlicerSegment& slicer_segment, const MatSegment& mat, const Point p0, const Point p1, coord_t& dist_left_over, coord_t corner_disregard_p1, PolygonRef result)
{
assert(mat.start.mat == mat.end.mat && "texture across face must be from one material!");
Point p0p1 = p1 - p0;
int64_t p0p1_size = vSize(p0p1);
if (dist_left_over >= p0p1_size - corner_disregard_p1)
{
dist_left_over -= p0p1_size;
return;
}
Point perp_to_p0p1 = turn90CCW(p0p1);
int64_t dist_last_point = -1; // p0p1_size * 2 - dist_left_over; // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size
for (int64_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size - corner_disregard_p1; p0pa_dist += settings.point_distance)
{
assert(p0pa_dist >= 0);
assert(p0pa_dist <= p0p1_size);
MatCoord mat_coord_now = mat.start;
mat_coord_now.coords = mat.start.coords + (mat.end.coords - mat.start.coords) * p0pa_dist / p0p1_size;
float val = mat_coord_now.getColor(settings.color_usage);
int offset = getOffset(val, slicer_segment.faceIndex);
Point fuzz = normal(perp_to_p0p1, offset);
Point pa = p0 + normal(p0p1, p0pa_dist) - fuzz;
result.add(pa);
dist_last_point = p0pa_dist;
}
assert(dist_last_point >= 0 && "above loop should have run at least once!");
assert(p0p1_size > dist_last_point);
dist_left_over = p0p1_size - dist_last_point;
assert(dist_left_over <= settings.point_distance + corner_disregard_p1);
}
void TextureBumpMapProcessor::processBumpMap(Polygons& layer_polygons, unsigned int layer_nr)
{
if (layer_polygons.size() == 0)
{
return;
}
Polygons preprocessed;
for (PolygonRef poly : layer_polygons)
{ // remove duplicate points
PolygonRef preprocessed_poly = preprocessed.newPoly();
Point p0 = poly.back();
for (const Point p1 : poly)
{
if (p1 == p0)
continue;
preprocessed_poly.add(p1);
p0 = p1;
}
}
Polygons results;
for (PolygonRef poly : preprocessed)
{
if (poly.size() < 3)
{
results.add(poly);
continue;
}
PolygonRef result = results.newPoly();
std::vector<std::optional<TexturedFaceSlice>> texture_poly;
{
Point p0 = poly.back();
for (Point& p1 : poly)
{
texture_poly.emplace_back(getTexturedFaceSlice(p0, p1));
p0 = p1;
}
}
coord_t corner_disregard_p0 = getCornerDisregard(poly[poly.size() - 2], poly.back(), poly[0], texture_poly.back(), texture_poly[0]);; // TODO
coord_t dist_left_over = (settings.point_distance / 2); // the distance to be traversed on the line before making the first new point
Point* p0 = &poly.back();
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{ // 'a' is the (next) new point between p0 and p1
Point& p1 = poly[point_idx];
unsigned int next_point_idx = (point_idx + 1 == poly.size())? 0 : point_idx + 1;
Point& p2 = poly[next_point_idx];
if (*p0 == p1)
{
continue;
}
std::optional<TexturedFaceSlice>& textured_face_slice = texture_poly[point_idx];
std::optional<TexturedFaceSlice>& next_textured_face_slice = texture_poly[next_point_idx];
coord_t corner_disregard_p1 = getCornerDisregard(*p0, p1, p2, textured_face_slice, next_textured_face_slice); // TODO
if (dist_left_over < corner_disregard_p0)
{
dist_left_over = corner_disregard_p0;
}
if (textured_face_slice)
{
processSegmentBumpMap(layer_nr, textured_face_slice->face_segment, textured_face_slice->mat_segment, *p0, p1, dist_left_over, corner_disregard_p1, result);
}
else
{
coord_t p0p1_size2 = vSize2(p1 - *p0);
if (p0p1_size2 < dist_left_over * dist_left_over)
{
dist_left_over -= sqrt(p0p1_size2);
}
else
{
result.emplace_back(*p0);
result.emplace_back(p1);
dist_left_over = settings.point_distance;
}
}
if (corner_disregard_p1 == 0
&& (textured_face_slice || next_textured_face_slice)
&& (textured_face_slice || !shorterThen(p1 - *p0, SLICE_SEGMENT_SNAP_GAP)) // don't introduce corner points for gap closer poly segments
&& (next_textured_face_slice || !shorterThen(p2 - p1, SLICE_SEGMENT_SNAP_GAP)) // don't introduce corner points for gap closer poly segments
)
{ // add point for outward corner
// TODO: remove code duplication with getCornerDisregard
coord_t offset = getCornerOffset(textured_face_slice, next_textured_face_slice);
Point v01 = p1 - *p0;
Point v12 = p2 - p1;
Point n01 = normal(turn90CCW(v01), -1000);
Point n12 = normal(turn90CCW(v12), -1000);
Point corner_normal = normal(n01 + n12, offset);
result.add(p1 + corner_normal);
}
p0 = &p1;
corner_disregard_p0 = corner_disregard_p1;
}
while (result.size() < 3 )
{
unsigned int point_idx = poly.size() - 2;
result.add(poly[point_idx]);
if (point_idx == 0) { break; }
point_idx--;
}
if (result.size() < 3)
{
result.clear();
for (Point& p : poly)
result.add(p);
}
}
// a negative offset on two sides of a corner, may introduce complexities in the model which should be removed:
// ^↘
// ^ ↘
// <<<<<<<<^<<<< should become <<<<<<<<
// ^ ^
// ^ ^
// ^ ^
layer_polygons = results.removeComplexParts();
}
}//namespace cura
@@ -0,0 +1,150 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_TEXTURE_BUMP_MAP_PROCESSOR_H
#define TEXTURE_PROCESSING_TEXTURE_BUMP_MAP_PROCESSOR_H
#include <vector>
#include <math.h> // tan
#include "../utils/polygon.h"
#include "../utils/optional.h"
#include "../utils/SparsePointGrid.h"
#include "../settings/settings.h"
#include "../slicer/SlicerSegment.h"
#include "TexturedMesh.h"
#include "FaceNormalStorage.h"
namespace cura
{
class TextureBumpMapProcessor
{
public:
/*!
* Helper class to retrieve and store texture to bump map settings
*/
struct Settings
{
coord_t layer_height;
coord_t point_distance;
coord_t amplitude;
coord_t offset;
bool alternate;
float face_angle_correction;
float max_tan_correction_angle;
ColourUsage color_usage;
Settings(SettingsBaseVirtual* settings_base)
: layer_height(settings_base->getSettingInMicrons("layer_height"))
, point_distance(settings_base->getSettingInMicrons("bump_map_point_dist"))
, amplitude(settings_base->getSettingInMicrons("bump_map_amplitude"))
, offset(settings_base->getSettingInMicrons("bump_map_offset"))
, alternate(settings_base->getSettingBoolean("bump_map_alternate"))
, face_angle_correction(settings_base->getSettingAsRatio("bump_map_face_angle_correction"))
, max_tan_correction_angle(std::tan(0.5 * M_PI - settings_base->getSettingInAngleRadians("bump_map_angle_correction_min")))
, color_usage(settings_base->getSettingAsColourUsage("bump_map_texture_color"))
{
}
};
/*!
* default constructor
*
* initializes the \ref SparseGrid::cell_size of \ref TextureBumpMapProcessor::loc_to_slice
*
* \param settings The settings with which to \ref TextureBumpMapProcessor::processBumpMap
*/
TextureBumpMapProcessor(TexturedMesh* mesh, const Settings settings, FaceNormalStorage* face_normal_storage);
/*!
* Process the texture bump map.
* Change the polygons in a layer
*
* \warning Where no texture is present, no offset is applied to the outer boundary!
* Such segments are copied to the result as is
*
* \param[in,out] layer_polygons The polygons to be offsetted by texture color values
* \param layer_nr The layer nr for which we are processing the bump map
*/
void processBumpMap(Polygons& layer_polygons, unsigned int layer_nr);
/*!
* Register that a particular face was sliced to a particular texture segment.
* \param face_segment The geometrical segment of the face
* \param texture_segment The corresponding texture coordinates
*/
void registerTexturedFaceSlice(SlicerSegment face_segment, MatSegment texture_segment);
protected:
/*!
* A sliced segment in combination with the corresponding texture slice.
*/
struct TexturedFaceSlice
{
SlicerSegment face_segment;
MatSegment mat_segment;
};
TexturedMesh* mesh;
/*!
* The settings with which to \ref TextureBumpMapProcessor::processBumpMap
*/
Settings settings;
/*!
* The face normal statistics to correct offsets for slanted faces - if provided
*
* This is stored as a pointer so that the default assignment operator = can be defined automatically.
*/
FaceNormalStorage* face_normal_storage;
/*!
* A grid to efficiently look op which texture segment best fits the slicer segment.
*/
SparseGrid<TexturedFaceSlice> loc_to_slice;
/*!
* Get the offset to be applied at a given location
*/
coord_t getOffset(const float color, const int face_idx);
/*!
* Get the offset to be applied at a given corner
*
* Computes the average offset from the end of \p textured_face_slice and start of \p next_textured_face_slice
* If either of those is not present, the \ref TextureBumpMapProcessor::Settings::default_color is used for that segment
*
* \warning Where no texture is present, no offset is applied to the outer boundary!
*
* \param textured_face_slice From which to determine the offset at the end of the line segment - or default to zero
* \param next_textured_face_slice From which to determine the offset at the start of the line segment - or default to zero
*/
coord_t getCornerOffset(std::optional<TextureBumpMapProcessor::TexturedFaceSlice>& textured_face_slice, std::optional<TextureBumpMapProcessor::TexturedFaceSlice>& next_textured_face_slice);
/*!
* Get how much of a corner to skip generating offsetted indices for inner corners,
* because those points would be removed by the offset itseld
*/
coord_t getCornerDisregard(Point p0, Point p1, Point p2, std::optional<TexturedFaceSlice>& textured_face_slice, std::optional<TexturedFaceSlice>& next_textured_face_slice);
/*!
* Get the TexturedFaceSlice corresponding to an outline segment
*
* Note that due to snapping in the \ref Slicer::makePolygons function, an outline segment may be a bit different from the originally sliced SlicerSegment
*
* \param p0 The start of the segment
* \param p1 The end of the segment
*/
std::optional<TexturedFaceSlice> getTexturedFaceSlice(Point p0, Point p1);
/*!
*
* \param layer_nr The layer number for which we process the bump map
* \param slicer_segment The segment closest matching \p p0 - \p p1
* \param corner_disregard_p1 The distance at the end of p0p1 in which not to place offsetted points
*/
void processSegmentBumpMap(unsigned int layer_nr, const SlicerSegment& slicer_segment, const MatSegment& mat, const Point p0, const Point p1, coord_t& dist_left_over, coord_t corner_disregard_p1, PolygonRef result);
};
} // namespace cura
#endif // TEXTURE_PROCESSING_TEXTURE_BUMP_MAP_PROCESSOR_H
@@ -0,0 +1,85 @@
#include "TextureProximityProcessor.h"
#include <algorithm> // swap
#include <functional> // function
#include "../utils/optional.h"
#include "../utils/linearAlg2D.h"
#include "../slicer/SlicerSegment.h"
namespace cura
{
TextureProximityProcessor::TextureProximityProcessor(const TextureProximityProcessor::Settings settings, unsigned int slice_layer_count)
: settings(settings)
{
loc_to_slice.resize(slice_layer_count, SparseLineGrid<TexturedFaceSlice, TexturedFaceSliceLocator>(settings.proximity));
}
void TextureProximityProcessor::registerTexturedFaceSlice(SlicerSegment face_segment, MatSegment texture_segment, unsigned int layer_nr)
{
TexturedFaceSlice slice{face_segment, texture_segment};
assert((int)layer_nr >= 0 && layer_nr < loc_to_slice.size());
loc_to_slice[layer_nr].insert(slice);
}
float TextureProximityProcessor::getColor(const Point location, const unsigned int layer_nr, ColourUsage color, float default_color)
{
assert((int)layer_nr >= 0 && layer_nr < loc_to_slice.size());
SparseLineGrid<TexturedFaceSlice, TexturedFaceSliceLocator> grid = loc_to_slice[layer_nr];
coord_t best_dist2 = std::numeric_limits<coord_t>::max();
std::optional<TexturedFaceSlice> best;
std::function<bool (const TexturedFaceSlice& in)> process_func = [location, &best_dist2, &best](const TexturedFaceSlice& in)
{
coord_t dist2 = LinearAlg2D::getDist2FromLineSegment(in.face_segment.start, location, in.face_segment.end);
if (dist2 < best_dist2)
{
best_dist2 = dist2;
best = in;
}
return true; // keep going, we're not sure whether we have found the best yet
};
grid.processNearby(location, settings.proximity, process_func);
if (best_dist2 > settings.proximity * settings.proximity * 4)
{
return default_color;
}
assert(best && "given that dist2 != max int this variable should have been innitialized");
const Point p0 = best->face_segment.start;
const Point p1 = best->face_segment.end;
const Point x = location;
// Point r = resulting point on the nearest segment, nearest to [location]
const MatSegment mat_segment = best->mat_segment;
const Point v01 = p1 - p0;
const Point v0x = x - p0;
const coord_t v01_length2 = vSize2(v01);
if (v01_length2 <= 4)
{
return mat_segment.start.getColor(color);
}
const coord_t dot_prod = dot(v0x, v01);
const int64_t v0r_length2 = dot_prod * dot_prod / v01_length2;
if (v0r_length2 <= 0)
{
return mat_segment.start.getColor(color);
}
if (v0r_length2 >= v01_length2)
{
return mat_segment.end.getColor(color);
}
const coord_t v0r_length = sqrt(v0r_length2);
const coord_t v01_length = sqrt(v01_length2);
MatCoord mat_in_between = mat_segment.start;
mat_in_between.coords = mat_segment.start.coords + (mat_segment.end.coords - mat_segment.start.coords) * v0r_length / v01_length;
return mat_in_between.getColor(color);
}
}//namespace cura
@@ -0,0 +1,93 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_TEXTURE_PROXIMITY_PROCESSOR_H
#define TEXTURE_PROCESSING_TEXTURE_PROXIMITY_PROCESSOR_H
#include <vector>
#include "../utils/intpoint.h"
#include "../utils/SparseLineGrid.h"
#include "../settings/settings.h"
#include "../slicer/SlicerSegment.h"
#include "TexturedMesh.h"
namespace cura
{
/*!
* Class for recording texture coordinates at places where textures are defined, for later looking in the proximity of a texture.
*/
class TextureProximityProcessor
{
public:
/*!
* Helper class to retrieve and store texture to bump map settings
*/
struct Settings
{
coord_t proximity; //!< The distance within which to search for nearby texture
Settings(coord_t proximity)
: proximity(proximity)
{
}
};
/*!
* default constructor
*
* initializes the \ref SparseGrid::cell_size of \ref TextureProximityProcessor::loc_to_slice
*
* \param settings The settings with which to \ref TextureProximityProcessor::processBumpMap
*/
TextureProximityProcessor(const Settings settings, unsigned int slice_layer_count);
/*!
* Register that a particular face was sliced to a particular texture segment.
* \param face_segment The geometrical segment of the face
* \param texture_segment The corresponding texture coordinates
* \param layer_nr The layer for which to register a face being sliced
*/
void registerTexturedFaceSlice(SlicerSegment face_segment, MatSegment texture_segment, unsigned int layer_nr);
/*!
*
* \param default_color Default color where no texture is present
*/
float getColor(const Point location, const unsigned int layer_nr, ColourUsage color, float default_color);
protected:
/*!
* A sliced segment in combination with the corresponding texture slice.
*/
struct TexturedFaceSlice
{
SlicerSegment face_segment;
MatSegment mat_segment;
};
/*!
* Locator to find the line segment of a \ref TexturedFaceSlice
*/
struct TexturedFaceSliceLocator
{
std::pair<Point, Point> operator()(const TexturedFaceSlice& elem) const
{
return std::make_pair(elem.face_segment.start, elem.face_segment.end);
}
};
/*!
* The settings with which to \ref TextureBumpMapProcessor::processBumpMap
*/
Settings settings;
/*!
* A grid to efficiently look op which texture segment best fits the slicer segment.
*
* A vector of elements for each layer
*/
std::vector<SparseLineGrid<TexturedFaceSlice, TexturedFaceSliceLocator>> loc_to_slice;
};
} // namespace cura
#endif // TEXTURE_PROCESSING_TEXTURE_PROXIMITY_PROCESSOR_H
+144
Ver Arquivo
@@ -0,0 +1,144 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "TexturedMesh.h"
#include <cassert>
#include <math.h>
#include "../utils/logoutput.h"
namespace cura
{
TexturedMesh::TexturedMesh(SettingsBaseVirtual* sb)
: Mesh(sb)
, current_mat(-1) // not set yet
{
}
void TexturedMesh::addTextureCoord(float x, float y)
{
// some textures use wrapping for some unholy reason
// unwrap for texture coordinates to fall within [0,1]
if (x > 1.0f || x < 0.0f)
{ // only apply fmod when more than 1.0
x = fmod(x, 1.0f);
if (x < 0.0)
{
x += 1.0f;
}
}
if (y > 1.0f || y < 0.0f)
{ // only apply fmod when more than 1.0
y = fmod(y, 1.0f);
if (y < 0.0)
{
y += 1.0f;
}
}
texture_coords.emplace_back(x, y);
}
void TexturedMesh::addFace(int vi0, int vi1, int vi2, int ti0, int ti1, int ti2)
{
if (vi0 < -1)
{
vi0 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (vi1 < -1)
{
vi1 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (vi2 < -1)
{
vi2 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (ti0 < -1)
{
ti0 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (ti1 < -1)
{
ti1 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
if (ti2 < -1)
{
ti2 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
}
bool made_new_face = Mesh::addFace(vi0, vi1, vi2);
if (made_new_face)
{
face_texture_indices.emplace_back(ti0, ti1, ti2, current_mat);
assert(Mesh::faces.size() == face_texture_indices.size());
}
}
bool TexturedMesh::setMaterial(std::string name)
{
current_mat = material_base.getMatId(name);
return current_mat >= 0;
}
Material* TexturedMesh::addMaterial(std::string name)
{
return material_base.add(name);
}
bool TexturedMesh::getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigned int p0_idx, unsigned int p1_idx, MatCoord& result) const
{
if (face_idx >= face_texture_indices.size() || face_idx >= faces.size())
{
return false;
}
FaceTextureCoordIndices texture_idxs = face_texture_indices[face_idx];
if (texture_idxs.index[0] < 0 || texture_idxs.index[1] < 0 || texture_idxs.index[2] < 0 || texture_idxs.mat_id < 0)
{
return false;
}
const MeshFace& face = faces[face_idx];
Point3 p0(vertices[face.vertex_index[p0_idx]].p);
Point3 p1(vertices[face.vertex_index[p1_idx]].p);
float dzp0 = z - p0.z;
float dp0p1 = p1.z - p0.z;
if (dzp0 * dp0p1 < 0)
{ // z doesn't lie between p0 and p1
return false;
}
if (dzp0 == 0)
{ // edge is not cut by horizontal plane!
return false;
}
float ratio = INT2MM(dzp0) / INT2MM(dp0p1);
FPoint t0 = texture_coords[texture_idxs.index[p0_idx]];
FPoint t1 = texture_coords[texture_idxs.index[p1_idx]];
result.mat = material_base.getMat(texture_idxs.mat_id);
result.coords.x = t0.x + (t1.x - t0.x) * ratio;
result.coords.y = t0.y + (t1.y - t0.y) * ratio;
if (result.coords.x > 1.001 || result.coords.x < -0.001 || result.coords.y > 1.001 || result.coords.y < -0.001)
{
logError("WARNING: wrapping material to outside image!\n");
}
return true;
}
bool TexturedMesh::sliceFaceTexture(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const
{
if (!getFaceEdgeMatCoord(face_idx, z, idx_shared, idx_first, result.start))
{
return false;
}
if (!getFaceEdgeMatCoord(face_idx, z, idx_shared, idx_second, result.end))
{
return false;
}
return true;
}
} // namespace cura
+77
Ver Arquivo
@@ -0,0 +1,77 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSING_TEXTURED_MESH_H
#define TEXTURE_PROCESSING_TEXTURED_MESH_H
#include <vector>
#include <string>
#include "MaterialBase.h"
#include "../mesh.h"
#include "../utils/intpoint.h"
#include "MatSegment.h"
namespace cura
{
/*!
* A mesh with bitmap textures to it.
*
* material coordinates are defined separately, and can be reused for different bitmap textures
*/
class TexturedMesh : public Mesh
{
public:
TexturedMesh(SettingsBaseVirtual* sb);
/*!
*
*/
struct FaceTextureCoordIndices
{
int index[3]; //!< indices into texture_coords or -1 if no texture data available
int mat_id; //!< Material id
FaceTextureCoordIndices(int i1, int i2, int i3, int mat_id)
: mat_id(mat_id)
{
index[0] = i1;
index[1] = i2;
index[2] = i3;
}
};
void addTextureCoord(float x, float y);
void addFace(int vi0, int vi1, int vi2, int ti0, int ti1, int ti2);
using Mesh::addFace; // otherwise above addFace would shadow the parent addFace
bool setMaterial(std::string name); //!< set the material to be used in the comming data to be loaded
Material* addMaterial(std::string name);
/*!
* \return Whether a texture line segment has been created
*/
bool sliceFaceTexture(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const;
protected:
std::vector<FPoint> texture_coords; //!< all texture coordinates by all faces
std::vector<FaceTextureCoordIndices> face_texture_indices; //!< for each face the corresponding texture coordinates in TexturedMesh::texture_coords
// TODO clean up above lists when super class clear() is called
// TODO when to clean up below material base?
MaterialBase material_base;
/*!
* Get the material coordinate corresponding to the point on a plane cutting a given edge of the face.
* \param face_idx The face for which to get the material coord
* \param z The z of the horizontal plane cutting the face
* \param p0_idx The index into the first vert of the edge
* \param p1_idx The index into the second vert of the edge
* \param result The resulting material Coordinates
* \return Whether a Material coordinate is defined at the given location
*/
bool getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigned int p0_idx, unsigned int p1_idx, MatCoord& result) const;
private:
int current_mat; //!< material currently used in loading the face material info
};
} // namespace cura
#endif // TEXTURE_PROCESSING_TEXTURED_MESH_H
+2 -2
Ver Arquivo
@@ -24,7 +24,7 @@ AABB::AABB(const Polygons& polys)
calculate(polys);
}
AABB::AABB(ConstPolygonRef poly)
AABB::AABB(const PolygonRef poly)
: min(POINT_MAX, POINT_MAX), max(POINT_MIN, POINT_MIN)
{
calculate(poly);
@@ -43,7 +43,7 @@ void AABB::calculate(const Polygons& polys)
}
}
void AABB::calculate(ConstPolygonRef poly)
void AABB::calculate(const PolygonRef poly)
{
min = Point(POINT_MAX, POINT_MAX);
max = Point(POINT_MIN, POINT_MIN);
+2 -2
Ver Arquivo
@@ -20,10 +20,10 @@ public:
AABB(); //!< initializes with invalid min and max
AABB(Point& min, Point& max); //!< initializes with given min and max
AABB(const Polygons& polys); //!< Computes the boundary box for the given polygons
AABB(ConstPolygonRef poly); //!< Computes the boundary box for the given polygons
AABB(const PolygonRef poly); //!< Computes the boundary box for the given polygons
void calculate(const Polygons& polys); //!< Calculates the aabb for the given polygons (throws away old min and max data of this aabb)
void calculate(ConstPolygonRef poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb)
void calculate(const PolygonRef poly); //!< Calculates the aabb for the given polygon (throws away old min and max data of this aabb)
/*!
* Check whether this aabb overlaps with another.
-6
Ver Arquivo
@@ -37,12 +37,6 @@ void AABB3D::include(Point3 p)
max.z = std::max(max.z, p.z);
}
void AABB3D::includeZ(int32_t z)
{
min.z = std::min(min.z, z);
max.z = std::max(max.z, z);
}
void AABB3D::offset(Point3 offset)
{
min += offset;
-8
Ver Arquivo
@@ -38,14 +38,6 @@ struct AABB3D
*/
void include(Point3 p);
/*!
* Expand the AABB3D to include a z-coordinate.
*
* This is for including a point of which the X and Y coordinates are
* unknown but known to already be included in the bounding box.
*/
void includeZ(int32_t z);
/*!
* Offset the coordinates of the bounding box.
* \param offset The offset with which to offset the AABB3D.
+74
Ver Arquivo
@@ -0,0 +1,74 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef UTILS_F_POINT_H
#define UTILS_F_POINT_H
#include <cmath> // sqrt
#include <iostream> // auto-serialization / auto-toString() '<<'
namespace cura
{
/*!
* 2D coordinates represented by floats
*/
class FPoint
{
public:
float x, y; //!< Coordinates
FPoint() //!< non-initializing constructor
{}
FPoint(float x, float y) //!< constructor
: x(x)
, y(y)
{}
FPoint operator+(const FPoint& p) const { return FPoint(x+p.x, y+p.y); }
FPoint operator-(const FPoint& p) const { return FPoint(x-p.x, y-p.y); }
FPoint operator/(const float i) const { return FPoint(x/i, y/i); }
FPoint operator*(const float i) const { return FPoint(x*i, y*i); }
FPoint& operator += (const FPoint& p) { x += p.x; y += p.y; return *this; }
FPoint& operator -= (const FPoint& p) { x -= p.x; y -= p.y; return *this; }
bool operator==(const FPoint& p) const { return x == p.x && y == p.y; }
bool operator!=(const FPoint& p) const { return x != p.x || y != p.y; }
/*!
* output to string stream in standard format
*/
template<class CharT, class TraitsT>
friend
std::basic_ostream<CharT, TraitsT>&
operator <<(std::basic_ostream<CharT, TraitsT>& os, const FPoint& p)
{
return os << "(" << p.x << ", " << p.y << ")";
}
/*!
* squared vector size
*/
float vSize2() const
{
return x * x + y * y;
}
/*!
* vector size
*/
float vSize() const
{
return sqrt(vSize2());
}
/*!
* dot product
*/
float dot(const FPoint& p) const
{
return x * p.x + y * p.y;
}
};
} // namespace cura
#endif // UTILS_F_POINT_H
+41 -22
Ver Arquivo
@@ -10,49 +10,68 @@ namespace cura
{
void ListPolyIt::convertPolygonsToLists(const Polygons& polys, ListPolygons& result)
void ListPolyIt::convertPolygonsToLists(Polygons& polys, ListPolygons& result, bool remove_duplicates)
{
for (ConstPolygonRef poly : polys)
for (PolygonRef poly : polys)
{
result.emplace_back();
convertPolygonToList(poly, result.back());
convertPolygonToList(poly, result.back(), remove_duplicates);
}
}
void ListPolyIt::convertPolygonToList(ConstPolygonRef poly, ListPolygon& result)
void ListPolyIt::convertPolygonToList(PolygonRef poly, ListPolygon& result, bool remove_duplicates)
{
#ifdef DEBUG
Point last = poly.back();
#endif // DEBUG
for (const Point& p : poly)
if (remove_duplicates)
{
result.push_back(p);
#ifdef DEBUG
// usually polygons shouldn't have such degenerate verts
// in PolygonProximityLinker (where this function is (also) used) it is
// required to not have degenerate verts, because verts are mapped
// to links, but if two different verts are at the same place the mapping fails.
assert(p != last);
last = p;
#endif // DEBUG
Point last = poly.back();
for (Point& p : poly)
{
if (p != last)
{
result.push_back(p);
last = p;
}
}
}
else
{
for (Point& p : poly)
{
result.push_back(p);
}
}
}
void ListPolyIt::convertListPolygonsToPolygons(const ListPolygons& list_polygons, Polygons& polygons)
void ListPolyIt::convertListPolygonsToPolygons(ListPolygons& list_polygons, Polygons& polygons, bool remove_duplicates)
{
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++)
{
polygons[poly_idx].clear();
convertListPolygonToPolygon(list_polygons[poly_idx], polygons[poly_idx]);
convertListPolygonToPolygon(list_polygons[poly_idx], polygons[poly_idx], remove_duplicates);
}
}
void ListPolyIt::convertListPolygonToPolygon(const ListPolygon& list_polygon, PolygonRef polygon)
void ListPolyIt::convertListPolygonToPolygon(ListPolygon& list_polygon, PolygonRef polygon, bool remove_duplicates)
{
for (const Point& p : list_polygon)
if (remove_duplicates)
{
polygon.add(p);
Point last = list_polygon.back();
for (Point& p : list_polygon)
{
if (p != last)
{
polygon.add(p);
last = p;
}
}
}
else
{
for (Point& p : list_polygon)
{
polygon.add(p);
}
}
}
+8 -4
Ver Arquivo
@@ -93,29 +93,33 @@ public:
*
* \param polys The polygons to convert
* \param result The converted polygons
* \param remove_duplicates Whether to skip the conversion of duplicate consecutive points in the input
*/
static void convertPolygonsToLists(const Polygons& polys, ListPolygons& result);
static void convertPolygonsToLists(Polygons& polys, ListPolygons& result, bool remove_duplicates = false);
/*!
* Convert Polygons to ListPolygons
*
* \param polys The polygons to convert
* \param result The converted polygons
* \param remove_duplicates Whether to skip the conversion of duplicate consecutive points in the input
*/
static void convertPolygonToList(ConstPolygonRef poly, ListPolygon& result);
static void convertPolygonToList(PolygonRef poly, ListPolygon& result, bool remove_duplicates = false);
/*!
* Convert ListPolygons to Polygons
*
* \param list_polygons The polygons to convert
* \param polygons The converted polygons
* \param remove_duplicates Whether to skip the conversion of duplicate consecutive points in the input
*/
static void convertListPolygonsToPolygons(const ListPolygons& list_polygons, Polygons& polygons);
static void convertListPolygonsToPolygons(ListPolygons& list_polygons, Polygons& polygons, bool remove_duplicates = false);
/*!
* Convert ListPolygons to Polygons
*
* \param list_polygons The polygons to convert
* \param polygons The converted polygons
* \param remove_duplicates Whether to skip the conversion of duplicate consecutive points in the input
*/
static void convertListPolygonToPolygon(const ListPolygon& list_polygon, PolygonRef polygon);
static void convertListPolygonToPolygon(ListPolygon& list_polygon, PolygonRef polygon, bool remove_duplicates = false);
/*!
* Insert a point into a ListPolygon if it's not a duplicate of the point before or the point after.
+2 -1
Ver Arquivo
@@ -21,7 +21,8 @@ PolygonProximityLinker::PolygonProximityLinker(Polygons& polygons, int proximity
proximity_point_links.reserve(polygons.pointCount()); // When the whole model consists of thin walls, there will generally be a link for every point, plus some endings minus some points which map to eachother
// convert to list polygons for insertion of points
ListPolyIt::convertPolygonsToLists(polygons, list_polygons);
constexpr bool remove_duplicates = true;
ListPolyIt::convertPolygonsToLists(polygons, list_polygons, remove_duplicates);
// link each corner to itself
addSharpCorners();
+1 -1
Ver Arquivo
@@ -46,7 +46,7 @@ public:
/*!
* Get the polygon to which this PolygonsPointIndex refers
*/
ConstPolygonRef getPolygon() const
const PolygonRef getPolygon() const
{
return (*polygons)[poly_idx];
}
+6 -5
Ver Arquivo
@@ -93,8 +93,9 @@ public:
{
for(unsigned int j=0;j<parts.size();j++)
{
Polygon poly = parts[j];
fprintf(out, "<polygon points=\"");
for (Point& p : parts[j])
for(Point& p : poly)
{
Point fp = transform(p);
fprintf(out, "%lli,%lli ", fp.X, fp.Y);
@@ -129,9 +130,9 @@ public:
}
}
void writePoints(ConstPolygonRef poly, bool write_coords=false, int size = 5, Color color = Color::BLACK)
void writePoints(PolygonRef poly, bool write_coords=false, int size = 5, Color color = Color::BLACK)
{
for (const Point& p : poly)
for (Point& p : poly)
{
writePoint(p, write_coords, size, color);
}
@@ -208,12 +209,12 @@ public:
}
void writePolygons(const Polygons& polys, Color color = Color::BLACK)
{
for (ConstPolygonRef poly : polys)
for (const PolygonRef poly : const_cast<Polygons&>(polys))
{
writePolygon(poly, color);
}
}
void writePolygon(ConstPolygonRef poly, Color color = Color::BLACK)
void writePolygon(const PolygonRef poly, Color color = Color::BLACK)
{
Point p0 = poly.back();
for (Point p1 : poly)
+68 -6
Ver Arquivo
@@ -14,9 +14,6 @@ namespace cura {
/*! \brief Sparse grid which can locate spatially nearby elements efficiently.
*
* \note This is an abstract template class which doesn't have any functions to insert elements.
* \see SparsePointGrid
*
* \tparam ElemT The element type to store.
*/
template<class ElemT>
@@ -24,6 +21,11 @@ class SparseGrid
{
public:
using Elem = ElemT;
protected:
using GridPoint = Point;
using grid_coord_t = coord_t;
using GridMap = std::unordered_multimap<GridPoint, Elem>;
public:
/*! \brief Constructs a sparse grid with the specified cell size.
*
@@ -95,10 +97,50 @@ public:
coord_t getCellSize() const;
/*! \brief Inserts elem into the sparse grid.
*
* \param[in] location The location where to insert the element
* \param[in] elem The element to be inserted.
*/
void insert(Point location, const Elem &elem);
class iterator
{
friend class SparseGrid<ElemT>;
typename GridMap::iterator it;
iterator(typename GridMap::iterator it)
:it(it)
{}
public:
iterator operator++() // pre-increment
{
++it;
return *this;
}
iterator operator++(int) // post increment
{
iterator ret(it);
++it;
return ret;
}
Elem operator*()
{
return it->second;
}
bool operator==(iterator other)
{
return it == other.it;
}
bool operator!=(iterator other)
{
return it != other.it;
}
// TODO: fully implement iterator interface
};
iterator begin();
iterator end();
protected:
using GridPoint = Point;
using grid_coord_t = coord_t;
using GridMap = std::unordered_multimap<GridPoint, Elem>;
/*! \brief Process elements from the cell indicated by \p grid_pt.
*
@@ -221,6 +263,26 @@ typename cura::coord_t SGI_THIS::toLowerCoord(const grid_coord_t& grid_coord) c
return grid_coord * m_cell_size;
}
SGI_TEMPLATE
void SGI_THIS::insert(Point loc, const Elem &elem)
{
GridPoint grid_loc = toGridPoint(loc);
m_grid.emplace(grid_loc, elem);
}
SGI_TEMPLATE
typename SGI_THIS::iterator SGI_THIS::begin()
{
return iterator(m_grid.begin());
}
SGI_TEMPLATE
typename SGI_THIS::iterator SGI_THIS::end()
{
return iterator(m_grid.end());
}
SGI_TEMPLATE
bool SGI_THIS::processFromCell(
const GridPoint &grid_pt,
+1 -3
Ver Arquivo
@@ -62,9 +62,7 @@ SGI_TEMPLATE
void SGI_THIS::insert(const Elem &elem)
{
Point loc = m_locator(elem);
GridPoint grid_loc = SparseGrid<ElemT>::toGridPoint(loc);
SparseGrid<ElemT>::m_grid.emplace(grid_loc,elem);
SparseGrid<ElemT>::insert(loc, elem);
}
+29 -21
Ver Arquivo
@@ -46,17 +46,19 @@ Integer points are used to avoid floating point rounding errors, and because Cli
namespace cura
{
using coord_t = ClipperLib::cInt;
class Point3
{
public:
int32_t x,y,z;
coord_t x,y,z;
Point3() {}
Point3(const int32_t _x, const int32_t _y, const int32_t _z): x(_x), y(_y), z(_z) {}
Point3(const coord_t _x, const coord_t _y, const coord_t _z): x(_x), y(_y), z(_z) {}
Point3 operator+(const Point3& p) const { return Point3(x+p.x, y+p.y, z+p.z); }
Point3 operator-(const Point3& p) const { return Point3(x-p.x, y-p.y, z-p.z); }
Point3 operator/(const int32_t i) const { return Point3(x/i, y/i, z/i); }
Point3 operator*(const int32_t i) const { return Point3(x*i, y*i, z*i); }
Point3 operator/(const coord_t i) const { return Point3(x/i, y/i, z/i); }
Point3 operator*(const coord_t i) const { return Point3(x*i, y*i, z*i); }
Point3 operator*(const double d) const { return Point3(d*x, d*y, d*z); }
Point3& operator += (const Point3& p) { x += p.x; y += p.y; z += p.z; return *this; }
@@ -75,14 +77,14 @@ public:
}
int32_t max() const
coord_t max() const
{
if (x > y && x > z) return x;
if (y > z) return y;
return z;
}
bool testLength(int32_t len) const
bool testLength(coord_t len) const
{
if (x > len || x < -len)
return false;
@@ -93,12 +95,12 @@ public:
return vSize2() <= len*len;
}
int64_t vSize2() const
coord_t vSize2() const
{
return int64_t(x)*int64_t(x)+int64_t(y)*int64_t(y)+int64_t(z)*int64_t(z);
return x * x + y * y + z * z;
}
int32_t vSize() const
coord_t vSize() const
{
return sqrt(vSize2());
}
@@ -110,25 +112,33 @@ public:
double fz = INT2MM(z);
return sqrt(fx*fx+fy*fy+fz*fz);
}
/*! this function is deprecated because it can cause overflows for vectors which easily fit inside a printer. Use FPoint3.cross(a,b) instead. */
DEPRECATED(Point3 cross(const Point3& p))
Point3 cross(const Point3& p)
{
return Point3(
y*p.z-z*p.y, /// dangerous for vectors longer than 4.6 cm !!!!!
z*p.x-x*p.z, /// can cause overflows
y*p.z-z*p.y,
z*p.x-x*p.z,
x*p.y-y*p.x);
}
int64_t dot(const Point3& p) const
coord_t dot(const Point3& p) const
{
return x*p.x + y*p.y + z*p.z;
}
Point3 normal(coord_t desired_length) const
{
coord_t current_length = vSize();
if (current_length < 1)
{
return Point3(0, 0, desired_length);
}
return *this * desired_length / current_length;
}
};
static Point3 no_point3(std::numeric_limits<int32_t>::infinity(), std::numeric_limits<int32_t>::infinity(), std::numeric_limits<int32_t>::infinity());
static Point3 no_point3(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max());
inline Point3 operator*(const int32_t i, const Point3& rhs) {
inline Point3 operator*(const coord_t i, const Point3& rhs) {
return rhs * i;
}
@@ -136,8 +146,6 @@ inline Point3 operator*(const double d, const Point3& rhs) {
return rhs * d;
}
using coord_t = ClipperLib::cInt;
/* 64bit Points are used mostly troughout the code, these are the 2D points from ClipperLib */
typedef ClipperLib::IntPoint Point;
@@ -146,10 +154,10 @@ public:
int X, Y;
Point p() { return Point(X, Y); }
};
#define POINT_MIN std::numeric_limits<ClipperLib::cInt>::min()
#define POINT_MAX std::numeric_limits<ClipperLib::cInt>::max()
#define POINT_MIN std::numeric_limits<coord_t>::min()
#define POINT_MAX std::numeric_limits<coord_t>::max()
static Point no_point(std::numeric_limits<int32_t>::infinity(), std::numeric_limits<int32_t>::infinity());
static Point no_point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max());
/* Extra operators to make it easier to do math with the 64bit Point objects */
INLINE Point operator-(const Point& p0) { return Point(-p0.X, -p0.Y); }
+1 -1
Ver Arquivo
@@ -160,7 +160,7 @@ public:
if (ac_size == 0)
{
int64_t ab_dist2 = vSize2(ab);
if (ab_dist2 == 0)
if (ab_dist2 == 0 && b_is_beyond_ac)
{
*b_is_beyond_ac = 0; // a is on b is on c
}
+42 -33
Ver Arquivo
@@ -8,9 +8,9 @@
namespace cura
{
bool ConstPolygonRef::shorterThan(int64_t check_length) const
bool PolygonRef::shorterThan(int64_t check_length) const
{
const ConstPolygonRef& polygon = *this;
const PolygonRef& polygon = *this;
const Point* p0 = &polygon.back();
int64_t length = 0;
for (const Point& p1 : polygon)
@@ -25,9 +25,9 @@ bool ConstPolygonRef::shorterThan(int64_t check_length) const
return true;
}
bool ConstPolygonRef::_inside(Point p, bool border_result) const
bool PolygonRef::_inside(Point p, bool border_result) const
{
const ConstPolygonRef thiss = *this;
PolygonRef thiss = *this;
if (size() < 1)
{
return false;
@@ -190,6 +190,16 @@ unsigned int Polygons::findInside(Point p, bool border_result)
return ret;
}
Polygons Polygons::removeComplexParts() const
{
Polygons ret;
ClipperLib::Clipper clipper(clipper_init);
clipper.AddPaths(paths, ClipperLib::ptSubject, true);
clipper.Execute(ClipperLib::ctUnion, ret.paths, ClipperLib::pftPositive);
return ret;
}
Polygons Polygons::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const
{
Polygons ret;
@@ -200,11 +210,11 @@ Polygons Polygons::offset(int distance, ClipperLib::JoinType join_type, double m
return ret;
}
Polygons ConstPolygonRef::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const
Polygons PolygonRef::offset(int distance, ClipperLib::JoinType joinType, double miter_limit) const
{
Polygons ret;
ClipperLib::ClipperOffset clipper(miter_limit, 10.0);
clipper.AddPath(*path, join_type, ClipperLib::etClosedPolygon);
clipper.AddPath(*path, joinType, ClipperLib::etClosedPolygon);
clipper.MiterLimit = miter_limit;
clipper.Execute(ret.paths, distance);
return ret;
@@ -521,7 +531,7 @@ void Polygons::removeEmptyHoles_processPolyTreeNode(const ClipperLib::PolyNode&
}
}
bool ConstPolygonRef::smooth_corner_complex(ListPolygon& poly, const Point p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length)
bool PolygonRef::smooth_corner_complex(ListPolygon& poly, const Point p1, ListPolyIt& p0_it, ListPolyIt& p2_it, const int64_t shortcut_length)
{
// walk away from the corner until the shortcut > shortcut_length or it would smooth a piece inward
// - walk in both directions untill shortcut > shortcut_length
@@ -703,7 +713,7 @@ bool ConstPolygonRef::smooth_corner_complex(ListPolygon& poly, const Point p1, L
return false;
}
void ConstPolygonRef::smooth_outward_step(const Point p1, const int64_t shortcut_length2, ListPolyIt& p0_it, ListPolyIt& p2_it, bool& forward_is_blocked, bool& backward_is_blocked, bool& forward_is_too_far, bool& backward_is_too_far)
void PolygonRef::smooth_outward_step(const Point p1, const int64_t shortcut_length2, ListPolyIt& p0_it, ListPolyIt& p2_it, bool& forward_is_blocked, bool& backward_is_blocked, bool& forward_is_too_far, bool& backward_is_too_far)
{
const bool forward_has_converged = forward_is_blocked || forward_is_too_far;
const bool backward_has_converged = backward_is_blocked || backward_is_too_far;
@@ -759,7 +769,7 @@ void ConstPolygonRef::smooth_outward_step(const Point p1, const int64_t shortcut
}
}
void ConstPolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const Point p1, const Point p2, const ListPolyIt p0_it, const ListPolyIt p1_it, const ListPolyIt p2_it, const Point v10, const Point v12, const Point v02, const int64_t shortcut_length, float cos_angle)
void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const Point p1, const Point p2, const ListPolyIt p0_it, const ListPolyIt p1_it, const ListPolyIt p2_it, const Point v10, const Point v12, const Point v02, const int64_t shortcut_length, float cos_angle)
{
// 1----b---->2
// ^ /
@@ -837,6 +847,7 @@ void ConstPolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, co
Point b;
bool success = LinearAlg2D::getPointOnLineWithDist(a, p1, p2, shortcut_length, b);
// v02 has to be longer than ab!
p1_it.remove();
if (success)
{ // if not success then assume b is negligibly close to 2, but rounding errors caused a problem
#ifdef ASSERT_INSANE_OUTPUT
@@ -844,12 +855,11 @@ void ConstPolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, co
#endif // #ifdef ASSERT_INSANE_OUTPUT
ListPolyIt::insertPointNonDuplicate(p1_it, p2_it, b);
}
p1_it.remove();
}
}
}
void ConstPolygonRef::smooth_outward(float min_angle, int shortcut_length, PolygonRef result) const
void PolygonRef::smooth_outward(float min_angle, int shortcut_length, PolygonRef result) const
{
// example of smoothed out corner:
//
@@ -952,8 +962,7 @@ Polygons Polygons::smooth_outward(float max_angle, int shortcut_length)
return ret;
}
void ConstPolygonRef::smooth(int remove_length, PolygonRef result) const
void PolygonRef::smooth(int remove_length, PolygonRef result)
{
// a typical zigzag with the middle part to be removed by removing (1) :
//
@@ -968,7 +977,7 @@ void ConstPolygonRef::smooth(int remove_length, PolygonRef result) const
// |
// |
// 0
const ConstPolygonRef& thiss = *path;
PolygonRef& thiss = *this;
ClipperLib::Path* poly = result.path;
if (size() > 0)
{
@@ -1037,12 +1046,12 @@ void ConstPolygonRef::smooth(int remove_length, PolygonRef result) const
}
}
Polygons Polygons::smooth(int remove_length) const
Polygons Polygons::smooth(int remove_length)
{
Polygons ret;
for (unsigned int p = 0; p < size(); p++)
{
ConstPolygonRef poly(paths[p]);
PolygonRef poly(paths[p]);
if (poly.size() < 3)
{
continue;
@@ -1062,23 +1071,23 @@ Polygons Polygons::smooth(int remove_length) const
return ret;
}
void ConstPolygonRef::smooth2(int remove_length, PolygonRef result) const
void PolygonRef::smooth2(int remove_length, PolygonRef result)
{
const ConstPolygonRef& thiss = *this;
PolygonRef& thiss = *this;
ClipperLib::Path* poly = result.path;
if (thiss.size() > 0)
if (size() > 0)
{
poly->push_back(thiss[0]);
}
for (unsigned int poly_idx = 1; poly_idx < thiss.size(); poly_idx++)
for (unsigned int poly_idx = 1; poly_idx < size(); poly_idx++)
{
const Point& last = thiss[poly_idx - 1];
const Point& now = thiss[poly_idx];
const Point& next = thiss[(poly_idx + 1) % thiss.size()];
if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length))
Point& last = thiss[poly_idx - 1];
Point& now = thiss[poly_idx];
Point& next = thiss[(poly_idx + 1) % size()];
if (shorterThen(last - now, remove_length) && shorterThen(now - next, remove_length))
{
poly_idx++; // skip the next line piece (dont escalate the removal of edges)
if (poly_idx < thiss.size())
if (poly_idx < size())
{
poly->push_back(thiss[poly_idx]);
}
@@ -1090,12 +1099,12 @@ void ConstPolygonRef::smooth2(int remove_length, PolygonRef result) const
}
}
Polygons Polygons::smooth2(int remove_length, int min_area) const
Polygons Polygons::smooth2(int remove_length, int min_area)
{
Polygons ret;
for (unsigned int p = 0; p < size(); p++)
{
ConstPolygonRef poly(paths[p]);
PolygonRef poly(paths[p]);
if (poly.size() == 0)
{
continue;
@@ -1148,14 +1157,14 @@ void Polygons::splitIntoParts_processPolyTreeNode(ClipperLib::PolyNode* node, st
}
}
unsigned int PartsView::getPartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx) const
unsigned int PartsView::getPartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx)
{
const PartsView& partsView = *this;
PartsView& partsView = *this;
for (unsigned int part_idx_now = 0; part_idx_now < partsView.size(); part_idx_now++)
{
const std::vector<unsigned int>& partView = partsView[part_idx_now];
std::vector<unsigned int>& partView = partsView[part_idx_now];
if (partView.size() == 0) { continue; }
std::vector<unsigned int>::const_iterator result = std::find(partView.begin(), partView.end(), poly_idx);
std::vector<unsigned int>::iterator result = std::find(partView.begin(), partView.end(), poly_idx);
if (result != partView.end())
{
if (boundary_poly_idx) { *boundary_poly_idx = partView[0]; }
@@ -1179,7 +1188,7 @@ PolygonsPart PartsView::assemblePart(unsigned int part_idx) const
return ret;
}
PolygonsPart PartsView::assemblePartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx) const
PolygonsPart PartsView::assemblePartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx)
{
PolygonsPart ret;
unsigned int part_idx = getPartContaining(poly_idx, boundary_poly_idx);
@@ -1216,7 +1225,7 @@ void Polygons::splitIntoPartsView_processPolyTreeNode(PartsView& partsView, Poly
partsView.emplace_back();
unsigned int pos = partsView.size() - 1;
partsView[pos].push_back(reordered.size());
reordered.add(child->Contour); //TODO: should this steal the internal representation for speed?
reordered.add(child->Contour);
for(int i = 0; i < child->ChildCount(); i++)
{
partsView[pos].push_back(reordered.size());
+133 -184
Ver Arquivo
@@ -27,8 +27,6 @@ namespace cura {
class PartsView;
class Polygons;
class Polygon;
class PolygonRef;
class ListPolyIt;
@@ -38,60 +36,31 @@ typedef std::vector<ListPolygon> ListPolygons; //!< Polygons represented by a ve
const static int clipper_init = (0);
#define NO_INDEX (std::numeric_limits<unsigned int>::max())
class ConstPolygonRef
class PolygonRef
{
friend class Polygons;
friend class Polygon;
friend class PolygonRef;
protected:
ClipperLib::Path* path;
ConstPolygonRef()
PolygonRef()
: path(nullptr)
{}
public:
ConstPolygonRef(const ClipperLib::Path& polygon)
: path(const_cast<ClipperLib::Path*>(&polygon))
PolygonRef(ClipperLib::Path& polygon)
: path(&polygon)
{}
bool operator==(ConstPolygonRef& other) const =delete;
// needed in std::optional<ConstPolygonRef>
// ConstPolygonRef& operator=(const ConstPolygonRef& other) =delete;
ConstPolygonRef& operator=(const ConstPolygonRef& other)
{
path = other.path;
return *this;
}
unsigned int size() const
{
return path->size();
}
const Point& operator[] (unsigned int index) const
Point& operator[] (unsigned int index) const
{
POLY_ASSERT(index < size());
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return (*path)[index];
}
const ClipperLib::Path& operator*() const
void* data()
{
return *path;
}
ClipperLib::Path::const_iterator begin() const
{
return path->begin();
}
ClipperLib::Path::const_iterator end() const
{
return path->end();
}
ClipperLib::Path::const_reference back() const
{
return path->back();
return path->data();
}
const void* data() const
@@ -99,10 +68,37 @@ public:
return path->data();
}
void add(const Point p)
{
path->push_back(p);
}
PolygonRef& operator=(const PolygonRef& other) { path = other.path; return *this; }
bool operator==(const PolygonRef& other) const =delete;
ClipperLib::Path& operator*() { return *path; }
template <typename... Args>
void emplace_back(Args&&... args)
{
path->emplace_back(args...);
}
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
path->erase(path->begin() + index);
}
void clear()
{
path->clear();
}
/*!
* On Y-axis positive upward displays, Orientation will return true if the polygon's orientation is counter-clockwise.
*
*
* from http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Functions/Orientation.htm
*/
bool orientation() const
@@ -110,6 +106,11 @@ public:
return ClipperLib::Orientation(*path);
}
void reverse()
{
ClipperLib::ReversePath(*path);
}
Polygons offset(int distance, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miter_limit = 1.2) const;
int64_t polygonLength() const
@@ -124,7 +125,7 @@ public:
}
return length;
}
bool shorterThan(int64_t check_length) const;
Point min() const
@@ -137,7 +138,7 @@ public:
}
return ret;
}
Point max() const
{
Point ret = Point(POINT_MIN, POINT_MIN);
@@ -153,6 +154,19 @@ public:
{
return ClipperLib::Area(*path);
}
/*!
* Translate the whole polygon in some direction.
*
* \param translation The direction in which to move the polygon
*/
void translate(Point translation)
{
for (Point& p : *this)
{
p += translation;
}
}
Point centerOfMass() const
{
@@ -169,14 +183,14 @@ public:
}
double area = Area(*path);
x = x / 6 / area;
y = y / 6 / area;
return Point(x, y);
}
Point closestPointTo(Point p) const
Point closestPointTo(Point p)
{
Point ret = p;
float bestDist = FLT_MAX;
@@ -191,7 +205,7 @@ public:
}
return ret;
}
/*!
* Check if we are inside the polygon. We do this by tracing from the point towards the positive X direction,
* every line we cross increments the crossings counter. If we have an even number of crossings then we are not inside the polygon.
@@ -227,7 +241,7 @@ public:
}
return res == 1;
}
/*!
* Smooth out small perpendicular segments and store the result in \p result.
* Smoothing is performed by removing the inner most vertex of a line segment smaller than \p remove_length
@@ -239,7 +253,7 @@ public:
* \param remove_length The length of the largest segment removed
* \param result (output) The result polygon, assumed to be empty
*/
void smooth(int remove_length, PolygonRef result) const;
void smooth(int remove_length, PolygonRef result);
/*!
* Smooth out sharp inner corners, by taking a shortcut which bypasses the corner
@@ -257,8 +271,51 @@ public:
* \param remove_length The length of the largest segment removed
* \param result (output) The result polygon, assumed to be empty
*/
void smooth2(int remove_length, PolygonRef result) const;
void smooth2(int remove_length, PolygonRef result);
/*!
* Removes consecutive line segments with same orientation and changes this polygon.
*
* Removes verts which are connected to line segments which are both too small.
* Removes verts which detour from a direct line from the previous and next vert by a too small amount.
*
* \param smallest_line_segment_squared maximal squared length of removed line segments
* \param allowed_error_distance_squared The square of the distance of the middle point to the line segment of the consecutive and previous point for which the middle point is removed
*/
void simplify(int smallest_line_segment_squared = 100, int allowed_error_distance_squared = 25);
void pop_back()
{
path->pop_back();
}
ClipperLib::Path::reference back() const
{
return path->back();
}
ClipperLib::Path::iterator begin()
{
return path->begin();
}
ClipperLib::Path::iterator end()
{
return path->end();
}
ClipperLib::Path::const_iterator begin() const
{
return path->begin();
}
ClipperLib::Path::const_iterator end() const
{
return path->end();
}
friend class Polygons;
friend class Polygon;
private:
/*!
@@ -318,113 +375,6 @@ private:
static void smooth_outward_step(const Point p1, const int64_t shortcut_length2, ListPolyIt& p0_it, ListPolyIt& p2_it, bool& forward_is_blocked, bool& backward_is_blocked, bool& forward_is_too_far, bool& backward_is_too_far);
};
class PolygonRef : public ConstPolygonRef
{
PolygonRef()
: ConstPolygonRef()
{}
public:
PolygonRef(ClipperLib::Path& polygon)
: ConstPolygonRef(polygon)
{}
PolygonRef& operator=(const PolygonRef& other)
{
path = other.path;
return *this;
}
Point& operator[] (unsigned int index)
{
POLY_ASSERT(index < size());
return (*path)[index];
}
ClipperLib::Path::iterator begin()
{
return path->begin();
}
ClipperLib::Path::iterator end()
{
return path->end();
}
ClipperLib::Path::reference back()
{
return path->back();
}
void* data()
{
return path->data();
}
void add(const Point p)
{
path->push_back(p);
}
PolygonRef& operator=(ConstPolygonRef& other) { path = other.path; return *this; }
ClipperLib::Path& operator*()
{
return *path;
}
template <typename... Args>
void emplace_back(Args&&... args)
{
path->emplace_back(args...);
}
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
path->erase(path->begin() + index);
}
void clear()
{
path->clear();
}
void reverse()
{
ClipperLib::ReversePath(*path);
}
/*!
* Translate the whole polygon in some direction.
*
* \param translation The direction in which to move the polygon
*/
void translate(Point translation)
{
for (Point& p : *this)
{
p += translation;
}
}
/*!
* Removes consecutive line segments with same orientation and changes this polygon.
*
* Removes verts which are connected to line segments which are both too small.
* Removes verts which detour from a direct line from the previous and next vert by a too small amount.
*
* \param smallest_line_segment_squared maximal squared length of removed line segments
* \param allowed_error_distance_squared The square of the distance of the middle point to the line segment of the consecutive and previous point for which the middle point is removed
*/
void simplify(int smallest_line_segment_squared = 100, int allowed_error_distance_squared = 25);
void pop_back()
{
path->pop_back();
}
};
class Polygon : public PolygonRef
{
ClipperLib::Path poly;
@@ -434,7 +384,7 @@ public:
{
}
Polygon(PolygonRef& other)
Polygon(const PolygonRef& other)
: PolygonRef(poly)
{
poly = *other.path;
@@ -447,7 +397,6 @@ class Polygons
{
friend class Polygon;
friend class PolygonRef;
friend class ConstPolygonRef;
protected:
ClipperLib::Paths paths;
public:
@@ -461,12 +410,11 @@ public:
PolygonRef operator[] (unsigned int index)
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return paths[index];
return PolygonRef(paths[index]);
}
ConstPolygonRef operator[] (unsigned int index) const
const PolygonRef operator[] (unsigned int index) const
{
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return paths[index];
return const_cast<Polygons*>(this)->operator[](index);
}
ClipperLib::Paths::iterator begin()
{
@@ -509,11 +457,7 @@ public:
{
paths.clear();
}
void add(ConstPolygonRef& poly)
{
paths.push_back(*poly.path);
}
void add(const ConstPolygonRef& poly)
void add(const PolygonRef& poly)
{
paths.push_back(*poly.path);
}
@@ -549,10 +493,6 @@ public:
{
return PolygonRef(paths.back());
}
ConstPolygonRef back() const
{
return ConstPolygonRef(paths.back());
}
Polygons() {}
@@ -707,7 +647,7 @@ public:
* \param remove_length The length of the largest segment removed
* \return The smoothed polygon
*/
Polygons smooth(int remove_length) const;
Polygons smooth(int remove_length);
/*!
* Smooth out sharp inner corners, by taking a shortcut which bypasses the corner
@@ -718,7 +658,7 @@ public:
*/
Polygons smooth_outward(float angle, int shortcut_length);
Polygons smooth2(int remove_length, int min_area) const; //!< removes points connected to small lines
Polygons smooth2(int remove_length, int min_area); //!< removes points connected to small lines
/*!
* removes points connected to similarly oriented lines
@@ -858,16 +798,16 @@ public:
* Removes the same polygons from this set (and also empty polygons).
* Polygons are considered the same if all points lie within [same_distance] of their counterparts.
*/
Polygons remove(const Polygons& to_be_removed, int same_distance = 0) const
Polygons remove(Polygons& to_be_removed, int same_distance = 0)
{
Polygons result;
for (unsigned int poly_keep_idx = 0; poly_keep_idx < size(); poly_keep_idx++)
{
ConstPolygonRef poly_keep = (*this)[poly_keep_idx];
PolygonRef poly_keep = (*this)[poly_keep_idx];
bool should_be_removed = false;
if (poly_keep.size() > 0)
// for (int hole_poly_idx = 0; hole_poly_idx < to_be_removed.size(); hole_poly_idx++)
for (ConstPolygonRef poly_rem : to_be_removed)
for (PolygonRef poly_rem : to_be_removed)
{
// PolygonRef poly_rem = to_be_removed[hole_poly_idx];
if (poly_rem.size() != poly_keep.size() || poly_rem.size() == 0) continue;
@@ -919,6 +859,18 @@ public:
return ret;
}
/*!
* Remove holes which are lying outside of parts, and outlines inside of parts
*
* ^
* ^
* <<<<<<<<^<<<< should become <<<<<<<<
* ^ ^
* ^ ^
* ^ ^
*/
Polygons removeComplexParts() const;
int64_t polygonLength() const
{
int64_t length = 0;
@@ -983,13 +935,10 @@ public:
class PolygonsPart : public Polygons
{
public:
PolygonRef outerPolygon()
PolygonRef outerPolygon()
{
return this->paths[0];
}
ConstPolygonRef outerPolygon() const
{
return this->paths[0];
Polygons& thiss = *this;
return thiss[0];
}
bool inside(Point p)
@@ -1022,7 +971,7 @@ public:
* \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons
* \return The PolygonsPart containing the polygon with index \p poly_idx
*/
unsigned int getPartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx = nullptr) const;
unsigned int getPartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx = nullptr);
/*!
* Assemble the PolygonsPart of which the polygon with index \p poly_idx is part.
*
@@ -1030,7 +979,7 @@ public:
* \param boundary_poly_idx Optional output parameter: The index of the boundary polygon of the part in \p polygons
* \return The PolygonsPart containing the polygon with index \p poly_idx
*/
PolygonsPart assemblePartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx = nullptr) const;
PolygonsPart assemblePartContaining(unsigned int poly_idx, unsigned int* boundary_poly_idx = nullptr);
/*!
* Assemble the PolygonsPart of which the polygon with index \p poly_idx is part.
*
+39 -39
Ver Arquivo
@@ -22,7 +22,7 @@ int64_t PolygonUtils::segmentLength(PolygonsPointIndex start, PolygonsPointIndex
assert(start.poly_idx == end.poly_idx);
int64_t segment_length = 0;
Point prev_vert = start.p();
ConstPolygonRef poly = (*start.polygons)[start.poly_idx];
const PolygonRef poly = (*start.polygons)[start.poly_idx];
for (unsigned int point_idx = 1; point_idx <= poly.size(); point_idx++)
{
unsigned int vert_idx = (start.point_idx + point_idx) % poly.size();
@@ -44,7 +44,7 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end,
assert(start.poly_idx == end.poly_idx);
int64_t segment_length = segmentLength(start, end);
ConstPolygonRef poly = (*start.polygons)[start.poly_idx];
const PolygonRef poly = (*start.polygons)[start.poly_idx];
unsigned int n_dots_in_between = n_dots;
if (start == end)
{
@@ -80,7 +80,7 @@ void PolygonUtils::spreadDots(PolygonsPointIndex start, PolygonsPointIndex end,
assert(result.size() == n_dots && "we didn't generate as many wipe locations as we asked for.");
}
Point PolygonUtils::getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx)
Point PolygonUtils::getVertexInwardNormal(PolygonRef poly, unsigned int point_idx)
{
Point p1 = poly[point_idx];
@@ -110,7 +110,7 @@ Point PolygonUtils::getVertexInwardNormal(ConstPolygonRef poly, unsigned int poi
break;
}
}
const Point& p2 = poly[p2_idx];
Point& p2 = poly[p2_idx];
Point off0 = turn90CCW(normal(p1 - p0, MM2INT(10.0))); // 10.0 for some precision
Point off1 = turn90CCW(normal(p2 - p1, MM2INT(10.0))); // 10.0 for some precision
@@ -119,7 +119,7 @@ Point PolygonUtils::getVertexInwardNormal(ConstPolygonRef poly, unsigned int poi
}
Point PolygonUtils::getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset)
Point PolygonUtils::getBoundaryPointWithOffset(PolygonRef poly, unsigned int point_idx, int64_t offset)
{
return poly[point_idx] + normal(getVertexInwardNormal(poly, point_idx), -offset);
}
@@ -130,7 +130,7 @@ Point PolygonUtils::moveInsideDiagonally(ClosestPolygonPoint point_on_boundary,
{
return no_point;
}
ConstPolygonRef poly = *point_on_boundary.poly;
PolygonRef poly = *point_on_boundary.poly;
Point p0 = poly[point_on_boundary.point_idx];
Point p1 = poly[(point_on_boundary.point_idx + 1) % poly.size()];
if (vSize2(p0 - point_on_boundary.location) < vSize2(p1 - point_on_boundary.location))
@@ -163,7 +163,7 @@ ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& polygons, Point& f
return _moveInside2(*closest_polygon_point, distance, from, max_dist2);
}
ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function<int(Point)>& penalty_function)
ClosestPolygonPoint PolygonUtils::moveInside2(const Polygons& loc_to_line_polygons, const PolygonRef polygon, Point& from, const int distance, const int64_t max_dist2, const LocToLineGrid* loc_to_line_grid, const std::function<int(Point)>& penalty_function)
{
std::optional<ClosestPolygonPoint> closest_polygon_point;
if (loc_to_line_grid)
@@ -225,7 +225,7 @@ unsigned int PolygonUtils::moveInside(const Polygons& polygons, Point& from, int
bool is_already_on_correct_side_of_boundary = false; // whether [from] is already on the right side of the boundary
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++)
{
ConstPolygonRef poly = polygons[poly_idx];
const PolygonRef poly = polygons[poly_idx];
if (poly.size() < 2)
continue;
Point p0 = poly[poly.size()-2];
@@ -344,11 +344,11 @@ Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distanc
{ // the point which is assumed to be on the boundary doesn't have to be moved
return cpp.location;
}
ConstPolygonRef poly = *cpp.poly;
const PolygonRef poly = *cpp.poly;
unsigned int point_idx = cpp.point_idx;
const Point& on_boundary = cpp.location;
const Point& p1 = poly[point_idx];
Point& p1 = poly[point_idx];
unsigned int p2_idx;
for (p2_idx = point_idx + 1; p2_idx != point_idx; p2_idx = p2_idx + 1)
{ // find the next point different from p1
@@ -361,7 +361,7 @@ Point PolygonUtils::moveInside(const ClosestPolygonPoint& cpp, const int distanc
break;
}
}
const Point& p2 = poly[p2_idx];
Point& p2 = poly[p2_idx];
if (on_boundary == p1)
{
@@ -392,7 +392,7 @@ ClosestPolygonPoint PolygonUtils::ensureInsideOrOutside(const Polygons& polygons
{
return ClosestPolygonPoint(); // we couldn't move inside
}
ConstPolygonRef closest_poly = *closest_polygon_point.poly;
PolygonRef closest_poly = *closest_polygon_point.poly;
bool is_outside_boundary = closest_poly.orientation();
{
@@ -481,8 +481,8 @@ void PolygonUtils::findSmallestConnection(ClosestPolygonPoint& poly1_result, Clo
{
return;
}
ConstPolygonRef poly1 = *poly1_result.poly;
ConstPolygonRef poly2 = *poly2_result.poly;
PolygonRef poly1 = *poly1_result.poly;
PolygonRef poly2 = *poly2_result.poly;
if (poly1.size() == 0 || poly2.size() == 0)
{
return;
@@ -515,8 +515,8 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re
{
return;
}
ConstPolygonRef poly1 = *poly1_result.poly;
ConstPolygonRef poly2 = *poly2_result.poly;
PolygonRef poly1 = *poly1_result.poly;
PolygonRef poly2 = *poly2_result.poly;
if (poly1_result.point_idx < 0 || poly2_result.point_idx < 0)
{
return;
@@ -537,7 +537,7 @@ void PolygonUtils::walkToNearestSmallestConnection(ClosestPolygonPoint& poly1_re
}
}
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx)
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, PolygonRef polygon, int start_idx)
{
ClosestPolygonPoint forth = findNearestClosest(from, polygon, start_idx, 1);
if (!forth.isValid())
@@ -556,7 +556,7 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef
}
}
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx, int direction)
ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, PolygonRef polygon, int start_idx, int direction)
{
if (polygon.size() == 0)
{
@@ -572,8 +572,8 @@ ClosestPolygonPoint PolygonUtils::findNearestClosest(Point from, ConstPolygonRef
{
int p1_idx = (polygon.size() + direction*p + start_idx) % polygon.size();
int p2_idx = (polygon.size() + direction*(p+1) + start_idx) % polygon.size();
const Point& p1 = polygon[p1_idx];
const Point& p2 = polygon[p2_idx];
Point& p1 = polygon[p1_idx];
Point& p2 = polygon[p2_idx];
Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2);
int64_t dist = vSize2(from - closest_here);
@@ -600,7 +600,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
{
return none;
}
ConstPolygonRef any_polygon = polygons[0];
PolygonRef any_polygon = polygons[0];
unsigned int any_poly_idx;
for (any_poly_idx = 0; any_poly_idx < polygons.size(); any_poly_idx++)
{ // find first point in all polygons
@@ -620,7 +620,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
for (unsigned int ply = 0; ply < polygons.size(); ply++)
{
ConstPolygonRef poly = polygons[ply];
const PolygonRef poly = polygons[ply];
if (poly.size() == 0) continue;
ClosestPolygonPoint closest_here = findClosest(from, poly, penalty_function);
if (!closest_here.isValid())
@@ -639,7 +639,7 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, const Polygons& polygo
return best;
}
ClosestPolygonPoint PolygonUtils::findClosest(Point from, ConstPolygonRef polygon, const std::function<int(Point)>& penalty_function)
ClosestPolygonPoint PolygonUtils::findClosest(Point from, const PolygonRef polygon, const std::function<int(Point)>& penalty_function)
{
if (polygon.size() == 0)
{
@@ -653,11 +653,11 @@ ClosestPolygonPoint PolygonUtils::findClosest(Point from, ConstPolygonRef polygo
//
for (unsigned int p = 0; p<polygon.size(); p++)
{
const Point& p1 = polygon[p];
Point& p1 = polygon[p];
unsigned int p2_idx = p+1;
if (p2_idx >= polygon.size()) p2_idx = 0;
const Point& p2 = polygon[p2_idx];
Point& p2 = polygon[p2_idx];
Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2);
int64_t dist2_score = vSize2(from - closest_here) + penalty_function(closest_here);
@@ -678,7 +678,7 @@ PolygonsPointIndex PolygonUtils::findNearestVert(const Point from, const Polygon
PolygonsPointIndex closest_vert;
for (unsigned int poly_idx = 0; poly_idx < polys.size(); poly_idx++)
{
ConstPolygonRef poly = polys[poly_idx];
const PolygonRef poly = polys[poly_idx];
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
int64_t dist2 = vSize2(poly[point_idx] - from);
@@ -692,7 +692,7 @@ PolygonsPointIndex PolygonUtils::findNearestVert(const Point from, const Polygon
return closest_vert;
}
unsigned int PolygonUtils::findNearestVert(const Point from, ConstPolygonRef poly)
unsigned int PolygonUtils::findNearestVert(const Point from, const PolygonRef poly)
{
int64_t best_dist2 = std::numeric_limits<int64_t>::max();
unsigned int closest_vert_idx = -1;
@@ -721,7 +721,7 @@ LocToLineGrid* PolygonUtils::createLocToLineGrid(const Polygons& polygons, int s
for (unsigned int poly_idx = 0; poly_idx < polygons.size(); poly_idx++)
{
ConstPolygonRef poly = polygons[poly_idx];
const PolygonRef poly = polygons[poly_idx];
for (unsigned int point_idx = 0; point_idx < poly.size(); point_idx++)
{
ret->insert(PolygonsPointIndex(&polygons, poly_idx, point_idx));
@@ -752,9 +752,9 @@ std::optional<ClosestPolygonPoint> PolygonUtils::findClose(
PolygonsPointIndex best_point_poly_idx(nullptr, NO_INDEX, NO_INDEX);
for (PolygonsPointIndex& point_poly_index : near_lines)
{
ConstPolygonRef poly = polygons[point_poly_index.poly_idx];
const Point& p1 = poly[point_poly_index.point_idx];
const Point& p2 = poly[(point_poly_index.point_idx + 1) % poly.size()];
const PolygonRef poly = polygons[point_poly_index.poly_idx];
Point& p1 = poly[point_poly_index.point_idx];
Point& p2 = poly[(point_poly_index.point_idx + 1) % poly.size()];
Point closest_here = LinearAlg2D::getClosestOnLineSegment(from, p1 ,p2);
int64_t dist2_score = vSize2(from - closest_here) + penalty_function(closest_here);
@@ -778,7 +778,7 @@ std::optional<ClosestPolygonPoint> PolygonUtils::findClose(
std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> PolygonUtils::findClose(
ConstPolygonRef from, const Polygons& destination,
const PolygonRef from, const Polygons& destination,
const LocToLineGrid& destination_loc_to_line,
const std::function<int(Point)>& penalty_function)
{
@@ -817,7 +817,7 @@ std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> PolygonUtils::f
bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result)
bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, const PolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result)
{
Point prev_poly_point = poly[(start_idx + poly_start_idx) % poly.size()];
@@ -825,7 +825,7 @@ bool PolygonUtils::getNextPointWithDistance(Point from, int64_t dist, ConstPolyg
for (unsigned int prev_idx = start_idx; prev_idx < poly.size(); prev_idx++)
{
int next_idx = (prev_idx + 1 + poly_start_idx) % poly.size(); // last checked segment is between last point in poly and poly[0]...
const Point& next_poly_point = poly[next_idx];
Point& next_poly_point = poly[next_idx];
if ( !shorterThen(next_poly_point - from, dist) )
{
/*
@@ -932,7 +932,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Point from, const Point
return ret;
}
bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix)
bool PolygonUtils::polygonCollidesWithLineSegment(const PolygonRef poly, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix)
{
Point p0 = transformation_matrix.apply(poly.back());
for(Point p1_ : poly)
@@ -947,7 +947,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Po
return false;
}
bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& startPoint, const Point& endPoint)
bool PolygonUtils::polygonCollidesWithLineSegment(const PolygonRef poly, Point& startPoint, Point& endPoint)
{
Point diff = endPoint - startPoint;
@@ -958,9 +958,9 @@ bool PolygonUtils::polygonCollidesWithLineSegment(ConstPolygonRef poly, const Po
return PolygonUtils::polygonCollidesWithLineSegment(poly, transformed_startPoint, transformed_endPoint, transformation_matrix);
}
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix)
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix)
{
for (ConstPolygonRef poly : polys)
for (const PolygonRef poly : const_cast<Polygons&>(polys))
{
if (poly.size() == 0) { continue; }
if (PolygonUtils::polygonCollidesWithLineSegment(poly, transformed_startPoint, transformed_endPoint, transformation_matrix))
@@ -973,7 +973,7 @@ bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const P
}
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, const Point& startPoint, const Point& endPoint)
bool PolygonUtils::polygonCollidesWithLineSegment(const Polygons& polys, Point& startPoint, Point& endPoint)
{
Point diff = endPoint - startPoint;
+18 -18
Ver Arquivo
@@ -20,12 +20,12 @@ namespace cura
struct ClosestPolygonPoint
{
Point location; //!< Result location
std::optional<ConstPolygonRef> poly; //!< Polygon in which the result was found (or none if no result was found)
std::optional<PolygonRef> poly; //!< Polygon in which the result was found (or none if no result was found)
unsigned int poly_idx; //!< The index of the polygon in some Polygons where ClosestPolygonPoint::poly can be found
unsigned int point_idx; //!< Index to the first point in the polygon of the line segment on which the result was found
ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly) : location(p), poly(true, poly), poly_idx(NO_INDEX), point_idx(pos) {};
ClosestPolygonPoint(Point p, int pos, ConstPolygonRef poly, int poly_idx) : location(p), poly(true, poly), poly_idx(poly_idx), point_idx(pos) {};
ClosestPolygonPoint(ConstPolygonRef poly) : poly(true, poly), poly_idx(NO_INDEX), point_idx(NO_INDEX) {};
ClosestPolygonPoint(Point p, int pos, PolygonRef poly) : location(p), poly(true, poly), poly_idx(NO_INDEX), point_idx(pos) {};
ClosestPolygonPoint(Point p, int pos, PolygonRef poly, int poly_idx) : location(p), poly(true, poly), poly_idx(poly_idx), point_idx(pos) {};
ClosestPolygonPoint(PolygonRef poly) : poly(true, poly), poly_idx(NO_INDEX), point_idx(NO_INDEX) {};
ClosestPolygonPoint() : poly_idx(NO_INDEX), point_idx(NO_INDEX) {};
Point p() const
{ // conformity with other classes
@@ -53,7 +53,7 @@ struct PolygonsPointIndexSegmentLocator
{
std::pair<Point, Point> operator()(const PolygonsPointIndex& val) const
{
ConstPolygonRef poly = (*val.polygons)[val.poly_idx];
PolygonRef poly = (*val.polygons)[val.poly_idx];
Point start = poly[val.point_idx];
unsigned int next_point_idx = (val.point_idx + 1) % poly.size();
Point end = poly[next_point_idx];
@@ -104,7 +104,7 @@ public:
* \param poly The polygon.
* \param point_idx The index of the point in the polygon.
*/
static Point getVertexInwardNormal(ConstPolygonRef poly, unsigned int point_idx);
static Point getVertexInwardNormal(PolygonRef poly, unsigned int point_idx);
/*!
* Get a point from the \p poly with a given \p offset.
@@ -114,7 +114,7 @@ public:
* \param offset The distance the point has to be moved outward from the polygon.
* \return A point at the given distance inward from the point on the boundary polygon.
*/
static Point getBoundaryPointWithOffset(ConstPolygonRef poly, unsigned int point_idx, int64_t offset);
static Point getBoundaryPointWithOffset(PolygonRef poly, unsigned int point_idx, int64_t offset);
/*!
* Move a point away from the boundary by looking at the boundary normal of the nearest vert.
@@ -178,7 +178,7 @@ public:
* \param penalty_function A function returning a penalty term on the squared distance score of a candidate point.
* \return The point on the polygon closest to \p from
*/
static ClosestPolygonPoint moveInside2(const Polygons& loc_to_line_polygons, ConstPolygonRef polygon, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits<int64_t>::max(), const LocToLineGrid* loc_to_line_grid = nullptr, const std::function<int(Point)>& penalty_function = no_penalty_function);
static ClosestPolygonPoint moveInside2(const Polygons& loc_to_line_polygons, const PolygonRef polygon, Point& from, const int distance = 0, const int64_t max_dist2 = std::numeric_limits<int64_t>::max(), const LocToLineGrid* loc_to_line_grid = nullptr, const std::function<int(Point)>& penalty_function = no_penalty_function);
/*!
* The opposite of moveInside.
@@ -298,7 +298,7 @@ public:
* \param start_idx The index of the point in the polygon from which to start looking.
* \return The nearest point from \p start_idx going along the \p polygon (in both directions) with a locally minimal distance to \p from.
*/
static ClosestPolygonPoint findNearestClosest(Point from, ConstPolygonRef polygon, int start_idx);
static ClosestPolygonPoint findNearestClosest(Point from, const PolygonRef polygon, int start_idx);
/*!
* Find the nearest closest point on a polygon from a given index walking in one direction along the polygon.
@@ -309,7 +309,7 @@ public:
* \param direction The direction to walk: 1 for walking along the \p polygon, -1 for walking in opposite direction
* \return The nearest point from \p start_idx going along the \p polygon with a locally minimal distance to \p from.
*/
static ClosestPolygonPoint findNearestClosest(const Point from, ConstPolygonRef polygon, int start_idx, int direction);
static ClosestPolygonPoint findNearestClosest(const Point from, const PolygonRef polygon, int start_idx, int direction);
/*!
* Find the point closest to \p from in all polygons in \p polygons.
@@ -327,7 +327,7 @@ public:
*
* \param penalty_function A function returning a penalty term on the squared distance score of a candidate point.
*/
static ClosestPolygonPoint findClosest(Point from, ConstPolygonRef polygon, const std::function<int(Point)>& penalty_function = no_penalty_function);
static ClosestPolygonPoint findClosest(Point from, const PolygonRef polygon, const std::function<int(Point)>& penalty_function = no_penalty_function);
/*!
* Find the nearest vertex to \p from in \p polys
@@ -343,7 +343,7 @@ public:
* \param poly The polygon in which to search
* \return The index to the nearest vertex on the polygon
*/
static unsigned int findNearestVert(const Point from, ConstPolygonRef poly);
static unsigned int findNearestVert(const Point from, const PolygonRef poly);
/*!
* Create a SparsePointGridInclusive mapping from locations to line segments occurring in the \p polygons
@@ -382,7 +382,7 @@ public:
* \param penalty_function A function returning a penalty term on the squared distance score of a candidate point.
* \return A collection of near crossing from the \p from polygon to the \p destination polygon. Each element in the sollection is a pair with as first a cpp in the \p from polygon and as second a cpp in the \p destination polygon.
*/
static std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findClose(ConstPolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function<int(Point)>& penalty_function = no_penalty_function);
static std::vector<std::pair<ClosestPolygonPoint, ClosestPolygonPoint>> findClose(const PolygonRef from, const Polygons& destination, const LocToLineGrid& destination_loc_to_line, const std::function<int(Point)>& penalty_function = no_penalty_function);
/*!
* Checks whether a given line segment collides with polygons as given in a loc_to_line grid.
@@ -409,7 +409,7 @@ public:
* \param start_idx the index of the prev poly point on the poly.
* \param poly_start_idx The index of the point in the polygon which is to be handled as the start of the polygon. No point further than this point will be the result.
*/
static bool getNextPointWithDistance(Point from, int64_t dist, ConstPolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result);
static bool getNextPointWithDistance(Point from, int64_t dist, const PolygonRef poly, int start_idx, int poly_start_idx, GivenDistPoint& result);
@@ -433,7 +433,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix);
static bool polygonCollidesWithLineSegment(const PolygonRef poly, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix);
/*!
* Checks whether a given line segment collides with a given polygon(s).
@@ -449,7 +449,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(ConstPolygonRef poly, const Point& startPoint, const Point& endPoint);
static bool polygonCollidesWithLineSegment(const PolygonRef poly, Point& startPoint, Point& endPoint);
/*!
* Checks whether a given line segment collides with a given polygon(s).
@@ -471,7 +471,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(const Polygons& polys, const Point& transformed_startPoint, const Point& transformed_endPoint, PointMatrix transformation_matrix);
static bool polygonCollidesWithLineSegment(const Polygons& polys, Point& transformed_startPoint, Point& transformed_endPoint, PointMatrix transformation_matrix);
/*!
* Checks whether a given line segment collides with a given polygon(s).
@@ -487,7 +487,7 @@ public:
* \return whether the line segment collides with the boundary of the
* polygon(s)
*/
static bool polygonCollidesWithLineSegment(const Polygons& polys, const Point& startPoint, const Point& endPoint);
static bool polygonCollidesWithLineSegment(const Polygons& polys, Point& startPoint, Point& endPoint);
private:
/*!

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais