mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-11 08:18:58 +08:00
New command for importing 2.5D/TIN meshes in plater
This commit is contained in:
parent
a7693c4719
commit
01cd85f7cf
@ -21,7 +21,7 @@ sub read_file {
|
|||||||
|
|
||||||
my $mesh = Slic3r::TriangleMesh->new;
|
my $mesh = Slic3r::TriangleMesh->new;
|
||||||
$mesh->ReadFromPerl($vertices, $facets);
|
$mesh->ReadFromPerl($vertices, $facets);
|
||||||
$mesh->repair;
|
$mesh->check_topology;
|
||||||
|
|
||||||
my $model = Slic3r::Model->new;
|
my $model = Slic3r::Model->new;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ sub read_file {
|
|||||||
|
|
||||||
my $mesh = Slic3r::TriangleMesh->new;
|
my $mesh = Slic3r::TriangleMesh->new;
|
||||||
$mesh->ReadSTLFile($path);
|
$mesh->ReadSTLFile($path);
|
||||||
$mesh->repair;
|
$mesh->check_topology;
|
||||||
|
|
||||||
die "This STL file couldn't be read because it's empty.\n"
|
die "This STL file couldn't be read because it's empty.\n"
|
||||||
if $mesh->facets_count == 0;
|
if $mesh->facets_count == 0;
|
||||||
|
@ -179,6 +179,13 @@ sub _init_menubar {
|
|||||||
# File menu
|
# File menu
|
||||||
my $fileMenu = Wx::Menu->new;
|
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->_append_menu_item($fileMenu, "&Load Config…\tCtrl+L", 'Load exported configuration file', sub {
|
||||||
$self->load_config_file;
|
$self->load_config_file;
|
||||||
}, undef, 'plugin_add.png');
|
}, undef, 'plugin_add.png');
|
||||||
|
@ -510,6 +510,36 @@ sub add {
|
|||||||
$self->load_file($_) for @input_files;
|
$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 {
|
sub load_file {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($input_file) = @_;
|
my ($input_file) = @_;
|
||||||
@ -555,6 +585,7 @@ sub load_model_objects {
|
|||||||
my @obj_idx = ();
|
my @obj_idx = ();
|
||||||
foreach my $model_object (@model_objects) {
|
foreach my $model_object (@model_objects) {
|
||||||
my $o = $self->{model}->add_object($model_object);
|
my $o = $self->{model}->add_object($model_object);
|
||||||
|
$o->repair;
|
||||||
|
|
||||||
push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(
|
push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(
|
||||||
name => basename($model_object->input_file),
|
name => basename($model_object->input_file),
|
||||||
|
@ -186,6 +186,7 @@ if (@ARGV) { # slicing from command line
|
|||||||
} else {
|
} else {
|
||||||
$model = Slic3r::Model->read_from_file($input_file);
|
$model = Slic3r::Model->read_from_file($input_file);
|
||||||
}
|
}
|
||||||
|
$model->repair;
|
||||||
|
|
||||||
if ($opt{info}) {
|
if ($opt{info}) {
|
||||||
$model->print_info;
|
$model->print_info;
|
||||||
|
@ -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) {
|
for (t_config_option_keys::const_iterator it = input_files.begin(); it != input_files.end(); ++it) {
|
||||||
TriangleMesh mesh;
|
TriangleMesh mesh;
|
||||||
Slic3r::IO::STL::read(*it, &mesh);
|
Slic3r::IO::STL::read(*it, &mesh);
|
||||||
calculate_normals(&mesh.stl);
|
mesh.extrude_tin(config.option("offset", true)->getFloat());
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
std::string outfile = config.option("output", true)->getString();
|
std::string outfile = config.option("output", true)->getString();
|
||||||
if (outfile.empty()) outfile = *it + "_extruded.stl";
|
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());
|
printf("Extruded mesh written to %s\n", outfile.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
var/map_add.png
Executable file
BIN
var/map_add.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 836 B |
@ -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.
|
// 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.
|
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
|
||||||
uint32_t *f = (uint32_t*)&facet;
|
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)
|
if (*f == 0x80000000)
|
||||||
// Negative zero, switch to positive zero.
|
// Negative zero, switch to positive zero.
|
||||||
*f = 0;
|
*f = 0;
|
||||||
|
@ -251,8 +251,8 @@ static void
|
|||||||
stl_rotate(float *x, float *y, const double c, const double s) {
|
stl_rotate(float *x, float *y, const double c, const double s) {
|
||||||
double xold = *x;
|
double xold = *x;
|
||||||
double yold = *y;
|
double yold = *y;
|
||||||
*x = float(c * xold - s * yold);
|
*x = c * xold - s * yold;
|
||||||
*y = float(s * xold + c * yold);
|
*y = s * xold + c * yold;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
@ -426,6 +427,55 @@ TriangleMesh::require_shared_vertices()
|
|||||||
if (this->stl.v_shared == NULL) stl_generate_shared_vertices(&(this->stl));
|
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
|
void
|
||||||
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
|
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,7 @@ class TriangleMesh
|
|||||||
void reset_repair_stats();
|
void reset_repair_stats();
|
||||||
bool needed_repair() const;
|
bool needed_repair() const;
|
||||||
size_t facets_count() const;
|
size_t facets_count() const;
|
||||||
|
void extrude_tin(float offset);
|
||||||
stl_file stl;
|
stl_file stl;
|
||||||
bool repaired;
|
bool repaired;
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
void duplicate_objects(unsigned int copies_num, double dist, BoundingBoxf* bb = NULL);
|
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 duplicate_objects_grid(unsigned int x, unsigned int y, double dist);
|
||||||
void print_info();
|
void print_info();
|
||||||
|
void repair();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -142,6 +143,8 @@ ModelMaterial::attributes()
|
|||||||
void clear_volumes();
|
void clear_volumes();
|
||||||
int volumes_count()
|
int volumes_count()
|
||||||
%code%{ RETVAL = THIS->volumes.size(); %};
|
%code%{ RETVAL = THIS->volumes.size(); %};
|
||||||
|
Ref<ModelVolume> get_volume(int idx)
|
||||||
|
%code%{ RETVAL = THIS->volumes.at(idx); %};
|
||||||
|
|
||||||
%name{_add_instance} Ref<ModelInstance> add_instance();
|
%name{_add_instance} Ref<ModelInstance> add_instance();
|
||||||
Ref<ModelInstance> _add_instance_clone(ModelInstance* other)
|
Ref<ModelInstance> _add_instance_clone(ModelInstance* other)
|
||||||
@ -198,6 +201,7 @@ ModelMaterial::attributes()
|
|||||||
%};
|
%};
|
||||||
|
|
||||||
void print_info();
|
void print_info();
|
||||||
|
void repair();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -225,6 +229,15 @@ ModelMaterial::attributes()
|
|||||||
%code%{ THIS->modifier = modifier; %};
|
%code%{ THIS->modifier = modifier; %};
|
||||||
|
|
||||||
ModelMaterial* assign_unique_material();
|
ModelMaterial* assign_unique_material();
|
||||||
|
|
||||||
|
void extrude_tin(float offset)
|
||||||
|
%code%{
|
||||||
|
try {
|
||||||
|
THIS->mesh.extrude_tin(offset);
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
croak("%s", e.what());
|
||||||
|
}
|
||||||
|
%};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user