New command for importing 2.5D/TIN meshes in plater

This commit is contained in:
Alessandro Ranellucci 2016-11-27 18:04:39 +01:00
parent a7693c4719
commit 01cd85f7cf
12 changed files with 111 additions and 54 deletions

View File

@ -21,7 +21,7 @@ sub read_file {
my $mesh = Slic3r::TriangleMesh->new;
$mesh->ReadFromPerl($vertices, $facets);
$mesh->repair;
$mesh->check_topology;
my $model = Slic3r::Model->new;

View File

@ -12,7 +12,7 @@ sub read_file {
my $mesh = Slic3r::TriangleMesh->new;
$mesh->ReadSTLFile($path);
$mesh->repair;
$mesh->check_topology;
die "This STL file couldn't be read because it's empty.\n"
if $mesh->facets_count == 0;

View File

@ -179,6 +179,13 @@ sub _init_menubar {
# File menu
my $fileMenu = Wx::Menu->new;
{
$self->_append_menu_item($fileMenu, "Open STL/OBJ/AMF…\tCtrl+O", 'Open a model', sub {
$self->{plater}->add if $self->{plater};
}, undef, 'brick_add.png');
$self->_append_menu_item($fileMenu, "Open 2.5D TIN mesh…", 'Import a 2.5D TIN mesh', sub {
$self->{plater}->add_tin if $self->{plater};
}, undef, 'map_add.png');
$fileMenu->AppendSeparator();
$self->_append_menu_item($fileMenu, "&Load Config…\tCtrl+L", 'Load exported configuration file', sub {
$self->load_config_file;
}, undef, 'plugin_add.png');

View File

@ -510,6 +510,36 @@ sub add {
$self->load_file($_) for @input_files;
}
sub add_tin {
my $self = shift;
my @input_files = wxTheApp->open_model($self);
return if !@input_files;
my $offset = Wx::GetNumberFromUser("", "Enter the minimum thickness in mm (i.e. the offset from the lowest point):", "2.5D TIN",
5, 0, 1000000, $self);
return if $offset < 0;
foreach my $input_file (@input_files) {
my $model = eval { Slic3r::Model->read_from_file($input_file) };
Slic3r::GUI::show_error($self, $@) if $@;
next if !$model;
if ($model->looks_like_multipart_object) {
Slic3r::GUI::show_error($self, "Multi-part models cannot be opened as 2.5D TIN files. Please load a single continuous mesh.");
next;
}
my $model_object = $model->get_object(0);
eval {
$model_object->get_volume(0)->extrude_tin($offset);
};
Slic3r::GUI::show_error($self, $@) if $@;
$self->load_model_objects($model_object);
}
}
sub load_file {
my $self = shift;
my ($input_file) = @_;
@ -555,6 +585,7 @@ sub load_model_objects {
my @obj_idx = ();
foreach my $model_object (@model_objects) {
my $o = $self->{model}->add_object($model_object);
$o->repair;
push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(
name => basename($model_object->input_file),

View File

@ -186,6 +186,7 @@ if (@ARGV) { # slicing from command line
} else {
$model = Slic3r::Model->read_from_file($input_file);
}
$model->repair;
if ($opt{info}) {
$model->print_info;

View File

@ -34,59 +34,12 @@ main(const int argc, const char **argv)
for (t_config_option_keys::const_iterator it = input_files.begin(); it != input_files.end(); ++it) {
TriangleMesh mesh;
Slic3r::IO::STL::read(*it, &mesh);
calculate_normals(&mesh.stl);
if (mesh.facets_count() == 0) {
printf("Error: file is empty: %s\n", it->c_str());
continue;
}
float z = mesh.stl.stats.min.z - config.option("offset", true)->getFloat();
printf("min.z = %f, z = %f\n", mesh.stl.stats.min.z, z);
TriangleMesh mesh2 = mesh;
for (int i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
const stl_facet &facet = mesh.stl.facet_start[i];
if (facet.normal.z < 0) {
printf("Invalid 2.5D mesh / TIN (one facet points downwards = %f)\n", facet.normal.z);
exit(1);
}
for (int j = 0; j < 3; ++j) {
if (mesh.stl.neighbors_start[i].neighbor[j] == -1) {
stl_facet new_facet;
float normal[3];
// first triangle
new_facet.vertex[0] = new_facet.vertex[2] = facet.vertex[(j+1)%3];
new_facet.vertex[1] = facet.vertex[j];
new_facet.vertex[2].z = z;
stl_calculate_normal(normal, &new_facet);
stl_normalize_vector(normal);
new_facet.normal.x = normal[0];
new_facet.normal.y = normal[1];
new_facet.normal.z = normal[2];
stl_add_facet(&mesh2.stl, &new_facet);
// second triangle
new_facet.vertex[0] = new_facet.vertex[1] = facet.vertex[j];
new_facet.vertex[2] = facet.vertex[(j+1)%3];
new_facet.vertex[1].z = new_facet.vertex[2].z = z;
new_facet.normal.x = normal[0];
new_facet.normal.y = normal[1];
new_facet.normal.z = normal[2];
stl_add_facet(&mesh2.stl, &new_facet);
}
}
}
mesh2.repair();
mesh.extrude_tin(config.option("offset", true)->getFloat());
std::string outfile = config.option("output", true)->getString();
if (outfile.empty()) outfile = *it + "_extruded.stl";
Slic3r::IO::STL::write(mesh2, outfile);
Slic3r::IO::STL::write(mesh, outfile);
printf("Extruded mesh written to %s\n", outfile.c_str());
}

BIN
var/map_add.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

View File

@ -321,7 +321,8 @@ stl_read(stl_file *stl, int first_facet, int first) {
// When using a memcmp on raw floats, those numbers report to be different.
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
uint32_t *f = (uint32_t*)&facet;
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
int j;
for (j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
if (*f == 0x80000000)
// Negative zero, switch to positive zero.
*f = 0;

View File

@ -251,8 +251,8 @@ static void
stl_rotate(float *x, float *y, const double c, const double s) {
double xold = *x;
double yold = *y;
*x = float(c * xold - s * yold);
*y = float(s * xold + c * yold);
*x = c * xold - s * yold;
*y = s * xold + c * yold;
}
extern void

View File

@ -11,6 +11,7 @@
#include <algorithm>
#include <math.h>
#include <assert.h>
#include <stdexcept>
#ifdef SLIC3R_DEBUG
#include "SVG.hpp"
@ -426,6 +427,55 @@ TriangleMesh::require_shared_vertices()
if (this->stl.v_shared == NULL) stl_generate_shared_vertices(&(this->stl));
}
void
TriangleMesh::extrude_tin(float offset)
{
calculate_normals(&this->stl);
const int number_of_facets = this->stl.stats.number_of_facets;
if (number_of_facets == 0)
throw std::runtime_error("Error: file is empty");
const float z = this->stl.stats.min.z - offset;
for (int i = 0; i < number_of_facets; ++i) {
const stl_facet &facet = this->stl.facet_start[i];
if (facet.normal.z < 0)
throw std::runtime_error("Invalid 2.5D mesh: at least one facet points downwards.");
for (int j = 0; j < 3; ++j) {
if (this->stl.neighbors_start[i].neighbor[j] == -1) {
stl_facet new_facet;
float normal[3];
// first triangle
new_facet.vertex[0] = new_facet.vertex[2] = facet.vertex[(j+1)%3];
new_facet.vertex[1] = facet.vertex[j];
new_facet.vertex[2].z = z;
stl_calculate_normal(normal, &new_facet);
stl_normalize_vector(normal);
new_facet.normal.x = normal[0];
new_facet.normal.y = normal[1];
new_facet.normal.z = normal[2];
stl_add_facet(&this->stl, &new_facet);
// second triangle
new_facet.vertex[0] = new_facet.vertex[1] = facet.vertex[j];
new_facet.vertex[2] = facet.vertex[(j+1)%3];
new_facet.vertex[1].z = new_facet.vertex[2].z = z;
new_facet.normal.x = normal[0];
new_facet.normal.y = normal[1];
new_facet.normal.z = normal[2];
stl_add_facet(&this->stl, &new_facet);
}
}
}
stl_get_size(&this->stl);
this->repair();
}
void
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
{

View File

@ -55,6 +55,7 @@ class TriangleMesh
void reset_repair_stats();
bool needed_repair() const;
size_t facets_count() const;
void extrude_tin(float offset);
stl_file stl;
bool repaired;

View File

@ -71,6 +71,7 @@
void duplicate_objects(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL);
void duplicate_objects_grid(unsigned int x, unsigned int y, double dist);
void print_info();
void repair();
};
@ -142,6 +143,8 @@ ModelMaterial::attributes()
void clear_volumes();
int volumes_count()
%code%{ RETVAL = THIS->volumes.size(); %};
Ref<ModelVolume> get_volume(int idx)
%code%{ RETVAL = THIS->volumes.at(idx); %};
%name{_add_instance} Ref<ModelInstance> add_instance();
Ref<ModelInstance> _add_instance_clone(ModelInstance* other)
@ -198,6 +201,7 @@ ModelMaterial::attributes()
%};
void print_info();
void repair();
};
@ -225,6 +229,15 @@ ModelMaterial::attributes()
%code%{ THIS->modifier = modifier; %};
ModelMaterial* assign_unique_material();
void extrude_tin(float offset)
%code%{
try {
THIS->mesh.extrude_tin(offset);
} catch (std::exception& e) {
croak("%s", e.what());
}
%};
};