Comparar commits

...

102 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
Ghostkeeper 05be030c45 Document range check for pre-computed cubes
Contributes to issue CURA-3137.
2016-12-14 15:15:20 +01:00
Ghostkeeper 3c5e745f83 Reintroduce assert for coordinates exceeding maximum int
Because we might still test with models of 2km size.

Contributes to issue CURA-3137.
2016-12-14 14:09:16 +01:00
Ghostkeeper 2e6cd36f20 Make unused parameters unnamed
This way they cannot be used any more.

Shuts the compiler up for issue CURA-3137.
2016-12-14 12:02:00 +01:00
Ghostkeeper 9fc4a427cd Removed checks of unsigned ints being >= 0
Because that's always true. Even the compiler says that.

Contributes sorta to issue CURA-3137.
2016-12-14 12:00:39 +01:00
Ghostkeeper 5729908023 Remove unused path parameter
According to the compiler, the path parameter of handleChildren was not unused, but that was only because it went recursively to subcalls to handleChildren, so it was actually also unused.

Contributes to issue CURA-3137.
2016-12-14 11:55:40 +01:00
Ghostkeeper c5b90b0ad9 Put check for empty extruder trains before size check
Could save a miniscule amount of time.

Contributes to issue CURA-3137.
2016-12-14 11:50:45 +01:00
Ghostkeeper 382343e558 Make recursion depth unsigned
It can't be negative anyway. And it helps with the signed-unsigned comparison checks.

Contributes to issue CURA-3137.
2016-12-14 11:48:46 +01:00
Ghostkeeper 68b293b880 Make subdivided cubic infill robust to 0% infill
Otherwise it would crash or loop forever.

Contributes to issue CURA-3137.
2016-12-14 11:44:34 +01:00
Ghostkeeper f867c0f53a Prevent crashing when given no extruder trains
Instead we return -1. A bit more robust.

Contributes to issue CURA-3137.
2016-12-14 11:05:05 +01:00
Ghostkeeper ee7e83d138 Merge branch 'mb-layer-height-comment' of https://github.com/smartavionics/CuraEngine into smartavionics-mb-layer-height-comment 2016-12-14 09:29:53 +01:00
Ghostkeeper 50df40c6c6 Revert "Re-use extruder train variable"
This reverts commit c9217d4738.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 4d924fd33d Revert "Add park distance information to retraction config"
This reverts commit 23ef513cce.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper c953a726cb Revert "Add function to move filament to park position"
This reverts commit ae00cbe497.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 7c8c0b2417 Revert "Correct speed of retraction"
This reverts commit 6925f39426.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper a834754d64 Revert "Remove some annoying compile warnings"
This reverts commit d75882a707.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 9957a0c733 Revert "Fix updating current E value"
This reverts commit 80f8760f68.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper f6ce0b4141 Revert "Put filament in parking position when we never use it any more"
This reverts commit 3cb3e5de45.

Contributes to issue CURA-2795.
2016-12-13 15:35:47 +01:00
Ghostkeeper 120a9c440c Revert "Park filament even if printer doesn't support retraction"
This reverts commit 837f992f69.

Contributes to issue CURA-2795.
2016-12-13 15:35:46 +01:00
Ghostkeeper 59f72bdd98 Revert "Expand documentation of writePark"
This reverts commit 4f3b4f429d.

Contributes to issue CURA-2795.
2016-12-13 15:35:46 +01:00
Ghostkeeper abc43302ac Revert "Correct retraction speed"
This reverts commit 36eb3471df.

Contributes to issue CURA-2795.
2016-12-13 15:35:46 +01:00
Mark Burton c2725bdf83 Move layer_height out of the GCodeExport class - it doesn't need to be a member. 2016-12-13 13:47:39 +00:00
Tim Kuipers fb761dfd9d fix: don't generate perimeter_gaps between inner wall and infill/skin when there is no infill (CURA-3108) 2016-12-13 13:53:05 +01:00
Mark Burton 90727a0578 Merge branch 'master' into mb-layer-height-comment 2016-12-13 08:05:31 +00:00
Mark Burton fd7d1a4bd4 Add comment that reports layer height in RepRap flavour gcode. 2016-12-12 16:54:13 +00:00
Ghostkeeper 2b1266c647 Move implementation to CPP file
Contributes to issue CURA-3006.
2016-12-12 14:04:32 +01:00
Ghostkeeper 901bf47610 Move implementation to CPP file
Contributes to issue CURA-3006.
2016-12-12 13:55:47 +01:00
Ghostkeeper 80a6115537 Move implementation to CPP file
Contributes to issue CURA-3006.
2016-12-12 13:44:23 +01:00
Ghostkeeper f94ca645bd Make writeRetraction accept const ref instead of const pointer
This change was already made for CURA-2795, and upon this change was built by other commits for other issues. I had to revert CURA-2795, so that would undo the changes that the other commits depend on. Instead though, I un-reverted the change because it's nice and doesn't have anything inherently to do with CURA-2795.

Contributes to issue CURA-2795.
2016-12-12 13:11:03 +01:00
Ghostkeeper 2067644d30 Revert "Update prime speed corresponding to park retraction"
This reverts commit 6c986e6cfe.

Contributes to issue CURA-2795.
2016-12-12 12:57:15 +01:00
Ghostkeeper 0285e2f025 Revert "Add additional safety check for extruder switching off in later layers"
This reverts commit bc82fd98c9.

Contributes to issue CURA-2795.
2016-12-12 12:57:15 +01:00
Ghostkeeper 38a1ee4270 Revert "Allow going to stand-by temperature if nozzle is later used"
This reverts commit 3c0d3f1b2d.

Contributes to issue CURA-2795.
2016-12-12 12:57:15 +01:00
Ghostkeeper 63459d5cd4 Revert "Correct documentation on why the temperature is switched off later"
This reverts commit 6972101d7e.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 138691436e Revert "Correct technicality in documentation"
This reverts commit ab2c2eed4b.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper b9c5b4593b Revert "Remove unused parameter"
This reverts commit b7e9f72023.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper a0a3a24dc1 Revert "Restore park distance exception for BFB g-code"
This reverts commit b6355b69e7.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 5959b41132 Revert "Use filament park distance setting instead of direct heat & cool zones"
This reverts commit b0487fa4c7.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 3d7229c9f2 Revert "Turn extruder temperature off only if it parked the filament"
This reverts commit 84d3381be6.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper e1cfc3d93b Revert "Break retraction in two"
This reverts commit a0625aa735.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 5834540bec Revert "Rename writeRetractionMove to writeMoveFilament"
This reverts commit 7c39b6b26a.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper f191d23e17 Revert "Pass retraction configs by reference instead of pointer"
This reverts commit 7a8be50b8f.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 5114ab4218 Revert "Use writeMoveFilament to retract to parking distance"
This reverts commit cb7b7bf22a.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 9f5645ecac Revert "Protect writeMoveFilament"
This reverts commit 52220ccab8.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper 66befe5827 Revert "Correct documentation of extruder_switch parameter"
This reverts commit 4263801d16.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper c9de64f946 Revert "Use optional to denote uninitiated previous extruder temperature"
This reverts commit 460c52ea6c.

Contributes to issue CURA-2795.
2016-12-12 12:57:14 +01:00
Ghostkeeper dbfa3a0f4b Revert "Move park distance data to ExtruderTrainAttributes"
This reverts commit 7777668b86.

Contributes to issue CURA-2795.
2016-12-12 12:54:56 +01:00
Ghostkeeper 02268eb7e8 Revert "Park via E-moves instead of via a retraction"
This reverts commit 6350f47cd6.

Contributes to issue CURA-2795.
2016-12-12 12:54:56 +01:00
67 arquivos alterados com 1897 adições e 733 exclusões
+10 -4
Ver Arquivo
@@ -54,14 +54,13 @@ 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/WallsComputation.cpp
src/LayerPlanBuffer.cpp
src/Material.cpp
src/MaterialBase.cpp
src/MergeInfillLines.cpp
src/mesh.cpp
src/MeshGroup.cpp
@@ -74,8 +73,6 @@ set(engine_SRCS # Except main.cpp.
src/sliceDataStorage.cpp
src/support.cpp
src/timeEstimate.cpp
src/TexturedMesh.cpp
src/TextureProcessor.cpp
src/WallsComputation.cpp
src/wallOverlap.cpp
src/Weaver.cpp
@@ -93,8 +90,17 @@ set(engine_SRCS # Except main.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
src/pathPlanning/NozzleTempInsert.cpp
src/pathPlanning/TimeMaterialEstimates.cpp
src/progress/Progress.cpp
+5
Ver Arquivo
@@ -0,0 +1,5 @@
https://github.com/nothings/stb
Thanks to Sean T. Barrett
license: public domain
+46 -19
Ver Arquivo
@@ -1,5 +1,3 @@
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
#include <list>
@@ -8,6 +6,7 @@
#include "FffProcessor.h"
#include "progress/Progress.h"
#include "wallOverlap.h"
#include "FuzzyWalls.h"
#include "utils/orderOptimizer.h"
namespace cura
@@ -739,9 +738,24 @@ void FffGcodeWriter::addMeshLayerToGCode_meshSurfaceMode(SliceDataStorage& stora
polygons.add(layer->parts[partNr].outline);
}
PolygonFlowAdjuster* flow_adjuster(nullptr);
if (mesh->getSettingBoolean("fuzz_map_enabled") || mesh->getSettingBoolean("magic_fuzzy_skin_enabled"))
{
FuzzyWalls* fuzzy_processor = new FuzzyWalls(*mesh);
flow_adjuster = fuzzy_processor;
polygons = fuzzy_processor->makeFuzzy(*mesh, layer_nr, polygons);
} else if (mesh->getSettingBoolean("compensate_overlap_0"))
{
flow_adjuster = new WallOverlapComputation(polygons, mesh->getSettingInMicrons("wall_line_width_0"));
}
EZSeamType z_seam_type = mesh->getSettingAsZSeamType("z_seam_type");
Point z_seam_pos(mesh->getSettingInMicrons("z_seam_x"), mesh->getSettingInMicrons("z_seam_y"));
gcode_layer.addPolygonsByOptimizer(polygons, &mesh->inset0_config, nullptr, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), mesh->getSettingBoolean("magic_spiralize"));
gcode_layer.addPolygonsByOptimizer(polygons, &mesh->inset0_config, flow_adjuster, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), mesh->getSettingBoolean("magic_spiralize"));
if (flow_adjuster)
{
delete flow_adjuster;
}
addMeshOpenPolyLinesToGCode(storage, mesh, gcode_layer, layer_nr);
}
@@ -1012,16 +1026,23 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
}
if (processed_inset_number == 0)
{
if (!compensate_overlap_0)
Polygons* outer_wall = &part.insets[0];
Polygons fuzzy_outer_wall;
PolygonFlowAdjuster* flow_adjuster(nullptr);
if (mesh->getSettingBoolean("fuzz_map_enabled") || mesh->getSettingBoolean("magic_fuzzy_skin_enabled"))
{
WallOverlapComputation* wall_overlap_computation(nullptr);
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->inset0_config, wall_overlap_computation, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
FuzzyWalls* fuzzy_processor = new FuzzyWalls(*mesh);
flow_adjuster = fuzzy_processor;
fuzzy_outer_wall = fuzzy_processor->makeFuzzy(*mesh, layer_nr, *outer_wall);
outer_wall = &fuzzy_outer_wall;
} else if (compensate_overlap_0)
{
flow_adjuster = new WallOverlapComputation(*outer_wall, mesh->getSettingInMicrons("wall_line_width_0"));
}
else
gcode_layer.addPolygonsByOptimizer(*outer_wall, &mesh->inset0_config, flow_adjuster, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
if (flow_adjuster)
{
Polygons& outer_wall = part.insets[0];
WallOverlapComputation wall_overlap_computation(outer_wall, mesh->getSettingInMicrons("wall_line_width_0"));
gcode_layer.addPolygonsByOptimizer(outer_wall, &mesh->inset0_config, &wall_overlap_computation, z_seam_type, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), spiralize);
delete flow_adjuster;
}
}
else
@@ -1141,24 +1162,30 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
{ // handle perimeter gaps of normal insets
Polygons perimeter_gaps;
int line_width = mesh->inset0_config.getLineWidth();
for (unsigned int inset_idx = 0; inset_idx < part.insets.size(); inset_idx++)
for (unsigned int inset_idx = 0; inset_idx < part.insets.size() - 1; inset_idx++)
{
if (inset_idx == 0 && (mesh->getSettingBoolean("fuzz_map_enabled") || mesh->getSettingBoolean("magic_fuzzy_skin_enabled")))
{
continue;
}
const Polygons outer = part.insets[inset_idx].offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
line_width = mesh->insetX_config.getLineWidth();
Polygons inner;
if (inset_idx + 1 < part.insets.size())
Polygons inner = part.insets[inset_idx + 1].offset(line_width / 2);
perimeter_gaps.add(outer.difference(inner));
}
{ // gap between inner wall and skin/infill
if (mesh->getSettingInMicrons("infill_line_distance") > 0 && !mesh->getSettingBoolean("infill_hollow"))
{
inner = part.insets[inset_idx + 1].offset(line_width / 2);
}
else
{
inner = part.infill_area;
const Polygons outer = part.insets.back().offset(-1 * line_width / 2 - perimeter_gaps_extra_offset);
Polygons inner = part.infill_area;
for (SkinPart& skin_part : part.skin_parts)
{
inner.add(skin_part.outline);
}
perimeter_gaps.add(outer.difference(inner));
}
perimeter_gaps.add(outer.difference(inner));
}
Polygons skin_polygons; // unused
+1 -1
Ver Arquivo
@@ -37,7 +37,7 @@ 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 GCodePlanner)
+22 -74
Ver Arquivo
@@ -2,6 +2,7 @@
#include <algorithm>
#include <map> // multimap (ordered map allowing duplicate keys)
#include <functional> // function
#include "utils/math.h"
#include "slicer/Slicer.h"
@@ -12,7 +13,8 @@
#include "support.h"
#include "slicer/MultiVolumes.h"
#include "slicer/LayerPart.h"
#include "TextureProcessor.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"));
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)
@@ -136,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];
// 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"))
{
@@ -472,12 +488,6 @@ 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);
}
}
void FffPolygonGenerator::processInsets(SliceMeshStorage& mesh, unsigned int layer_nr)
@@ -708,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
+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
-27
Ver Arquivo
@@ -1,27 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MAT_COORD_H
#define MAT_COORD_H
#include "utils/FPoint.h"
namespace cura
{
/*!
* Coordinates in a specific texture bitmap
*/
struct MatCoord
{
FPoint coords;
int mat_id; //!< Material id
MatCoord() //!< non-initializing constructor
{}
MatCoord(FPoint coords, int mat_id) //!< constructor
: coords(coords)
, mat_id(mat_id)
{}
};
} // namespace cura
#endif // MAT_COORD_H
+17 -30
Ver Arquivo
@@ -3,9 +3,6 @@
#include <strings.h>
#include <stdio.h>
#define STB_IMAGE_IMPLEMENTATION // needed in order to enable the implementation of libs/std_image.h
#include "stb/stb_image.h"
#include "MeshGroup.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
@@ -340,24 +337,6 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
return loadMeshSTL_binary(mesh, filename, matrix);
}
void loadMatImage(Material* mat, const char* filename)
{
int width;
int height;
int depth;
// in RGBA order
unsigned char* data = stbi_load(filename, &width, &height, &depth, 0);
if (data)
{
mat->setData(data);
mat->setDimensions(width, height, depth);
}
else
{
logError("Cannot load image %s.", filename);
}
}
void loadMaterialBase(TexturedMesh* mesh, const char* filename)
{
FILE* f = fopen(filename, "rt");
@@ -388,7 +367,7 @@ void loadMaterialBase(TexturedMesh* mesh, const char* filename)
std::string mtl_file = parent_dir + "/" + mat_file;
if (last_mat)
{
loadMatImage(last_mat, mtl_file.c_str());
last_mat->loadImage(mtl_file.c_str());
}
}
else if (sscanf(buffer, "newmtl %s", mat_name) == 1)
@@ -408,7 +387,7 @@ bool loadMeshOBJ(TexturedMesh* mesh, const char* filename, const FMatrix3x3& mat
}
char buffer[1024];
FPoint3 vertex;
Point3 vertex_indices;
int vertex_indices[3];
float texture_x;
float texture_y;
float temp;
@@ -434,15 +413,19 @@ bool loadMeshOBJ(TexturedMesh* mesh, const char* filename, const FMatrix3x3& mat
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
Point3 texture_indices(0, 0, 0); // becomes -1 if no texture data supplied
int n_scanned_1 = sscanf(face_index_buffer_1, "%d/%d/%d", &vertex_indices.x, &texture_indices.x, &normal_vector_index);
int n_scanned_2 = sscanf(face_index_buffer_2, "%d/%d/%d", &vertex_indices.y, &texture_indices.y, &normal_vector_index);
int n_scanned_3 = sscanf(face_index_buffer_3, "%d/%d/%d", &vertex_indices.z, &texture_indices.z, &normal_vector_index);
if (n_scanned_1 > 0 && n_scanned_2 > 0 && n_scanned_3 > 0)
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.x - 1, vertex_indices.y - 1, vertex_indices.z - 1, texture_indices.x - 1, texture_indices.y - 1, texture_indices.z - 1);
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)
{
@@ -456,7 +439,11 @@ bool loadMeshOBJ(TexturedMesh* mesh, const char* filename, const FMatrix3x3& mat
}
else if (sscanf(buffer, "vn %f %f %f", &temp, &temp, &temp) == 3)
{
// do nothing
// do nothing with vertex normals
}
else if (sscanf(buffer, "g %s", str_buffer) == 1)
{
// do nothing with polygon groups
}
else if (buffer[0] == '\0')
{
+1 -1
Ver Arquivo
@@ -4,7 +4,7 @@
#include "utils/NoCopy.h"
#include "mesh.h"
#include "TexturedMesh.h"
#include "textureProcessing/TexturedMesh.h"
#include "ExtruderTrain.h"
namespace cura
+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
-141
Ver Arquivo
@@ -1,141 +0,0 @@
#include "TextureProcessor.h"
#include <algorithm> // swap
#include "utils/optional.h"
#include "slicer/SlicerSegment.h"
namespace cura
{
#define POINT_DIST 400
#define AMPLITUDE 3000
#define EXTRA_OFFSET 3000
/*
void TextureProcessor::process(std::vector< Slicer* >& slicer_list)
{
for (Slicer* slicer : slicer_list)
{
for (SlicerLayer& layer : slicer->layers)
{
process(slicer->mesh, layer);
}
}
}
*/
void TextureProcessor::processSegmentBumpMap(const Mesh* mesh, const SlicerSegment& slicer_segment, const MatSegment& mat, const Point p0, const Point p1, coord_t& dist_left_over, PolygonRef result)
{
MatCoord mat_start = mat.start;
MatCoord mat_end = mat.end;
if (vSize2(slicer_segment.start - p0) > vSize2(slicer_segment.start - p1))
{
std::swap(mat_start, mat_end);
}
Point p0p1 = p1 - p0;
int64_t p0p1_size = vSize(p0p1);
if (dist_left_over >= p0p1_size)
{
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
// TODO: move start point (which was already moved last iteration
for (int64_t p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; p0pa_dist += POINT_DIST)
{
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 = mesh->getColor(mat_coord_now, ColourUsage::GREY);
int offset = val * (AMPLITUDE * 2) - AMPLITUDE + EXTRA_OFFSET;
Point fuzz = normal(perp_to_p0p1, offset);
Point pa = p0 + normal(p0p1, p0pa_dist) - fuzz;
result.add(pa);
dist_last_point = p0pa_dist;
}
// TODO: move end point as well
float val = mesh->getColor(mat_end, ColourUsage::GREY);
int r = val * (AMPLITUDE * 2) - AMPLITUDE + EXTRA_OFFSET;
Point fuzz = normal(perp_to_p0p1, r);
result.emplace_back(p1 - fuzz);
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 <= POINT_DIST);
}
void TextureProcessor::processBumpMap(const Mesh* mesh, SlicerLayer& layer)
{
Polygons results;
for (PolygonRef poly : layer.polygons)
{
// generate points in between p0 and p1
PolygonRef result = results.newPoly();
coord_t dist_left_over = (POINT_DIST / 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
if (*p0 == p1)
{
continue;
}
SlicerSegment segment(*p0, p1);
std::optional<std::pair<SlicerSegment, MatSegment>> best_mat_segment_it;
coord_t best_dist_score = std::numeric_limits<coord_t>::max();
for (std::unordered_map<SlicerSegment, MatSegment>::iterator it = layer.segment_to_material_segment.begin(); it != layer.segment_to_material_segment.end(); ++it)
{
const SlicerSegment& sliced_segment = it->first;
coord_t dist_score = std::min(
vSize2(sliced_segment.start - segment.start) + vSize2(sliced_segment.end - segment.end)
, vSize2(sliced_segment.end - segment.start) + vSize2(sliced_segment.start - segment.end)
);
if (dist_score < best_dist_score)
{
best_dist_score = dist_score;
best_mat_segment_it = *it;
}
}
if (best_dist_score < 30 * 30) // TODO: magic value of 0.03mm for total stitching distance > should be something like SlicerLayer.cpp::largest_neglected_gap_second_phase (?)
{
assert(best_mat_segment_it);
processSegmentBumpMap(mesh, best_mat_segment_it->first, best_mat_segment_it->second, *p0, p1, dist_left_over, result);
}
else
{
result.emplace_back(p1);
}
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);
}
}
// 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
-25
Ver Arquivo
@@ -1,25 +0,0 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURE_PROCESSOR_H
#define TEXTURE_PROCESSOR_H
#include <vector>
#include "slicer/Slicer.h"
#include "mesh.h"
namespace cura
{
class TextureProcessor
{
public:
// static void process(std::vector<Slicer*>& slicer_list);
static void processBumpMap(const Mesh* mesh, SlicerLayer& layer);
protected:
static void processSegmentBumpMap(const Mesh* mesh, const SlicerSegment& slicer_segment, const MatSegment& mat, const Point p0, const Point p1, coord_t& dist_left_over, PolygonRef result);
};
} // namespace cura
#endif // TEXTURE_PROCESSOR_H
+1 -1
Ver Arquivo
@@ -25,7 +25,7 @@ void Weaver::weave(MeshGroup* meshgroup)
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);
}
+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;
+16 -16
Ver Arquivo
@@ -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.
+14 -32
Ver Arquivo
@@ -1,7 +1,4 @@
//Copyright (c) 2013 David Braam
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdarg.h>
#include <iomanip>
#include <cmath>
@@ -14,6 +11,8 @@
namespace cura {
double layer_height; //!< report basic layer height in RepRap gcode file.
GCodeExport::GCodeExport()
: output_stream(&std::cout)
, currentPosition(0,0,MM2INT(20))
@@ -84,7 +83,7 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
extruder_attr[extruder_nr].prime_pos = Point3(train->getSettingInMicrons("extruder_prime_pos_x"), train->getSettingInMicrons("extruder_prime_pos_y"), train->getSettingInMicrons("extruder_prime_pos_z"));
extruder_attr[extruder_nr].prime_pos_is_abs = train->getSettingBoolean("extruder_prime_pos_abs");
extruder_attr[extruder_nr].park_distance = train->getSettingInMillimeters("machine_filament_park_distance");
extruder_attr[extruder_nr].nozzle_size = train->getSettingInMicrons("machine_nozzle_size");
extruder_attr[extruder_nr].nozzle_offset = Point(train->getSettingInMicrons("machine_nozzle_offset_x"), train->getSettingInMicrons("machine_nozzle_offset_y"));
extruder_attr[extruder_nr].material_guid = train->getSettingString("material_guid");
@@ -100,6 +99,8 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
machine_name = meshgroup->getSettingString("machine_name");
layer_height = meshgroup->getSettingInMillimeters("layer_height");
if (flavor == EGCodeFlavor::BFB)
{
new_line = "\r\n";
@@ -197,6 +198,7 @@ std::string GCodeExport::getFileHeader(const double* print_time, const std::vect
else if (flavor == EGCodeFlavor::REPRAP)
{
prefix << ";Filament used: " << ((filament_used.size() >= 1)? filament_used[0] / (1000 * extruder_attr[0].filament_area) : 0) << "m" << new_line;
prefix << ";Layer height: " << layer_height << new_line;
}
return prefix.str();
}
@@ -689,11 +691,12 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
extruded_volume_at_previous_n_retractions.pop_back();
}
}
if (firmware_retract)
{
if (extruder_switch && extr_attr.retraction_e_amount_current)
if (extruder_switch && extr_attr.retraction_e_amount_current)
{
return;
return;
}
*output_stream << "G10";
if (extruder_switch)
@@ -704,20 +707,6 @@ void GCodeExport::writeRetraction(const RetractionConfig& config, bool force, bo
//Assume default UM2 retraction settings.
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), eToMm(current_e_value + retraction_diff_e_amount)), 25); // TODO: hardcoded values!
}
writeMoveFilament(config, config.distance);
}
void GCodeExport::writeMoveFilament(const RetractionConfig& config, const double new_retraction_distance)
{
ExtruderTrainAttributes& extr_attr = extruder_attr[current_extruder];
const double old_retraction_e_amount = extr_attr.retraction_e_amount_current;
const double new_retraction_e_amount = mmToE(new_retraction_distance);
const double retraction_diff_e_amount = old_retraction_e_amount - new_retraction_e_amount;
if (std::abs(retraction_diff_e_amount) < 0.000001)
{
return; //No need to have detailed extrusion moves this small.
}
else
{
double speed = ((retraction_diff_e_amount < 0.0)? config.speed : extr_attr.last_retraction_prime_speed) * 60;
@@ -780,21 +769,14 @@ void GCodeExport::startExtruder(int new_extruder)
currentPosition.z += 1;
}
void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder, const bool turn_off_extruder)
void GCodeExport::switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder)
{
if (current_extruder == new_extruder)
return;
if (turn_off_extruder)
{
writeMoveFilament(retraction_config_old_extruder, extruder_attr[current_extruder].park_distance);
}
else
{
bool force = true;
bool extruder_switch = true;
writeRetraction(const_cast<RetractionConfig&>(retraction_config_old_extruder), force, extruder_switch);
}
bool force = true;
bool extruder_switch = true;
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
+2 -21
Ver Arquivo
@@ -1,7 +1,4 @@
//Copyright (c) 2013 David Braam
//Copyright (c) 2016 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef GCODEEXPORT_H
#define GCODEEXPORT_H
@@ -62,7 +59,6 @@ private:
double retraction_e_amount_current; //!< The current retracted amount (in mm or mm^3), or zero(i.e. false) if it is not currently retracted (positive values mean retracted amount, so negative impact on E values)
double retraction_e_amount_at_e_start; //!< The ExtruderTrainAttributes::retraction_amount_current value at E0, i.e. the offset (in mm or mm^3) from E0 to the situation where the filament is at the tip of the nozzle.
double park_distance; //!< The distance from the nozzle at which to park filament after having completed printing with it.
double prime_volume; //!< Amount of material (in mm^3) to be primed after an unretration (due to oozing and/or coasting)
double last_retraction_prime_speed; //!< The last prime speed (in mm/s) of the to-be-primed amount
@@ -83,7 +79,6 @@ private:
, initial_temp(0)
, retraction_e_amount_current(0.0)
, retraction_e_amount_at_e_start(0.0)
, park_distance(0.0)
, prime_volume(0.0)
, last_retraction_prime_speed(0.0)
{ }
@@ -163,18 +158,6 @@ protected:
*/
double mmToE(double mm);
/*!
* \brief Write a move in the E-direction such that the filament is
* retracted or unretracted to the specified distance.
*
* No checks are made for the maximum number of retractions.
*
* \param config The configuration from which to get the distance and speed.
* \param new_retraction_distance The distance from the tip of the nozzle
* where the filament is supposed to end up.
*/
void writeMoveFilament(const RetractionConfig& config, const double new_retraction_distance);
public:
GCodeExport();
@@ -313,10 +296,8 @@ public:
*
* \param new_extruder The extruder to switch to
* \param retraction_config_old_extruder The extruder switch retraction config of the old extruder, to perform the extruder switch retraction with.
* \param turn_off_extruder Should the old extruder be turned off
* completely?
*/
void switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder, const bool turn_off_extruder = false);
void switchExtruder(int new_extruder, const RetractionConfig& retraction_config_old_extruder);
void writeCode(const char* str);
+29 -26
Ver Arquivo
@@ -355,21 +355,25 @@ void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config, SpaceFillT
lastPosition = p;
}
void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, 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)
{
Point& p1 = polygon[start_idx];
float flow = (wall_overlap_computation)? wall_overlap_computation->getFlow(p0, p1) : 1.0;
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)
@@ -403,7 +407,7 @@ void GCodePlanner::addPolygon(PolygonRef polygon, int start_idx, GCodePathConfig
}
}
void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, 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)
{
@@ -417,7 +421,7 @@ void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* c
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 GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config, SpaceFillType space_fill_type, int wipe_dist)
@@ -663,17 +667,14 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
{
ExtruderPlan& extruder_plan = extruder_plans[extruder_plan_idx];
RetractionConfig& retraction_config = storage.retraction_config_per_extruder[extruder_plan.extruder];
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder);
if (extruder != extruder_plan.extruder)
{
int prev_extruder = extruder;
extruder = extruder_plan.extruder;
gcode.switchExtruder(extruder, storage.extruder_switch_retraction_config_per_extruder[prev_extruder]);
const int prev_layer_nr = (extruder_plan_idx == 0) ? layer_nr - 1 : layer_nr;
const bool turn_off_extruder = prev_layer_nr >= storage.max_print_height_per_extruder[prev_extruder]; //Previous extruder is not used any more in this mesh group.
gcode.switchExtruder(extruder, storage.extruder_switch_retraction_config_per_extruder[prev_extruder], turn_off_extruder);
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder);
if (train->getSettingInMillimetersPerSecond("max_feedrate_z_override") > 0)
{
gcode.writeMaxZFeedrate(train->getSettingInMillimetersPerSecond("max_feedrate_z_override"));
@@ -684,22 +685,23 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
gcode.writeTemperatureCommand(extruder, extruder_plan.initial_printing_temperature, wait);
}
std::optional<double> prev_extruder_temp = std::optional<double>();
if (turn_off_extruder)
{
prev_extruder_temp = 0; //Turn previous extruder off entirely. TODO: Should there be a setting for the temperature to turn an extruder off?
}
else if (extruder_plan.prev_extruder_standby_temp)
{
prev_extruder_temp = *extruder_plan.prev_extruder_standby_temp; //Not entirely, but just to stand-by temperature.
}
if (prev_extruder_temp) //One of the if-statements above went through.
{
// prime extruder if it hadn't been used yet
gcode.writePrimeTrain(storage.meshgroup->getExtruderTrain(extruder)->getSettingInMillimetersPerSecond("speed_travel"));
gcode.writeRetraction(retraction_config);
if (extruder_plan.prev_extruder_standby_temp)
{ // turn off previous extruder
constexpr bool wait = false;
gcode.writeTemperatureCommand(prev_extruder, *prev_extruder_temp, wait);
double prev_extruder_temp = *extruder_plan.prev_extruder_standby_temp;
int prev_layer_nr = (extruder_plan_idx == 0)? layer_nr - 1 : layer_nr;
if (prev_layer_nr == storage.max_print_height_per_extruder[prev_extruder])
{
prev_extruder_temp = 0; // TODO ? should there be a setting for extruder_off_temperature ?
}
gcode.writeTemperatureCommand(prev_extruder, prev_extruder_temp, wait);
}
}
else if (extruder_plan_idx == 0 && layer_nr != 0 && train->getSettingBoolean("retract_at_layer_change"))
else if (extruder_plan_idx == 0 && layer_nr != 0 && storage.meshgroup->getExtruderTrain(extruder)->getSettingBoolean("retract_at_layer_change"))
{
gcode.writeRetraction(retraction_config);
}
@@ -710,6 +712,7 @@ void GCodePlanner::writeGCode(GCodeExport& gcode)
return a.path_idx < b.path_idx;
} );
const ExtruderTrain* train = storage.meshgroup->getExtruderTrain(extruder);
if (train->getSettingInMillimetersPerSecond("max_feedrate_z_override") > 0)
{
gcode.writeMaxZFeedrate(train->getSettingInMillimetersPerSecond("max_feedrate_z_override"));
@@ -987,7 +990,7 @@ void GCodePlanner::processInitialLayersSpeedup()
bool GCodePlanner::makeRetractSwitchRetract(unsigned int extruder_plan_idx, unsigned int path_idx)
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++)
+10 -8
Ver Arquivo
@@ -11,7 +11,7 @@
#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"
@@ -381,14 +381,15 @@ public:
/*!
* 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(PolygonRef polygon, int startIdx, 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.
@@ -401,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(Polygons& polygons, 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.
@@ -451,12 +452,13 @@ public:
/*!
* Whether the current retracted path is to be an extruder switch retraction.
* This function is used to avoid a G10 S1 after a G10.
*
*
* \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 of the current retracted path
* \return Whether the path should be an extgruder switch retracted path
*/
bool makeRetractSwitchRetract(unsigned int extruder_plan_idx, unsigned int path_idx);
bool makeRetractSwitchRetract(GCodeExport& gcode, unsigned int extruder_plan_idx, unsigned int path_idx);
/*!
* Writes a path to GCode and performs coasting, or returns false if it did nothing.
+25 -13
Ver Arquivo
@@ -41,16 +41,20 @@ void SubDivCube::precomputeOctree(SliceMeshStorage& mesh)
coord_t max_side_length = furthest_dist_from_origin * 2;
int curr_recursion_depth = 0;
for (int64_t curr_side_length = mesh.getSettingInMicrons("infill_line_distance") * 2; curr_side_length < max_side_length * 2; curr_side_length *= 2)
const int64_t infill_line_distance = mesh.getSettingInMicrons("infill_line_distance");
if (infill_line_distance > 0)
{
cube_properties_per_recursion_step.emplace_back();
CubeProperties& cube_properties_here = cube_properties_per_recursion_step.back();
cube_properties_here.side_length = curr_side_length;
cube_properties_here.height = sqrt(3) * curr_side_length;
cube_properties_here.square_height = sqrt(2) * curr_side_length;
cube_properties_here.max_draw_z_diff = ONE_OVER_SQRT_3 * curr_side_length;
cube_properties_here.max_line_offset = ONE_OVER_SQRT_6 * curr_side_length;
curr_recursion_depth++;
for (int64_t curr_side_length = infill_line_distance * 2; curr_side_length < max_side_length * 2; curr_side_length *= 2)
{
cube_properties_per_recursion_step.emplace_back();
CubeProperties& cube_properties_here = cube_properties_per_recursion_step.back();
cube_properties_here.side_length = curr_side_length;
cube_properties_here.height = sqrt(3) * curr_side_length;
cube_properties_here.square_height = sqrt(2) * curr_side_length;
cube_properties_here.max_draw_z_diff = ONE_OVER_SQRT_3 * curr_side_length;
cube_properties_here.max_line_offset = ONE_OVER_SQRT_6 * curr_side_length;
curr_recursion_depth++;
}
}
Point3 center(0, 0, 0);
@@ -80,6 +84,10 @@ void SubDivCube::precomputeOctree(SliceMeshStorage& mesh)
void SubDivCube::generateSubdivisionLines(int64_t z, Polygons& result)
{
if (cube_properties_per_recursion_step.empty()) //Infill is set to 0%.
{
return;
}
Polygons directional_line_groups[3];
generateSubdivisionLines(z, result, directional_line_groups);
@@ -136,17 +144,21 @@ void SubDivCube::generateSubdivisionLines(int64_t z, Polygons& result, Polygons
}
}
SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth)
SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int depth)
{
this->depth = depth;
this->center = center;
CubeProperties cube_properties = cube_properties_per_recursion_step[depth];
if (depth == 0) // lowest layer, no need for subdivision, exit.
{
return;
}
if (depth >= cube_properties_per_recursion_step.size()) //Depth is out of bounds of what we pre-computed.
{
return;
}
CubeProperties cube_properties = cube_properties_per_recursion_step[depth];
Point3 child_center;
coord_t radius = double(radius_multiplier * double(cube_properties.height)) / 4.0 + radius_addition;
@@ -162,7 +174,7 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth)
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);
+2 -2
Ver Arquivo
@@ -17,7 +17,7 @@ public:
* \param my_center the center of the cube
* \param depth the recursion depth of the cube (0 is most recursed)
*/
SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth);
SubDivCube(SliceMeshStorage& mesh, Point3& center, unsigned int depth);
~SubDivCube(); //!< destructor (also destroys children
@@ -84,7 +84,7 @@ private:
*/
void addLineAndCombine(Polygons& group, Point from, Point to);
int depth; //!< the recursion depth of the cube (0 is most recursed)
unsigned int depth; //!< the recursion depth of the cube (0 is most recursed)
Point3 center; //!< center location of the cube in absolute coordinates
SubDivCube* children[8] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; //!< pointers to this cube's eight octree children
static std::vector<CubeProperties> cube_properties_per_recursion_step; //!< precomputed array of basic properties of cubes based on recursion depth.
+1
Ver Arquivo
@@ -11,6 +11,7 @@
#include <stddef.h>
#include <vector>
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/string.h"
-11
Ver Arquivo
@@ -208,16 +208,5 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx, int notFaceVe
return bestIdx;
}
bool Mesh::registerFaceSlice(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
{
// do nothing for a non-textured mesh
return false;
}
float Mesh::getColor(MatCoord, ColourUsage) const
{
return 0.0f;
}
}//namespace cura
+1 -8
Ver Arquivo
@@ -3,7 +3,7 @@
#include "settings/settings.h"
#include "utils/AABB3D.h"
#include "MatSegment.h"
#include "textureProcessing/MatSegment.h"
namespace cura
{
@@ -106,13 +106,6 @@ public:
aabb.offset(offset);
}
/*!
* \return Whether a texture line segment has been created
*/
virtual bool registerFaceSlice(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;
virtual float getColor(MatCoord bitmap_coord, ColourUsage color) const;
private:
int findIndexOfVertex(const Point3& v); //!< find index of vertex close to the given point, or create a new vertex and return its index.
+1 -1
Ver Arquivo
@@ -8,7 +8,7 @@
#include "../utils/polygonUtils.h"
#include "../utils/PolygonsPointIndex.h"
#include "../sliceDataStorage.h"
#include "../utils/SVG.h"
#include "../utils/linearAlg2D.h"
namespace cura {
+24
Ver Arquivo
@@ -0,0 +1,24 @@
//Copyright (C) 2016 Ultimaker
//Released under terms of the AGPLv3 License
#include "GCodePath.h"
namespace cura
{
bool GCodePath::isTravelPath()
{
return config->isTravelPath();
}
double GCodePath::getExtrusionMM3perMM()
{
return flow * config->getExtrusionMM3perMM();
}
int GCodePath::getLineWidth()
{
return flow * config->getLineWidth() * config->getFlowPercentage() / 100.0;
}
}
+3 -12
Ver Arquivo
@@ -41,10 +41,7 @@ public:
*
* \return Whether this config is the config of a travel path.
*/
bool isTravelPath()
{
return config->isTravelPath();
}
bool isTravelPath();
/*!
* Get the material flow in mm^3 per mm traversed.
@@ -53,19 +50,13 @@ public:
*
* \return The flow
*/
double getExtrusionMM3perMM()
{
return flow * config->getExtrusionMM3perMM();
}
double getExtrusionMM3perMM();
/*!
* Get the actual line width (modulated by the flow)
* \return the actual line width as shown in layer view
*/
int getLineWidth()
{
return flow * config->getLineWidth() * config->getFlowPercentage() / 100.0;
}
int getLineWidth();
};
}//namespace cura
+24
Ver Arquivo
@@ -0,0 +1,24 @@
//Copyright (C) 2016 Ultimaker
//Released under terms of the AGPLv3 License
#include "NozzleTempInsert.h"
namespace cura
{
NozzleTempInsert::NozzleTempInsert(unsigned int path_idx, int extruder, double temperature, bool wait, double time_after_path_start)
: path_idx(path_idx)
, time_after_path_start(time_after_path_start)
, extruder(extruder)
, temperature(temperature)
, wait(wait)
{
assert(temperature != 0 && temperature != -1 && "Temperature command must be set!");
}
void NozzleTempInsert::write(GCodeExport& gcode)
{
gcode.writeTemperatureCommand(extruder, temperature, wait);
}
}
+2 -13
Ver Arquivo
@@ -19,24 +19,13 @@ struct NozzleTempInsert
int extruder; //!< The extruder for which to set the temp
double temperature; //!< The temperature of the temperature command to insert
bool wait; //!< Whether to wait for the temperature to be reached
NozzleTempInsert(unsigned int path_idx, int extruder, double temperature, bool wait, double time_after_path_start = 0.0)
: path_idx(path_idx)
, time_after_path_start(time_after_path_start)
, extruder(extruder)
, temperature(temperature)
, wait(wait)
{
assert(temperature != 0 && temperature != -1 && "Temperature command must be set!");
}
NozzleTempInsert(unsigned int path_idx, int extruder, double temperature, bool wait, double time_after_path_start = 0.0);
/*!
* Write the temperature command at the current position in the gcode.
* \param gcode The actual gcode writer
*/
void write(GCodeExport& gcode)
{
gcode.writeTemperatureCommand(extruder, temperature, wait);
}
void write(GCodeExport& gcode);
};
}//namespace cura
+63
Ver Arquivo
@@ -4,6 +4,22 @@
namespace cura
{
TimeMaterialEstimates::TimeMaterialEstimates(double extrude_time, double unretracted_travel_time, double retracted_travel_time, double material)
: extrude_time(extrude_time)
, unretracted_travel_time(unretracted_travel_time)
, retracted_travel_time(retracted_travel_time)
, material(material)
{
}
TimeMaterialEstimates::TimeMaterialEstimates()
: extrude_time(0.0)
, unretracted_travel_time(0.0)
, retracted_travel_time(0.0)
, material(0.0)
{
}
TimeMaterialEstimates TimeMaterialEstimates::operator-(const TimeMaterialEstimates& other)
{
return TimeMaterialEstimates(extrude_time - other.extrude_time,unretracted_travel_time - other.unretracted_travel_time,retracted_travel_time - other.retracted_travel_time,material - other.material);
@@ -18,4 +34,51 @@ TimeMaterialEstimates& TimeMaterialEstimates::operator-=(const TimeMaterialEstim
return *this;
}
TimeMaterialEstimates TimeMaterialEstimates::operator+(const TimeMaterialEstimates& other)
{
return TimeMaterialEstimates(extrude_time+other.extrude_time, unretracted_travel_time+other.unretracted_travel_time, retracted_travel_time+other.retracted_travel_time, material+other.material);
}
TimeMaterialEstimates& TimeMaterialEstimates::operator+=(const TimeMaterialEstimates& other)
{
extrude_time += other.extrude_time;
unretracted_travel_time += other.unretracted_travel_time;
retracted_travel_time += other.retracted_travel_time;
material += other.material;
return *this;
}
double TimeMaterialEstimates::getExtrudeTime() const
{
return extrude_time;
}
double TimeMaterialEstimates::getMaterial() const
{
return material;
}
double TimeMaterialEstimates::getTotalTime() const
{
return extrude_time + unretracted_travel_time + retracted_travel_time;
}
double TimeMaterialEstimates::getTotalUnretractedTime() const
{
return extrude_time + unretracted_travel_time;
}
double TimeMaterialEstimates::getTravelTime() const
{
return retracted_travel_time + unretracted_travel_time;
}
void TimeMaterialEstimates::reset()
{
extrude_time = 0.0;
unretracted_travel_time = 0.0;
retracted_travel_time = 0.0;
material = 0.0;
}
}//namespace cura
+10 -53
Ver Arquivo
@@ -29,35 +29,17 @@ public:
* \param retracted_travel_time Time in seconds occupied by retracted travel (non-extrusion)
* \param material Material used (in mm^3)
*/
TimeMaterialEstimates(double extrude_time, double unretracted_travel_time, double retracted_travel_time, double material)
: extrude_time(extrude_time)
, unretracted_travel_time(unretracted_travel_time)
, retracted_travel_time(retracted_travel_time)
, material(material)
{
}
TimeMaterialEstimates(double extrude_time, double unretracted_travel_time, double retracted_travel_time, double material);
/*!
* Basic constructor initializing all estimates to zero.
*/
TimeMaterialEstimates()
: extrude_time(0.0)
, unretracted_travel_time(0.0)
, retracted_travel_time(0.0)
, material(0.0)
{
}
TimeMaterialEstimates();
/*!
* Set all estimates to zero.
*/
void reset()
{
extrude_time = 0.0;
unretracted_travel_time = 0.0;
retracted_travel_time = 0.0;
material = 0.0;
}
void reset();
/*!
* Pointwise addition of estimate stats
@@ -65,10 +47,7 @@ public:
* \param other The estimates to add to these estimates.
* \return The resulting estimates
*/
TimeMaterialEstimates operator+(const TimeMaterialEstimates& other)
{
return TimeMaterialEstimates(extrude_time+other.extrude_time, unretracted_travel_time+other.unretracted_travel_time, retracted_travel_time+other.retracted_travel_time, material+other.material);
}
TimeMaterialEstimates operator+(const TimeMaterialEstimates& other);
/*!
* In place pointwise addition of estimate stats
@@ -76,14 +55,7 @@ public:
* \param other The estimates to add to these estimates.
* \return These estimates
*/
TimeMaterialEstimates& operator+=(const TimeMaterialEstimates& other)
{
extrude_time += other.extrude_time;
unretracted_travel_time += other.unretracted_travel_time;
retracted_travel_time += other.retracted_travel_time;
material += other.material;
return *this;
}
TimeMaterialEstimates& operator+=(const TimeMaterialEstimates& other);
/*!
* \brief Subtracts the specified estimates from these estimates and returns
@@ -112,10 +84,7 @@ public:
*
* \return the total of all different time estimate values
*/
double getTotalTime() const
{
return extrude_time + unretracted_travel_time + retracted_travel_time;
}
double getTotalTime() const;
/*!
* Get the total time during which the head is not retracted.
@@ -124,10 +93,7 @@ public:
*
* \return the total time during which the head is not retracted.
*/
double getTotalUnretractedTime() const
{
return extrude_time + unretracted_travel_time;
}
double getTotalUnretractedTime() const;
/*!
* Get the total travel time.
@@ -136,30 +102,21 @@ public:
*
* \return the total travel time.
*/
double getTravelTime() const
{
return retracted_travel_time + unretracted_travel_time;
}
double getTravelTime() const;
/*!
* Get the extrusion time.
*
* \return extrusion time.
*/
double getExtrudeTime() const
{
return extrude_time;
}
double getExtrudeTime() const;
/*!
* Get the amount of material used in mm^3.
*
* \return amount of material
*/
double getMaterial() const
{
return material;
}
double getMaterial() const;
};
}//namespace cura
+10 -8
Ver Arquivo
@@ -125,6 +125,11 @@ 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()) //... Tough luck, buddy.
{
logError("Couldn't find any extruder trains!\n");
return -1;
}
if (extruder_nr >= extruder_train_ids.size())
{
logWarning("Couldn't load extruder.def.json file for extruder %i. Index out of bounds.\n Loading first extruder definition instead.\n", extruder_nr);
@@ -220,8 +225,7 @@ int SettingRegistry::loadJSONsettingsFromDoc(rapidjson::Document& json_document,
if (json_document.HasMember("settings"))
{
std::list<std::string> path;
handleChildren(json_document["settings"], path, settings_base, warn_duplicates);
handleChildren(json_document["settings"], settings_base, warn_duplicates);
}
if (json_document.HasMember("overrides"))
@@ -243,7 +247,7 @@ int SettingRegistry::loadJSONsettingsFromDoc(rapidjson::Document& json_document,
return 0;
}
void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates)
void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, SettingsBase* settings_base, bool warn_duplicates)
{
if (!settings_list.IsObject())
{
@@ -252,12 +256,10 @@ void SettingRegistry::handleChildren(const rapidjson::Value& settings_list, std:
}
for (rapidjson::Value::ConstMemberIterator setting_iterator = settings_list.MemberBegin(); setting_iterator != settings_list.MemberEnd(); ++setting_iterator)
{
handleSetting(setting_iterator, path, settings_base, warn_duplicates);
handleSetting(setting_iterator, settings_base, warn_duplicates);
if (setting_iterator->value.HasMember("children"))
{
std::list<std::string> path_here = path;
path_here.push_back(setting_iterator->name.GetString());
handleChildren(setting_iterator->value["children"], path_here, settings_base, warn_duplicates);
handleChildren(setting_iterator->value["children"], settings_base, warn_duplicates);
}
}
}
@@ -275,7 +277,7 @@ bool SettingRegistry::settingIsUsedByEngine(const rapidjson::Value& setting)
}
void SettingRegistry::handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates)
void SettingRegistry::handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, SettingsBase* settings_base, bool warn_duplicates)
{
const rapidjson::Value& json_setting = json_setting_it->value;
if (!json_setting.IsObject())
+2 -3
Ver Arquivo
@@ -174,17 +174,16 @@ private:
* \param settings_base The settings base where to store the default values.
* \param warn_duplicates whether to warn for duplicate setting definitions
*/
void handleChildren(const rapidjson::Value& settings_list, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates);
void handleChildren(const rapidjson::Value& settings_list, SettingsBase* settings_base, bool warn_duplicates);
/*!
* Handle a json object for a setting.
*
* \param json_setting_it Iterator for the setting which contains the key (setting name) and attributes info
* \param path The path of (internal) setting names traversed to get to this object
* \param settings_base The settings base where to store the default values.
* \param warn_duplicates whether to warn for duplicate setting definitions
*/
void handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, std::list<std::string>& path, SettingsBase* settings_base, bool warn_duplicates);
void handleSetting(const rapidjson::Value::ConstMemberIterator& json_setting_it, SettingsBase* settings_base, bool warn_duplicates);
};
}//namespace cura
+28 -2
Ver Arquivo
@@ -426,7 +426,7 @@ FillPerimeterGapMode SettingsBaseVirtual::getSettingAsFillPerimeterGapMode(std::
return FillPerimeterGapMode::NOWHERE;
}
CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key)
CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key) const
{
std::string value = getSettingString(key);
if (value == "off")
@@ -444,7 +444,7 @@ CombingMode SettingsBaseVirtual::getSettingAsCombingMode(std::string key)
return CombingMode::ALL;
}
SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::string key)
SupportDistPriority SettingsBaseVirtual::getSettingAsSupportDistPriority(std::string key) const
{
std::string value = getSettingString(key);
if (value == "xy_overrides_z")
@@ -458,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
+3 -2
Ver Arquivo
@@ -263,8 +263,9 @@ public:
EZSeamType getSettingAsZSeamType(std::string key) const;
ESurfaceMode getSettingAsSurfaceMode(std::string key) const;
FillPerimeterGapMode getSettingAsFillPerimeterGapMode(std::string key) const;
CombingMode getSettingAsCombingMode(std::string key);
SupportDistPriority getSettingAsSupportDistPriority(std::string key);
CombingMode getSettingAsCombingMode(std::string key) const;
SupportDistPriority getSettingAsSupportDistPriority(std::string key) const;
ColourUsage getSettingAsColourUsage(std::string key) const;
};
class SettingRegistry;
+39
Ver Arquivo
@@ -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()
@@ -124,6 +158,11 @@ SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(mes
{
}
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))
+17 -17
Ver Arquivo
@@ -12,6 +12,7 @@
#include "MeshGroup.h"
#include "PrimeTower.h"
#include "GCodePathConfig.h"
#include "textureProcessing/TextureProximityProcessor.h"
namespace cura
{
@@ -145,7 +146,13 @@ public:
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;
@@ -159,19 +166,14 @@ public:
SubDivCube* base_subdiv_cube;
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)
{
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);
}
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();
};
@@ -242,9 +244,7 @@ public:
*/
SliceDataStorage(MeshGroup* meshgroup);
~SliceDataStorage()
{
}
~SliceDataStorage();
/*!
* Get all outlines within a given layer.
+67 -34
Ver Arquivo
@@ -3,49 +3,74 @@
#include "../utils/gettime.h"
#include "../utils/logoutput.h"
#include "../MatCoord.h"
#include "../textureProcessing/MatCoord.h"
#include "../textureProcessing/FaceNormalStorage.h"
#include "Slicer.h"
namespace cura {
SlicerSegment 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)
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];
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);
MatSegment mat_segment;
bool got_texture_coords = mesh->registerFaceSlice(face_idx, idx_shared, idx_first, idx_second, z, seg.start, seg.end, mat_segment);
if (got_texture_coords)
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];
layer.segment_to_material_segment.emplace(seg, mat_segment);
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);
}
}
}
return seg;
}
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keep_none_closed, bool extensive_stitching)
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(slice_layer_count > 0);
assert((int) 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++)
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];
@@ -66,61 +91,67 @@ Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bo
if (p1.z > maxZ) maxZ = p1.z;
if (p2.z > maxZ) maxZ = p2.z;
int32_t layer_max = (maxZ - initial) / thickness;
int32_t z = 0;
for (int32_t layer_nr = (minZ - initial + thickness - 1) / thickness; layer_nr < layer_max; layer_nr++) // + thickness - 1 to get the first layer above or at minZ
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++)
{
z = layer_nr * thickness + initial;
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;
int end_edge_idx = -1;
s.faceIndex = face_idx;
assert(face_idx >= 0);
s.addedToPolygon = false;
if (p0.z < z && p1.z >= z && p2.z >= z)
{
s = project2D(face_idx, p, 0, 2, 1, z, layer_nr);
end_edge_idx = 0;
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 = project2D(face_idx, p, 0, 1, 2, z, layer_nr);
end_edge_idx = 2;
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 = project2D(face_idx, p, 1, 0, 2, z, layer_nr);
end_edge_idx = 1;
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 = project2D(face_idx, p, 1, 2, 0, z, layer_nr);
end_edge_idx = 0;
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 = project2D(face_idx, p, 2, 1, 0, z, layer_nr);
end_edge_idx = 2;
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 = project2D(face_idx, p, 2, 0, 1, z, layer_nr);
end_edge_idx = 1;
s.endOtherFaceIdx = face.connected_face_index[1];
project2D(face_idx, p, 2, 0, 1, z, layer_nr, s);
}
else
{
@@ -129,9 +160,6 @@ Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bo
continue;
}
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(face_idx, layers[layer_nr].segments.size()));
s.faceIndex = face_idx;
s.endOtherFaceIdx = face.connected_face_index[end_edge_idx];
s.addedToPolygon = false;
layers[layer_nr].segments.push_back(s);
}
}
@@ -142,6 +170,11 @@ Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bo
}
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
+18 -3
Ver Arquivo
@@ -11,7 +11,8 @@
#include "ClosePolygonResult.h"
#include "SlicerLayer.h"
#include "../MatSegment.h"
#include "../textureProcessing/MatSegment.h"
#include "../textureProcessing/TextureProximityProcessor.h"
/*
The Slicer creates layers of polygons from an optimized 3D model.
@@ -30,7 +31,15 @@ public:
const Mesh* mesh = nullptr; //!< The sliced mesh
Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keepNoneClosed, bool extensiveStitching);
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);
@@ -50,7 +59,13 @@ public:
return y;
}
SlicerSegment 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);
/*!
*
* \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);
};
+18 -2
Ver Arquivo
@@ -1,7 +1,7 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "SlicerLayer.h"
#include "../TextureProcessor.h"
#include "../textureProcessing/TextureBumpMapProcessor.h"
#include "../utils/SparsePointGridInclusive.h"
namespace cura
@@ -11,6 +11,19 @@ int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance between two
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++)
@@ -769,7 +782,10 @@ 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());
TextureProcessor::processBumpMap(mesh, *this);
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();
+15 -3
Ver Arquivo
@@ -4,6 +4,7 @@
#include <unordered_map>
#include "../utils/optional.h"
#include "../mesh.h"
#include "../utils/intpoint.h"
#include "../utils/polygon.h"
@@ -12,7 +13,9 @@
#include "GapCloserResult.h"
#include "ClosePolygonResult.h"
#include "../MatSegment.h"
#include "../textureProcessing/MatSegment.h"
#include "../textureProcessing/TextureBumpMapProcessor.h"
#include "../textureProcessing/FaceNormalStorage.h"
namespace cura
{
@@ -20,14 +23,23 @@ namespace cura
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::unordered_map<SlicerSegment, MatSegment> segment_to_material_segment;
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
+2
Ver Arquivo
@@ -6,6 +6,8 @@
#include "../utils/intpoint.h"
#include "../mesh.h"
namespace cura
{
+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
@@ -1,6 +1,6 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MAT_SEGMENT_H
#define MAT_SEGMENT_H
#ifndef TEXTURE_PROCESSING_MAT_SEGMENT_H
#define TEXTURE_PROCESSING_MAT_SEGMENT_H
#include "MatCoord.h"
@@ -24,4 +24,4 @@ struct MatSegment
} // namespace cura
#endif // MAT_SEGMENT_H
#endif // TEXTURE_PROCESSING_MAT_SEGMENT_H
@@ -6,14 +6,28 @@
#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)
: data(nullptr, ArrayDeleter())
, width(0)
, height(0)
, depth(0)
@@ -21,21 +35,42 @@ Material::Material()
}
void Material::setData(unsigned char* data)
Material::~Material()
{
this->data = data;
}
void Material::setDimensions(unsigned int width, unsigned int height, unsigned int depth)
void Material::loadImage(const char* filename)
{
this->width = width;
this->height = height;
this->depth = depth;
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)
@@ -67,7 +102,7 @@ float Material::getColorData(float x, float y, unsigned int z) const
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[(y_idx * width + x_idx) * depth + z];
unsigned char col = data.get()[((height - y_idx - 1) * width + x_idx) * depth + z];
return (float) col / std::numeric_limits<unsigned char>::max();
}
@@ -88,7 +123,7 @@ void Material::debugOutput(bool dw) const
std::cerr << "|";
for (unsigned int x = 0; x < width; x++)
{
int val = (data[(y*width+x)*depth] * 10 / 256);
int val = (data.get()[((height - y) * width + x) * depth] * 10 / 256);
switch (val)
{
@@ -1,8 +1,11 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MATERIAL_H
#define MATERIAL_H
#ifndef TEXTURE_PROCESSING_MATERIAL_H
#define TEXTURE_PROCESSING_MATERIAL_H
#include <memory> // shared_ptr
#include "../settings/settings.h" // ColourUsage
#include "settings/settings.h" // ColourUsage
namespace cura
{
@@ -21,18 +24,18 @@ public:
Material();
/*!
* Set the pixel data of the image
* \param data pointer to the array of data in RGBA, left-to-right, top-to-bottom
* Destructor
*
* deletes the image data
*/
void setData(unsigned char* data);
~Material();
/*!
* Set the dimensions of the image
* \param width The horizontal length of the imnage
* \param height The vertical length of the imnage
* \param depth The number of color channels
* Load an image from file.
*
* Crash if this doesn't work. (unsupported file type, IO exception, etc.)
*/
void setDimensions(unsigned int width, unsigned int height, unsigned int depth);
void loadImage(const char* filename);
/*!
* get the color value at a particular place in the image
@@ -50,7 +53,8 @@ public:
*/
void debugOutput(bool double_width = true) const;
protected:
unsigned char* data; //!< pixel data in rgb-row-first (or bgr-row first ?)
std::shared_ptr<unsigned char> data; //!< pixel data in rgb-row-first (or bgr-row first ?)
unsigned int width, height, depth; //!< image dimensions
/*!
@@ -64,4 +68,4 @@ protected:
} // namespace cura
#endif // MATERIAL_H
#endif // TEXTURE_PROCESSING_MATERIAL_H
@@ -1,6 +1,6 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MATERIAL_BASE_H
#define MATERIAL_BASE_H
#ifndef TEXTURE_PROCESSING_MATERIAL_BASE_H
#define TEXTURE_PROCESSING_MATERIAL_BASE_H
#include <unordered_map>
#include <string>
@@ -24,4 +24,4 @@ protected:
} // namespace cura
#endif // MATERIAL_BASE_H
#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
@@ -3,7 +3,9 @@
#include "TexturedMesh.h"
#include <cassert>
#include "utils/logoutput.h"
#include <math.h>
#include "../utils/logoutput.h"
namespace cura
{
@@ -16,6 +18,24 @@ TexturedMesh::TexturedMesh(SettingsBaseVirtual* sb)
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);
}
@@ -59,7 +79,7 @@ bool TexturedMesh::setMaterial(std::string name)
return current_mat >= 0;
}
Material* TexturedMesh::addMaterial(std::__cxx11::string name)
Material* TexturedMesh::addMaterial(std::string name)
{
return material_base.add(name);
}
@@ -96,18 +116,18 @@ bool TexturedMesh::getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigne
FPoint t0 = texture_coords[texture_idxs.index[p0_idx]];
FPoint t1 = texture_coords[texture_idxs.index[p1_idx]];
result.mat_id = texture_idxs.mat_id;
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: wapping material to outside image!");
logError("WARNING: wrapping material to outside image!\n");
}
return true;
}
bool TexturedMesh::registerFaceSlice(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
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))
{
@@ -120,18 +140,5 @@ bool TexturedMesh::registerFaceSlice(unsigned int face_idx, unsigned int idx_sha
return true;
}
float TexturedMesh::getColor(MatCoord bitmap_coord, ColourUsage color) const
{
const Material* mat = material_base.getMat(bitmap_coord.mat_id);
if (mat)
{
return mat->getColor(bitmap_coord.coords.x, bitmap_coord.coords.y, color);
}
else
{
return 0.0f;
}
}
} // namespace cura
@@ -1,14 +1,14 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef TEXTURED_MESH_H
#define TEXTURED_MESH_H
#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 "../mesh.h"
#include "../utils/intpoint.h"
#include "MatSegment.h"
namespace cura
@@ -47,9 +47,10 @@ public:
bool setMaterial(std::string name); //!< set the material to be used in the comming data to be loaded
Material* addMaterial(std::string name);
virtual bool registerFaceSlice(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;
/*!
* \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
@@ -67,12 +68,10 @@ protected:
* \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;
virtual float getColor(MatCoord bitmap_coord, ColourUsage color) const;
private:
int current_mat; //!< material currently used in loading the face material info
};
} // namespace cura
#endif // TEXTURED_MESH_H
#endif // TEXTURE_PROCESSING_TEXTURED_MESH_H
+40 -21
Ver Arquivo
@@ -10,49 +10,68 @@ namespace cura
{
void ListPolyIt::convertPolygonsToLists(Polygons& polys, ListPolygons& result)
void ListPolyIt::convertPolygonsToLists(Polygons& polys, ListPolygons& result, bool remove_duplicates)
{
for (PolygonRef poly : polys)
{
result.emplace_back();
convertPolygonToList(poly, result.back());
convertPolygonToList(poly, result.back(), remove_duplicates);
}
}
void ListPolyIt::convertPolygonToList(PolygonRef poly, ListPolygon& result)
void ListPolyIt::convertPolygonToList(PolygonRef poly, ListPolygon& result, bool remove_duplicates)
{
#ifdef DEBUG
Point last = poly.back();
#endif // DEBUG
for (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(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(ListPolygon& list_polygon, PolygonRef polygon)
void ListPolyIt::convertListPolygonToPolygon(ListPolygon& list_polygon, PolygonRef polygon, bool remove_duplicates)
{
for (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(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(PolygonRef 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(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(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();
+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
}
+4 -4
Ver Arquivo
@@ -54,7 +54,7 @@ public:
Point& operator[] (unsigned int index) const
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return (*path)[index];
}
@@ -87,7 +87,7 @@ public:
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
path->erase(path->begin() + index);
}
@@ -409,7 +409,7 @@ public:
PolygonRef operator[] (unsigned int index)
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
return PolygonRef(paths[index]);
}
const PolygonRef operator[] (unsigned int index) const
@@ -439,7 +439,7 @@ public:
*/
void remove(unsigned int index)
{
POLY_ASSERT(index < size() && index >= 0);
POLY_ASSERT(index < size() && index <= std::numeric_limits<int>::max());
if (index < paths.size() - 1)
{
paths[index] = std::move(paths.back());
+9
Ver Arquivo
@@ -17,6 +17,15 @@ WallOverlapComputation::WallOverlapComputation(Polygons& polygons, int line_widt
}
float WallOverlapComputation::getFlow(const Polygons& from, unsigned int poly_idx, unsigned int from_point_idx, unsigned int to_point_idx)
{
assert(poly_idx < from.size());
PolygonRef poly = from[poly_idx];
assert(from_point_idx < poly.size());
assert(to_point_idx < poly.size());
return getFlow(poly[from_point_idx], poly[to_point_idx]);
}
float WallOverlapComputation::getFlow(Point& from, Point& to)
{
+10 -1
Ver Arquivo
@@ -17,6 +17,8 @@
#include "utils/ProximityPointLink.h"
#include "utils/PolygonProximityLinker.h"
#include "PolygonFlowAdjuster.h"
namespace cura
{
@@ -44,7 +46,7 @@ namespace cura
* The main functionality of this class is performed by the constructor, by calling the constructor of PolygonProximityLinker.
* The adjustment during gcode generation is made with the help of WallOverlapComputation::getFlow
*/
class WallOverlapComputation
class WallOverlapComputation : public PolygonFlowAdjuster
{
PolygonProximityLinker overlap_linker;
int64_t line_width;
@@ -62,6 +64,13 @@ public:
*/
float getFlow(Point& from, Point& to);
/*!
* \see \ref WallOverlapComputation::getFlow(Point&,Point&)
*
* \see \ref PolygonFlowAdjuster::getFlow
*/
float getFlow(const Polygons& from, unsigned int poly_idx, unsigned int from_point_idx, unsigned int to_point_idx);
/*!
* Computes the neccesary priliminaries in order to efficiently compute the flow when generatign gcode paths.
* \param polygons The wall polygons for which to compute the overlaps