Comparar commits

...

50 Commits

Autor SHA1 Mensagem Data
Tim Kuipers afefa64505 fix: obj loading ignores normals and empty lines (CURA-1371) 2016-04-29 13:40:51 +02:00
Tim Kuipers c41ffa669f feat: switch extruder every layer (CURA-1371) 2016-04-29 13:40:24 +02:00
Tim Kuipers beb2199b4f feat: texture to dual color pixel zigzag stuffs (CURA-1371) 2016-04-28 20:04:12 +02:00
Tim Kuipers 005bfa5b02 refactor: process ==> processBumpMap (CURA-1371) 2016-04-28 19:31:07 +02:00
Tim Kuipers 4f5c9d235f lil fix 2016-04-15 18:29:29 +02:00
Tim Kuipers e2f3540d6b fix: added corner point handling to mesh texture offset (CURA-1371) 2016-04-10 23:11:05 +02:00
Tim Kuipers 1ccded78cc fix: material coordinates were out of bounds (inverted) (CURA-1371) 2016-04-10 22:46:42 +02:00
Tim Kuipers e47318bdbd fix: getFaceEdgeMatCoord converted to MM implicitly (CURA-1371) 2016-04-10 22:19:33 +02:00
Tim Kuipers ca5a8904fc Merge branch 'feature_textured_obj' of https://github.com/Ultimaker/CuraEngine into feature_textured_obj 2016-04-10 18:35:39 +02:00
Tim Kuipers 6c1e833d06 feat: actual texture to offset computation (still buggy) (CURA-1371)
not all material coordinates seem to be recorded
material coordinates seem always around the same value
2016-04-10 18:32:47 +02:00
Tim Kuipers 9c1b21184f fix: ambiguous overload in FPoint (CURA-1371) 2016-04-10 18:17:56 +02:00
Tim Kuipers 4feddf5da8 lil (CURA-1371) 2016-04-10 17:30:46 +02:00
Tim Kuipers 672d12105e feat: TextureProcessor for polygons (CURA-1371) 2016-04-10 17:19:00 +02:00
Tim Kuipers 8f3af9a6cc fix: SlicerSegment hashing fix (CURA-1371) 2016-04-10 17:16:44 +02:00
Tim Kuipers 9eed417b31 feat: segment to material mapping (CURA-1371) 2016-04-10 17:05:19 +02:00
Tim Kuipers 51a670ee99 fix: obj parsing fixes and output (CURA-1371) 2016-04-10 17:01:22 +02:00
Tim Kuipers 3833ed3cf2 lil: SlicerSegment operator== (CURA-1371) 2016-04-10 16:18:40 +02:00
Tim Kuipers 5ea109af98 refactor: registerFaceSlice result in MatSegment (CURA-1371) 2016-04-10 16:09:28 +02:00
Tim Kuipers 05f7d7fd61 refactor: factored out child classes from TexturedMesh into MatCoord and FPoint (CURA-1371) 2016-04-10 16:03:32 +02:00
Tim Kuipers ac41b10c05 refactor: factored out child classes from TexturedMesh into MatCoord and FPoint (CURA-1371) 2016-04-10 15:36:48 +02:00
Tim Kuipers 91a2a0c8e9 fix: getFaceEdgeMatCoord should result in MatCoord (CURA-1371) 2016-04-10 15:11:41 +02:00
Tim Kuipers 795c5a24ef fix: obj texture coordinates didn't get loaded (CURA-1371) 2016-04-10 15:07:48 +02:00
Tim Kuipers c89476a9ac refactor: moved slicer related files into slicer folder (CURA-1371) 2016-04-10 14:17:15 +02:00
Tim Kuipers c457bbefe4 refactor: moved slicer classes to separate files (CURA-1371) 2016-04-10 14:04:57 +02:00
Tim Kuipers 027e26b3a6 feat: mesh.registerFaceSlice for textured meshes (CURA-1371) 2016-04-10 13:47:53 +02:00
Tim Kuipers 732822d3fb refactor: send order information to project2D (slicer) (CURA-1371) 2016-04-10 13:10:38 +02:00
Tim Kuipers 6507ef5fa0 feat: small optimization in slicer (CURA-1371) 2016-04-10 12:58:47 +02:00
Tim Kuipers 489ca9e644 refactor: inlined sliceFace again, more documentation, code conventions (CURA-1371) 2016-04-10 12:21:22 +02:00
Tim Kuipers e12272e2fa Revert "refactor: slicing of a single face is moved to two loops (CURA-1371)"
This reverts commit 367f51be27.

That commit was an optimization which took effect foremost when a face would cross multiple layers, which means this is an optimization only for low poly models and a bit of a slowdown for hi poly models.
2016-04-10 12:03:04 +02:00
Tim Kuipers 367f51be27 refactor: slicing of a single face is moved to two loops (CURA-1371)
instead of checking inside the loop what the slice is compared the three verts, we now check the order of the verts outside and walk from the bottom to the middle and then from the middle to the top.
This way there is only one call to project2D and no more lots of deeply nested if statements.
2016-04-08 23:20:34 +02:00
Tim Kuipers 6af639b092 refactor slicer (CURA-1371) 2016-04-08 21:53:19 +02:00
Tim Kuipers 94234c6d2f feat: TexturedMesh.getFaceEdgeMatCoord (CURA-1371) 2016-04-08 21:14:14 +02:00
Tim Kuipers 055135a740 quick hack: sdfsdsgdgsda 2016-04-08 18:32:34 +02:00
Tim Kuipers 27a9bbfa4c refactor: material coords double ==> float; feat: TexturedMesh.getMatCoord (CURA-1371) 2016-04-08 16:42:22 +02:00
Tim Kuipers 78e1595b83 fix: lil int casting thing (CURA-1371) 2016-04-08 15:39:59 +02:00
Tim Kuipers 510ddca188 feat: retrieve color from material (CURA-1371) 2016-04-08 01:59:24 +02:00
Tim Kuipers e2fe742df7 fix: use updated material in obj file (CURA-1371) 2016-04-08 01:58:57 +02:00
Tim Kuipers 844024b089 feat: load material image (CURA-1371) 2016-04-08 01:29:47 +02:00
Tim Kuipers e04714ae40 feat: loading of mtl (obj) (CURA-1371) 2016-04-08 01:03:48 +02:00
Tim Kuipers 763fa1f17b fix: support obj relative indexing (CURA-1371) 2016-04-07 23:36:27 +02:00
Tim Kuipers b86d82068f fix: made obj loading robust against not having texture data (CURA-1371) 2016-04-07 23:21:53 +02:00
Tim Kuipers 8574563d76 fix: load obj file into a TexturedMesh (CURA-1371) 2016-04-07 23:01:06 +02:00
Tim Kuipers 3879cc9485 fix: TexturedMesh contructor (CURA-1371) 2016-04-07 23:00:35 +02:00
Tim Kuipers 5f1bf1bb10 fix: delete mesh if it didn't load properly (CURA-1371) 2016-04-07 22:59:21 +02:00
Tim Kuipers 49bc2ec79c fix: TexturedMesh.addFace wasn't finished yet (CURA-1371) 2016-04-07 22:47:54 +02:00
Tim Kuipers d8fec42059 feat: let mesh.addFace return whether it actually inserted a face (CURA-1371) 2016-04-07 22:40:47 +02:00
Tim Kuipers fa19e9a5a3 feat: preliminary work for textured meshes (CURA-1371)
basic file structure and functions
2016-04-07 22:35:23 +02:00
Tim Kuipers 081c3be70c refactor: meshgroup.meshes became a vector of pointers (CURA-1371)
This to support future objects inheriting from Mesh
2016-04-07 22:02:38 +02:00
Tim Kuipers 85b2fb7c26 feat: support basic obj files (non-textured) (CURA-1371) 2016-04-07 21:49:18 +02:00
Tim Kuipers a1880b371e added functionality to Mesh to load obj files 2016-03-29 10:29:14 +02:00
36 arquivos alterados com 1356 adições e 277 exclusões
+9 -3
Ver Arquivo
@@ -55,12 +55,12 @@ set(engine_SRCS # Except main.cpp.
src/gcodePlanner.cpp
src/infill.cpp
src/inset.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/PrimeTower.cpp
src/Progress.cpp
@@ -70,9 +70,10 @@ set(engine_SRCS # Except main.cpp.
src/skin.cpp
src/skirt.cpp
src/sliceDataStorage.cpp
src/slicer.cpp
src/support.cpp
src/timeEstimate.cpp
src/TexturedMesh.cpp
src/TextureProcessor.cpp
src/wallOverlap.cpp
src/Weaver.cpp
src/Wireframe2gcode.cpp
@@ -83,6 +84,11 @@ set(engine_SRCS # Except main.cpp.
src/infill/ZigzagConnectorProcessorEndPieces.cpp
src/infill/ZigzagConnectorProcessorNoEndPieces.cpp
src/slicer/LayerPart.cpp
src/slicer/MultiVolumes.cpp
src/slicer/SlicerLayer.cpp
src/slicer/Slicer.cpp
src/utils/gettime.cpp
src/utils/LinearAlg2D.cpp
src/utils/logoutput.cpp
+10 -1
Ver Arquivo
@@ -562,7 +562,16 @@ void FffGcodeWriter::addMeshLayerToGCode(SliceDataStorage& storage, SliceMeshSto
return;
}
setExtruder_addPrime(storage, gcode_layer, layer_nr, mesh->getSettingAsIndex("extruder_nr"));
int extruder_nr = mesh->getSettingAsIndex("extruder_nr");
{ // TODO: only do this for dual color texture
if (layer_nr % 2 == 0)
{
extruder_nr = 1 - extruder_nr;
}
}
setExtruder_addPrime(storage, gcode_layer, layer_nr, extruder_nr);
EZSeamType z_seam_type = mesh->getSettingAsZSeamType("z_seam_type");
+8 -6
Ver Arquivo
@@ -2,13 +2,14 @@
#include <algorithm>
#include "slicer.h"
#include "slicer/Slicer.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "MeshGroup.h"
#include "support.h"
#include "multiVolumes.h"
#include "layerPart.h"
#include "slicer/MultiVolumes.h"
#include "slicer/LayerPart.h"
#include "TextureProcessor.h"
#include "inset.h"
#include "skirt.h"
#include "skin.h"
@@ -73,7 +74,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, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
slicerList.push_back(slicer);
/*
@@ -93,14 +94,15 @@ bool FffPolygonGenerator::sliceModel(MeshGroup* meshgroup, TimeKeeper& timeKeepe
Progress::messageProgressStage(Progress::Stage::PARTS, &timeKeeper);
//carveMultipleVolumes(storage.meshes);
generateMultipleVolumesOverlap(slicerList, getSettingInMicrons("multiple_mesh_overlap"));
storage.meshes.reserve(slicerList.size()); // causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated.
for(unsigned int meshIdx=0; meshIdx < slicerList.size(); meshIdx++)
{
storage.meshes.emplace_back(&meshgroup->meshes[meshIdx]); // new mesh in storage had settings from the Mesh
storage.meshes.emplace_back(meshgroup->meshes[meshIdx]); // new mesh in storage had settings from the Mesh
SliceMeshStorage& meshStorage = storage.meshes.back();
Mesh& mesh = storage.meshgroup->meshes[meshIdx];
Mesh& mesh = *storage.meshgroup->meshes[meshIdx];
createLayerParts(meshStorage, slicerList[meshIdx], mesh.getSettingBoolean("meshfix_union_all"), mesh.getSettingBoolean("meshfix_union_all_remove_holes"));
delete slicerList[meshIdx];
+1 -1
Ver Arquivo
@@ -26,7 +26,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.getSettingAsCount("extruder_nr") << " -l \"" << mesh_idx << "\"" << mesh.getAllLocalSettingsString();
}
sstream << "\n";
+27
Ver Arquivo
@@ -0,0 +1,27 @@
/** 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
+27
Ver Arquivo
@@ -0,0 +1,27 @@
/** 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
+33
Ver Arquivo
@@ -0,0 +1,33 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include <limits> // numeric limits
#include <algorithm> // min max
#include <iostream>
#include "Material.h"
namespace cura
{
void Material::setData(unsigned char* data)
{
this->data = data;
}
void Material::setWidthHeight(int width, int height)
{
this->width = width;
this->height = height;
}
float Material::getColor(float x, float y)
{
int w_idx = std::max(0, std::min(int (x * width), width - 1));
int h_idx = std::max(0, std::min(int (y * height), height - 1));
unsigned char r = data[(h_idx * width + w_idx) * 3];
return (float) r / std::numeric_limits<unsigned char>::max();
}
} // namespace cura
+30
Ver Arquivo
@@ -0,0 +1,30 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef MATERIAL_H
#define MATERIAL_H
namespace cura
{
class Material
{
public:
void setData(unsigned char* data);
void setWidthHeight(int width, int height);
/*!
* get some value representing the getColor
*
* red?
*
* TODO
*
* \return a value between zero and one
*/
float getColor(float x, float y);
protected:
unsigned char* data; //!< pixel data in rgb-row-first (or bgr-row first ?)
int width, height; //!< image dimensions
};
} // namespace cura
#endif // MATERIAL_H
+42
Ver Arquivo
@@ -0,0 +1,42 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "MaterialBase.h"
namespace cura
{
Material* MaterialBase::add(std::string name)
{
name_to_mat_idx[name] = materials.size();
materials.emplace_back();
return &materials.back();
}
Material* MaterialBase::getMat(unsigned int id)
{
if (id < materials.size())
{
return &materials[id];
}
else
{
return nullptr;
}
}
int MaterialBase::getMatId(std::string name)
{
auto it = name_to_mat_idx.find(name);
if (it == name_to_mat_idx.end())
{
return -1;
}
else
{
return it->second;
}
}
} // namespace cura
+27
Ver Arquivo
@@ -0,0 +1,27 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef 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);
Material* add(std::string name);
Material* getMat(unsigned int id);
protected:
std::unordered_map<std::string, int> name_to_mat_idx;
std::vector<Material> materials;
};
} // namespace cura
#endif // MATERIAL_BASE_H
+181 -2
Ver Arquivo
@@ -22,6 +22,10 @@ void* fgets_(char* ptr, size_t len, FILE* f)
*ptr = '\0';
return ptr;
}
else if (*ptr =='\0')
{
return ptr;
}
ptr++;
len--;
}
@@ -168,18 +172,193 @@ bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
return loadMeshSTL_binary(mesh, filename, matrix);
}
void readBMP(Material* mat, const char* filename)
{
FILE* f = fopen(filename, "rb");
if (f == nullptr)
{
logError("ERROR: couldn't load image file %s.\n", filename);
return;
}
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f); // read the 54-byte header
// extract image height and width from header
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = 3 * width * height;
unsigned char* data = new unsigned char[size]; // allocate 3 bytes per pixel
fread(data, sizeof(unsigned char), size, f); // read the rest of the data at once
fclose(f);
// for (int i = 0; i < size; i += 3)
// {
// unsigned char tmp = data[i];
// data[i] = data[i+2];
// data[i+2] = tmp;
// } // BGR ==> RGB
mat->setData(data);
mat->setWidthHeight(width, height);
}
void loadMatImage(Material* mat, const char* filename)
{
const char* ext = strrchr(filename, '.');
if (ext && (strcmp(ext, ".bmp") == 0 || strcmp(ext, ".BMP") == 0))
{
readBMP(mat, filename);
}
else
{
logError("ERROR: trying to load unsupported image. File %s has %s extension.\n", filename, ext);
}
}
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)
{
const char* ext = strrchr(filename, '.');
if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
{
Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
Mesh* mesh = new Mesh(object_parent_settings ? object_parent_settings : meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if (loadMeshSTL(mesh,filename,transformation)) //Load it! If successful...
{
meshgroup->meshes.push_back(mesh);
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;
}
+18 -13
Ver Arquivo
@@ -4,6 +4,7 @@
#include "utils/NoCopy.h"
#include "mesh.h"
#include "TexturedMesh.h"
#include "ExtruderTrain.h"
namespace cura
@@ -43,6 +44,10 @@ public:
delete extruders[extruder];
}
}
for (Mesh* mesh : meshes)
{
delete mesh;
}
}
/*!
@@ -63,7 +68,7 @@ public:
return extruders[extruder_nr];
}
std::vector<Mesh> meshes;
std::vector<Mesh*> meshes;
Point3 min() const //! minimal corner of bounding box
{
@@ -71,10 +76,10 @@ public:
{
return Point3(0, 0, 0);
}
Point3 ret = meshes[0].min();
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);
@@ -87,10 +92,10 @@ public:
{
return Point3(0, 0, 0);
}
Point3 ret = meshes[0].max();
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);
@@ -100,9 +105,9 @@ public:
void clear()
{
for(Mesh& m : meshes)
for(Mesh* m : meshes)
{
m.clear();
m->clear();
}
}
@@ -117,17 +122,17 @@ public:
}
// 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);
}
}
};
+130
Ver Arquivo
@@ -0,0 +1,130 @@
#include "TextureProcessor.h"
#include <algorithm> // swap
#include "slicer/SlicerSegment.h"
namespace cura
{
#define POINT_DIST 400
#define AMPLITUDE 500
#define EXTRA_OFFSET 500
/*
void TextureProcessor::process(std::vector< Slicer* >& slicer_list)
{
for (Slicer* slicer : slicer_list)
{
for (SlicerLayer& layer : slicer->layers)
{
process(slicer->mesh, layer);
}
}
}
*/
void TextureProcessor::processBumpMap(Mesh* mesh, SlicerLayer& layer)
{
process(mesh, layer, false);
}
void TextureProcessor::processDualColorTexture(Mesh* mesh, SlicerLayer& layer)
{
process(mesh, layer, true);
}
void TextureProcessor::process(Mesh* mesh, SlicerLayer& layer, bool dual_color_texture)
{
bool flipped = false;
if (dual_color_texture)
{
flipped = layer.layer_nr % 2 == 0;
}
Polygons results;
for (PolygonRef poly : layer.polygonList)
{
// generate points in between p0 and p1
PolygonRef result = results.newPoly();
int64_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();
bool even = false;
for (Point& p1 : poly)
{
SlicerSegment segment(*p0, p1);
auto it = layer.segment_to_material_segment.find(segment);
if (it != layer.segment_to_material_segment.end())
{
MatSegment& mat = it->second;
MatCoord mat_start = mat.start;
MatCoord mat_end = mat.end;
if (it->first.start != *p0)
{
std::swap(mat_start, mat_end);
}
Point p0p1 = p1 - *p0;
Point perp_to_p0p1 = turn90CCW(p0p1);
int64_t p0p1_size = vSize(p0p1);
int64_t dist_last_point = dist_left_over + p0p1_size * 2; // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size
// 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)
{
Point pa = *p0 + normal(p0p1, p0pa_dist);
if (even ^ flipped)
{
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); // between 0 and 1
if (flipped)
{
val = 1.0f - val;
}
assert(val > -0.001 && val < 1.001);
int r = val * (AMPLITUDE * 2) - AMPLITUDE + EXTRA_OFFSET;
Point displacement = normal(perp_to_p0p1, r);
pa -= displacement;
}
result.add(pa);
dist_last_point = p0pa_dist;
even = !even;
}
// TODO: move end point as well
float val = mesh->getColor(mat_end);
int r = val * (AMPLITUDE * 2) - AMPLITUDE + EXTRA_OFFSET;
Point displacement = normal(perp_to_p0p1, r);
if (dual_color_texture)
{
result.emplace_back(p1);
}
else
{
result.emplace_back(p1 - displacement);
}
dist_left_over = p0p1_size - dist_last_point;
}
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);
}
}
layer.polygonList = results;
}
}//namespace cura
+32
Ver Arquivo
@@ -0,0 +1,32 @@
/** 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:
/*!
* Apply offsets in the xy plane corresponding to pixel intensities
*/
static void processBumpMap(Mesh* mesh, SlicerLayer& layer);
/*!
* Apply a zigzag pattern with offsets corresponding to pixel intensities
*/
static void processDualColorTexture(Mesh* mesh, SlicerLayer& layer);
protected:
static void process(Mesh* mesh, SlicerLayer& layer, bool dual_color_texture);
};
} // namespace cura
#endif // TEXTURE_PROCESSOR_H
+137
Ver Arquivo
@@ -0,0 +1,137 @@
/** 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)
{
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;
}
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)
{
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)
{
Material* mat = material_base.getMat(bitmap_coord.mat_id);
if (mat)
{
return mat->getColor(bitmap_coord.coords.x, bitmap_coord.coords.y);
}
else
{
return 0.0f;
}
}
} // namespace cura
+78
Ver Arquivo
@@ -0,0 +1,78 @@
/** 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);
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);
virtual float getColor(MatCoord bitmap_coord);
private:
int current_mat; //!< material currently used in loading the face material info
};
} // namespace cura
#endif // TEXTURED_MESH_H
+2 -2
Ver Arquivo
@@ -23,9 +23,9 @@ void Weaver::weave(MeshGroup* meshgroup)
std::vector<cura::Slicer*> slicerList;
for(Mesh& mesh : meshgroup->meshes)
for (Mesh* mesh : meshgroup->meshes)
{
cura::Slicer* slicer = new cura::Slicer(&mesh, initial_layer_thickness, connectionHeight, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
cura::Slicer* slicer = new cura::Slicer(mesh, initial_layer_thickness, connectionHeight, layer_count, mesh->getSettingBoolean("meshfix_keep_open_polygons"), mesh->getSettingBoolean("meshfix_extensive_stitching"));
slicerList.push_back(slicer);
}
+1 -1
Ver Arquivo
@@ -6,7 +6,7 @@
#include "settings.h"
#include "MeshGroup.h"
#include "slicer.h"
#include "slicer/Slicer.h"
#include "utils/NoCopy.h"
#include "utils/polygon.h"
+1 -1
Ver Arquivo
@@ -11,7 +11,7 @@
#include "settings.h"
#include "MeshGroup.h"
#include "slicer.h"
#include "slicer/Slicer.h"
#include "utils/polygon.h"
#include "Weaver.h"
+2 -2
Ver Arquivo
@@ -261,8 +261,8 @@ void CommandSocket::handleObjectList(cura::proto::ObjectList* list)
}
SettingsBase* extruder_train = meshgroup->getExtruderTrain(extruder_train_nr);
meshgroup->meshes.push_back(extruder_train); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
Mesh& mesh = meshgroup->meshes.back();
meshgroup->meshes.push_back(new Mesh(extruder_train)); //Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
Mesh& mesh = *meshgroup->meshes.back();
for(int i = 0; i < face_count; ++i)
{
+1 -1
Ver Arquivo
@@ -194,7 +194,7 @@ void slice(int argc, char **argv)
}
else
{
last_settings_object = &(meshgroup->meshes.back()); // pointer is valid until a new object is added, so this is OK
last_settings_object = meshgroup->meshes.back();
}
break;
case 'o':
+33 -2
Ver Arquivo
@@ -15,12 +15,21 @@ Mesh::Mesh(SettingsBaseVirtual* parent)
{
}
void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
bool Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
{
int vi0 = findIndexOfVertex(v0);
int vi1 = findIndexOfVertex(v1);
int vi2 = findIndexOfVertex(v2);
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face.
return addFace(vi0, vi1, vi2);
}
bool Mesh::addFace(int vi0, int vi1, int vi2)
{
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2)
{
// the face has two vertices which get assigned the same location. Don't add the face.
return false;
}
int idx = faces.size(); // index of face to be added
faces.emplace_back();
@@ -31,6 +40,8 @@ void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
vertices[face.vertex_index[0]].connected_faces.push_back(idx);
vertices[face.vertex_index[1]].connected_faces.push_back(idx);
vertices[face.vertex_index[2]].connected_faces.push_back(idx);
return true;
}
void Mesh::clear()
@@ -64,6 +75,14 @@ Point3 Mesh::max() const
return aabb.max;
}
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);
@@ -179,4 +198,16 @@ int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx) const
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)
{
// do nothing for a non-textured mesh
return false;
}
float Mesh::getColor(MatCoord bitmap_coord)
{
return 0.0f;
}
}//namespace cura
+28 -1
Ver Arquivo
@@ -3,6 +3,7 @@
#include "settings.h"
#include "utils/AABB.h"
#include "MatSegment.h"
namespace cura
{
@@ -65,7 +66,26 @@ public:
Mesh(SettingsBaseVirtual* parent); //!< initializes the settings
void addFace(Point3& v0, Point3& v1, Point3& v2); //!< add a face to the mesh without settings it's connected_faces.
virtual ~Mesh() {} //!< Destructor
/*!
* add a face to the mesh without settings it's connected_faces.
*
* Don't add a face when the surface is zero mm^2
*
* \return whether a face has been added
*/
bool addFace(Point3& v0, Point3& v1, Point3& v2);
/*!
* add a face to the mesh without settings it's connected_faces.
*
* Don't add a face when the surface is zero mm^2
*
* \return whether a face has been added
*/
bool addFace(int vi0, int vi1, int vi2);
void addVertex(const Point3& v);
void clear(); //!< clears all data
void finish(); //!< complete the model : set the connected_face_index fields of the faces.
@@ -84,6 +104,13 @@ 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);
virtual float getColor(MatCoord bitmap_coord);
private:
int findIndexOfVertex(const Point3& v); //!< find index of vertex close to the given point, or create a new vertex and return its index.
/*!
-163
Ver Arquivo
@@ -1,163 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_H
#define SLICER_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 {
class SlicerSegment
{
public:
Point start, end;
int faceIndex;
bool addedToPolygon;
};
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;
unsigned int pointIdx;
};
class GapCloserResult
{
public:
int64_t len;
int polygonIdx;
unsigned int pointIdxA;
unsigned int pointIdxB;
bool AtoB;
};
class SlicerLayer
{
public:
std::vector<SlicerSegment> segmentList;
std::unordered_map<int, int> face_idx_to_segment_index; // topology
int z;
Polygons polygonList;
Polygons openPolylines;
void makePolygons(Mesh* mesh, bool keepNoneClosed, bool extensiveStitching);
private:
GapCloserResult findPolygonGapCloser(Point ip0, Point ip1)
{
GapCloserResult ret;
ClosePolygonResult c1 = findPolygonPointClosestTo(ip0);
ClosePolygonResult c2 = findPolygonPointClosestTo(ip1);
if (c1.polygonIdx < 0 || c1.polygonIdx != c2.polygonIdx)
{
ret.len = -1;
return ret;
}
ret.polygonIdx = c1.polygonIdx;
ret.pointIdxA = c1.pointIdx;
ret.pointIdxB = c2.pointIdx;
ret.AtoB = true;
if (ret.pointIdxA == ret.pointIdxB)
{
//Connection points are on the same line segment.
ret.len = vSize(ip0 - ip1);
}else{
//Find out if we have should go from A to B or the other way around.
Point p0 = polygonList[ret.polygonIdx][ret.pointIdxA];
int64_t lenA = vSize(p0 - ip0);
for(unsigned int i = ret.pointIdxA; i != ret.pointIdxB; i = (i + 1) % polygonList[ret.polygonIdx].size())
{
Point p1 = polygonList[ret.polygonIdx][i];
lenA += vSize(p0 - p1);
p0 = p1;
}
lenA += vSize(p0 - ip1);
p0 = polygonList[ret.polygonIdx][ret.pointIdxB];
int64_t lenB = vSize(p0 - ip1);
for(unsigned int i = ret.pointIdxB; i != ret.pointIdxA; i = (i + 1) % polygonList[ret.polygonIdx].size())
{
Point p1 = polygonList[ret.polygonIdx][i];
lenB += vSize(p0 - p1);
p0 = p1;
}
lenB += vSize(p0 - ip0);
if (lenA < lenB)
{
ret.AtoB = true;
ret.len = lenA;
}else{
ret.AtoB = false;
ret.len = lenB;
}
}
return ret;
}
ClosePolygonResult findPolygonPointClosestTo(Point input)
{
ClosePolygonResult ret;
for(unsigned int n=0; n<polygonList.size(); n++)
{
Point p0 = polygonList[n][polygonList[n].size()-1];
for(unsigned int i=0; i<polygonList[n].size(); i++)
{
Point p1 = polygonList[n][i];
//Q = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B ));
Point pDiff = p1 - p0;
int64_t lineLength = vSize(pDiff);
if (lineLength > 1)
{
int64_t distOnLine = dot(pDiff, input - p0) / lineLength;
if (distOnLine >= 0 && distOnLine <= lineLength)
{
Point q = p0 + pDiff * distOnLine / lineLength;
if (shorterThen(q - input, 100))
{
ret.intersectionPoint = q;
ret.polygonIdx = n;
ret.pointIdx = i;
return ret;
}
}
}
p0 = p1;
}
}
ret.polygonIdx = -1;
return ret;
}
};
class Slicer
{
public:
std::vector<SlicerLayer> layers;
Slicer(Mesh* mesh, int initial, int thickness, int layer_count, bool keepNoneClosed, bool extensiveStitching);
SlicerSegment project2D(Point3& p0, Point3& p1, Point3& p2, int32_t z) const
{
SlicerSegment seg;
seg.start.X = p0.x + int64_t(p1.x - p0.x) * int64_t(z - p0.z) / int64_t(p1.z - p0.z);
seg.start.Y = p0.y + int64_t(p1.y - p0.y) * int64_t(z - p0.z) / int64_t(p1.z - p0.z);
seg.end.X = p0.x + int64_t(p2.x - p0.x) * int64_t(z - p0.z) / int64_t(p2.z - p0.z);
seg.end.Y = p0.y + int64_t(p2.y - p0.y) * int64_t(z - p0.z) / int64_t(p2.z - p0.z);
return seg;
}
void dumpSegmentsToHTML(const char* filename);
};
}//namespace cura
#endif//SLICER_H
+21
Ver Arquivo
@@ -0,0 +1,21 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_CLOSE_POLYGON_RESULT_H
#define SLICER_CLOSE_POLYGON_RESULT_H
#include "../utils/intpoint.h"
namespace cura
{
class ClosePolygonResult
{ //The result of trying to find a point on a closed polygon line. This gives back the point index, the polygon index, and the point of the connection.
//The line on which the point lays is between pointIdx-1 and pointIdx
public:
Point intersectionPoint;
int polygonIdx;
unsigned int pointIdx;
};
} // namespace cura
#endif // SLICER_CLOSE_POLYGON_RESULT_H
+22
Ver Arquivo
@@ -0,0 +1,22 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_GAP_CLOSER_RESULT_H
#define SLICER_GAP_CLOSER_RESULT_H
#include "../utils/intpoint.h"
namespace cura
{
class GapCloserResult
{
public:
int64_t len;
int polygonIdx;
unsigned int pointIdxA;
unsigned int pointIdxB;
bool AtoB;
};
} // namespace cura
#endif // SLICER_GAP_CLOSER_RESULT_H
+4 -4
Ver Arquivo
@@ -1,10 +1,10 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "layerPart.h"
#include "settings.h"
#include "Progress.h"
#include "LayerPart.h"
#include "../settings.h"
#include "../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.
+6 -6
Ver Arquivo
@@ -1,10 +1,10 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef LAYERPART_H
#define LAYERPART_H
#ifndef SLICER_LAYERPART_H
#define SLICER_LAYERPART_H
#include "sliceDataStorage.h"
#include "slicer.h"
#include "commandSocket.h"
#include "../sliceDataStorage.h"
#include "Slicer.h"
#include "../commandSocket.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
@@ -28,4 +28,4 @@ void layerparts2HTML(SliceDataStorage& storage, const char* filename, bool all_l
}//namespace cura
#endif//LAYERPART_H
#endif//SLICER_LAYERPART_H
@@ -1,4 +1,4 @@
#include "multiVolumes.h"
#include "MultiVolumes.h"
namespace cura
{
@@ -1,8 +1,8 @@
#ifndef MULTIVOLUMES_H
#define MULTIVOLUMES_H
#ifndef SLICER_MULTIVOLUMES_H
#define SLICER_MULTIVOLUMES_H
#include "sliceDataStorage.h"
#include "slicer.h"
#include "../sliceDataStorage.h"
#include "Slicer.h"
/* This file contains code to help fixing up and changing layers that are build from multiple volumes. */
namespace cura {
@@ -17,4 +17,4 @@ void generateMultipleVolumesOverlap(std::vector<Slicer*> &meshes, int overlap);
}//namespace cura
#endif//MULTIVOLUMES_H
#endif//SLICER_MULTIVOLUMES_H
+133
Ver Arquivo
@@ -0,0 +1,133 @@
/** 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, Point3 p[3], unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, int32_t layer_nr)
{
Point3& p0 = p[idx_shared];
Point3& p1 = p[idx_first];
Point3& p2 = p[idx_second];
SlicerSegment seg;
seg.start.X = p0.x + int64_t(p1.x - p0.x) * int64_t(z - p0.z) / int64_t(p1.z - p0.z);
seg.start.Y = p0.y + int64_t(p1.y - p0.y) * int64_t(z - p0.z) / int64_t(p1.z - p0.z);
seg.end.X = p0.x + int64_t(p2.x - p0.x) * int64_t(z - p0.z) / int64_t(p2.z - p0.z);
seg.end.Y = p0.y + int64_t(p2.y - p0.y) * int64_t(z - p0.z) / int64_t(p2.z - p0.z);
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 layer_count, bool keep_none_closed, bool extensive_stitching)
: mesh(mesh)
, layer_height_0(initial)
, layer_height(thickness)
{
assert(layer_count > 0);
layers.resize(layer_count);
for(int32_t layer_nr = 0; layer_nr < layer_count; layer_nr++)
{
layers[layer_nr].z = initial + thickness * layer_nr;
layers[layer_nr].layer_nr = layer_nr;
}
for (unsigned int face_idx = 0; face_idx < mesh->faces.size(); face_idx++)
{
MeshFace& face = mesh->faces[face_idx];
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 z = 0;
for (int32_t layer_nr = (minZ - initial + thickness - 1) / thickness; z <= maxZ; layer_nr++) // + thickness - 1 to get the first layer above or at minZ
{
SlicerSegment s;
z = layer_nr * layer_height + layer_height_0;
if (layer_nr < 0)
{
continue;
}
// below code checks the position of the points w.r.t. the layer z
// also the direction of the resulting sliced line is determined
// p0 is odd one out
if (p0.z < z && p1.z >= z && p2.z >= z)
{
s = project2D(face_idx, p, 0, 2, 1, z, layer_nr);
}
else if (p0.z > z && p1.z < z && p2.z < z)
{
s = project2D(face_idx, p, 0, 1, 2, z, layer_nr);
}
// p1 is odd one out
else if (p1.z < z && p0.z >= z && p2.z >= z)
{
s = project2D(face_idx, p, 1, 0, 2, z, layer_nr);
}
else if (p1.z > z && p0.z < z && p2.z < z)
{
s = project2D(face_idx, p, 1, 2, 0, z, layer_nr);
}
// p2 is odd one out
else if (p2.z < z && p1.z >= z && p0.z >= z)
{
s = project2D(face_idx, p, 2, 1, 0, z, layer_nr);
}
else if (p2.z > z && p1.z < z && p0.z < z)
{
s = project2D(face_idx, p, 2, 0, 1, z, layer_nr);
}
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_index.insert(std::make_pair(face_idx, layers[layer_nr].segmentList.size()));
s.faceIndex = face_idx;
s.addedToPolygon = false;
layers[layer_nr].segmentList.push_back(s);
}
}
for (unsigned int layer_nr = 0; layer_nr < layers.size(); layer_nr++)
{
layers[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
}
}
}//namespace cura
+47
Ver Arquivo
@@ -0,0 +1,47 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_H
#define SLICER_SLICER_H
#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;
Slicer(Mesh* mesh, int initial, int thickness, int layer_count, bool keepNoneClosed, bool extensiveStitching);
void dumpSegmentsToHTML(const char* filename);
protected:
Mesh* mesh;
int layer_height_0;
int layer_height;
/*!
* Create a SlicerSegment along the lines going through p0p1 (Start) and p0p2 (End)
*
* \warning \p p0 may not have the same z as either \p p1 or \p p2
*
* \param p The face vertice locations in the order the vertices are given in the face
*/
SlicerSegment project2D(unsigned int face_idx, Point3 p[3], unsigned int idx_shared, unsigned int idx_first, unsigned int idx_second, int32_t z, int32_t layer_nr);
};
}//namespace cura
#endif//SLICER_SLICER_H
+88 -62
Ver Arquivo
@@ -1,13 +1,64 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "SlicerLayer.h"
#include "../TextureProcessor.h"
#include "slicer.h"
#include "debug.h" // TODO remove
namespace cura
{
GapCloserResult SlicerLayer::findPolygonGapCloser(Point ip0, Point ip1)
{
GapCloserResult ret;
ClosePolygonResult c1 = findPolygonPointClosestTo(ip0);
ClosePolygonResult c2 = findPolygonPointClosestTo(ip1);
if (c1.polygonIdx < 0 || c1.polygonIdx != c2.polygonIdx)
{
ret.len = -1;
return ret;
}
ret.polygonIdx = c1.polygonIdx;
ret.pointIdxA = c1.pointIdx;
ret.pointIdxB = c2.pointIdx;
ret.AtoB = true;
if (ret.pointIdxA == ret.pointIdxB)
{
//Connection points are on the same line segment.
ret.len = vSize(ip0 - ip1);
}else{
//Find out if we have should go from A to B or the other way around.
Point p0 = polygonList[ret.polygonIdx][ret.pointIdxA];
int64_t lenA = vSize(p0 - ip0);
for(unsigned int i = ret.pointIdxA; i != ret.pointIdxB; i = (i + 1) % polygonList[ret.polygonIdx].size())
{
Point p1 = polygonList[ret.polygonIdx][i];
lenA += vSize(p0 - p1);
p0 = p1;
}
lenA += vSize(p0 - ip1);
p0 = polygonList[ret.polygonIdx][ret.pointIdxB];
int64_t lenB = vSize(p0 - ip1);
for(unsigned int i = ret.pointIdxB; i != ret.pointIdxA; i = (i + 1) % polygonList[ret.polygonIdx].size())
{
Point p1 = polygonList[ret.polygonIdx][i];
lenB += vSize(p0 - p1);
p0 = p1;
}
lenB += vSize(p0 - ip0);
if (lenA < lenB)
{
ret.AtoB = true;
ret.len = lenA;
}else{
ret.AtoB = false;
ret.len = lenB;
}
}
return ret;
}
namespace cura {
void SlicerLayer::makePolygons(Mesh* mesh, bool keep_none_closed, bool extensive_stitching)
{
@@ -304,6 +355,9 @@ void SlicerLayer::makePolygons(Mesh* mesh, bool keep_none_closed, bool extensive
}
}
// TextureProcessor::processBumpMap(mesh, *this);
TextureProcessor::processDualColorTexture(mesh, *this);
//Finally optimize all the polygons. Every point removed saves time in the long run.
polygonList.simplify();
@@ -316,68 +370,40 @@ void SlicerLayer::makePolygons(Mesh* mesh, bool keep_none_closed, bool extensive
}
}
Slicer::Slicer(Mesh* mesh, int initial, int thickness, int layer_count, bool keep_none_closed, bool extensive_stitching)
ClosePolygonResult SlicerLayer::findPolygonPointClosestTo(Point input)
{
assert(layer_count > 0);
layers.resize(layer_count);
for(int32_t layer_nr = 0; layer_nr < layer_count; layer_nr++)
ClosePolygonResult ret;
for(unsigned int n=0; n<polygonList.size(); n++)
{
layers[layer_nr].z = initial + thickness * layer_nr;
}
for(unsigned int mesh_idx = 0; mesh_idx < mesh->faces.size(); mesh_idx++)
{
MeshFace& face = mesh->faces[mesh_idx];
Point3 p0 = mesh->vertices[face.vertex_index[0]].p;
Point3 p1 = mesh->vertices[face.vertex_index[1]].p;
Point3 p2 = mesh->vertices[face.vertex_index[2]].p;
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++)
Point p0 = polygonList[n][polygonList[n].size()-1];
for(unsigned int i=0; i<polygonList[n].size(); i++)
{
int32_t z = layer_nr * thickness + initial;
if (z < minZ) continue;
if (layer_nr < 0) continue;
Point p1 = polygonList[n][i];
SlicerSegment s;
if (p0.z < z && p1.z >= z && p2.z >= z)
s = project2D(p0, p2, p1, z);
else if (p0.z > z && p1.z < z && p2.z < z)
s = project2D(p0, p1, p2, z);
else if (p1.z < z && p0.z >= z && p2.z >= z)
s = project2D(p1, p0, p2, z);
else if (p1.z > z && p0.z < z && p2.z < z)
s = project2D(p1, p2, p0, z);
else if (p2.z < z && p1.z >= z && p0.z >= z)
s = project2D(p2, p1, p0, z);
else if (p2.z > z && p1.z < z && p0.z < z)
s = project2D(p2, p0, p1, z);
else
//Q = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B ));
Point pDiff = p1 - p0;
int64_t lineLength = vSize(pDiff);
if (lineLength > 1)
{
//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;
int64_t distOnLine = dot(pDiff, input - p0) / lineLength;
if (distOnLine >= 0 && distOnLine <= lineLength)
{
Point q = p0 + pDiff * distOnLine / lineLength;
if (shorterThen(q - input, 100))
{
ret.intersectionPoint = q;
ret.polygonIdx = n;
ret.pointIdx = i;
return ret;
}
}
}
layers[layer_nr].face_idx_to_segment_index.insert(std::make_pair(mesh_idx, layers[layer_nr].segmentList.size()));
s.faceIndex = mesh_idx;
s.addedToPolygon = false;
layers[layer_nr].segmentList.push_back(s);
p0 = p1;
}
}
for(unsigned int layer_nr=0; layer_nr<layers.size(); layer_nr++)
{
layers[layer_nr].makePolygons(mesh, keep_none_closed, extensive_stitching);
}
ret.polygonIdx = -1;
return ret;
}
}//namespace cura
} // namespace cura
+45
Ver Arquivo
@@ -0,0 +1,45 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef SLICER_SLICER_LAYER_H
#define SLICER_SLICER_LAYER_H
#include <unordered_map>
#include "../mesh.h"
#include "../utils/intpoint.h"
#include "../utils/polygon.h"
#include "SlicerSegment.h"
#include "GapCloserResult.h"
#include "ClosePolygonResult.h"
#include "../MatSegment.h"
namespace cura
{
class SlicerLayer
{
public:
std::vector<SlicerSegment> segmentList;
std::unordered_map<int, int> face_idx_to_segment_index; // topology
int z;
int layer_nr;
Polygons polygonList;
Polygons openPolylines;
std::unordered_map<SlicerSegment, MatSegment> segment_to_material_segment;
void makePolygons(Mesh* mesh, bool keepNoneClosed, bool extensiveStitching);
private:
GapCloserResult findPolygonGapCloser(Point ip0, Point ip1);
ClosePolygonResult findPolygonPointClosestTo(Point input);
};
} // namespace cura
#endif // SLICER_SLICER_LAYER_H
+52
Ver Arquivo
@@ -0,0 +1,52 @@
/** 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;
bool addedToPolygon;
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
+74
Ver Arquivo
@@ -0,0 +1,74 @@
/** Copyright (C) 2016 Tim Kuipers - Released under terms of the AGPLv3 License */
#ifndef UTILS_F_POINT_H
#define UTILS_F_POINT_H
#include <cmath> // sqrt
#include <iostream> // auto-serialization / auto-toString() '<<'
namespace cura
{
/*!
* 2D coordinates represented by floats
*/
class FPoint
{
public:
float x, y; //!< Coordinates
FPoint() //!< non-initializing constructor
{}
FPoint(float x, float y) //!< constructor
: x(x)
, y(y)
{}
FPoint operator+(const FPoint& p) const { return FPoint(x+p.x, y+p.y); }
FPoint operator-(const FPoint& p) const { return FPoint(x-p.x, y-p.y); }
FPoint operator/(const float i) const { return FPoint(x/i, y/i); }
FPoint operator*(const float i) const { return FPoint(x*i, y*i); }
FPoint& operator += (const FPoint& p) { x += p.x; y += p.y; return *this; }
FPoint& operator -= (const FPoint& p) { x -= p.x; y -= p.y; return *this; }
bool operator==(const FPoint& p) const { return x == p.x && y == p.y; }
bool operator!=(const FPoint& p) const { return x != p.x || y != p.y; }
/*!
* output to string stream in standard format
*/
template<class CharT, class TraitsT>
friend
std::basic_ostream<CharT, TraitsT>&
operator <<(std::basic_ostream<CharT, TraitsT>& os, const FPoint& p)
{
return os << "(" << p.x << ", " << p.y << ")";
}
/*!
* squared vector size
*/
float vSize2() const
{
return x * x + y * y;
}
/*!
* vector size
*/
float vSize() const
{
return sqrt(vSize2());
}
/*!
* dot product
*/
float dot(const FPoint& p) const
{
return x * p.x + y * p.y;
}
};
} // namespace cura
#endif // UTILS_F_POINT_H