Comparar commits
64 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 85ac4e69bd | |||
| 45bb64a0c1 | |||
| c2ffb7c81d | |||
| 9c3170b277 | |||
| e2f89778e2 | |||
| 8f74952aca | |||
| 17463e1139 | |||
| 8df26ae916 | |||
| c2aa1d59bc | |||
| 113202cd34 | |||
| 4bc706d618 | |||
| 5766e2db11 | |||
| 671ebccdbb | |||
| 2516165c86 | |||
| 0315aaf404 | |||
| 49f09ed204 | |||
| 3e7d623c86 | |||
| d694bff227 | |||
| 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 |
+5
-9
@@ -59,12 +59,12 @@ set(engine_SRCS # Except main.cpp.
|
||||
src/gcodePlanner.cpp
|
||||
src/infill.cpp
|
||||
src/WallsComputation.cpp
|
||||
src/layerPart.cpp
|
||||
src/LayerPlanBuffer.cpp
|
||||
src/Material.cpp
|
||||
src/MaterialBase.cpp
|
||||
src/MergeInfillLines.cpp
|
||||
src/mesh.cpp
|
||||
src/MeshGroup.cpp
|
||||
src/multiVolumes.cpp
|
||||
src/pathOrderOptimizer.cpp
|
||||
src/Preheat.cpp
|
||||
src/PrimeTower.cpp
|
||||
@@ -72,10 +72,9 @@ set(engine_SRCS # Except main.cpp.
|
||||
src/skin.cpp
|
||||
src/SkirtBrim.cpp
|
||||
src/sliceDataStorage.cpp
|
||||
src/slicer.cpp
|
||||
src/support.cpp
|
||||
src/timeEstimate.cpp
|
||||
src/TexturedMesh.cpp
|
||||
src/TextureProcessor.cpp
|
||||
src/WallsComputation.cpp
|
||||
src/wallOverlap.cpp
|
||||
src/Weaver.cpp
|
||||
@@ -88,13 +87,10 @@ set(engine_SRCS # Except main.cpp.
|
||||
src/infill/ZigzagConnectorProcessorNoEndPieces.cpp
|
||||
src/infill/SubDivCube.cpp
|
||||
|
||||
src/slicer/LayerPart.cpp
|
||||
src/slicer/MultiVolumes.cpp
|
||||
src/slicer/SlicerLayer.cpp
|
||||
src/slicer/Slicer.cpp
|
||||
|
||||
src/pathPlanning/Comb.cpp
|
||||
src/pathPlanning/GCodePath.cpp
|
||||
src/pathPlanning/LinePolygonsCrossings.cpp
|
||||
src/pathPlanning/NozzleTempInsert.cpp
|
||||
src/pathPlanning/TimeMaterialEstimates.cpp
|
||||
|
||||
src/progress/Progress.cpp
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -2,7 +2,7 @@
|
||||
#ifndef CONICAL_OVERHANG_H
|
||||
#define CONICAL_OVERHANG_H
|
||||
|
||||
#include "slicer/Slicer.h"
|
||||
#include "slicer.h"
|
||||
|
||||
|
||||
namespace cura {
|
||||
|
||||
+46
-27
@@ -1,5 +1,3 @@
|
||||
//Copyright (c) 2016 Ultimaker B.V.
|
||||
//CuraEngine is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
#include <list>
|
||||
|
||||
@@ -196,7 +194,17 @@ void FffGcodeWriter::initConfigs(SliceDataStorage& storage)
|
||||
mesh.inset0_config.init(mesh.getSettingInMillimetersPerSecond("speed_wall_0"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_0"), mesh.getSettingInMillimetersPerSecond("jerk_wall_0"), mesh.getSettingInMicrons("wall_line_width_0"), mesh.getSettingInPercentage("material_flow"));
|
||||
mesh.insetX_config.init(mesh.getSettingInMillimetersPerSecond("speed_wall_x"), mesh.getSettingInMillimetersPerSecond("acceleration_wall_x"), mesh.getSettingInMillimetersPerSecond("jerk_wall_x"), mesh.getSettingInMicrons("wall_line_width_x"), mesh.getSettingInPercentage("material_flow"));
|
||||
mesh.skin_config.init(mesh.getSettingInMillimetersPerSecond("speed_topbottom"), mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), mesh.getSettingInMicrons("skin_line_width"), mesh.getSettingInPercentage("material_flow"));
|
||||
|
||||
|
||||
// The perimeter gap config follows the skin config, but has a different line width:
|
||||
// wall_line_width_x divided by two because the gaps are between 0 and 1 times the wall line width
|
||||
const int perimeter_gaps_line_width = mesh.getSettingInMicrons("wall_line_width_x") / 2;
|
||||
double perimeter_gaps_speed = mesh.getSettingInMillimetersPerSecond("speed_topbottom");
|
||||
if (mesh.getSettingBoolean("speed_equalize_flow_enabled"))
|
||||
{
|
||||
perimeter_gaps_speed = perimeter_gaps_speed * mesh.getSettingInMicrons("skin_line_width") / perimeter_gaps_line_width;
|
||||
}
|
||||
mesh.perimeter_gap_config.init(perimeter_gaps_speed, mesh.getSettingInMillimetersPerSecond("acceleration_topbottom"), mesh.getSettingInMillimetersPerSecond("jerk_topbottom"), perimeter_gaps_line_width, mesh.getSettingInPercentage("material_flow"));
|
||||
|
||||
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
mesh.infill_config[idx].init(mesh.getSettingInMillimetersPerSecond("speed_infill"), mesh.getSettingInMillimetersPerSecond("acceleration_infill"), mesh.getSettingInMillimetersPerSecond("jerk_infill"), mesh.getSettingInMicrons("infill_line_width") * (idx + 1), mesh.getSettingInPercentage("material_flow"));
|
||||
@@ -698,7 +706,7 @@ std::vector<unsigned int> FffGcodeWriter::calculateMeshOrder(SliceDataStorage& s
|
||||
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
|
||||
if (mesh.getSettingAsIndex("extruder_nr") == extruder_nr)
|
||||
{
|
||||
Mesh& mesh_data = *storage.meshgroup->meshes[mesh_idx];
|
||||
Mesh& mesh_data = storage.meshgroup->meshes[mesh_idx];
|
||||
Point3 middle = (mesh_data.getAABB().min + mesh_data.getAABB().max) / 2;
|
||||
mesh_idx_order_optimizer.addItem(Point(middle.x, middle.y), mesh_idx);
|
||||
}
|
||||
@@ -999,7 +1007,7 @@ void FffGcodeWriter::processInsets(GCodePlanner& gcode_layer, SliceMeshStorage*
|
||||
{ // on the last normal layer first make the outer wall normally and then start a second outer wall from the same hight, but gradually moving upward
|
||||
WallOverlapComputation* wall_overlap_computation(nullptr);
|
||||
int wall_0_wipe_dist(0);
|
||||
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, mesh->getSettingInMicrons("wall_0_wipe_dist"), wall_0_wipe_dist);
|
||||
gcode_layer.addPolygonsByOptimizer(part.insets[0], &mesh->insetX_config, wall_overlap_computation, EZSeamType::SHORTEST, z_seam_pos, wall_0_wipe_dist, spiralize);
|
||||
}
|
||||
}
|
||||
int processed_inset_number = -1;
|
||||
@@ -1046,9 +1054,11 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
{
|
||||
int64_t z = layer_nr * getSettingInMicrons("layer_height");
|
||||
const unsigned int skin_line_width = mesh->skin_config.getLineWidth();
|
||||
const unsigned int perimeter_gaps_line_width = mesh->perimeter_gap_config.getLineWidth();
|
||||
|
||||
constexpr int perimeter_gaps_extra_offset = 15; // extra offset so that the perimeter gaps aren't created everywhere due to rounding errors
|
||||
bool fill_perimeter_gaps = mesh->getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") != FillPerimeterGapMode::NOWHERE;
|
||||
bool fill_perimeter_gaps = mesh->getSettingAsFillPerimeterGapMode("fill_perimeter_gaps") != FillPerimeterGapMode::NOWHERE
|
||||
&& !mesh->getSettingBoolean("magic_spiralize");
|
||||
|
||||
Point z_seam_pos(0, 0); // not used
|
||||
PathOrderOptimizer part_order_optimizer(gcode_layer.getLastPosition(), z_seam_pos, EZSeamType::SHORTEST);
|
||||
@@ -1118,13 +1128,6 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
Infill infill_comp(pattern, *inner_skin_outline, offset_from_inner_skin_outline, skin_line_width, skin_line_width, skin_overlap, skin_angle, z, extra_infill_shift, perimeter_gaps_output);
|
||||
infill_comp.generate(skin_polygons, skin_lines);
|
||||
|
||||
if (fill_perimeter_gaps)
|
||||
{ // handle perimeter_gaps of skin insets
|
||||
int offset = 0;
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, skin_line_width, skin_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(skin_polygons, skin_lines);
|
||||
}
|
||||
|
||||
gcode_layer.addPolygonsByOptimizer(skin_polygons, &mesh->skin_config);
|
||||
|
||||
if (pattern == EFillMethod::GRID || pattern == EFillMethod::LINES || pattern == EFillMethod::TRIANGLES)
|
||||
@@ -1135,40 +1138,56 @@ void FffGcodeWriter::processSkinAndPerimeterGaps(GCodePlanner& gcode_layer, Slic
|
||||
{
|
||||
gcode_layer.addLinesByOptimizer(skin_lines, &mesh->skin_config, (pattern == EFillMethod::ZIG_ZAG)? SpaceFillType::PolyLines : SpaceFillType::Lines);
|
||||
}
|
||||
|
||||
if (fill_perimeter_gaps)
|
||||
{ // handle perimeter_gaps of skin insets
|
||||
Polygons gap_polygons; // will remain empty
|
||||
Polygons gap_lines;
|
||||
int offset = 0;
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, perimeter_gaps_line_width, perimeter_gaps_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(gap_polygons, gap_lines);
|
||||
gcode_layer.addLinesByOptimizer(gap_lines, &mesh->perimeter_gap_config, SpaceFillType::Lines);
|
||||
}
|
||||
}
|
||||
|
||||
if (fill_perimeter_gaps)
|
||||
{ // 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++)
|
||||
{
|
||||
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")
|
||||
&& mesh->getSettingInMicrons("infill_overlap_mm") >= 0
|
||||
)
|
||||
{
|
||||
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);
|
||||
}
|
||||
inner = inner.unionPolygons();
|
||||
perimeter_gaps.add(outer.difference(inner));
|
||||
}
|
||||
perimeter_gaps.add(outer.difference(inner));
|
||||
}
|
||||
|
||||
Polygons skin_polygons; // unused
|
||||
Polygons skin_lines; // soon to be generated gap filler lines
|
||||
Polygons gap_polygons; // unused
|
||||
Polygons gap_lines; // soon to be generated gap filler lines
|
||||
int offset = 0;
|
||||
int extra_infill_shift = 0;
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, skin_line_width, skin_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(skin_polygons, skin_lines);
|
||||
Infill infill_comp(EFillMethod::LINES, perimeter_gaps, offset, perimeter_gaps_line_width, perimeter_gaps_line_width, skin_overlap, skin_angle, z, extra_infill_shift);
|
||||
infill_comp.generate(gap_polygons, gap_lines);
|
||||
|
||||
gcode_layer.addLinesByOptimizer(skin_lines, &mesh->skin_config, SpaceFillType::Lines);
|
||||
gcode_layer.addLinesByOptimizer(gap_lines, &mesh->perimeter_gap_config, SpaceFillType::Lines);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
#include <map> // multimap (ordered map allowing duplicate keys)
|
||||
|
||||
#include "utils/math.h"
|
||||
#include "slicer/Slicer.h"
|
||||
#include "utils/algorithm.h"
|
||||
#include "slicer.h"
|
||||
#include "utils/gettime.h"
|
||||
#include "utils/logoutput.h"
|
||||
#include "MeshGroup.h"
|
||||
#include "support.h"
|
||||
#include "slicer/MultiVolumes.h"
|
||||
#include "slicer/LayerPart.h"
|
||||
#include "TextureProcessor.h"
|
||||
#include "multiVolumes.h"
|
||||
#include "layerPart.h"
|
||||
#include "WallsComputation.h"
|
||||
#include "SkirtBrim.h"
|
||||
#include "skin.h"
|
||||
@@ -89,7 +88,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
std::vector<Slicer*> slicerList;
|
||||
for(unsigned int mesh_idx = 0; mesh_idx < meshgroup->meshes.size(); mesh_idx++)
|
||||
{
|
||||
Mesh& mesh = *meshgroup->meshes[mesh_idx];
|
||||
Mesh& mesh = meshgroup->meshes[mesh_idx];
|
||||
Slicer* slicer = new Slicer(&mesh, initial_slice_z, layer_thickness, slice_layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
|
||||
slicerList.push_back(slicer);
|
||||
/*
|
||||
@@ -108,7 +107,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
|
||||
for(unsigned int meshIdx=0; meshIdx < slicerList.size(); meshIdx++)
|
||||
{
|
||||
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
|
||||
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
|
||||
if (mesh.getSettingBoolean("conical_overhang_enabled") && !mesh.getSettingBoolean("anti_overhang_mesh"))
|
||||
{
|
||||
ConicalOverhang::apply(slicerList[meshIdx], mesh.getSettingInAngleRadians("conical_overhang_angle"), layer_thickness);
|
||||
@@ -117,7 +116,6 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
|
||||
Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper);
|
||||
|
||||
|
||||
if (storage.getSettingBoolean("carve_multiple_volumes"))
|
||||
{
|
||||
carveMultipleVolumes(slicerList, storage.getSettingBoolean("alternate_carve_order"));
|
||||
@@ -127,7 +125,7 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
storage.print_layer_count = 0;
|
||||
for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++)
|
||||
{
|
||||
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
|
||||
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
|
||||
Slicer* slicer = slicerList[meshIdx];
|
||||
if (!mesh.getSettingBoolean("anti_overhang_mesh") && !mesh.getSettingBoolean("infill_mesh"))
|
||||
{
|
||||
@@ -140,10 +138,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
for (unsigned int meshIdx = 0; meshIdx < slicerList.size(); meshIdx++)
|
||||
{
|
||||
Slicer* slicer = slicerList[meshIdx];
|
||||
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
|
||||
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
|
||||
|
||||
// always make a new SliceMeshStorage, so that they have the same ordering / indexing as meshgroup.meshes
|
||||
storage.meshes.emplace_back(meshgroup->meshes[meshIdx], slicer->layers.size()); // new mesh in storage had settings from the Mesh
|
||||
storage.meshes.emplace_back(&meshgroup->meshes[meshIdx], slicer->layers.size()); // new mesh in storage had settings from the Mesh
|
||||
SliceMeshStorage& meshStorage = storage.meshes.back();
|
||||
|
||||
if (mesh.getSettingBoolean("anti_overhang_mesh"))
|
||||
@@ -153,6 +151,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
SupportLayer& support_layer = storage.support.supportLayers[layer_nr];
|
||||
SlicerLayer& slicer_layer = slicer->layers[layer_nr];
|
||||
support_layer.anti_overhang = support_layer.anti_overhang.unionPolygons(slicer_layer.polygons);
|
||||
meshStorage.layers[layer_nr].printZ =
|
||||
slicer_layer.z
|
||||
+ getSettingInMicrons("layer_height_0")
|
||||
- initial_slice_z;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -163,6 +165,10 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
|
||||
SupportLayer& support_layer = storage.support.supportLayers[layer_nr];
|
||||
SlicerLayer& slicer_layer = slicer->layers[layer_nr];
|
||||
support_layer.support_mesh.add(slicer_layer.polygons);
|
||||
meshStorage.layers[layer_nr].printZ =
|
||||
slicer_layer.z
|
||||
+ getSettingInMicrons("layer_height_0")
|
||||
- initial_slice_z;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -359,8 +365,8 @@ void FffPolygonGenerator::processBasicWallsSkinInfill(SliceDataStorage& storage,
|
||||
SliceMeshStorage& other_mesh = storage.meshes[other_mesh_idx];
|
||||
if (other_mesh.getSettingBoolean("infill_mesh"))
|
||||
{
|
||||
AABB3D aabb = storage.meshgroup->meshes[mesh_idx]->getAABB();
|
||||
AABB3D other_aabb = storage.meshgroup->meshes[other_mesh_idx]->getAABB();
|
||||
AABB3D aabb = storage.meshgroup->meshes[mesh_idx].getAABB();
|
||||
AABB3D other_aabb = storage.meshgroup->meshes[other_mesh_idx].getAABB();
|
||||
if (aabb.hit(other_aabb))
|
||||
{
|
||||
process_infill = true;
|
||||
|
||||
@@ -38,7 +38,7 @@ std::string FffProcessor::getAllSettingsString(MeshGroup& meshgroup, bool first_
|
||||
}
|
||||
for (unsigned int mesh_idx = 0; mesh_idx < meshgroup.meshes.size(); mesh_idx++)
|
||||
{
|
||||
Mesh& mesh = *meshgroup.meshes[mesh_idx];
|
||||
Mesh& mesh = meshgroup.meshes[mesh_idx];
|
||||
sstream << " -e" << mesh.getSettingAsIndex("extruder_nr") << " -l \"" << mesh_idx << "\"" << mesh.getAllLocalSettingsString();
|
||||
}
|
||||
sstream << "\n";
|
||||
@@ -58,9 +58,9 @@ bool FffProcessor::processMeshGroup(MeshGroup* meshgroup)
|
||||
gcode_writer.setParent(meshgroup);
|
||||
|
||||
bool empty = true;
|
||||
for (Mesh* mesh : meshgroup->meshes)
|
||||
for (Mesh& mesh : meshgroup->meshes)
|
||||
{
|
||||
if (!mesh->getSettingBoolean("infill_mesh") && !mesh->getSettingBoolean("anti_overhang_mesh"))
|
||||
if (!mesh.getSettingBoolean("infill_mesh") && !mesh.getSettingBoolean("anti_overhang_mesh"))
|
||||
{
|
||||
empty = false;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,27 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef MAT_SEGMENT_H
|
||||
#define MAT_SEGMENT_H
|
||||
|
||||
#include "MatCoord.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
/*!
|
||||
* Coordinates in a specific texture bitmap
|
||||
*/
|
||||
struct MatSegment
|
||||
{
|
||||
MatCoord start;
|
||||
MatCoord end;
|
||||
MatSegment() //!< non-initializing constructor
|
||||
{}
|
||||
MatSegment(MatCoord start, MatCoord end)
|
||||
: start(start)
|
||||
, end(end)
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // MAT_SEGMENT_H
|
||||
@@ -1,143 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
|
||||
#include <limits> // numeric limits
|
||||
#include <algorithm> // min max
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#include "Material.h"
|
||||
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
Material::Material()
|
||||
: data(nullptr)
|
||||
, width(0)
|
||||
, height(0)
|
||||
, depth(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Material::setData(unsigned char* data)
|
||||
{
|
||||
this->data = data;
|
||||
}
|
||||
|
||||
void Material::setDimensions(unsigned int width, unsigned int height, unsigned int depth)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->depth = depth;
|
||||
}
|
||||
|
||||
float Material::getColor(float x, float y, ColourUsage color) const
|
||||
{
|
||||
assert(x >= 0.0f && x <= 1.0f);
|
||||
assert(y >= 0.0f && y <= 1.0f);
|
||||
switch (color)
|
||||
{
|
||||
case ColourUsage::RED:
|
||||
case ColourUsage::GREEN:
|
||||
case ColourUsage::BLUE:
|
||||
case ColourUsage::ALPHA:
|
||||
{
|
||||
assert((int)color >= 0 && (unsigned int)color < depth && "Z out of bounds!");
|
||||
return getColorData(x, y, (unsigned int) color);
|
||||
}
|
||||
case ColourUsage::GREY:
|
||||
default:
|
||||
{
|
||||
float r = getColorData(x, y, (unsigned int) ColourUsage::RED);
|
||||
float g = getColorData(x, y, (unsigned int) ColourUsage::GREEN);
|
||||
float b = getColorData(x, y, (unsigned int) ColourUsage::BLUE);
|
||||
return (r + g + b) / 3.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float Material::getColorData(float x, float y, unsigned int z) const
|
||||
{
|
||||
unsigned int x_idx = (unsigned int) (x * (width - 1) + 0.5);
|
||||
assert(x_idx >= 0 && x_idx < width && "requested X is out of bounds!");
|
||||
unsigned int y_idx = (unsigned int) (y * (height - 1) + 0.5);
|
||||
assert(y_idx >= 0 && y_idx < height && "requested Y is out of bounds!");
|
||||
|
||||
unsigned char col = data[(y_idx * width + x_idx) * depth + z];
|
||||
return (float) col / std::numeric_limits<unsigned char>::max();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Material::debugOutput(bool dw) const
|
||||
{
|
||||
std::cerr << "\nImage size: " << width << " x " << height << " (" << depth << "channels)\n";
|
||||
std::cerr << '+';
|
||||
for (unsigned int i = 0; i < width; i++)
|
||||
{
|
||||
std::cerr << ((dw)? "--" : "-");
|
||||
}
|
||||
std::cerr << "+\n";
|
||||
for (unsigned int y = 0; y < height; y++)
|
||||
{
|
||||
std::cerr << "|";
|
||||
for (unsigned int x = 0; x < width; x++)
|
||||
{
|
||||
int val = (data[(y*width+x)*depth] * 10 / 256);
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case 0:
|
||||
std::cerr << ((dw)? " " : " ");
|
||||
break;
|
||||
case 1:
|
||||
std::cerr << ((dw)? ".." : ".");
|
||||
break;
|
||||
case 2:
|
||||
std::cerr << ((dw)? ",," : ",");
|
||||
break;
|
||||
case 3:
|
||||
std::cerr << ((dw)? "::" : ":");
|
||||
break;
|
||||
case 4:
|
||||
std::cerr << ((dw)? ";;" : ";");
|
||||
break;
|
||||
case 5:
|
||||
std::cerr << ((dw)? "++" : "+");
|
||||
break;
|
||||
case 6:
|
||||
std::cerr << ((dw)? "░░" : "░");
|
||||
break;
|
||||
case 7:
|
||||
std::cerr << ((dw)? "▒▒" : "▒");
|
||||
break;
|
||||
case 8:
|
||||
std::cerr << ((dw)? "▓▓" : "▓");
|
||||
break;
|
||||
default:
|
||||
if (val > 8)
|
||||
{
|
||||
std::cerr << ((dw)? "██" : "█");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << ((dw)? " " : " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cerr << "|\n";
|
||||
}
|
||||
std::cerr << '+';
|
||||
for (unsigned int i = 0; i < width; i++)
|
||||
{
|
||||
std::cerr << ((dw)? "--" : "-");
|
||||
}
|
||||
std::cerr << "+\n";
|
||||
}
|
||||
|
||||
} // namespace cura
|
||||
@@ -1,67 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef MATERIAL_H
|
||||
#define MATERIAL_H
|
||||
|
||||
#include "settings/settings.h" // ColourUsage
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
/*!
|
||||
* The material used in a texture.
|
||||
*
|
||||
* This class just holds the image data and has some nice utility functions.
|
||||
*/
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* non-initializing constructor
|
||||
*/
|
||||
Material();
|
||||
|
||||
/*!
|
||||
* Set the pixel data of the image
|
||||
* \param data pointer to the array of data in RGBA, left-to-right, top-to-bottom
|
||||
*/
|
||||
void setData(unsigned char* data);
|
||||
|
||||
/*!
|
||||
* 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
|
||||
*/
|
||||
void setDimensions(unsigned int width, unsigned int height, unsigned int depth);
|
||||
|
||||
/*!
|
||||
* get the color value at a particular place in the image
|
||||
*
|
||||
* \param x place in the horizontal direction left to right (value between zero and one)
|
||||
* \param y place in the vertical direction top to bottom (value between zero and one)
|
||||
* \param color The color channel to check
|
||||
* \return a value between zero and one
|
||||
*/
|
||||
float getColor(float x, float y, ColourUsage color) const;
|
||||
|
||||
/*!
|
||||
* print out something which looks like the picture through std::cerr
|
||||
* \param double_width Whether to double each character being written, so that the width is visually similar to the height of each pixel.
|
||||
*/
|
||||
void debugOutput(bool double_width = true) const;
|
||||
protected:
|
||||
unsigned char* data; //!< pixel data in rgb-row-first (or bgr-row first ?)
|
||||
unsigned int width, height, depth; //!< image dimensions
|
||||
|
||||
/*!
|
||||
* Get a color value from the data
|
||||
* \param x place in the horizontal direction left to right (value between zero and one)
|
||||
* \param y place in the vertical direction top to bottom (value between zero and one)
|
||||
* \return the color data (0-256)
|
||||
*/
|
||||
float getColorData(float x, float y, unsigned int z) const;
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // MATERIAL_H
|
||||
@@ -1,42 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
|
||||
#include "MaterialBase.h"
|
||||
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
Material* MaterialBase::add(std::string name)
|
||||
{
|
||||
name_to_mat_idx[name] = materials.size();
|
||||
materials.emplace_back();
|
||||
return &materials.back();
|
||||
}
|
||||
|
||||
const Material* MaterialBase::getMat(unsigned int id) const
|
||||
{
|
||||
if (id < materials.size())
|
||||
{
|
||||
return &materials[id];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MaterialBase::getMatId(std::string name) const
|
||||
{
|
||||
auto it = name_to_mat_idx.find(name);
|
||||
if (it == name_to_mat_idx.end())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cura
|
||||
@@ -1,27 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef MATERIAL_BASE_H
|
||||
#define MATERIAL_BASE_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Material.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
class MaterialBase
|
||||
{
|
||||
public:
|
||||
int getMatId(std::string name) const;
|
||||
Material* add(std::string name);
|
||||
const Material* getMat(unsigned int id) const;
|
||||
protected:
|
||||
std::unordered_map<std::string, int> name_to_mat_idx;
|
||||
std::vector<Material> materials;
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // MATERIAL_BASE_H
|
||||
+22
-183
@@ -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"
|
||||
@@ -28,10 +25,6 @@ void* fgets_(char* ptr, size_t len, FILE* f)
|
||||
*ptr = '\0';
|
||||
return ptr;
|
||||
}
|
||||
else if (*ptr =='\0')
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
ptr++;
|
||||
len--;
|
||||
}
|
||||
@@ -52,10 +45,6 @@ MeshGroup::~MeshGroup()
|
||||
delete extruders[extruder];
|
||||
}
|
||||
}
|
||||
for (Mesh* mesh : meshes)
|
||||
{
|
||||
delete mesh;
|
||||
}
|
||||
}
|
||||
|
||||
int MeshGroup::getExtruderCount() const
|
||||
@@ -101,10 +90,10 @@ Point3 MeshGroup::min() const
|
||||
{
|
||||
return Point3(0, 0, 0);
|
||||
}
|
||||
Point3 ret = meshes[0]->min();
|
||||
for (unsigned int i = 1; i < meshes.size(); i++)
|
||||
Point3 ret = meshes[0].min();
|
||||
for(unsigned int i=1; i<meshes.size(); i++)
|
||||
{
|
||||
Point3 v = meshes[i]->min();
|
||||
Point3 v = meshes[i].min();
|
||||
ret.x = std::min(ret.x, v.x);
|
||||
ret.y = std::min(ret.y, v.y);
|
||||
ret.z = std::min(ret.z, v.z);
|
||||
@@ -118,10 +107,10 @@ Point3 MeshGroup::max() const
|
||||
{
|
||||
return Point3(0, 0, 0);
|
||||
}
|
||||
Point3 ret = meshes[0]->max();
|
||||
for (unsigned int i = 1; i < meshes.size(); i++)
|
||||
Point3 ret = meshes[0].max();
|
||||
for(unsigned int i=1; i<meshes.size(); i++)
|
||||
{
|
||||
Point3 v = meshes[i]->max();
|
||||
Point3 v = meshes[i].max();
|
||||
ret.x = std::max(ret.x, v.x);
|
||||
ret.y = std::max(ret.y, v.y);
|
||||
ret.z = std::max(ret.z, v.z);
|
||||
@@ -131,9 +120,9 @@ Point3 MeshGroup::max() const
|
||||
|
||||
void MeshGroup::clear()
|
||||
{
|
||||
for (Mesh* m : meshes)
|
||||
for(Mesh& m : meshes)
|
||||
{
|
||||
m->clear();
|
||||
m.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +140,9 @@ void MeshGroup::finalize()
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const Mesh* mesh : meshes)
|
||||
for (const Mesh& mesh : meshes)
|
||||
{
|
||||
if (mesh->getSettingBoolean("support_enable")
|
||||
if (mesh.getSettingBoolean("support_enable")
|
||||
&& (
|
||||
getSettingAsIndex("support_infill_extruder_nr") == extruder_nr
|
||||
|| getSettingAsIndex("support_extruder_nr_layer_0") == extruder_nr
|
||||
@@ -167,13 +156,13 @@ void MeshGroup::finalize()
|
||||
}
|
||||
}
|
||||
|
||||
for (const Mesh* mesh : meshes)
|
||||
for (const Mesh& mesh : meshes)
|
||||
{
|
||||
if (!mesh->getSettingBoolean("anti_overhang_mesh")
|
||||
&& !mesh->getSettingBoolean("support_mesh")
|
||||
if (!mesh.getSettingBoolean("anti_overhang_mesh")
|
||||
&& !mesh.getSettingBoolean("support_mesh")
|
||||
)
|
||||
{
|
||||
getExtruderTrain(mesh->getSettingAsIndex("extruder_nr"))->setIsUsed(true);
|
||||
getExtruderTrain(mesh.getSettingAsIndex("extruder_nr"))->setIsUsed(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,17 +175,17 @@ void MeshGroup::finalize()
|
||||
}
|
||||
|
||||
// If a mesh position was given, put the mesh at this position in 3D space.
|
||||
for (Mesh* mesh : meshes)
|
||||
for(Mesh& mesh : meshes)
|
||||
{
|
||||
Point3 mesh_offset(mesh->getSettingInMicrons("mesh_position_x"), mesh->getSettingInMicrons("mesh_position_y"), mesh->getSettingInMicrons("mesh_position_z"));
|
||||
if (mesh->getSettingBoolean("center_object"))
|
||||
Point3 mesh_offset(mesh.getSettingInMicrons("mesh_position_x"), mesh.getSettingInMicrons("mesh_position_y"), mesh.getSettingInMicrons("mesh_position_z"));
|
||||
if (mesh.getSettingBoolean("center_object"))
|
||||
{
|
||||
Point3 object_min = mesh->min();
|
||||
Point3 object_max = mesh->max();
|
||||
Point3 object_min = mesh.min();
|
||||
Point3 object_max = mesh.max();
|
||||
Point3 object_size = object_max - object_min;
|
||||
mesh_offset += Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z);
|
||||
}
|
||||
mesh->offset(mesh_offset + meshgroup_offset);
|
||||
mesh.offset(mesh_offset + meshgroup_offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,138 +329,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");
|
||||
if (f == nullptr)
|
||||
{
|
||||
logError("ERROR: Couldn't load MTL file %s.\n", filename);
|
||||
return;
|
||||
}
|
||||
char buffer[1024];
|
||||
char mat_name [100];
|
||||
char mat_file [100];
|
||||
char map_type [10];
|
||||
Material* last_mat = nullptr;
|
||||
while(fgets_(buffer, sizeof(buffer), f))
|
||||
{
|
||||
if (buffer[0] == '#')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sscanf(buffer, "map_%s %s", map_type, mat_file) == 2 // we don't care what type of map it specifies (currently)
|
||||
|| sscanf(buffer, "bump %s", mat_file) == 1
|
||||
|| sscanf(buffer, "disp %s", mat_file) == 1
|
||||
|| sscanf(buffer, "decal %s", mat_file) == 1
|
||||
|| sscanf(buffer, "refl %s", mat_file) == 1
|
||||
)
|
||||
{
|
||||
std::string parent_dir = std::string(filename).substr(0, std::string(filename).find_last_of("/\\"));
|
||||
std::string mtl_file = parent_dir + "/" + mat_file;
|
||||
if (last_mat)
|
||||
{
|
||||
loadMatImage(last_mat, mtl_file.c_str());
|
||||
}
|
||||
}
|
||||
else if (sscanf(buffer, "newmtl %s", mat_name) == 1)
|
||||
{
|
||||
last_mat = mesh->addMaterial(mat_name);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
bool loadMeshOBJ(TexturedMesh* mesh, const char* filename, const FMatrix3x3& matrix)
|
||||
{
|
||||
FILE* f = fopen(filename, "rt");
|
||||
if (f == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
char buffer[1024];
|
||||
FPoint3 vertex;
|
||||
Point3 vertex_indices;
|
||||
float texture_x;
|
||||
float texture_y;
|
||||
float temp;
|
||||
char face_index_buffer_1 [100];
|
||||
char face_index_buffer_2 [100];
|
||||
char face_index_buffer_3 [100];
|
||||
char str_buffer [100];
|
||||
while(fgets_(buffer, sizeof(buffer), f))
|
||||
{
|
||||
if (buffer[0] == '#')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sscanf(buffer, "v %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
|
||||
{
|
||||
Point3 v = matrix.apply(vertex);
|
||||
mesh->addVertex(v);
|
||||
}
|
||||
else if (sscanf(buffer, "vt %f %f", &texture_x, &texture_y) == 2)
|
||||
{
|
||||
mesh->addTextureCoord(texture_x, texture_y);
|
||||
}
|
||||
else if (sscanf(buffer, "f %s %s %s", face_index_buffer_1, face_index_buffer_2, face_index_buffer_3) == 3)
|
||||
{
|
||||
int normal_vector_index; // unused
|
||||
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)
|
||||
{
|
||||
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);
|
||||
// obj files count vertex indices starting from 1!
|
||||
}
|
||||
}
|
||||
else if (sscanf(buffer, "mtllib %s", str_buffer) == 1)
|
||||
{
|
||||
std::string parent_dir = std::string(filename).substr(0, std::string(filename).find_last_of("/\\"));
|
||||
std::string mtl_file = parent_dir + "/" + str_buffer;
|
||||
loadMaterialBase(mesh, mtl_file.c_str());
|
||||
}
|
||||
else if (sscanf(buffer, "usemtl %s", str_buffer) == 1)
|
||||
{
|
||||
mesh->setMaterial(str_buffer);
|
||||
}
|
||||
else if (sscanf(buffer, "vn %f %f %f", &temp, &temp, &temp) == 3)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if (buffer[0] == '\0')
|
||||
{
|
||||
// empty line, do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
logError("Cannot parse line \"%s\"\n", buffer);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
mesh->finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
|
||||
{
|
||||
TimeKeeper load_timer;
|
||||
@@ -479,32 +336,14 @@ bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMa
|
||||
const char* ext = strrchr(filename, '.');
|
||||
if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
|
||||
{
|
||||
Mesh* mesh = new Mesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
|
||||
if (loadMeshSTL(mesh,filename,transformation)) //Load it! If successful...
|
||||
Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
|
||||
if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
|
||||
{
|
||||
meshgroup->meshes.push_back(mesh);
|
||||
log("loading '%s' took %.3f seconds\n",filename,load_timer.restart());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete mesh;
|
||||
}
|
||||
}
|
||||
else if (ext && (strcmp(ext, ".obj") == 0 || strcmp(ext, ".OBJ") == 0))
|
||||
{
|
||||
TexturedMesh* mesh = new TexturedMesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
|
||||
if (loadMeshOBJ(mesh,filename,transformation)) //Load it! If successful...
|
||||
{
|
||||
meshgroup->meshes.push_back(mesh);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete mesh;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@
|
||||
|
||||
#include "utils/NoCopy.h"
|
||||
#include "mesh.h"
|
||||
#include "TexturedMesh.h"
|
||||
#include "ExtruderTrain.h"
|
||||
|
||||
namespace cura
|
||||
@@ -36,7 +35,7 @@ public:
|
||||
|
||||
const ExtruderTrain* getExtruderTrain(unsigned int extruder_nr) const;
|
||||
|
||||
std::vector<Mesh*> meshes;
|
||||
std::vector<Mesh> meshes;
|
||||
|
||||
Point3 min() const; //! minimal corner of bounding box
|
||||
Point3 max() const; //! maximal corner of bounding box
|
||||
|
||||
@@ -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,137 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
|
||||
#include "TexturedMesh.h"
|
||||
|
||||
#include <cassert>
|
||||
#include "utils/logoutput.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
TexturedMesh::TexturedMesh(SettingsBaseVirtual* sb)
|
||||
: Mesh(sb)
|
||||
, current_mat(-1) // not set yet
|
||||
{
|
||||
}
|
||||
|
||||
void TexturedMesh::addTextureCoord(float x, float y)
|
||||
{
|
||||
texture_coords.emplace_back(x, y);
|
||||
}
|
||||
|
||||
void TexturedMesh::addFace(int vi0, int vi1, int vi2, int ti0, int ti1, int ti2)
|
||||
{
|
||||
if (vi0 < -1)
|
||||
{
|
||||
vi0 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
|
||||
}
|
||||
if (vi1 < -1)
|
||||
{
|
||||
vi1 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
|
||||
}
|
||||
if (vi2 < -1)
|
||||
{
|
||||
vi2 = Mesh::faces.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
|
||||
}
|
||||
if (ti0 < -1)
|
||||
{
|
||||
ti0 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
|
||||
}
|
||||
if (ti1 < -1)
|
||||
{
|
||||
ti1 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
|
||||
}
|
||||
if (ti2 < -1)
|
||||
{
|
||||
ti2 = texture_coords.size() + vi0 + 1; // + 1 because of relative indexing doesn't start counting from 1
|
||||
}
|
||||
bool made_new_face = Mesh::addFace(vi0, vi1, vi2);
|
||||
if (made_new_face)
|
||||
{
|
||||
face_texture_indices.emplace_back(ti0, ti1, ti2, current_mat);
|
||||
assert(Mesh::faces.size() == face_texture_indices.size());
|
||||
}
|
||||
}
|
||||
|
||||
bool TexturedMesh::setMaterial(std::string name)
|
||||
{
|
||||
current_mat = material_base.getMatId(name);
|
||||
return current_mat >= 0;
|
||||
}
|
||||
|
||||
Material* TexturedMesh::addMaterial(std::__cxx11::string name)
|
||||
{
|
||||
return material_base.add(name);
|
||||
}
|
||||
|
||||
|
||||
bool TexturedMesh::getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigned int p0_idx, unsigned int p1_idx, MatCoord& result) const
|
||||
{
|
||||
if (face_idx >= face_texture_indices.size() || face_idx >= faces.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
FaceTextureCoordIndices texture_idxs = face_texture_indices[face_idx];
|
||||
if (texture_idxs.index[0] < 0 || texture_idxs.index[1] < 0 || texture_idxs.index[2] < 0 || texture_idxs.mat_id < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const MeshFace& face = faces[face_idx];
|
||||
Point3 p0(vertices[face.vertex_index[p0_idx]].p);
|
||||
Point3 p1(vertices[face.vertex_index[p1_idx]].p);
|
||||
|
||||
float dzp0 = z - p0.z;
|
||||
float dp0p1 = p1.z - p0.z;
|
||||
|
||||
if (dzp0 * dp0p1 < 0)
|
||||
{ // z doesn't lie between p0 and p1
|
||||
return false;
|
||||
}
|
||||
if (dzp0 == 0)
|
||||
{ // edge is not cut by horizontal plane!
|
||||
return false;
|
||||
}
|
||||
float ratio = INT2MM(dzp0) / INT2MM(dp0p1);
|
||||
|
||||
FPoint t0 = texture_coords[texture_idxs.index[p0_idx]];
|
||||
FPoint t1 = texture_coords[texture_idxs.index[p1_idx]];
|
||||
|
||||
result.mat_id = 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!");
|
||||
}
|
||||
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
|
||||
{
|
||||
if (!getFaceEdgeMatCoord(face_idx, z, idx_shared, idx_first, result.start))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!getFaceEdgeMatCoord(face_idx, z, idx_shared, idx_second, result.end))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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,78 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef TEXTURED_MESH_H
|
||||
#define TEXTURED_MESH_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "MaterialBase.h"
|
||||
|
||||
#include "mesh.h"
|
||||
#include "utils/intpoint.h"
|
||||
#include "MatSegment.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
/*!
|
||||
* A mesh with bitmap textures to it.
|
||||
*
|
||||
* material coordinates are defined separately, and can be reused for different bitmap textures
|
||||
*/
|
||||
class TexturedMesh : public Mesh
|
||||
{
|
||||
public:
|
||||
TexturedMesh(SettingsBaseVirtual* sb);
|
||||
|
||||
|
||||
/*!
|
||||
*
|
||||
*/
|
||||
struct FaceTextureCoordIndices
|
||||
{
|
||||
int index[3]; //!< indices into texture_coords or -1 if no texture data available
|
||||
int mat_id; //!< Material id
|
||||
FaceTextureCoordIndices(int i1, int i2, int i3, int mat_id)
|
||||
: mat_id(mat_id)
|
||||
{
|
||||
index[0] = i1;
|
||||
index[1] = i2;
|
||||
index[2] = i3;
|
||||
}
|
||||
};
|
||||
void addTextureCoord(float x, float y);
|
||||
void addFace(int vi0, int vi1, int vi2, int ti0, int ti1, int ti2);
|
||||
using Mesh::addFace; // otherwise above addFace would shadow the parent addFace
|
||||
|
||||
bool setMaterial(std::string name); //!< set the material to be used in the comming data to be loaded
|
||||
Material* addMaterial(std::string name);
|
||||
|
||||
|
||||
|
||||
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;
|
||||
|
||||
protected:
|
||||
std::vector<FPoint> texture_coords; //!< all texture coordinates by all faces
|
||||
std::vector<FaceTextureCoordIndices> face_texture_indices; //!< for each face the corresponding texture coordinates in TexturedMesh::texture_coords
|
||||
// TODO clean up above lists when super class clear() is called
|
||||
// TODO when to clean up below material base?
|
||||
MaterialBase material_base;
|
||||
/*!
|
||||
* Get the material coordinate corresponding to the point on a plane cutting a given edge of the face.
|
||||
* \param face_idx The face for which to get the material coord
|
||||
* \param z The z of the horizontal plane cutting the face
|
||||
* \param p0_idx The index into the first vert of the edge
|
||||
* \param p1_idx The index into the second vert of the edge
|
||||
* \param result The resulting material Coordinates
|
||||
* \return Whether a Material coordinate is defined at the given location
|
||||
*/
|
||||
bool getFaceEdgeMatCoord(unsigned int face_idx, int64_t z, unsigned int p0_idx, unsigned int p1_idx, MatCoord& result) const;
|
||||
|
||||
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
|
||||
+2
-2
@@ -23,9 +23,9 @@ void Weaver::weave(MeshGroup* meshgroup)
|
||||
|
||||
std::vector<cura::Slicer*> slicerList;
|
||||
|
||||
for (Mesh* mesh : meshgroup->meshes)
|
||||
for(Mesh& mesh : meshgroup->meshes)
|
||||
{
|
||||
cura::Slicer* slicer = new cura::Slicer(mesh, initial_layer_thickness, connectionHeight, layer_count, mesh->getSettingBoolean("meshfix_keep_open_polygons"), mesh->getSettingBoolean("meshfix_extensive_stitching"));
|
||||
cura::Slicer* slicer = new cura::Slicer(&mesh, initial_layer_thickness, connectionHeight, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
|
||||
slicerList.push_back(slicer);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#include "settings/settings.h"
|
||||
|
||||
#include "MeshGroup.h"
|
||||
#include "slicer/Slicer.h"
|
||||
#include "slicer.h"
|
||||
|
||||
#include "utils/NoCopy.h"
|
||||
#include "utils/polygon.h"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "settings/settings.h"
|
||||
|
||||
#include "MeshGroup.h"
|
||||
#include "slicer/Slicer.h"
|
||||
#include "slicer.h"
|
||||
|
||||
#include "utils/polygon.h"
|
||||
#include "Weaver.h"
|
||||
|
||||
@@ -346,9 +346,9 @@ void CommandSocket::connect(const std::string& ip, int port)
|
||||
continue;
|
||||
}
|
||||
const ExtruderTrain* settings_base = meshgroup->getExtruderTrain(extruder_nr); //The extruder train that the setting should fall back to.
|
||||
for (Mesh* mesh : meshgroup->meshes)
|
||||
for (Mesh& mesh : meshgroup->meshes)
|
||||
{
|
||||
mesh->setSettingInheritBase(setting_extruder.name(), *settings_base);
|
||||
mesh.setSettingInheritBase(setting_extruder.name(), *settings_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,8 +455,8 @@ void CommandSocket::handleObjectList(cura::proto::ObjectList* list, const google
|
||||
}
|
||||
SettingsBase* extruder_train = meshgroup->getExtruderTrain(extruder_train_nr);
|
||||
|
||||
meshgroup->meshes.push_back(new Mesh(extruder_train)); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
|
||||
Mesh& mesh = *meshgroup->meshes.back();
|
||||
meshgroup->meshes.push_back(extruder_train); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
|
||||
Mesh& mesh = meshgroup->meshes.back();
|
||||
|
||||
for (int i = 0; i < face_count; ++i)
|
||||
{
|
||||
@@ -642,6 +642,7 @@ void CommandSocket::sendLayerData()
|
||||
{
|
||||
for (std::pair<const int, std::shared_ptr<cura::proto::Layer>> entry : data.slice_data) //Note: This is in no particular order!
|
||||
{
|
||||
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
|
||||
private_data->socket->sendMessage(entry.second); //Send the actual layers.
|
||||
}
|
||||
data.sliced_objects = 0;
|
||||
@@ -667,6 +668,7 @@ void CommandSocket::sendOptimizedLayerData()
|
||||
{
|
||||
for (std::pair<const int, std::shared_ptr<cura::proto::LayerOptimized>> entry : data.slice_data) //Note: This is in no particular order!
|
||||
{
|
||||
logDebug("Sending layer data for layer %i of %i.\n", entry.first, data.slice_data.size());
|
||||
private_data->socket->sendMessage(entry.second); //Send the actual layers.
|
||||
}
|
||||
data.sliced_objects = 0;
|
||||
|
||||
+25
-44
@@ -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))
|
||||
@@ -52,13 +51,13 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
|
||||
|
||||
extruder_count = meshgroup->getSettingAsCount("machine_extruder_count");
|
||||
|
||||
for (const Mesh* mesh : meshgroup->meshes)
|
||||
for (const Mesh& mesh : meshgroup->meshes)
|
||||
{
|
||||
if (!mesh->getSettingBoolean("anti_overhang_mesh")
|
||||
&& !mesh->getSettingBoolean("support_mesh")
|
||||
if (!mesh.getSettingBoolean("anti_overhang_mesh")
|
||||
&& !mesh.getSettingBoolean("support_mesh")
|
||||
)
|
||||
{
|
||||
extruder_attr[mesh->getSettingAsIndex("extruder_nr")].is_used = true;
|
||||
extruder_attr[mesh.getSettingAsIndex("extruder_nr")].is_used = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,11 +69,11 @@ void GCodeExport::preSetup(const MeshGroup* meshgroup)
|
||||
{
|
||||
extruder_attr[extruder_nr].is_used = true;
|
||||
}
|
||||
for (const Mesh* mesh : meshgroup->meshes)
|
||||
for (const Mesh& mesh : meshgroup->meshes)
|
||||
{
|
||||
if ((mesh->getSettingBoolean("support_enable") && mesh->getSettingBoolean("support_interface_enable") && meshgroup->getSettingAsIndex("support_interface_extruder_nr") == int(extruder_nr))
|
||||
|| (mesh->getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_infill_extruder_nr") == int(extruder_nr))
|
||||
|| (mesh->getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_extruder_nr_layer_0") == int(extruder_nr))
|
||||
if ((mesh.getSettingBoolean("support_enable") && mesh.getSettingBoolean("support_interface_enable") && meshgroup->getSettingAsIndex("support_interface_extruder_nr") == int(extruder_nr))
|
||||
|| (mesh.getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_infill_extruder_nr") == int(extruder_nr))
|
||||
|| (mesh.getSettingBoolean("support_enable") && meshgroup->getSettingAsIndex("support_extruder_nr_layer_0") == int(extruder_nr))
|
||||
)
|
||||
{
|
||||
extruder_attr[extruder_nr].is_used = true;
|
||||
@@ -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();
|
||||
}
|
||||
@@ -554,8 +556,6 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
|
||||
assert((Point3(x,y,z) - currentPosition).vSize() < MM2INT(300)); // no crazy positions (this code should not be compiled for release)
|
||||
#endif //ASSERT_INSANE_OUTPUT
|
||||
|
||||
total_bounding_box.include(Point3(x, y, z));
|
||||
|
||||
if (extrusion_mm3_per_mm < 0)
|
||||
logWarning("Warning! Negative extrusion move!");
|
||||
|
||||
@@ -568,6 +568,7 @@ void GCodeExport::writeMove(int x, int y, int z, double speed, double extrusion_
|
||||
double extrusion_per_mm = mm3ToE(extrusion_mm3_per_mm);
|
||||
|
||||
Point gcode_pos = getGcodePos(x,y, current_extruder);
|
||||
total_bounding_box.include(Point3(gcode_pos.X, gcode_pos.Y, z));
|
||||
|
||||
if (extrusion_mm3_per_mm > 0.000001)
|
||||
{
|
||||
@@ -689,11 +690,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 +706,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;
|
||||
@@ -740,7 +728,7 @@ void GCodeExport::writeZhopStart(int hop_height)
|
||||
{
|
||||
isZHopped = hop_height;
|
||||
*output_stream << "G1 Z" << MMtoStream{currentPosition.z + isZHopped} << new_line;
|
||||
total_bounding_box.include(currentPosition + Point3(0, 0, isZHopped));
|
||||
total_bounding_box.includeZ(currentPosition.z + isZHopped);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,21 +768,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
|
||||
|
||||
@@ -941,7 +922,7 @@ void GCodeExport::finalize(const char* endCode)
|
||||
{
|
||||
writeFanCommand(0);
|
||||
writeCode(endCode);
|
||||
long print_time = getTotalPrintTime();
|
||||
int64_t print_time = getTotalPrintTime();
|
||||
int mat_0 = getTotalFilamentUsed(0);
|
||||
log("Print time: %d\n", print_time);
|
||||
log("Print time (readable): %dh %dm %ds\n", print_time / 60 / 60, (print_time / 60) % 60, print_time % 60);
|
||||
|
||||
+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);
|
||||
|
||||
|
||||
+21
-19
@@ -663,17 +663,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 +681,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 +708,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"));
|
||||
@@ -898,6 +897,7 @@ void GCodePlanner::completeConfigs()
|
||||
|
||||
mesh.insetX_config.setLayerHeight(layer_thickness);
|
||||
mesh.skin_config.setLayerHeight(layer_thickness);
|
||||
mesh.perimeter_gap_config.setLayerHeight(layer_thickness);
|
||||
for(unsigned int idx=0; idx<MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
mesh.infill_config[idx].setLayerHeight(layer_thickness);
|
||||
@@ -956,6 +956,7 @@ void GCodePlanner::processInitialLayersSpeedup()
|
||||
|
||||
//Skin speed (per mesh).
|
||||
mesh.skin_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
|
||||
mesh.perimeter_gap_config.smoothSpeed(initial_layer_speed_config, layer_nr, initial_speedup_layers);
|
||||
|
||||
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
@@ -977,6 +978,7 @@ void GCodePlanner::processInitialLayersSpeedup()
|
||||
mesh.inset0_config.setSpeedIconic();
|
||||
mesh.insetX_config.setSpeedIconic();
|
||||
mesh.skin_config.setSpeedIconic();
|
||||
mesh.perimeter_gap_config.setSpeedIconic();
|
||||
for (unsigned int idx = 0; idx < MAX_INFILL_COMBINE; idx++)
|
||||
{
|
||||
mesh.infill_config[idx].setSpeedIconic();
|
||||
@@ -987,7 +989,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++)
|
||||
|
||||
@@ -451,12 +451,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.
|
||||
|
||||
+32
-19
@@ -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;
|
||||
|
||||
@@ -174,15 +186,15 @@ SubDivCube::SubDivCube(SliceMeshStorage& mesh, Point3& center, int depth)
|
||||
bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int64_t radius)
|
||||
{
|
||||
int64_t distance2;
|
||||
long int sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
|
||||
coord_t sphere_slice_radius2;//!< squared radius of bounding sphere slice on target layer
|
||||
bool inside_somewhere = false;
|
||||
bool outside_somewhere = false;
|
||||
int inside;
|
||||
double part_dist;//what percentage of the radius the target layer is away from the center along the z axis. 0 - 1
|
||||
const long int layer_height = mesh.getSettingInMicrons("layer_height");
|
||||
long int bottom_layer = (center.z - radius) / layer_height;
|
||||
long int top_layer = (center.z + radius) / layer_height;
|
||||
for (long int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
|
||||
const coord_t layer_height = mesh.getSettingInMicrons("layer_height");
|
||||
int bottom_layer = (center.z - radius) / layer_height;
|
||||
int top_layer = (center.z + radius) / layer_height;
|
||||
for (int test_layer = bottom_layer; test_layer <= top_layer; test_layer += 3) // steps of three. Low-hanging speed gain.
|
||||
{
|
||||
part_dist = (double)(test_layer * layer_height - center.z) / radius;
|
||||
sphere_slice_radius2 = radius * radius * (1.0 - (part_dist * part_dist));
|
||||
@@ -209,11 +221,12 @@ bool SubDivCube::isValidSubdivision(SliceMeshStorage& mesh, Point3& center, int6
|
||||
return false;
|
||||
}
|
||||
|
||||
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, long int layer_nr, Point& location, int64_t* distance2)
|
||||
int SubDivCube::distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2)
|
||||
{
|
||||
if (layer_nr < 0 || (unsigned long int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
|
||||
if (layer_nr < 0 || (unsigned int)layer_nr >= mesh.layers.size()) //!< this layer is outside of valid range
|
||||
{
|
||||
return 2;
|
||||
*distance2 = 0;
|
||||
}
|
||||
Polygons collide;
|
||||
mesh.layers[layer_nr].getSecondOrInnermostWalls(collide);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
* \param[out] distance2 the squared distance to the infill border
|
||||
* \return Code 0: outside, 1: inside, 2: boundary does not exist at specified layer
|
||||
*/
|
||||
static int distanceFromPointToMesh(SliceMeshStorage& mesh, long int layer_nr, Point& location, int64_t* distance2);
|
||||
static int distanceFromPointToMesh(SliceMeshStorage& mesh, int layer_nr, Point& location, int64_t* distance2);
|
||||
|
||||
/*!
|
||||
* Adds the defined line to the specified polygons. It assumes that the specified polygons are all parallel lines. Combines line segments with touching ends closer than epsilon.
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
*/
|
||||
void addLineAndCombine(Polygons& group, Point from, Point to);
|
||||
|
||||
int depth; //!< the recursion depth of the cube (0 is most recursed)
|
||||
unsigned int depth; //!< the recursion depth of the cube (0 is most recursed)
|
||||
Point3 center; //!< center location of the cube in absolute coordinates
|
||||
SubDivCube* children[8] = {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}; //!< pointers to this cube's eight octree children
|
||||
static std::vector<CubeProperties> cube_properties_per_recursion_step; //!< precomputed array of basic properties of cubes based on recursion depth.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
|
||||
#include "LayerPart.h"
|
||||
#include "../settings/settings.h"
|
||||
#include "../progress/Progress.h"
|
||||
#include "layerPart.h"
|
||||
#include "settings/settings.h"
|
||||
#include "progress/Progress.h"
|
||||
|
||||
#include "../utils/SVG.h" // debug output
|
||||
#include "utils/SVG.h" // debug output
|
||||
|
||||
/*
|
||||
The layer-part creation step is the first step in creating actual useful data for 3D printing.
|
||||
@@ -1,10 +1,10 @@
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_LAYERPART_H
|
||||
#define SLICER_LAYERPART_H
|
||||
#ifndef LAYERPART_H
|
||||
#define LAYERPART_H
|
||||
|
||||
#include "../sliceDataStorage.h"
|
||||
#include "Slicer.h"
|
||||
#include "../commandSocket.h"
|
||||
#include "sliceDataStorage.h"
|
||||
#include "slicer.h"
|
||||
#include "commandSocket.h"
|
||||
|
||||
/*
|
||||
The layer-part creation step is the first step in creating actual useful data for 3D printing.
|
||||
@@ -28,4 +28,4 @@ void layerparts2HTML(SliceDataStorage& mesh, const char* filename, bool all_laye
|
||||
|
||||
}//namespace cura
|
||||
|
||||
#endif//SLICER_LAYERPART_H
|
||||
#endif//LAYERPART_H
|
||||
+1
-1
@@ -210,7 +210,7 @@ void slice(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
last_settings_object = meshgroup->meshes.back();
|
||||
last_settings_object = &(meshgroup->meshes.back()); // pointer is valid until a new object is added, so this is OK
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
|
||||
+2
-33
@@ -19,21 +19,12 @@ Mesh::Mesh(SettingsBaseVirtual* parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
|
||||
void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
|
||||
{
|
||||
int vi0 = findIndexOfVertex(v0);
|
||||
int vi1 = findIndexOfVertex(v1);
|
||||
int vi2 = findIndexOfVertex(v2);
|
||||
return addFace(vi0, vi1, vi2);
|
||||
}
|
||||
|
||||
bool Mesh::addFace(int vi0, int vi1, int vi2)
|
||||
{
|
||||
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2)
|
||||
{
|
||||
// the face has two vertices which get assigned the same location. Don't add the face.
|
||||
return false;
|
||||
}
|
||||
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face.
|
||||
|
||||
int idx = faces.size(); // index of face to be added
|
||||
faces.emplace_back();
|
||||
@@ -44,8 +35,6 @@ bool Mesh::addFace(int vi0, int vi1, int vi2)
|
||||
vertices[face.vertex_index[0]].connected_faces.push_back(idx);
|
||||
vertices[face.vertex_index[1]].connected_faces.push_back(idx);
|
||||
vertices[face.vertex_index[2]].connected_faces.push_back(idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mesh::clear()
|
||||
@@ -92,14 +81,6 @@ void Mesh::expandXY(int64_t offset)
|
||||
}
|
||||
|
||||
|
||||
void Mesh::addVertex(const Point3& v)
|
||||
{
|
||||
uint32_t hash = pointHash(v);
|
||||
vertex_hash_map[hash].push_back(vertices.size());
|
||||
vertices.emplace_back(v);
|
||||
aabb.include(v);
|
||||
}
|
||||
|
||||
int Mesh::findIndexOfVertex(const Point3& v)
|
||||
{
|
||||
uint32_t hash = pointHash(v);
|
||||
@@ -208,16 +189,4 @@ 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
-28
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "settings/settings.h"
|
||||
#include "utils/AABB3D.h"
|
||||
#include "MatSegment.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
@@ -66,26 +65,7 @@ public:
|
||||
|
||||
Mesh(SettingsBaseVirtual* parent); //!< initializes the settings
|
||||
|
||||
virtual ~Mesh() {} //!< Destructor
|
||||
|
||||
/*!
|
||||
* add a face to the mesh without settings it's connected_faces.
|
||||
*
|
||||
* Don't add a face when the surface is zero mm^2
|
||||
*
|
||||
* \return whether a face has been added
|
||||
*/
|
||||
bool addFace(Point3& v0, Point3& v1, Point3& v2);
|
||||
/*!
|
||||
* add a face to the mesh without settings it's connected_faces.
|
||||
*
|
||||
* Don't add a face when the surface is zero mm^2
|
||||
*
|
||||
* \return whether a face has been added
|
||||
*/
|
||||
bool addFace(int vi0, int vi1, int vi2);
|
||||
void addVertex(const Point3& v);
|
||||
|
||||
void addFace(Point3& v0, Point3& v1, Point3& v2); //!< add a face to the mesh without settings it's connected_faces.
|
||||
void clear(); //!< clears all data
|
||||
void finish(); //!< complete the model : set the connected_face_index fields of the faces.
|
||||
|
||||
@@ -106,13 +86,6 @@ public:
|
||||
aabb.offset(offset);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \return Whether a texture line segment has been created
|
||||
*/
|
||||
virtual bool registerFaceSlice(unsigned int face_idx, unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, Point segment_start, Point segment_end, MatSegment& result) const;
|
||||
|
||||
virtual float getColor(MatCoord bitmap_coord, ColourUsage color) const;
|
||||
|
||||
private:
|
||||
int findIndexOfVertex(const Point3& v); //!< find index of vertex close to the given point, or create a new vertex and return its index.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "MultiVolumes.h"
|
||||
#include "multiVolumes.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef SLICER_MULTIVOLUMES_H
|
||||
#define SLICER_MULTIVOLUMES_H
|
||||
#ifndef MULTIVOLUMES_H
|
||||
#define MULTIVOLUMES_H
|
||||
|
||||
#include "../sliceDataStorage.h"
|
||||
#include "Slicer.h"
|
||||
#include "sliceDataStorage.h"
|
||||
#include "slicer.h"
|
||||
|
||||
/* This file contains code to help fixing up and changing layers that are build from multiple volumes. */
|
||||
namespace cura {
|
||||
@@ -21,4 +21,4 @@ void generateMultipleVolumesOverlap(std::vector<Slicer*> &meshes);
|
||||
|
||||
}//namespace cura
|
||||
|
||||
#endif//SLICER_MULTIVOLUMES_H
|
||||
#endif//MULTIVOLUMES_H
|
||||
@@ -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())
|
||||
{
|
||||
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
|
||||
|
||||
@@ -177,18 +177,6 @@ enum class SupportDistPriority
|
||||
Z_OVERRIDES_XY
|
||||
};
|
||||
|
||||
/*!
|
||||
* Which color(s) of a texture to use
|
||||
*/
|
||||
enum class ColourUsage
|
||||
{
|
||||
RED = 0,
|
||||
GREEN = 1,
|
||||
BLUE = 2,
|
||||
ALPHA = 3,
|
||||
GREY // use red, green and blue channels
|
||||
};
|
||||
|
||||
#define MAX_EXTRUDERS 16
|
||||
|
||||
//Maximum number of infill layers that can be combined into a single infill extrusion area.
|
||||
|
||||
@@ -155,6 +155,7 @@ public:
|
||||
GCodePathConfig inset0_config;
|
||||
GCodePathConfig insetX_config;
|
||||
GCodePathConfig skin_config;
|
||||
GCodePathConfig perimeter_gap_config;
|
||||
std::vector<GCodePathConfig> infill_config;
|
||||
|
||||
SubDivCube* base_subdiv_cube;
|
||||
@@ -165,6 +166,7 @@ public:
|
||||
, inset0_config(PrintFeatureType::OuterWall)
|
||||
, insetX_config(PrintFeatureType::InnerWall)
|
||||
, skin_config(PrintFeatureType::Skin)
|
||||
, perimeter_gap_config(PrintFeatureType::Skin)
|
||||
, base_subdiv_cube(nullptr)
|
||||
{
|
||||
layers.resize(slice_layer_count);
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
#include <stdio.h>
|
||||
|
||||
#include "SlicerLayer.h"
|
||||
#include "../TextureProcessor.h"
|
||||
#include "../utils/SparsePointGridInclusive.h"
|
||||
#include <algorithm> // remove_if
|
||||
|
||||
namespace cura
|
||||
{
|
||||
#include "utils/gettime.h"
|
||||
#include "utils/logoutput.h"
|
||||
#include "utils/SparsePointGridInclusive.h"
|
||||
|
||||
#include "slicer.h"
|
||||
|
||||
|
||||
namespace cura {
|
||||
|
||||
int largest_neglected_gap_first_phase = MM2INT(0.01); //!< distance between two line segments regarded as connected
|
||||
int largest_neglected_gap_second_phase = MM2INT(0.02); //!< distance between two line segments regarded as connected
|
||||
@@ -769,8 +774,6 @@ 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);
|
||||
|
||||
//Finally optimize all the polygons. Every point removed saves time in the long run.
|
||||
polygons.simplify();
|
||||
|
||||
@@ -783,4 +786,113 @@ void SlicerLayer::makePolygons(const Mesh* mesh, bool keep_none_closed, bool ext
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cura
|
||||
|
||||
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keep_none_closed, bool extensive_stitching)
|
||||
: mesh(mesh)
|
||||
{
|
||||
assert(slice_layer_count > 0);
|
||||
|
||||
TimeKeeper slice_timer;
|
||||
|
||||
layers.resize(slice_layer_count);
|
||||
|
||||
|
||||
for(int32_t layer_nr = 0; layer_nr < slice_layer_count; layer_nr++)
|
||||
{
|
||||
layers[layer_nr].z = initial + thickness * layer_nr;
|
||||
}
|
||||
|
||||
for(unsigned int mesh_idx = 0; mesh_idx < mesh->faces.size(); mesh_idx++)
|
||||
{
|
||||
const MeshFace& face = mesh->faces[mesh_idx];
|
||||
const MeshVertex& v0 = mesh->vertices[face.vertex_index[0]];
|
||||
const MeshVertex& v1 = mesh->vertices[face.vertex_index[1]];
|
||||
const MeshVertex& v2 = mesh->vertices[face.vertex_index[2]];
|
||||
Point3 p0 = v0.p;
|
||||
Point3 p1 = v1.p;
|
||||
Point3 p2 = v2.p;
|
||||
int32_t minZ = p0.z;
|
||||
int32_t maxZ = p0.z;
|
||||
if (p1.z < minZ) minZ = p1.z;
|
||||
if (p2.z < minZ) minZ = p2.z;
|
||||
if (p1.z > maxZ) maxZ = p1.z;
|
||||
if (p2.z > maxZ) maxZ = p2.z;
|
||||
int32_t layer_max = (maxZ - initial) / thickness;
|
||||
for(int32_t layer_nr = (minZ - initial) / thickness; layer_nr <= layer_max; layer_nr++)
|
||||
{
|
||||
int32_t z = layer_nr * thickness + initial;
|
||||
if (z < minZ) continue;
|
||||
if (layer_nr < 0) continue;
|
||||
|
||||
SlicerSegment s;
|
||||
s.endVertex = nullptr;
|
||||
int end_edge_idx = -1;
|
||||
if (p0.z < z && p1.z >= z && p2.z >= z)
|
||||
{
|
||||
s = project2D(p0, p2, p1, z);
|
||||
end_edge_idx = 0;
|
||||
if (p1.z == z)
|
||||
{
|
||||
s.endVertex = &v1;
|
||||
}
|
||||
}
|
||||
else if (p0.z > z && p1.z < z && p2.z < z)
|
||||
{
|
||||
s = project2D(p0, p1, p2, z);
|
||||
end_edge_idx = 2;
|
||||
|
||||
}
|
||||
|
||||
else if (p1.z < z && p0.z >= z && p2.z >= z)
|
||||
{
|
||||
s = project2D(p1, p0, p2, z);
|
||||
end_edge_idx = 1;
|
||||
if (p2.z == z)
|
||||
{
|
||||
s.endVertex = &v2;
|
||||
}
|
||||
}
|
||||
else if (p1.z > z && p0.z < z && p2.z < z)
|
||||
{
|
||||
s = project2D(p1, p2, p0, z);
|
||||
end_edge_idx = 0;
|
||||
|
||||
}
|
||||
|
||||
else if (p2.z < z && p1.z >= z && p0.z >= z)
|
||||
{
|
||||
s = project2D(p2, p1, p0, z);
|
||||
end_edge_idx = 2;
|
||||
if (p0.z == z)
|
||||
{
|
||||
s.endVertex = &v0;
|
||||
}
|
||||
}
|
||||
else if (p2.z > z && p1.z < z && p0.z < z)
|
||||
{
|
||||
s = project2D(p2, p0, p1, z);
|
||||
end_edge_idx = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
|
||||
// on the slice would create two segments
|
||||
continue;
|
||||
}
|
||||
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(mesh_idx, layers[layer_nr].segments.size()));
|
||||
s.faceIndex = mesh_idx;
|
||||
s.endOtherFaceIdx = face.connected_face_index[end_edge_idx];
|
||||
s.addedToPolygon = false;
|
||||
layers[layer_nr].segments.push_back(s);
|
||||
}
|
||||
}
|
||||
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
|
||||
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
|
||||
{
|
||||
layers[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
|
||||
}
|
||||
mesh->expandXY(mesh->getSettingInMicrons("xy_offset"));
|
||||
log("slice make polygons took %.3f seconds\n",slice_timer.restart());
|
||||
}
|
||||
|
||||
}//namespace cura
|
||||
@@ -1,21 +1,47 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_SLICER_LAYER_H
|
||||
#define SLICER_SLICER_LAYER_H
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_H
|
||||
#define SLICER_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
|
||||
#include "../mesh.h"
|
||||
#include "../utils/intpoint.h"
|
||||
#include "../utils/polygon.h"
|
||||
#include "mesh.h"
|
||||
#include "utils/polygon.h"
|
||||
/*
|
||||
The Slicer creates layers of polygons from an optimized 3D model.
|
||||
The result of the Slicer is a list of polygons without any order or structure.
|
||||
*/
|
||||
namespace cura {
|
||||
|
||||
#include "SlicerSegment.h"
|
||||
#include "GapCloserResult.h"
|
||||
#include "ClosePolygonResult.h"
|
||||
|
||||
#include "../MatSegment.h"
|
||||
|
||||
namespace cura
|
||||
class SlicerSegment
|
||||
{
|
||||
public:
|
||||
Point start, end;
|
||||
int faceIndex = -1;
|
||||
// The index of the other face connected via the edge that created end
|
||||
int endOtherFaceIdx = -1;
|
||||
// If end corresponds to a vertex of the mesh, then this is populated
|
||||
// with the vertex that it ended on.
|
||||
const MeshVertex *endVertex = nullptr;
|
||||
bool addedToPolygon = false;
|
||||
};
|
||||
|
||||
class ClosePolygonResult
|
||||
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
|
||||
//The line on which the point lays is between pointIdx-1 and pointIdx
|
||||
public:
|
||||
Point intersectionPoint;
|
||||
int polygonIdx = -1;
|
||||
unsigned int pointIdx = -1;
|
||||
};
|
||||
class GapCloserResult
|
||||
{
|
||||
public:
|
||||
int64_t len = -1;
|
||||
int polygonIdx = -1;
|
||||
unsigned int pointIdxA = -1;
|
||||
unsigned int pointIdxB = -1;
|
||||
bool AtoB = false;
|
||||
};
|
||||
|
||||
class SlicerLayer
|
||||
{
|
||||
@@ -26,8 +52,6 @@ public:
|
||||
int z = -1;
|
||||
Polygons polygons;
|
||||
Polygons openPolylines;
|
||||
|
||||
std::unordered_map<SlicerSegment, MatSegment> segment_to_material_segment;
|
||||
|
||||
/*!
|
||||
* Connect the segments into polygons for this layer of this \p mesh
|
||||
@@ -459,6 +483,44 @@ private:
|
||||
bool allow_reverse);
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
class Slicer
|
||||
{
|
||||
public:
|
||||
std::vector<SlicerLayer> layers;
|
||||
|
||||
#endif // SLICER_SLICER_LAYER_H
|
||||
const Mesh* mesh = nullptr; //!< The sliced mesh
|
||||
|
||||
Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keepNoneClosed, bool extensiveStitching);
|
||||
|
||||
/*!
|
||||
* Linear interpolation
|
||||
*
|
||||
* Get the Y of a point with X \p x in the line through (\p x0, \p y0) and (\p x1, \p y1)
|
||||
*/
|
||||
int64_t interpolate(int64_t x, int64_t x0, int64_t x1, int64_t y0, int64_t y1) const
|
||||
{
|
||||
int64_t dx_01 = x1 - x0;
|
||||
int64_t num = (y1 - y0) * (x - x0);
|
||||
num += num > 0 ? dx_01/2 : -dx_01/2; // add in offset to round result
|
||||
int64_t y = y0 + num / dx_01;
|
||||
return y;
|
||||
}
|
||||
|
||||
SlicerSegment project2D(Point3& p0, Point3& p1, Point3& p2, int32_t z) const
|
||||
{
|
||||
SlicerSegment seg;
|
||||
|
||||
seg.start.X = interpolate(z, p0.z, p1.z, p0.x, p1.x);
|
||||
seg.start.Y = interpolate(z, p0.z, p1.z, p0.y, p1.y);
|
||||
seg.end .X = interpolate(z, p0.z, p2.z, p0.x, p2.x);
|
||||
seg.end .Y = interpolate(z, p0.z, p2.z, p0.y, p2.y);
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
void dumpSegmentsToHTML(const char* filename);
|
||||
};
|
||||
|
||||
}//namespace cura
|
||||
|
||||
#endif//SLICER_H
|
||||
@@ -1,21 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_CLOSE_POLYGON_RESULT_H
|
||||
#define SLICER_CLOSE_POLYGON_RESULT_H
|
||||
|
||||
#include "../utils/intpoint.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
class ClosePolygonResult
|
||||
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
|
||||
//The line on which the point lays is between pointIdx-1 and pointIdx
|
||||
public:
|
||||
Point intersectionPoint;
|
||||
int polygonIdx = -1;
|
||||
unsigned int pointIdx = -1;
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // SLICER_CLOSE_POLYGON_RESULT_H
|
||||
@@ -1,22 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_GAP_CLOSER_RESULT_H
|
||||
#define SLICER_GAP_CLOSER_RESULT_H
|
||||
|
||||
#include "../utils/intpoint.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
class GapCloserResult
|
||||
{
|
||||
public:
|
||||
int64_t len = -1;
|
||||
int polygonIdx = -1;
|
||||
unsigned int pointIdxA = -1;
|
||||
unsigned int pointIdxB = -1;
|
||||
bool AtoB = false;
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // SLICER_GAP_CLOSER_RESULT_H
|
||||
@@ -1,147 +0,0 @@
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../utils/gettime.h"
|
||||
#include "../utils/logoutput.h"
|
||||
#include "../MatCoord.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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
SlicerLayer& layer = layers[layer_nr];
|
||||
layer.segment_to_material_segment.emplace(seg, mat_segment);
|
||||
}
|
||||
return seg;
|
||||
}
|
||||
|
||||
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keep_none_closed, bool extensive_stitching)
|
||||
: mesh(mesh)
|
||||
{
|
||||
assert(slice_layer_count > 0);
|
||||
|
||||
TimeKeeper slice_timer;
|
||||
|
||||
layers.resize(slice_layer_count);
|
||||
|
||||
|
||||
for(int32_t layer_nr = 0; layer_nr < slice_layer_count; layer_nr++)
|
||||
{
|
||||
layers[layer_nr].z = initial + thickness * layer_nr;
|
||||
}
|
||||
for(unsigned int face_idx = 0; face_idx < mesh->faces.size(); face_idx++)
|
||||
{
|
||||
const MeshFace& face = mesh->faces[face_idx];
|
||||
const MeshVertex& v0 = mesh->vertices[face.vertex_index[0]];
|
||||
const MeshVertex& v1 = mesh->vertices[face.vertex_index[1]];
|
||||
const MeshVertex& v2 = mesh->vertices[face.vertex_index[2]];
|
||||
Point3 p[3] =
|
||||
{ mesh->vertices[face.vertex_index[0]].p
|
||||
, mesh->vertices[face.vertex_index[1]].p
|
||||
, mesh->vertices[face.vertex_index[2]].p };
|
||||
Point3& p0 = p[0];
|
||||
Point3& p1 = p[1];
|
||||
Point3& p2 = p[2];
|
||||
int32_t minZ = p0.z;
|
||||
int32_t maxZ = p0.z;
|
||||
if (p1.z < minZ) minZ = p1.z;
|
||||
if (p2.z < minZ) minZ = p2.z;
|
||||
if (p1.z > maxZ) maxZ = p1.z;
|
||||
if (p2.z > maxZ) maxZ = p2.z;
|
||||
int32_t layer_max = (maxZ - initial) / thickness;
|
||||
int32_t 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
|
||||
{
|
||||
z = layer_nr * thickness + initial;
|
||||
if (z < minZ) continue;
|
||||
if (layer_nr < 0) continue;
|
||||
|
||||
SlicerSegment s;
|
||||
s.endVertex = nullptr;
|
||||
int end_edge_idx = -1;
|
||||
if (p0.z < z && p1.z >= z && p2.z >= z)
|
||||
{
|
||||
s = project2D(face_idx, p, 0, 2, 1, z, layer_nr);
|
||||
end_edge_idx = 0;
|
||||
if (p1.z == z)
|
||||
{
|
||||
s.endVertex = &v1;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
if (p2.z == z)
|
||||
{
|
||||
s.endVertex = &v2;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
if (p0.z == z)
|
||||
{
|
||||
s.endVertex = &v0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Not all cases create a segment, because a point of a face could create just a dot, and two touching faces
|
||||
// on the slice would create two segments
|
||||
continue;
|
||||
}
|
||||
layers[layer_nr].face_idx_to_segment_idx.insert(std::make_pair(face_idx, layers[layer_nr].segments.size()));
|
||||
s.faceIndex = face_idx;
|
||||
s.endOtherFaceIdx = face.connected_face_index[end_edge_idx];
|
||||
s.addedToPolygon = false;
|
||||
layers[layer_nr].segments.push_back(s);
|
||||
}
|
||||
}
|
||||
log("slice of mesh took %.3f seconds\n",slice_timer.restart());
|
||||
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
|
||||
{
|
||||
layers[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
|
||||
}
|
||||
mesh->expandXY(mesh->getSettingInMicrons("xy_offset"));
|
||||
log("slice make polygons took %.3f seconds\n",slice_timer.restart());
|
||||
}
|
||||
|
||||
}//namespace cura
|
||||
@@ -1,60 +0,0 @@
|
||||
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_SLICER_H
|
||||
#define SLICER_SLICER_H
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "../mesh.h"
|
||||
#include "../utils/polygon.h"
|
||||
|
||||
#include "SlicerSegment.h"
|
||||
#include "ClosePolygonResult.h"
|
||||
#include "SlicerLayer.h"
|
||||
|
||||
#include "../MatSegment.h"
|
||||
|
||||
/*
|
||||
The Slicer creates layers of polygons from an optimized 3D model.
|
||||
The result of the Slicer is a list of polygons without any order or structure.
|
||||
*/
|
||||
namespace cura {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Slicer
|
||||
{
|
||||
public:
|
||||
std::vector<SlicerLayer> layers;
|
||||
|
||||
const Mesh* mesh = nullptr; //!< The sliced mesh
|
||||
|
||||
Slicer(Mesh* mesh, int initial, int thickness, int slice_layer_count, bool keepNoneClosed, bool extensiveStitching);
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* Linear interpolation
|
||||
*
|
||||
* Get the Y of a point with X \p x in the line through (\p x0, \p y0) and (\p x1, \p y1)
|
||||
*
|
||||
* \param p The face vertice locations in the order the vertices are given in the face
|
||||
*/
|
||||
int64_t interpolate(int64_t x, int64_t x0, int64_t x1, int64_t y0, int64_t y1) const
|
||||
{
|
||||
int64_t dx_01 = x1 - x0;
|
||||
int64_t num = (y1 - y0) * (x - x0);
|
||||
num += num > 0 ? dx_01/2 : -dx_01/2; // add in offset to round result
|
||||
int64_t y = y0 + num / dx_01;
|
||||
return y;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
void dumpSegmentsToHTML(const char* filename);
|
||||
};
|
||||
|
||||
}//namespace cura
|
||||
|
||||
#endif//SLICER_SLICER_H
|
||||
@@ -1,57 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef SLICER_SLICER_SEGMENT_H
|
||||
#define SLICER_SLICER_SEGMENT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "../utils/intpoint.h"
|
||||
|
||||
namespace cura
|
||||
{
|
||||
|
||||
class SlicerSegment
|
||||
{
|
||||
public:
|
||||
Point start, end;
|
||||
int faceIndex = -1;
|
||||
// The index of the other face connected via the edge that created end
|
||||
int endOtherFaceIdx = -1;
|
||||
// If end corresponds to a vertex of the mesh, then this is populated
|
||||
// with the vertex that it ended on.
|
||||
const MeshVertex *endVertex = nullptr;
|
||||
bool addedToPolygon = false;
|
||||
|
||||
SlicerSegment() //!< non-initializing constructor
|
||||
{}
|
||||
SlicerSegment(Point start, Point end) //!< partially initializing constructor
|
||||
: start(start)
|
||||
, end(end)
|
||||
{}
|
||||
/*!
|
||||
* equivalence testing irrespective of start/end order
|
||||
*/
|
||||
bool operator==(const SlicerSegment& b) const
|
||||
{
|
||||
return (start == b.start && end == b.end) || (start == b.end && end == b.start);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
namespace std
|
||||
{
|
||||
/*!
|
||||
* hash function irrespective of start/end order
|
||||
*/
|
||||
template<> struct hash<cura::SlicerSegment>
|
||||
{
|
||||
typedef std::size_t result_type;
|
||||
result_type operator()(cura::SlicerSegment const& s) const
|
||||
{
|
||||
return std::hash<cura::Point>()(cura::operator+(s.start, s.end));
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
|
||||
#endif // SLICER_SLICER_SEGMENT_H
|
||||
+55
-49
@@ -90,6 +90,7 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
|
||||
storage.support.supportLayers.resize(layer_count);
|
||||
}
|
||||
|
||||
// generate support areas
|
||||
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
|
||||
{
|
||||
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
|
||||
@@ -100,25 +101,33 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int l
|
||||
std::vector<Polygons> supportAreas;
|
||||
supportAreas.resize(layer_count, Polygons());
|
||||
generateSupportAreas(storage, mesh_idx, layer_count, supportAreas);
|
||||
|
||||
if (mesh.getSettingBoolean("support_interface_enable"))
|
||||
|
||||
for (unsigned int layer_idx = 0; layer_idx < layer_count; layer_idx++)
|
||||
{
|
||||
generateSupportInterface(storage, mesh, supportAreas, layer_count);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
|
||||
{
|
||||
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[layer_idx]);
|
||||
}
|
||||
storage.support.supportLayers[layer_idx].supportAreas.add(supportAreas[layer_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
|
||||
{
|
||||
Polygons& support_areas = storage.support.supportLayers[layer_idx].supportAreas;
|
||||
support_areas = support_areas.unionPolygons();
|
||||
}
|
||||
|
||||
// handle support interface
|
||||
for (unsigned int mesh_idx = 0; mesh_idx < storage.meshes.size(); mesh_idx++)
|
||||
{
|
||||
SliceMeshStorage& mesh = storage.meshes[mesh_idx];
|
||||
if (mesh.getSettingBoolean("infill_mesh") || mesh.getSettingBoolean("anti_overhang_mesh"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh.getSettingBoolean("support_interface_enable"))
|
||||
{
|
||||
generateSupportInterface(storage, mesh, layer_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -342,14 +351,14 @@ void AreaSupport::generateSupportAreas(SliceDataStorage& storage, unsigned int m
|
||||
}
|
||||
|
||||
//Enforce top Z distance.
|
||||
if (layerZdistanceTop > 0)
|
||||
if (layerZdistanceTop > 1)
|
||||
{
|
||||
// this is performed after the main support generation loop above, because it affects the joining of polygons
|
||||
// if this would be performed in the main loop then some support would not have been generated under the overhangs and consequently no support is generated for that,
|
||||
// meaning almost no support would be generated in some cases which definitely need support.
|
||||
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - layerZdistanceTop; layer_idx++)
|
||||
for (size_t layer_idx = 0; layer_idx < storage.support.supportLayers.size() && layer_idx < support_layer_count - (layerZdistanceTop - 1); layer_idx++)
|
||||
{
|
||||
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop, false));
|
||||
supportAreas[layer_idx] = supportAreas[layer_idx].difference(storage.getLayerOutlines(layer_idx + layerZdistanceTop - 1, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,7 +568,7 @@ void AreaSupport::handleWallStruts(
|
||||
}
|
||||
|
||||
|
||||
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count)
|
||||
void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, const unsigned int layer_count)
|
||||
{
|
||||
const unsigned int roof_layer_count = round_divide(mesh.getSettingInMicrons("support_roof_height"), storage.getSettingInMicrons("layer_height"));
|
||||
const unsigned int bottom_layer_count = round_divide(mesh.getSettingInMicrons("support_bottom_height"), storage.getSettingInMicrons("layer_height"));
|
||||
@@ -576,44 +585,41 @@ void AreaSupport::generateSupportInterface(SliceDataStorage& storage, const Slic
|
||||
|
||||
const unsigned int top_layer_idx_above = layer_idx + roof_layer_count + z_distance_top;
|
||||
const unsigned int bottom_layer_idx_below = std::max(0, int(layer_idx) - int(bottom_layer_count) - int(z_distance_bottom));
|
||||
if (top_layer_idx_above < supportLayers.size())
|
||||
if (top_layer_idx_above >= supportLayers.size())
|
||||
{
|
||||
Polygons roofs;
|
||||
if (roof_layer_count > 0)
|
||||
{
|
||||
Polygons model;
|
||||
const unsigned int n_scans = std::max(1u, (roof_layer_count - 1) / skip_layer_count);
|
||||
const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(n_scans));
|
||||
for (float layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip)
|
||||
{
|
||||
const Polygons outlines_above = mesh.layers[std::round(layer_idx_above)].getOutlines();
|
||||
model = model.unionPolygons(outlines_above);
|
||||
}
|
||||
roofs = support_areas[layer_idx].intersection(model);
|
||||
}
|
||||
Polygons bottoms;
|
||||
if (bottom_layer_count > 0)
|
||||
{
|
||||
Polygons model;
|
||||
const unsigned int n_scans = std::max(1u, (bottom_layer_count - 1) / skip_layer_count);
|
||||
const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(n_scans));
|
||||
for (float layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip)
|
||||
{
|
||||
const Polygons outlines_below = mesh.layers[std::round(layer_idx_below)].getOutlines();
|
||||
model = model.unionPolygons(outlines_below);
|
||||
}
|
||||
bottoms = support_areas[layer_idx].intersection(model);
|
||||
}
|
||||
// expand skin a bit so that we're sure it's not too thin to be printed.
|
||||
Polygons skin = roofs.unionPolygons(bottoms).offset(interface_line_width).intersection(support_areas[layer_idx]);
|
||||
skin.removeSmallAreas(1.0);
|
||||
layer.skin.add(skin);
|
||||
layer.supportAreas.add(support_areas[layer_idx].difference(layer.skin));
|
||||
continue;
|
||||
}
|
||||
else
|
||||
Polygons roofs;
|
||||
if (roof_layer_count > 0)
|
||||
{
|
||||
layer.skin.add(support_areas[layer_idx]);
|
||||
Polygons model;
|
||||
const unsigned int n_scans = std::max(1u, (roof_layer_count - 1) / skip_layer_count);
|
||||
const float z_skip = std::max(1.0f, float(roof_layer_count - 1) / float(n_scans));
|
||||
for (float layer_idx_above = top_layer_idx_above; layer_idx_above > layer_idx + z_distance_top; layer_idx_above -= z_skip)
|
||||
{
|
||||
const Polygons outlines_above = mesh.layers[std::round(layer_idx_above)].getOutlines();
|
||||
model = model.unionPolygons(outlines_above);
|
||||
}
|
||||
roofs = layer.supportAreas.intersection(model);
|
||||
}
|
||||
Polygons bottoms;
|
||||
if (bottom_layer_count > 0)
|
||||
{
|
||||
Polygons model;
|
||||
const unsigned int n_scans = std::max(1u, (bottom_layer_count - 1) / skip_layer_count);
|
||||
const float z_skip = std::max(1.0f, float(bottom_layer_count - 1) / float(n_scans));
|
||||
for (float layer_idx_below = bottom_layer_idx_below; std::round(layer_idx_below) < (int)(layer_idx - z_distance_bottom); layer_idx_below += z_skip)
|
||||
{
|
||||
const Polygons outlines_below = mesh.layers[std::round(layer_idx_below)].getOutlines();
|
||||
model = model.unionPolygons(outlines_below);
|
||||
}
|
||||
bottoms = layer.supportAreas.intersection(model);
|
||||
}
|
||||
// expand skin a bit so that we're sure it's not too thin to be printed.
|
||||
Polygons skin = roofs.unionPolygons(bottoms).offset(interface_line_width).intersection(layer.supportAreas);
|
||||
skin.removeSmallAreas(1.0);
|
||||
layer.skin.add(skin);
|
||||
layer.supportAreas = layer.supportAreas.difference(layer.skin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -36,10 +36,9 @@ private:
|
||||
*
|
||||
* \param storage Output storage: support area + support skin area output
|
||||
* \param mesh The mesh to generate support skins for.
|
||||
* \param support_areas The basic support areas for the current mesh
|
||||
* \param layer_count The number of layers in this mesh group.
|
||||
*/
|
||||
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, std::vector<Polygons>& support_areas, const unsigned int layer_count);
|
||||
static void generateSupportInterface(SliceDataStorage& storage, const SliceMeshStorage& mesh, const unsigned int layer_count);
|
||||
|
||||
/*!
|
||||
* Join current support layer with the support of the layer above, (make support conical) and perform smoothing etc operations.
|
||||
|
||||
@@ -37,6 +37,12 @@ void AABB3D::include(Point3 p)
|
||||
max.z = std::max(max.z, p.z);
|
||||
}
|
||||
|
||||
void AABB3D::includeZ(int32_t z)
|
||||
{
|
||||
min.z = std::min(min.z, z);
|
||||
max.z = std::max(max.z, z);
|
||||
}
|
||||
|
||||
void AABB3D::offset(Point3 offset)
|
||||
{
|
||||
min += offset;
|
||||
|
||||
@@ -38,6 +38,14 @@ struct AABB3D
|
||||
*/
|
||||
void include(Point3 p);
|
||||
|
||||
/*!
|
||||
* Expand the AABB3D to include a z-coordinate.
|
||||
*
|
||||
* This is for including a point of which the X and Y coordinates are
|
||||
* unknown but known to already be included in the bounding box.
|
||||
*/
|
||||
void includeZ(int32_t z);
|
||||
|
||||
/*!
|
||||
* Offset the coordinates of the bounding box.
|
||||
* \param offset The offset with which to offset the AABB3D.
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
|
||||
#ifndef UTILS_F_POINT_H
|
||||
#define UTILS_F_POINT_H
|
||||
|
||||
#include <cmath> // sqrt
|
||||
#include <iostream> // auto-serialization / auto-toString() '<<'
|
||||
|
||||
namespace cura
|
||||
{
|
||||
/*!
|
||||
* 2D coordinates represented by floats
|
||||
*/
|
||||
class FPoint
|
||||
{
|
||||
public:
|
||||
float x, y; //!< Coordinates
|
||||
FPoint() //!< non-initializing constructor
|
||||
{}
|
||||
FPoint(float x, float y) //!< constructor
|
||||
: x(x)
|
||||
, y(y)
|
||||
{}
|
||||
|
||||
FPoint operator+(const FPoint& p) const { return FPoint(x+p.x, y+p.y); }
|
||||
FPoint operator-(const FPoint& p) const { return FPoint(x-p.x, y-p.y); }
|
||||
FPoint operator/(const float i) const { return FPoint(x/i, y/i); }
|
||||
FPoint operator*(const float i) const { return FPoint(x*i, y*i); }
|
||||
|
||||
FPoint& operator += (const FPoint& p) { x += p.x; y += p.y; return *this; }
|
||||
FPoint& operator -= (const FPoint& p) { x -= p.x; y -= p.y; return *this; }
|
||||
|
||||
bool operator==(const FPoint& p) const { return x == p.x && y == p.y; }
|
||||
bool operator!=(const FPoint& p) const { return x != p.x || y != p.y; }
|
||||
|
||||
/*!
|
||||
* output to string stream in standard format
|
||||
*/
|
||||
template<class CharT, class TraitsT>
|
||||
friend
|
||||
std::basic_ostream<CharT, TraitsT>&
|
||||
operator <<(std::basic_ostream<CharT, TraitsT>& os, const FPoint& p)
|
||||
{
|
||||
return os << "(" << p.x << ", " << p.y << ")";
|
||||
}
|
||||
|
||||
/*!
|
||||
* squared vector size
|
||||
*/
|
||||
float vSize2() const
|
||||
{
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
/*!
|
||||
* vector size
|
||||
*/
|
||||
float vSize() const
|
||||
{
|
||||
return sqrt(vSize2());
|
||||
}
|
||||
|
||||
/*!
|
||||
* dot product
|
||||
*/
|
||||
float dot(const FPoint& p) const
|
||||
{
|
||||
return x * p.x + y * p.y;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace cura
|
||||
|
||||
#endif // UTILS_F_POINT_H
|
||||
+1
-11
@@ -190,16 +190,6 @@ unsigned int Polygons::findInside(Point p, bool border_result)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Polygons Polygons::removeComplexParts() const
|
||||
{
|
||||
Polygons ret;
|
||||
ClipperLib::Clipper clipper(clipper_init);
|
||||
clipper.AddPaths(paths, ClipperLib::ptSubject, true);
|
||||
clipper.Execute(ClipperLib::ctUnion, ret.paths, ClipperLib::pftPositive);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Polygons Polygons::offset(int distance, ClipperLib::JoinType join_type, double miter_limit) const
|
||||
{
|
||||
Polygons ret;
|
||||
@@ -847,7 +837,6 @@ void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const P
|
||||
Point b;
|
||||
bool success = LinearAlg2D::getPointOnLineWithDist(a, p1, p2, shortcut_length, b);
|
||||
// v02 has to be longer than ab!
|
||||
p1_it.remove();
|
||||
if (success)
|
||||
{ // if not success then assume b is negligibly close to 2, but rounding errors caused a problem
|
||||
#ifdef ASSERT_INSANE_OUTPUT
|
||||
@@ -855,6 +844,7 @@ void PolygonRef::smooth_corner_simple(ListPolygon& poly, const Point p0, const P
|
||||
#endif // #ifdef ASSERT_INSANE_OUTPUT
|
||||
ListPolyIt::insertPointNonDuplicate(p1_it, p2_it, b);
|
||||
}
|
||||
p1_it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-16
@@ -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());
|
||||
@@ -859,18 +859,6 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Remove holes which are lying outside of parts, and outlines inside of parts
|
||||
*
|
||||
* ^↘
|
||||
* ^ ↘
|
||||
* <<<<<<<<^<<<< should become <<<<<<<<
|
||||
* ^ ^
|
||||
* ^ ^
|
||||
* ^ ^
|
||||
*/
|
||||
Polygons removeComplexParts() const;
|
||||
|
||||
int64_t polygonLength() const
|
||||
{
|
||||
int64_t length = 0;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//Copyright (c) 2017 Ultimaker B.V.
|
||||
//CuraEngine is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
#ifndef UTILS_STRING_H
|
||||
#define UTILS_STRING_H
|
||||
|
||||
@@ -35,7 +38,7 @@ static inline void writeInt2mm(const int64_t coord, std::ostream& ss)
|
||||
{
|
||||
constexpr size_t buffer_size = 24;
|
||||
char buffer[buffer_size];
|
||||
int char_count = sprintf(buffer, "%" PRId64, coord); // convert int to string
|
||||
int char_count = sprintf(buffer, "%d", int(coord)); // convert int to string
|
||||
#ifdef DEBUG
|
||||
if (char_count + 1 >= int(buffer_size)) // + 1 for the null character
|
||||
{
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário