Comparar commits
102 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 89a8fd8b4f | |||
| c73cf897ac | |||
| 43408040c7 | |||
| 0cd3c7829b | |||
| 05c4f3da01 | |||
| 44631f3a6f | |||
| 1ca622b048 | |||
| 17e02edff7 | |||
| 563317f47d | |||
| 4b3a4f57a1 | |||
| 0f15b885f2 | |||
| ecceb71fdd | |||
| b8d019ba4a | |||
| 310eba6e16 | |||
| 82c8ac78a5 | |||
| 60e5b6088e | |||
| f8d17c09bf | |||
| 72605c9d51 | |||
| dad342fefd | |||
| 5b0c3fd4aa | |||
| 7693630f5f | |||
| e4a23e2bef | |||
| f5e3cf4c91 | |||
| 22013f70ab | |||
| 7cf19f06ec | |||
| 314ee7ab2d | |||
| 16d67fcd3e | |||
| 508a093e26 | |||
| 97660d4c80 | |||
| 1f4640e4c2 | |||
| b7b9f15063 | |||
| 97432cf9f0 | |||
| c081f80d26 | |||
| 4307d39cc9 | |||
| 61f1b7d3ba | |||
| f4118da3e3 | |||
| dba466a029 | |||
| 019711e24b | |||
| 043110db69 | |||
| b53295ffd2 | |||
| 319ce6fcfd | |||
| 9d76bb3b3a | |||
| 4bc944ebf6 | |||
| d331687392 | |||
| 8a517de1d1 | |||
| bcd3347862 | |||
| aa8e928f0c | |||
| 4529164cdf | |||
| b4140d7772 | |||
| a9809f3581 | |||
| 2cc01756a0 | |||
| a5e9659676 | |||
| 1cf75345ba | |||
| a771600dec | |||
| 15df20fe99 | |||
| 4179178756 | |||
| 05be030c45 | |||
| 3c5e745f83 | |||
| 2e6cd36f20 | |||
| 9fc4a427cd | |||
| 5729908023 | |||
| c5b90b0ad9 | |||
| 382343e558 | |||
| 68b293b880 | |||
| f867c0f53a | |||
| ee7e83d138 | |||
| 50df40c6c6 | |||
| 4d924fd33d | |||
| c953a726cb | |||
| 7c8c0b2417 | |||
| a834754d64 | |||
| 9957a0c733 | |||
| f6ce0b4141 | |||
| 120a9c440c | |||
| 59f72bdd98 | |||
| abc43302ac | |||
| c2725bdf83 | |||
| fb761dfd9d | |||
| 90727a0578 | |||
| fd7d1a4bd4 | |||
| 2b1266c647 | |||
| 901bf47610 | |||
| 80a6115537 | |||
| f94ca645bd | |||
| 2067644d30 | |||
| 0285e2f025 | |||
| 38a1ee4270 | |||
| 63459d5cd4 | |||
| 138691436e | |||
| b9c5b4593b | |||
| a0a3a24dc1 | |||
| 5959b41132 | |||
| 3d7229c9f2 | |||
| e1cfc3d93b | |||
| 5834540bec | |||
| f191d23e17 | |||
| 5114ab4218 | |||
| 9f5645ecac | |||
| 66befe5827 | |||
| c9de64f946 | |||
| dbfa3a0f4b | |||
| 02268eb7e8 |
+10
-4
@@ -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
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
https://github.com/nothings/stb
|
||||
|
||||
Thanks to Sean T. Barrett
|
||||
|
||||
license: public domain
|
||||
+46
-19
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "utils/NoCopy.h"
|
||||
#include "mesh.h"
|
||||
#include "TexturedMesh.h"
|
||||
#include "textureProcessing/TexturedMesh.h"
|
||||
#include "ExtruderTrain.h"
|
||||
|
||||
namespace cura
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#include "utils/gettime.h"
|
||||
#include "utils/logoutput.h"
|
||||
#include "utils/string.h"
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "../utils/intpoint.h"
|
||||
|
||||
#include "../mesh.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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); }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário