mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-10 05:49:02 +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;
|
||||
$mesh->ReadFromPerl($vertices, $facets);
|
||||
$mesh->repair;
|
||||
$mesh->check_topology;
|
||||
|
||||
my $model = Slic3r::Model->new;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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
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.
|
||||
// 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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
%};
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user