Merge remote-tracking branch 'origin/dev2' into dev_native

This commit is contained in:
bubnikv 2018-09-20 16:48:40 +02:00
commit 20d0f046d2
34 changed files with 1300 additions and 694 deletions

View File

@ -150,12 +150,64 @@ sub new {
$self->rotate(rad2deg($angle), Z, 'absolute'); $self->rotate(rad2deg($angle), Z, 'absolute');
}; };
# callback to react to gizmo rotate
my $on_gizmo_rotate_3D = sub {
my ($angle_x, $angle_y, $angle_z) = @_;
my ($obj_idx, $object) = $self->selected_object;
return if !defined $obj_idx;
my $model_object = $self->{model}->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
$self->stop_background_process;
my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z);
foreach my $inst (@{ $model_object->instances }) {
$inst->set_rotations($rotation);
}
Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
# update print and start background processing
$self->{print}->add_model_object($model_object, $obj_idx);
$self->selection_changed; # refresh info (size etc.)
$self->update;
$self->schedule_background_process;
};
# callback to react to gizmo flatten # callback to react to gizmo flatten
my $on_gizmo_flatten = sub { my $on_gizmo_flatten = sub {
my ($angle, $axis_x, $axis_y, $axis_z) = @_; my ($angle, $axis_x, $axis_y, $axis_z) = @_;
$self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0; $self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0;
}; };
# callback to react to gizmo flatten
my $on_gizmo_flatten_3D = sub {
my ($angle_x, $angle_y, $angle_z) = @_;
my ($obj_idx, $object) = $self->selected_object;
return if !defined $obj_idx;
my $model_object = $self->{model}->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
$self->stop_background_process;
my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z);
foreach my $inst (@{ $model_object->instances }) {
$inst->set_rotations($rotation);
}
Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
# update print and start background processing
$self->{print}->add_model_object($model_object, $obj_idx);
$self->selection_changed; # refresh info (size etc.)
$self->update;
$self->schedule_background_process;
};
# callback to update object's geometry info while using gizmos # callback to update object's geometry info while using gizmos
my $on_update_geometry_info = sub { my $on_update_geometry_info = sub {
my ($size_x, $size_y, $size_z, $scale_factor) = @_; my ($size_x, $size_y, $size_z, $scale_factor) = @_;
@ -261,7 +313,9 @@ sub new {
Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons);
Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly);
Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate);
Slic3r::GUI::_3DScene::register_on_gizmo_rotate_3D_callback($self->{canvas3D}, $on_gizmo_rotate_3D);
Slic3r::GUI::_3DScene::register_on_gizmo_flatten_callback($self->{canvas3D}, $on_gizmo_flatten); Slic3r::GUI::_3DScene::register_on_gizmo_flatten_callback($self->{canvas3D}, $on_gizmo_flatten);
Slic3r::GUI::_3DScene::register_on_gizmo_flatten_3D_callback($self->{canvas3D}, $on_gizmo_flatten_3D);
Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info);
Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add); Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add);
Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete); Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete);

View File

@ -109,6 +109,7 @@ if ((!@ARGV || $opt{gui}) && !$opt{no_gui} && !$opt{save} && eval "require Slic3
$Slic3r::GUI::no_plater = $opt{no_plater}; $Slic3r::GUI::no_plater = $opt{no_plater};
$Slic3r::GUI::autosave = $opt{autosave}; $Slic3r::GUI::autosave = $opt{autosave};
} }
Slic3r::GUI::set_gui_appctl();
$gui = Slic3r::GUI->new; $gui = Slic3r::GUI->new;
#setlocale(LC_NUMERIC, 'C'); #setlocale(LC_NUMERIC, 'C');
$gui->{mainframe}->load_config_file($_) for @{$opt{load}}; $gui->{mainframe}->load_config_file($_) for @{$opt{load}};
@ -121,6 +122,9 @@ if ((!@ARGV || $opt{gui}) && !$opt{no_gui} && !$opt{save} && eval "require Slic3
die $@ if $@ && $opt{gui}; die $@ if $@ && $opt{gui};
if (@ARGV) { # slicing from command line if (@ARGV) { # slicing from command line
Slic3r::GUI::set_cli_appctl();
my $appctl = Slic3r::AppController->new();
$config->validate; $config->validate;
if ($opt{repair}) { if ($opt{repair}) {
@ -210,7 +214,10 @@ if (@ARGV) { # slicing from command line
$sprint->apply_config($config); $sprint->apply_config($config);
if ($opt{export_png}) { if ($opt{export_png}) {
$sprint->export_png; # $sprint->export_png;
$appctl->set_model($model);
$appctl->set_print($sprint->_print);
$appctl->print_ctl()->slice_to_png();
} else { } else {
my $t0 = [gettimeofday]; my $t0 = [gettimeofday];
# The following call may die if the output_filename_format template substitution fails, # The following call may die if the output_filename_format template substitution fails,

View File

@ -1284,6 +1284,9 @@ namespace Slic3r {
transform(1, 0) * inv_sx, transform(1, 1) * inv_sy, transform(1, 2) * inv_sz, transform(1, 0) * inv_sx, transform(1, 1) * inv_sy, transform(1, 2) * inv_sz,
transform(2, 0) * inv_sx, transform(2, 1) * inv_sy, transform(2, 2) * inv_sz; transform(2, 0) * inv_sx, transform(2, 1) * inv_sy, transform(2, 2) * inv_sz;
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d rotation = m3x3.eulerAngles(0, 1, 2);
#else
Eigen::AngleAxisd rotation; Eigen::AngleAxisd rotation;
rotation.fromRotationMatrix(m3x3); rotation.fromRotationMatrix(m3x3);
@ -1292,6 +1295,7 @@ namespace Slic3r {
return; return;
double angle_z = (rotation.axis() == Vec3d::UnitZ()) ? rotation.angle() : -rotation.angle(); double angle_z = (rotation.axis() == Vec3d::UnitZ()) ? rotation.angle() : -rotation.angle();
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
instance.set_offset(offset); instance.set_offset(offset);
@ -1300,7 +1304,11 @@ namespace Slic3r {
instance.offset(1) = offset_y; instance.offset(1) = offset_y;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
instance.scaling_factor = sx; instance.scaling_factor = sx;
#if ENABLE_MODELINSTANCE_3D_ROTATION
instance.set_rotation(rotation);
#else
instance.rotation = angle_z; instance.rotation = angle_z;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} }
bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes) bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes)

View File

@ -30,7 +30,12 @@
// 0 : .amf, .amf.xml and .zip.amf files saved by older slic3r. No version definition in them. // 0 : .amf, .amf.xml and .zip.amf files saved by older slic3r. No version definition in them.
// 1 : Introduction of amf versioning. No other change in data saved into amf files. // 1 : Introduction of amf versioning. No other change in data saved into amf files.
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
// 2 : Added z component of offset
// Added x and y components of rotation
#else
// 2 : Added z component of offset. // 2 : Added z component of offset.
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
const unsigned int VERSION_AMF = 2; const unsigned int VERSION_AMF = 2;
#else #else
const unsigned int VERSION_AMF = 1; const unsigned int VERSION_AMF = 1;
@ -127,6 +132,10 @@ struct AMFParserContext
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
NODE_TYPE_DELTAZ, // amf/constellation/instance/deltaz NODE_TYPE_DELTAZ, // amf/constellation/instance/deltaz
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
NODE_TYPE_RX, // amf/constellation/instance/rx
NODE_TYPE_RY, // amf/constellation/instance/ry
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
NODE_TYPE_RZ, // amf/constellation/instance/rz NODE_TYPE_RZ, // amf/constellation/instance/rz
NODE_TYPE_SCALE, // amf/constellation/instance/scale NODE_TYPE_SCALE, // amf/constellation/instance/scale
NODE_TYPE_METADATA, // anywhere under amf/*/metadata NODE_TYPE_METADATA, // anywhere under amf/*/metadata
@ -134,7 +143,11 @@ struct AMFParserContext
struct Instance { struct Instance {
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rx_set(false), ry_set(false), rz_set(false), scale_set(false) {}
#else
Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rz_set(false), scale_set(false) {} Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rz_set(false), scale_set(false) {}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
Instance() : deltax_set(false), deltay_set(false), rz_set(false), scale_set(false) {} Instance() : deltax_set(false), deltay_set(false), rz_set(false), scale_set(false) {}
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -149,6 +162,14 @@ struct AMFParserContext
float deltaz; float deltaz;
bool deltaz_set; bool deltaz_set;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Rotation around the X axis.
float rx;
bool rx_set;
// Rotation around the Y axis.
float ry;
bool ry_set;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
// Rotation around the Z axis. // Rotation around the Z axis.
float rz; float rz;
bool rz_set; bool rz_set;
@ -275,6 +296,12 @@ void AMFParserContext::startElement(const char *name, const char **atts)
else if (strcmp(name, "deltaz") == 0) else if (strcmp(name, "deltaz") == 0)
node_type_new = NODE_TYPE_DELTAZ; node_type_new = NODE_TYPE_DELTAZ;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
else if (strcmp(name, "rx") == 0)
node_type_new = NODE_TYPE_RX;
else if (strcmp(name, "ry") == 0)
node_type_new = NODE_TYPE_RY;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
else if (strcmp(name, "rz") == 0) else if (strcmp(name, "rz") == 0)
node_type_new = NODE_TYPE_RZ; node_type_new = NODE_TYPE_RZ;
else if (strcmp(name, "scale") == 0) else if (strcmp(name, "scale") == 0)
@ -339,6 +366,10 @@ void AMFParserContext::characters(const XML_Char *s, int len)
if (m_path.back() == NODE_TYPE_DELTAX || if (m_path.back() == NODE_TYPE_DELTAX ||
m_path.back() == NODE_TYPE_DELTAY || m_path.back() == NODE_TYPE_DELTAY ||
m_path.back() == NODE_TYPE_DELTAZ || m_path.back() == NODE_TYPE_DELTAZ ||
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_path.back() == NODE_TYPE_RX ||
m_path.back() == NODE_TYPE_RY ||
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_path.back() == NODE_TYPE_RZ || m_path.back() == NODE_TYPE_RZ ||
m_path.back() == NODE_TYPE_SCALE) m_path.back() == NODE_TYPE_SCALE)
#else #else
@ -391,6 +422,20 @@ void AMFParserContext::endElement(const char * /* name */)
m_value[0].clear(); m_value[0].clear();
break; break;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
case NODE_TYPE_RX:
assert(m_instance);
m_instance->rx = float(atof(m_value[0].c_str()));
m_instance->rx_set = true;
m_value[0].clear();
break;
case NODE_TYPE_RY:
assert(m_instance);
m_instance->ry = float(atof(m_value[0].c_str()));
m_instance->ry_set = true;
m_value[0].clear();
break;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
case NODE_TYPE_RZ: case NODE_TYPE_RZ:
assert(m_instance); assert(m_instance);
m_instance->rz = float(atof(m_value[0].c_str())); m_instance->rz = float(atof(m_value[0].c_str()));
@ -542,12 +587,16 @@ void AMFParserContext::endDocument()
if (instance.deltax_set && instance.deltay_set) { if (instance.deltax_set && instance.deltay_set) {
ModelInstance *mi = m_model.objects[object.second.idx]->add_instance(); ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
mi->set_offset(Vec3d((double)instance.deltax, (double)instance.deltay, (double)instance.deltaz)); mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
#else #else
mi->offset(0) = instance.deltax; mi->offset(0) = instance.deltax;
mi->offset(1) = instance.deltay; mi->offset(1) = instance.deltay;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
#else
mi->rotation = instance.rz_set ? instance.rz : 0.f; mi->rotation = instance.rz_set ? instance.rz : 0.f;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
mi->scaling_factor = instance.scale_set ? instance.scale : 1.f; mi->scaling_factor = instance.scale_set ? instance.scale : 1.f;
} }
} }
@ -851,6 +900,10 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
" <deltaz>%lf</deltaz>\n" " <deltaz>%lf</deltaz>\n"
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
" <rx>%lf</rx>\n"
" <ry>%lf</ry>\n"
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
" <rz>%lf</rz>\n" " <rz>%lf</rz>\n"
" <scale>%lf</scale>\n" " <scale>%lf</scale>\n"
" </instance>\n", " </instance>\n",
@ -863,8 +916,15 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
instance->offset(0), instance->offset(0),
instance->offset(1), instance->offset(1),
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
instance->get_rotation(X),
instance->get_rotation(Y),
instance->get_rotation(Z),
#else
instance->rotation, instance->rotation,
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
instance->scaling_factor); instance->scaling_factor);
//FIXME missing instance->scaling_factor //FIXME missing instance->scaling_factor
instances.append(buf); instances.append(buf);
} }

View File

@ -164,7 +164,11 @@ bool load_prus(const char *path, Model *model)
const char *zero_tag = "<zero>"; const char *zero_tag = "<zero>";
const char *zero_xml = strstr(scene_xml_data.data(), zero_tag); const char *zero_xml = strstr(scene_xml_data.data(), zero_tag);
float trafo[3][4] = { 0 }; float trafo[3][4] = { 0 };
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d instance_rotation = Vec3d::Zero();
#else
double instance_rotation = 0.; double instance_rotation = 0.;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
double instance_scaling_factor = 1.f; double instance_scaling_factor = 1.f;
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
Vec3d instance_offset = Vec3d::Zero(); Vec3d instance_offset = Vec3d::Zero();
@ -197,10 +201,14 @@ bool load_prus(const char *path, Model *model)
instance_scaling_factor = scale[0]; instance_scaling_factor = scale[0];
scale[0] = scale[1] = scale[2] = 1.; scale[0] = scale[1] = scale[2] = 1.;
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]);
#else
if (rotation[0] == 0. && rotation[1] == 0.) { if (rotation[0] == 0. && rotation[1] == 0.) {
instance_rotation = - rotation[2]; instance_rotation = - rotation[2];
rotation[2] = 0.; rotation[2] = 0.;
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
Eigen::Matrix3f mat_rot, mat_scale, mat_trafo; Eigen::Matrix3f mat_rot, mat_scale, mat_trafo;
mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) * mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) *
Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) * Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) *
@ -366,7 +374,11 @@ bool load_prus(const char *path, Model *model)
model_object = model->add_object(name_utf8.data(), path, std::move(mesh)); model_object = model->add_object(name_utf8.data(), path, std::move(mesh));
volume = model_object->volumes.front(); volume = model_object->volumes.front();
ModelInstance *instance = model_object->add_instance(); ModelInstance *instance = model_object->add_instance();
#if ENABLE_MODELINSTANCE_3D_ROTATION
instance->set_rotation(instance_rotation);
#else
instance->rotation = instance_rotation; instance->rotation = instance_rotation;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
instance->scaling_factor = instance_scaling_factor; instance->scaling_factor = instance_scaling_factor;
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
instance->set_offset(instance_offset); instance->set_offset(instance_offset);

View File

@ -1066,6 +1066,29 @@ size_t ModelVolume::split(unsigned int max_extruders)
return idx; return idx;
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
void ModelInstance::set_rotation(const Vec3d& rotation)
{
set_rotation(X, rotation(0));
set_rotation(Y, rotation(1));
set_rotation(Z, rotation(2));
}
void ModelInstance::set_rotation(Axis axis, double rotation)
{
static const double TWO_PI = 2.0 * (double)PI;
while (rotation < 0.0)
{
rotation += TWO_PI;
}
while (TWO_PI < rotation)
{
rotation -= TWO_PI;
}
m_rotation(axis) = rotation;
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
{ {
mesh->transform(world_matrix(dont_translate).cast<float>()); mesh->transform(world_matrix(dont_translate).cast<float>());
@ -1110,7 +1133,12 @@ Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const
void ModelInstance::transform_polygon(Polygon* polygon) const void ModelInstance::transform_polygon(Polygon* polygon) const
{ {
#if ENABLE_MODELINSTANCE_3D_ROTATION
// CHECK_ME -> Is the following correct or it should take in account all three rotations ?
polygon->rotate(this->m_rotation(2)); // rotate around polygon origin
#else
polygon->rotate(this->rotation); // rotate around polygon origin polygon->rotate(this->rotation); // rotate around polygon origin
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
polygon->scale(this->scaling_factor); // scale around polygon origin polygon->scale(this->scaling_factor); // scale around polygon origin
} }
@ -1126,7 +1154,15 @@ Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, b
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
if (!dont_rotate) if (!dont_rotate)
#if ENABLE_MODELINSTANCE_3D_ROTATION
{
m.rotate(Eigen::AngleAxisd(m_rotation(2), Vec3d::UnitZ()));
m.rotate(Eigen::AngleAxisd(m_rotation(1), Vec3d::UnitY()));
m.rotate(Eigen::AngleAxisd(m_rotation(0), Vec3d::UnitX()));
}
#else
m.rotate(Eigen::AngleAxisd(rotation, Vec3d::UnitZ())); m.rotate(Eigen::AngleAxisd(rotation, Vec3d::UnitZ()));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
if (!dont_scale) if (!dont_scale)
m.scale(scaling_factor); m.scale(scaling_factor);

View File

@ -248,11 +248,16 @@ public:
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
private: private:
Vec3d m_offset; // in unscaled coordinates Vec3d m_offset; // in unscaled coordinates
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
public: public:
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if !ENABLE_MODELINSTANCE_3D_ROTATION
double rotation; // Rotation around the Z axis, in radians around mesh center point double rotation; // Rotation around the Z axis, in radians around mesh center point
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
double scaling_factor; double scaling_factor;
#if !ENABLE_MODELINSTANCE_3D_OFFSET #if !ENABLE_MODELINSTANCE_3D_OFFSET
Vec2d offset; // in unscaled coordinates Vec2d offset; // in unscaled coordinates
@ -271,6 +276,14 @@ public:
void set_offset(Axis axis, double offset) { m_offset(axis) = offset; } void set_offset(Axis axis, double offset) { m_offset(axis) = offset; }
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& get_rotation() const { return m_rotation; }
double get_rotation(Axis axis) const { return m_rotation(axis); }
void set_rotation(const Vec3d& rotation);
void set_rotation(Axis axis, double rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
// To be called on an external mesh // To be called on an external mesh
void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const; void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const;
// Calculate a bounding box of a transformed mesh. To be called on an external mesh. // Calculate a bounding box of a transformed mesh. To be called on an external mesh.
@ -291,9 +304,15 @@ private:
ModelObject* object; ModelObject* object;
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
ModelInstance(ModelObject *object) : m_rotation(Vec3d::Zero()), scaling_factor(1), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {}
ModelInstance(ModelObject *object, const ModelInstance &other) :
m_rotation(other.m_rotation), scaling_factor(other.scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {}
#else
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {}
ModelInstance(ModelObject *object, const ModelInstance &other) : ModelInstance(ModelObject *object, const ModelInstance &other) :
rotation(other.rotation), scaling_factor(other.scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {} rotation(other.rotation), scaling_factor(other.scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), offset(Vec2d::Zero()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), offset(Vec2d::Zero()), object(object), print_volume_state(PVS_Inside) {}
ModelInstance(ModelObject *object, const ModelInstance &other) : ModelInstance(ModelObject *object, const ModelInstance &other) :

View File

@ -292,59 +292,59 @@ protected:
using Distance = TCoord<PointImpl>; using Distance = TCoord<PointImpl>;
using Pile = sl::Shapes<PolygonImpl>; using Pile = sl::Shapes<PolygonImpl>;
Packer pck_; Packer m_pck;
PConfig pconf_; // Placement configuration PConfig m_pconf; // Placement configuration
double bin_area_; double m_bin_area;
SpatIndex rtree_; SpatIndex m_rtree;
SpatIndex smallsrtree_; SpatIndex m_smallsrtree;
double norm_; double m_norm;
Pile merged_pile_; Pile m_merged_pile;
Box pilebb_; Box m_pilebb;
ItemGroup remaining_; ItemGroup m_remaining;
ItemGroup items_; ItemGroup m_items;
public: public:
_ArrBase(const TBin& bin, Distance dist, _ArrBase(const TBin& bin, Distance dist,
std::function<void(unsigned)> progressind, std::function<void(unsigned)> progressind,
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
pck_(bin, dist), bin_area_(sl::area(bin)), m_pck(bin, dist), m_bin_area(sl::area(bin)),
norm_(std::sqrt(sl::area(bin))) m_norm(std::sqrt(sl::area(bin)))
{ {
fillConfig(pconf_); fillConfig(m_pconf);
pconf_.before_packing = m_pconf.before_packing =
[this](const Pile& merged_pile, // merged pile [this](const Pile& merged_pile, // merged pile
const ItemGroup& items, // packed items const ItemGroup& items, // packed items
const ItemGroup& remaining) // future items to be packed const ItemGroup& remaining) // future items to be packed
{ {
items_ = items; m_items = items;
merged_pile_ = merged_pile; m_merged_pile = merged_pile;
remaining_ = remaining; m_remaining = remaining;
pilebb_ = sl::boundingBox(merged_pile); m_pilebb = sl::boundingBox(merged_pile);
rtree_.clear(); m_rtree.clear();
smallsrtree_.clear(); m_smallsrtree.clear();
// We will treat big items (compared to the print bed) differently // We will treat big items (compared to the print bed) differently
auto isBig = [this](double a) { auto isBig = [this](double a) {
return a/bin_area_ > BIG_ITEM_TRESHOLD ; return a/m_bin_area > BIG_ITEM_TRESHOLD ;
}; };
for(unsigned idx = 0; idx < items.size(); ++idx) { for(unsigned idx = 0; idx < items.size(); ++idx) {
Item& itm = items[idx]; Item& itm = items[idx];
if(isBig(itm.area())) rtree_.insert({itm.boundingBox(), idx}); if(isBig(itm.area())) m_rtree.insert({itm.boundingBox(), idx});
smallsrtree_.insert({itm.boundingBox(), idx}); m_smallsrtree.insert({itm.boundingBox(), idx});
} }
}; };
pck_.progressIndicator(progressind); m_pck.progressIndicator(progressind);
pck_.stopCondition(stopcond); m_pck.stopCondition(stopcond);
} }
template<class...Args> inline IndexedPackGroup operator()(Args&&...args) { template<class...Args> inline IndexedPackGroup operator()(Args&&...args) {
rtree_.clear(); m_rtree.clear();
return pck_.executeIndexed(std::forward<Args>(args)...); return m_pck.executeIndexed(std::forward<Args>(args)...);
} }
}; };
@ -358,18 +358,18 @@ public:
_ArrBase<Box>(bin, dist, progressind, stopcond) _ArrBase<Box>(bin, dist, progressind, stopcond)
{ {
pconf_.object_function = [this, bin] (const Item &item) { m_pconf.object_function = [this, bin] (const Item &item) {
auto result = objfunc(bin.center(), auto result = objfunc(bin.center(),
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
bin_area_, m_bin_area,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
double score = std::get<0>(result); double score = std::get<0>(result);
auto& fullbb = std::get<1>(result); auto& fullbb = std::get<1>(result);
@ -381,7 +381,7 @@ public:
return score; return score;
}; };
pck_.configure(pconf_); m_pck.configure(m_pconf);
} }
}; };
@ -396,27 +396,27 @@ public:
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
_ArrBase<lnCircle>(bin, dist, progressind, stopcond) { _ArrBase<lnCircle>(bin, dist, progressind, stopcond) {
pconf_.object_function = [this, &bin] (const Item &item) { m_pconf.object_function = [this, &bin] (const Item &item) {
auto result = objfunc(bin.center(), auto result = objfunc(bin.center(),
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
bin_area_, m_bin_area,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
double score = std::get<0>(result); double score = std::get<0>(result);
auto isBig = [this](const Item& itm) { auto isBig = [this](const Item& itm) {
return itm.area()/bin_area_ > BIG_ITEM_TRESHOLD ; return itm.area()/m_bin_area > BIG_ITEM_TRESHOLD ;
}; };
if(isBig(item)) { if(isBig(item)) {
auto mp = merged_pile_; auto mp = m_merged_pile;
mp.push_back(item.transformedShape()); mp.push_back(item.transformedShape());
auto chull = sl::convexHull(mp); auto chull = sl::convexHull(mp);
double miss = Placer::overfit(chull, bin); double miss = Placer::overfit(chull, bin);
@ -427,7 +427,7 @@ public:
return score; return score;
}; };
pck_.configure(pconf_); m_pck.configure(m_pconf);
} }
}; };
@ -439,25 +439,25 @@ public:
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
_ArrBase<PolygonImpl>(bin, dist, progressind, stopcond) _ArrBase<PolygonImpl>(bin, dist, progressind, stopcond)
{ {
pconf_.object_function = [this, &bin] (const Item &item) { m_pconf.object_function = [this, &bin] (const Item &item) {
auto binbb = sl::boundingBox(bin); auto binbb = sl::boundingBox(bin);
auto result = objfunc(binbb.center(), auto result = objfunc(binbb.center(),
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
bin_area_, m_bin_area,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
double score = std::get<0>(result); double score = std::get<0>(result);
return score; return score;
}; };
pck_.configure(pconf_); m_pck.configure(m_pconf);
} }
}; };
@ -469,22 +469,22 @@ public:
std::function<bool(void)> stopcond): std::function<bool(void)> stopcond):
_ArrBase<Box>(Box(0, 0), dist, progressind, stopcond) _ArrBase<Box>(Box(0, 0), dist, progressind, stopcond)
{ {
this->pconf_.object_function = [this] (const Item &item) { this->m_pconf.object_function = [this] (const Item &item) {
auto result = objfunc({0, 0}, auto result = objfunc({0, 0},
merged_pile_, m_merged_pile,
pilebb_, m_pilebb,
items_, m_items,
item, item,
0, 0,
norm_, m_norm,
rtree_, m_rtree,
smallsrtree_, m_smallsrtree,
remaining_); m_remaining);
return std::get<0>(result); return std::get<0>(result);
}; };
this->pck_.configure(pconf_); this->m_pck.configure(m_pconf);
} }
}; };
@ -527,7 +527,12 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) {
// Invalid geometries would throw exceptions when arranging // Invalid geometries would throw exceptions when arranging
if(item.vertexCount() > 3) { if(item.vertexCount() > 3) {
#if ENABLE_MODELINSTANCE_3D_ROTATION
// CHECK_ME -> is the following correct or it should take in account all three rotations ?
item.rotation(objinst->get_rotation(Z));
#else
item.rotation(objinst->rotation); item.rotation(objinst->rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
item.translation({ item.translation({
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR),
@ -668,18 +673,25 @@ void applyResult(
// Get the model instance from the shapemap using the index // Get the model instance from the shapemap using the index
ModelInstance *inst_ptr = shapemap[idx].first; ModelInstance *inst_ptr = shapemap[idx].first;
// Get the tranformation data from the item object and scale it // Get the transformation data from the item object and scale it
// appropriately // appropriately
auto off = item.translation(); auto off = item.translation();
Radians rot = item.rotation(); Radians rot = item.rotation();
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
Vec3d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR, 0.0); Vec3d foff(off.X*SCALING_FACTOR + batch_offset,
off.Y*SCALING_FACTOR,
0.0);
#else #else
Vec2d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR); Vec2d foff(off.X*SCALING_FACTOR + batch_offset, off.Y*SCALING_FACTOR);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
// write the tranformation data into the model instance // write the transformation data into the model instance
#if ENABLE_MODELINSTANCE_3D_ROTATION
// CHECK_ME -> Is the following correct ?
inst_ptr->set_rotation(Vec3d(0.0, 0.0, rot));
#else
inst_ptr->rotation = rot; inst_ptr->rotation = rot;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
inst_ptr->set_offset(foff); inst_ptr->set_offset(foff);
#else #else
@ -695,7 +707,7 @@ void applyResult(
* The arrangement considers multiple bins (aka. print beds) for placing all * The arrangement considers multiple bins (aka. print beds) for placing all
* the items provided in the model argument. If the items don't fit on one * the items provided in the model argument. If the items don't fit on one
* print bed, the remaining will be placed onto newly created print beds. * print bed, the remaining will be placed onto newly created print beds.
* The first_bin_only parameter, if set to true, disables this behaviour and * The first_bin_only parameter, if set to true, disables this behavior and
* makes sure that only one print bed is filled and the remaining items will be * makes sure that only one print bed is filled and the remaining items will be
* untouched. When set to false, the items which could not fit onto the * untouched. When set to false, the items which could not fit onto the
* print bed will be placed next to the print bed so the user should see a * print bed will be placed next to the print bed so the user should see a
@ -741,6 +753,7 @@ bool arrange(Model &model, coordf_t min_obj_distance,
IndexedPackGroup result; IndexedPackGroup result;
// If there is no hint about the shape, we will try to guess
if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed); if(bedhint.type == BedShapeType::WHO_KNOWS) bedhint = bedShape(bed);
BoundingBox bbb(bed); BoundingBox bbb(bed);

View File

@ -32,10 +32,10 @@ template<FilePrinterFormat format, class LayerFormat = void>
class FilePrinter { class FilePrinter {
public: public:
void printConfig(const Print&); void print_config(const Print&);
// Draw an ExPolygon which is a polygon inside a slice on the specified layer. // Draw an ExPolygon which is a polygon inside a slice on the specified layer.
void drawPolygon(const ExPolygon& p, unsigned lyr); void draw_polygon(const ExPolygon& p, unsigned lyr);
// Tell the printer how many layers should it consider. // Tell the printer how many layers should it consider.
void layers(unsigned layernum); void layers(unsigned layernum);
@ -47,45 +47,47 @@ public:
* specified layer number than an appropriate number of layers will be * specified layer number than an appropriate number of layers will be
* allocated in the printer. * allocated in the printer.
*/ */
void beginLayer(unsigned layer); void begin_layer(unsigned layer);
// Allocate a new layer on top of the last and switch to it. // Allocate a new layer on top of the last and switch to it.
void beginLayer(); void begin_layer();
/* /*
* Finish the selected layer. It means that no drawing is allowed on that * Finish the selected layer. It means that no drawing is allowed on that
* layer anymore. This fact can be used to prepare the file system output * layer anymore. This fact can be used to prepare the file system output
* data like png comprimation and so on. * data like png comprimation and so on.
*/ */
void finishLayer(unsigned layer); void finish_layer(unsigned layer);
// Finish the top layer. // Finish the top layer.
void finishLayer(); void finish_layer();
// Save all the layers into the file (or dir) specified in the path argument // Save all the layers into the file (or dir) specified in the path argument
void save(const std::string& path); void save(const std::string& path);
// Save only the selected layer to the file specified in path argument. // Save only the selected layer to the file specified in path argument.
void saveLayer(unsigned lyr, const std::string& path); void save_layer(unsigned lyr, const std::string& path);
}; };
template<class T = void> struct VeryFalse { static const bool value = false; }; template<class T = void> struct VeryFalse { static const bool value = false; };
// This has to be explicitly implemented in the gui layer or a default zlib // This has to be explicitly implemented in the gui layer or a default zlib
// based implementation is needed. // based implementation is needed.
template<class Backend> class Zipper { template<class Backend> class LayerWriter {
public: public:
Zipper(const std::string& /*zipfile_path*/) { LayerWriter(const std::string& /*zipfile_path*/) {
static_assert(VeryFalse<Backend>::value, static_assert(VeryFalse<Backend>::value,
"No zipper implementation provided!"); "No layer writer implementation provided!");
} }
void next_entry(const std::string& /*fname*/) {} void next_entry(const std::string& /*fname*/) {}
std::string get_name() { return ""; } std::string get_name() { return ""; }
template<class T> Zipper& operator<<(const T& /*arg*/) { bool is_ok() { return false; }
template<class T> LayerWriter& operator<<(const T& /*arg*/) {
return *this; return *this;
} }
@ -110,22 +112,22 @@ template<class LyrFormat> class FilePrinter<FilePrinterFormat::PNG, LyrFormat> {
// We will save the compressed PNG data into stringstreams which can be done // We will save the compressed PNG data into stringstreams which can be done
// in parallel. Later we can write every layer to the disk sequentially. // in parallel. Later we can write every layer to the disk sequentially.
std::vector<Layer> layers_rst_; std::vector<Layer> m_layers_rst;
Raster::Resolution res_; Raster::Resolution m_res;
Raster::PixelDim pxdim_; Raster::PixelDim m_pxdim;
const Print *print_ = nullptr; const Print *m_print = nullptr;
double exp_time_s_ = .0, exp_time_first_s_ = .0; double m_exp_time_s = .0, m_exp_time_first_s = .0;
std::string createIniContent(const std::string& projectname) { std::string createIniContent(const std::string& projectname) {
double layer_height = print_? double layer_height = m_print?
print_->default_object_config().layer_height.getFloat() : m_print->default_object_config().layer_height.getFloat() :
0.05; 0.05;
using std::string; using std::string;
using std::to_string; using std::to_string;
auto expt_str = to_string(exp_time_s_); auto expt_str = to_string(m_exp_time_s);
auto expt_first_str = to_string(exp_time_first_s_); auto expt_first_str = to_string(m_exp_time_first_s);
auto stepnum_str = to_string(static_cast<unsigned>(800*layer_height)); auto stepnum_str = to_string(static_cast<unsigned>(800*layer_height));
auto layerh_str = to_string(layer_height); auto layerh_str = to_string(layer_height);
@ -153,117 +155,84 @@ public:
inline FilePrinter(double width_mm, double height_mm, inline FilePrinter(double width_mm, double height_mm,
unsigned width_px, unsigned height_px, unsigned width_px, unsigned height_px,
double exp_time, double exp_time_first): double exp_time, double exp_time_first):
res_(width_px, height_px), m_res(width_px, height_px),
pxdim_(width_mm/width_px, height_mm/height_px), m_pxdim(width_mm/width_px, height_mm/height_px),
exp_time_s_(exp_time), m_exp_time_s(exp_time),
exp_time_first_s_(exp_time_first) m_exp_time_first_s(exp_time_first)
{ {
} }
FilePrinter(const FilePrinter& ) = delete; FilePrinter(const FilePrinter& ) = delete;
FilePrinter(FilePrinter&& m): FilePrinter(FilePrinter&& m):
layers_rst_(std::move(m.layers_rst_)), m_layers_rst(std::move(m.m_layers_rst)),
res_(m.res_), m_res(m.m_res),
pxdim_(m.pxdim_) {} m_pxdim(m.m_pxdim) {}
inline void layers(unsigned cnt) { if(cnt > 0) layers_rst_.resize(cnt); } inline void layers(unsigned cnt) { if(cnt > 0) m_layers_rst.resize(cnt); }
inline unsigned layers() const { return unsigned(layers_rst_.size()); } inline unsigned layers() const { return unsigned(m_layers_rst.size()); }
void printConfig(const Print& printconf) { print_ = &printconf; } void print_config(const Print& printconf) { m_print = &printconf; }
inline void drawPolygon(const ExPolygon& p, unsigned lyr) { inline void draw_polygon(const ExPolygon& p, unsigned lyr) {
assert(lyr < layers_rst_.size()); assert(lyr < m_layers_rst.size());
layers_rst_[lyr].first.draw(p); m_layers_rst[lyr].first.draw(p);
} }
inline void beginLayer(unsigned lyr) { inline void begin_layer(unsigned lyr) {
if(layers_rst_.size() <= lyr) layers_rst_.resize(lyr+1); if(m_layers_rst.size() <= lyr) m_layers_rst.resize(lyr+1);
layers_rst_[lyr].first.reset(res_, pxdim_, ORIGIN); m_layers_rst[lyr].first.reset(m_res, m_pxdim, ORIGIN);
} }
inline void beginLayer() { inline void begin_layer() {
layers_rst_.emplace_back(); m_layers_rst.emplace_back();
layers_rst_.front().first.reset(res_, pxdim_, ORIGIN); m_layers_rst.front().first.reset(m_res, m_pxdim, ORIGIN);
} }
inline void finishLayer(unsigned lyr_id) { inline void finish_layer(unsigned lyr_id) {
assert(lyr_id < layers_rst_.size()); assert(lyr_id < m_layers_rst.size());
layers_rst_[lyr_id].first.save(layers_rst_[lyr_id].second, m_layers_rst[lyr_id].first.save(m_layers_rst[lyr_id].second,
Raster::Compression::PNG); Raster::Compression::PNG);
layers_rst_[lyr_id].first.reset(); m_layers_rst[lyr_id].first.reset();
} }
inline void finishLayer() { inline void finish_layer() {
if(!layers_rst_.empty()) { if(!m_layers_rst.empty()) {
layers_rst_.back().first.save(layers_rst_.back().second, m_layers_rst.back().first.save(m_layers_rst.back().second,
Raster::Compression::PNG); Raster::Compression::PNG);
layers_rst_.back().first.reset(); m_layers_rst.back().first.reset();
} }
} }
inline void save(const std::string& path) { inline void save(const std::string& path) {
try { try {
Zipper<LyrFormat> zipper(path); LayerWriter<LyrFormat> writer(path);
std::string project = zipper.get_name(); std::string project = writer.get_name();
zipper.next_entry(project); writer.next_entry("config.ini");
zipper << createIniContent(project); writer << createIniContent(project);
for(unsigned i = 0; i < layers_rst_.size(); i++) { for(unsigned i = 0; i < m_layers_rst.size(); i++) {
if(layers_rst_[i].second.rdbuf()->in_avail() > 0) { if(m_layers_rst[i].second.rdbuf()->in_avail() > 0) {
char lyrnum[6]; char lyrnum[6];
std::sprintf(lyrnum, "%.5d", i); std::sprintf(lyrnum, "%.5d", i);
auto zfilename = project + lyrnum + ".png"; auto zfilename = project + lyrnum + ".png";
zipper.next_entry(zfilename); writer.next_entry(zfilename);
zipper << layers_rst_[i].second.rdbuf(); writer << m_layers_rst[i].second.rdbuf();
layers_rst_[i].second.str(""); m_layers_rst[i].second.str("");
} }
} }
zipper.close(); writer.close();
} catch(std::exception&) { } catch(std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers! " BOOST_LOG_TRIVIAL(error) << e.what();
<< path;
return; return;
} }
// wxFileName filepath(path);
// wxFFileOutputStream zipfile(path);
// std::string project = filepath.GetName().ToStdString();
// if(!zipfile.IsOk()) {
// BOOST_LOG_TRIVIAL(error) << "Can't create zip file for layers! "
// << path;
// return;
// }
// wxZipOutputStream zipstream(zipfile);
// wxStdOutputStream pngstream(zipstream);
// zipstream.PutNextEntry("config.ini");
// pngstream << createIniContent(project);
// for(unsigned i = 0; i < layers_rst_.size(); i++) {
// if(layers_rst_[i].second.rdbuf()->in_avail() > 0) {
// char lyrnum[6];
// std::sprintf(lyrnum, "%.5d", i);
// auto zfilename = project + lyrnum + ".png";
// zipstream.PutNextEntry(zfilename);
// pngstream << layers_rst_[i].second.rdbuf();
// layers_rst_[i].second.str("");
// }
// }
// zipstream.Close();
// zipfile.Close();
} }
void saveLayer(unsigned lyr, const std::string& path) { void save_layer(unsigned lyr, const std::string& path) {
unsigned i = lyr; unsigned i = lyr;
assert(i < layers_rst_.size()); assert(i < m_layers_rst.size());
char lyrnum[6]; char lyrnum[6];
std::sprintf(lyrnum, "%.5d", lyr); std::sprintf(lyrnum, "%.5d", lyr);
@ -271,13 +240,13 @@ public:
std::fstream out(loc, std::fstream::out | std::fstream::binary); std::fstream out(loc, std::fstream::out | std::fstream::binary);
if(out.good()) { if(out.good()) {
layers_rst_[i].first.save(out, Raster::Compression::PNG); m_layers_rst[i].first.save(out, Raster::Compression::PNG);
} else { } else {
BOOST_LOG_TRIVIAL(error) << "Can't create file for layer"; BOOST_LOG_TRIVIAL(error) << "Can't create file for layer";
} }
out.close(); out.close();
layers_rst_[i].first.reset(); m_layers_rst[i].first.reset();
} }
}; };
@ -337,7 +306,7 @@ void print_to(Print& print,
FilePrinter<format, LayerFormat> printer(width_mm, height_mm, FilePrinter<format, LayerFormat> printer(width_mm, height_mm,
std::forward<Args>(args)...); std::forward<Args>(args)...);
printer.printConfig(print); printer.print_config(print);
printer.layers(layers.size()); // Allocate space for all the layers printer.layers(layers.size()); // Allocate space for all the layers
@ -358,7 +327,7 @@ void print_to(Print& print,
{ {
LayerPtrs lrange = layers[keys[layer_id]]; LayerPtrs lrange = layers[keys[layer_id]];
printer.beginLayer(layer_id); // Switch to the appropriate layer printer.begin_layer(layer_id); // Switch to the appropriate layer
for(Layer *lp : lrange) { for(Layer *lp : lrange) {
Layer& l = *lp; Layer& l = *lp;
@ -379,7 +348,7 @@ void print_to(Print& print,
slice.translate(-px(print_bb.min) + cx, slice.translate(-px(print_bb.min) + cx,
-py(print_bb.min) + cy); -py(print_bb.min) + cy);
printer.drawPolygon(slice, layer_id); printer.draw_polygon(slice, layer_id);
} }
/*if(print.has_support_material() && layer_id > 0) { /*if(print.has_support_material() && layer_id > 0) {
@ -392,7 +361,7 @@ void print_to(Print& print,
} }
printer.finishLayer(layer_id); // Finish the layer for later saving it. printer.finish_layer(layer_id); // Finish the layer for later saving it.
auto st = static_cast<int>(layer_id*80.0/layers.size()); auto st = static_cast<int>(layer_id*80.0/layers.size());
m.lock(); m.lock();

View File

@ -37,37 +37,37 @@ public:
using Origin = Raster::Origin; using Origin = Raster::Origin;
private: private:
Raster::Resolution resolution_; Raster::Resolution m_resolution;
Raster::PixelDim pxdim_; Raster::PixelDim m_pxdim;
TBuffer buf_; TBuffer m_buf;
TRawBuffer rbuf_; TRawBuffer m_rbuf;
TPixelRenderer pixfmt_; TPixelRenderer m_pixfmt;
TRawRenderer raw_renderer_; TRawRenderer m_raw_renderer;
TRendererAA renderer_; TRendererAA m_renderer;
Origin o_; Origin m_o;
std::function<void(agg::path_storage&)> flipy_ = [](agg::path_storage&) {}; std::function<void(agg::path_storage&)> m_flipy = [](agg::path_storage&) {};
public: public:
inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd, inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd,
Origin o): Origin o):
resolution_(res), pxdim_(pd), m_resolution(res), m_pxdim(pd),
buf_(res.pixels()), m_buf(res.pixels()),
rbuf_(reinterpret_cast<TPixelRenderer::value_type*>(buf_.data()), m_rbuf(reinterpret_cast<TPixelRenderer::value_type*>(m_buf.data()),
res.width_px, res.height_px, res.width_px, res.height_px,
res.width_px*TPixelRenderer::num_components), res.width_px*TPixelRenderer::num_components),
pixfmt_(rbuf_), m_pixfmt(m_rbuf),
raw_renderer_(pixfmt_), m_raw_renderer(m_pixfmt),
renderer_(raw_renderer_), m_renderer(m_raw_renderer),
o_(o) m_o(o)
{ {
renderer_.color(ColorWhite); m_renderer.color(ColorWhite);
// If we would like to play around with gamma // If we would like to play around with gamma
// ras.gamma(agg::gamma_power(1.0)); // ras.gamma(agg::gamma_power(1.0));
clear(); clear();
if(o_ == Origin::TOP_LEFT) flipy_ = [this](agg::path_storage& path) { if(m_o == Origin::TOP_LEFT) m_flipy = [this](agg::path_storage& path) {
path.flip_y(0, resolution_.height_px); path.flip_y(0, m_resolution.height_px);
}; };
} }
@ -76,35 +76,35 @@ public:
agg::scanline_p8 scanlines; agg::scanline_p8 scanlines;
auto&& path = to_path(poly.contour); auto&& path = to_path(poly.contour);
flipy_(path); m_flipy(path);
ras.add_path(path); ras.add_path(path);
for(auto h : poly.holes) { for(auto h : poly.holes) {
auto&& holepath = to_path(h); auto&& holepath = to_path(h);
flipy_(holepath); m_flipy(holepath);
ras.add_path(holepath); ras.add_path(holepath);
} }
agg::render_scanlines(ras, scanlines, renderer_); agg::render_scanlines(ras, scanlines, m_renderer);
} }
inline void clear() { inline void clear() {
raw_renderer_.clear(ColorBlack); m_raw_renderer.clear(ColorBlack);
} }
inline TBuffer& buffer() { return buf_; } inline TBuffer& buffer() { return m_buf; }
inline const Raster::Resolution resolution() { return resolution_; } inline const Raster::Resolution resolution() { return m_resolution; }
inline Origin origin() const /*noexcept*/ { return o_; } inline Origin origin() const /*noexcept*/ { return m_o; }
private: private:
double getPx(const Point& p) { double getPx(const Point& p) {
return p(0) * SCALING_FACTOR/pxdim_.w_mm; return p(0) * SCALING_FACTOR/m_pxdim.w_mm;
} }
double getPy(const Point& p) { double getPy(const Point& p) {
return p(1) * SCALING_FACTOR/pxdim_.h_mm; return p(1) * SCALING_FACTOR/m_pxdim.h_mm;
} }
agg::path_storage to_path(const Polygon& poly) { agg::path_storage to_path(const Polygon& poly) {
@ -124,57 +124,57 @@ const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255);
const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0); const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0);
Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o): Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o):
impl_(new Impl(r, pd, o)) {} m_impl(new Impl(r, pd, o)) {}
Raster::Raster() {} Raster::Raster() {}
Raster::~Raster() {} Raster::~Raster() {}
Raster::Raster(Raster &&m): Raster::Raster(Raster &&m):
impl_(std::move(m.impl_)) {} m_impl(std::move(m.m_impl)) {}
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd) void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd)
{ {
// Free up the unnecessary memory and make sure it stays clear after // Free up the unnecessary memory and make sure it stays clear after
// an exception // an exception
auto o = impl_? impl_->origin() : Origin::TOP_LEFT; auto o = m_impl? m_impl->origin() : Origin::TOP_LEFT;
reset(r, pd, o); reset(r, pd, o);
} }
void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd, void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,
Raster::Origin o) Raster::Origin o)
{ {
impl_.reset(); m_impl.reset();
impl_.reset(new Impl(r, pd, o)); m_impl.reset(new Impl(r, pd, o));
} }
void Raster::reset() void Raster::reset()
{ {
impl_.reset(); m_impl.reset();
} }
Raster::Resolution Raster::resolution() const Raster::Resolution Raster::resolution() const
{ {
if(impl_) return impl_->resolution(); if(m_impl) return m_impl->resolution();
return Resolution(0, 0); return Resolution(0, 0);
} }
void Raster::clear() void Raster::clear()
{ {
assert(impl_); assert(m_impl);
impl_->clear(); m_impl->clear();
} }
void Raster::draw(const ExPolygon &poly) void Raster::draw(const ExPolygon &poly)
{ {
assert(impl_); assert(m_impl);
impl_->draw(poly); m_impl->draw(poly);
} }
void Raster::save(std::ostream& stream, Compression comp) void Raster::save(std::ostream& stream, Compression comp)
{ {
assert(impl_); assert(m_impl);
switch(comp) { switch(comp) {
case Compression::PNG: { case Compression::PNG: {
@ -188,7 +188,7 @@ void Raster::save(std::ostream& stream, Compression comp)
wr.write_info(); wr.write_info();
auto& b = impl_->buffer(); auto& b = m_impl->buffer();
auto ptr = reinterpret_cast<png::byte*>( b.data() ); auto ptr = reinterpret_cast<png::byte*>( b.data() );
unsigned stride = unsigned stride =
sizeof(Impl::TBuffer::value_type) * resolution().width_px; sizeof(Impl::TBuffer::value_type) * resolution().width_px;
@ -201,12 +201,12 @@ void Raster::save(std::ostream& stream, Compression comp)
} }
case Compression::RAW: { case Compression::RAW: {
stream << "P5 " stream << "P5 "
<< impl_->resolution().width_px << " " << m_impl->resolution().width_px << " "
<< impl_->resolution().height_px << " " << m_impl->resolution().height_px << " "
<< "255 "; << "255 ";
stream.write(reinterpret_cast<const char*>(impl_->buffer().data()), stream.write(reinterpret_cast<const char*>(m_impl->buffer().data()),
impl_->buffer().size()*sizeof(Impl::TBuffer::value_type)); m_impl->buffer().size()*sizeof(Impl::TBuffer::value_type));
} }
} }
} }

View File

@ -18,7 +18,7 @@ class ExPolygon;
*/ */
class Raster { class Raster {
class Impl; class Impl;
std::unique_ptr<Impl> impl_; std::unique_ptr<Impl> m_impl;
public: public:
/// Supported compression types /// Supported compression types
@ -65,7 +65,7 @@ public:
/** /**
* Release the allocated resources. Drawing in this state ends in * Release the allocated resources. Drawing in this state ends in
* unspecified behaviour. * unspecified behavior.
*/ */
void reset(); void reset();

View File

@ -6,6 +6,10 @@
// Add z coordinate to model instances' offset // Add z coordinate to model instances' offset
#define ENABLE_MODELINSTANCE_3D_OFFSET (1 && ENABLE_1_42_0) #define ENABLE_MODELINSTANCE_3D_OFFSET (1 && ENABLE_1_42_0)
// Add double click on gizmo grabbers to reset transformation components to their default value
#define ENABLE_GIZMOS_RESET (1 && ENABLE_1_42_0)
// Add x and y rotation components to model instances' offset
#define ENABLE_MODELINSTANCE_3D_ROTATION (1 && ENABLE_MODELINSTANCE_3D_OFFSET)
#endif // _technologies_h_ #endif // _technologies_h_

View File

@ -18,13 +18,10 @@
#include <Model.hpp> #include <Model.hpp>
#include <Utils.hpp> #include <Utils.hpp>
#include <wx/stdstream.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
namespace Slic3r { namespace Slic3r {
class AppControllerBoilerplate::PriData { class AppControllerGui::PriData {
public: public:
std::mutex m; std::mutex m;
std::thread::id ui_thread; std::thread::id ui_thread;
@ -32,16 +29,16 @@ public:
inline explicit PriData(std::thread::id uit): ui_thread(uit) {} inline explicit PriData(std::thread::id uit): ui_thread(uit) {}
}; };
AppControllerBoilerplate::AppControllerBoilerplate() AppControllerGui::AppControllerGui()
:pri_data_(new PriData(std::this_thread::get_id())) {} :m_pri_data(new PriData(std::this_thread::get_id())) {}
AppControllerBoilerplate::~AppControllerBoilerplate() { AppControllerGui::~AppControllerGui() {
pri_data_.reset(); m_pri_data.reset();
} }
bool AppControllerBoilerplate::is_main_thread() const bool AppControllerGui::is_main_thread() const
{ {
return pri_data_->ui_thread == std::this_thread::get_id(); return m_pri_data->ui_thread == std::this_thread::get_id();
} }
namespace GUI { namespace GUI {
@ -57,172 +54,32 @@ static const PrintStep STEP_SKIRT = psSkirt;
static const PrintStep STEP_BRIM = psBrim; static const PrintStep STEP_BRIM = psBrim;
static const PrintStep STEP_WIPE_TOWER = psWipeTower; static const PrintStep STEP_WIPE_TOWER = psWipeTower;
AppControllerBoilerplate::ProgresIndicatorPtr ProgresIndicatorPtr AppControllerGui::global_progress_indicator() {
AppControllerBoilerplate::global_progress_indicator() {
ProgresIndicatorPtr ret; ProgresIndicatorPtr ret;
pri_data_->m.lock(); m_pri_data->m.lock();
ret = global_progressind_; ret = m_global_progressind;
pri_data_->m.unlock(); m_pri_data->m.unlock();
return ret; return ret;
} }
void AppControllerBoilerplate::global_progress_indicator( void AppControllerGui::global_progress_indicator(ProgresIndicatorPtr gpri)
AppControllerBoilerplate::ProgresIndicatorPtr gpri)
{ {
pri_data_->m.lock(); m_pri_data->m.lock();
global_progressind_ = gpri; m_global_progressind = gpri;
pri_data_->m.unlock(); m_pri_data->m.unlock();
} }
//void PrintController::make_skirt()
//{
// assert(print_ != nullptr);
// // prerequisites
// for(auto obj : print_->objects) make_perimeters(obj);
// for(auto obj : print_->objects) infill(obj);
// for(auto obj : print_->objects) gen_support_material(obj);
// if(!print_->state.is_done(STEP_SKIRT)) {
// print_->state.set_started(STEP_SKIRT);
// print_->skirt.clear();
// if(print_->has_skirt()) print_->_make_skirt();
// print_->state.set_done(STEP_SKIRT);
// }
//}
//void PrintController::make_brim()
//{
// assert(print_ != nullptr);
// // prerequisites
// for(auto obj : print_->objects) make_perimeters(obj);
// for(auto obj : print_->objects) infill(obj);
// for(auto obj : print_->objects) gen_support_material(obj);
// make_skirt();
// if(!print_->state.is_done(STEP_BRIM)) {
// print_->state.set_started(STEP_BRIM);
// // since this method must be idempotent, we clear brim paths *before*
// // checking whether we need to generate them
// print_->brim.clear();
// if(print_->config.brim_width > 0) print_->_make_brim();
// print_->state.set_done(STEP_BRIM);
// }
//}
//void PrintController::make_wipe_tower()
//{
// assert(print_ != nullptr);
// // prerequisites
// for(auto obj : print_->objects) make_perimeters(obj);
// for(auto obj : print_->objects) infill(obj);
// for(auto obj : print_->objects) gen_support_material(obj);
// make_skirt();
// make_brim();
// if(!print_->state.is_done(STEP_WIPE_TOWER)) {
// print_->state.set_started(STEP_WIPE_TOWER);
// // since this method must be idempotent, we clear brim paths *before*
// // checking whether we need to generate them
// print_->brim.clear();
// if(print_->has_wipe_tower()) print_->_make_wipe_tower();
// print_->state.set_done(STEP_WIPE_TOWER);
// }
//}
//void PrintController::slice(PrintObject *pobj)
//{
// assert(pobj != nullptr && print_ != nullptr);
// if(pobj->state.is_done(STEP_SLICE)) return;
// pobj->state.set_started(STEP_SLICE);
// pobj->_slice();
// auto msg = pobj->_fix_slicing_errors();
// if(!msg.empty()) report_issue(IssueType::WARN, msg);
// // simplify slices if required
// if (print_->config.resolution)
// pobj->_simplify_slices(scale_(print_->config.resolution));
// if(pobj->layers.empty())
// report_issue(IssueType::ERR,
// L("No layers were detected. You might want to repair your "
// "STL file(s) or check their size or thickness and retry")
// );
// pobj->state.set_done(STEP_SLICE);
//}
//void PrintController::make_perimeters(PrintObject *pobj)
//{
// assert(pobj != nullptr);
// slice(pobj);
// if (!pobj->state.is_done(STEP_PERIMETERS)) {
// pobj->_make_perimeters();
// }
//}
//void PrintController::infill(PrintObject *pobj)
//{
// assert(pobj != nullptr);
// make_perimeters(pobj);
// if (!pobj->state.is_done(STEP_PREPARE_INFILL)) {
// pobj->state.set_started(STEP_PREPARE_INFILL);
// pobj->_prepare_infill();
// pobj->state.set_done(STEP_PREPARE_INFILL);
// }
// pobj->_infill();
//}
//void PrintController::gen_support_material(PrintObject *pobj)
//{
// assert(pobj != nullptr);
// // prerequisites
// slice(pobj);
// if(!pobj->state.is_done(STEP_SUPPORTMATERIAL)) {
// pobj->state.set_started(STEP_SUPPORTMATERIAL);
// pobj->clear_support_layers();
// if((pobj->config.support_material || pobj->config.raft_layers > 0)
// && pobj->layers.size() > 1) {
// pobj->_generate_support_material();
// }
// pobj->state.set_done(STEP_SUPPORTMATERIAL);
// }
//}
PrintController::PngExportData PrintController::PngExportData
PrintController::query_png_export_data(const DynamicPrintConfig& conf) PrintController::query_png_export_data(const DynamicPrintConfig& conf)
{ {
PngExportData ret; PngExportData ret;
auto zippath = query_destination_path("Output zip file", "*.zip", "out"); auto c = GUI::get_appctl();
auto zippath = c->query_destination_path("Output zip file", "*.zip",
"export-png",
"out");
ret.zippath = zippath; ret.zippath = zippath;
@ -246,98 +103,53 @@ PrintController::query_png_export_data(const DynamicPrintConfig& conf)
return ret; return ret;
} }
void PrintController::slice(AppControllerBoilerplate::ProgresIndicatorPtr pri) void PrintController::slice(ProgresIndicatorPtr pri)
{ {
auto st = pri->state(); m_print->set_status_callback([pri](int st, const std::string& msg){
pri->update(unsigned(st), msg);
});
Slic3r::trace(3, "Starting the slicing process."); m_print->process();
pri->update(st+20, L("Generating perimeters"));
// for(auto obj : print_->objects) make_perimeters(obj);
pri->update(st+60, L("Infilling layers"));
// for(auto obj : print_->objects) infill(obj);
pri->update(st+70, L("Generating support material"));
// for(auto obj : print_->objects) gen_support_material(obj);
// pri->message_fmt(L("Weight: %.1fg, Cost: %.1f"),
// print_->total_weight, print_->total_cost);
pri->state(st+85);
pri->update(st+88, L("Generating skirt"));
make_skirt();
pri->update(st+90, L("Generating brim"));
make_brim();
pri->update(st+95, L("Generating wipe tower"));
make_wipe_tower();
pri->update(st+100, L("Done"));
// time to make some statistics..
Slic3r::trace(3, L("Slicing process finished."));
} }
void PrintController::slice() void PrintController::slice()
{ {
auto pri = global_progress_indicator(); auto ctl = GUI::get_appctl();
if(!pri) pri = create_progress_indicator(100, L("Slicing")); auto pri = ctl->global_progress_indicator();
if(!pri) pri = ctl->create_progress_indicator(100, L("Slicing"));
slice(pri); slice(pri);
} }
struct wxZipper {}; template<> class LayerWriter<Zipper> {
Zipper m_zip;
template<> class Zipper<wxZipper> {
wxFileName m_fpath;
wxFFileOutputStream m_zipfile;
wxZipOutputStream m_zipstream;
wxStdOutputStream m_pngstream;
public: public:
Zipper(const std::string& zipfile_path): inline LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {}
m_fpath(zipfile_path),
m_zipfile(zipfile_path), inline void next_entry(const std::string& fname) { m_zip.next_entry(fname); }
m_zipstream(m_zipfile),
m_pngstream(m_zipstream) inline std::string get_name() const { return m_zip.get_name(); }
{
if(!m_zipfile.IsOk()) template<class T> inline LayerWriter& operator<<(const T& arg) {
throw std::runtime_error(L("Cannot create zip file.")); m_zip.stream() << arg; return *this;
} }
void next_entry(const std::string& fname) { inline void close() { m_zip.close(); }
m_zipstream.PutNextEntry(fname);
}
std::string get_name() {
return m_fpath.GetName().ToStdString();
}
template<class T> Zipper& operator<<(const T& arg) {
m_pngstream << arg; return *this;
}
void close() {
m_zipstream.Close();
m_zipfile.Close();
}
}; };
void PrintController::slice_to_png() void PrintController::slice_to_png()
{ {
using Pointf3 = Vec3d; using Pointf3 = Vec3d;
auto ctl = GUI::get_appctl();
auto presetbundle = GUI::get_preset_bundle(); auto presetbundle = GUI::get_preset_bundle();
assert(presetbundle); assert(presetbundle);
// FIXME: this crashes in command line mode
auto pt = presetbundle->printers.get_selected_preset().printer_technology(); auto pt = presetbundle->printers.get_selected_preset().printer_technology();
if(pt != ptSLA) { if(pt != ptSLA) {
report_issue(IssueType::ERR, L("Printer technology is not SLA!"), ctl->report_issue(IssueType::ERR, L("Printer technology is not SLA!"),
L("Error")); L("Error"));
return; return;
} }
@ -348,13 +160,13 @@ void PrintController::slice_to_png()
auto exd = query_png_export_data(conf); auto exd = query_png_export_data(conf);
if(exd.zippath.empty()) return; if(exd.zippath.empty()) return;
Print *print = print_; Print *print = m_print;
try { try {
print->apply_config(conf); print->apply_config(conf);
print->validate(); print->validate();
} catch(std::exception& e) { } catch(std::exception& e) {
report_issue(IssueType::ERR, e.what(), "Error"); ctl->report_issue(IssueType::ERR, e.what(), "Error");
return; return;
} }
@ -400,13 +212,13 @@ void PrintController::slice_to_png()
<< L("Width needed: ") << px(punsc) << " mm\n" << L("Width needed: ") << px(punsc) << " mm\n"
<< L("Height needed: ") << py(punsc) << " mm\n"; << L("Height needed: ") << py(punsc) << " mm\n";
if(!report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) { if(!ctl->report_issue(IssueType::WARN_Q, ss.str(), L("Warning"))) {
scale_back(); scale_back();
return; return;
} }
} }
auto pri = create_progress_indicator( auto pri = ctl->create_progress_indicator(
200, L("Slicing to zipped png files...")); 200, L("Slicing to zipped png files..."));
pri->on_cancel([&print](){ print->cancel(); }); pri->on_cancel([&print](){ print->cancel(); });
@ -415,7 +227,7 @@ void PrintController::slice_to_png()
pri->update(0, L("Slicing...")); pri->update(0, L("Slicing..."));
slice(pri); slice(pri);
} catch (std::exception& e) { } catch (std::exception& e) {
report_issue(IssueType::ERR, e.what(), L("Exception occurred")); ctl->report_issue(IssueType::ERR, e.what(), L("Exception occurred"));
scale_back(); scale_back();
if(print->canceled()) print->restart(); if(print->canceled()) print->restart();
return; return;
@ -428,22 +240,23 @@ void PrintController::slice_to_png()
}); });
try { try {
print_to<FilePrinterFormat::PNG, wxZipper>( *print, exd.zippath, print_to<FilePrinterFormat::PNG, Zipper>( *print, exd.zippath,
exd.width_mm, exd.height_mm, exd.width_mm, exd.height_mm,
exd.width_px, exd.height_px, exd.width_px, exd.height_px,
exd.exp_time_s, exd.exp_time_first_s); exd.exp_time_s, exd.exp_time_first_s);
} catch (std::exception& e) { } catch (std::exception& e) {
report_issue(IssueType::ERR, e.what(), L("Exception occurred")); ctl->report_issue(IssueType::ERR, e.what(), L("Exception occurred"));
} }
scale_back(); scale_back();
if(print->canceled()) print->restart(); if(print->canceled()) print->restart();
print->set_status_default();
} }
const PrintConfig &PrintController::config() const const PrintConfig &PrintController::config() const
{ {
return print_->config(); return m_print->config();
} }
void ProgressIndicator::message_fmt( void ProgressIndicator::message_fmt(
@ -477,15 +290,17 @@ void AppController::arrange_model()
{ {
using Coord = libnest2d::TCoord<libnest2d::PointImpl>; using Coord = libnest2d::TCoord<libnest2d::PointImpl>;
if(arranging_.load()) return; auto ctl = GUI::get_appctl();
if(m_arranging.load()) return;
// to prevent UI reentrancies // to prevent UI reentrancies
arranging_.store(true); m_arranging.store(true);
unsigned count = 0; unsigned count = 0;
for(auto obj : model_->objects) count += obj->instances.size(); for(auto obj : m_model->objects) count += obj->instances.size();
auto pind = global_progress_indicator(); auto pind = ctl->global_progress_indicator();
float pmax = 1.0; float pmax = 1.0;
@ -496,7 +311,7 @@ void AppController::arrange_model()
pind->max(count); pind->max(count);
pind->on_cancel([this](){ pind->on_cancel([this](){
arranging_.store(false); m_arranging.store(false);
}); });
} }
@ -517,20 +332,20 @@ void AppController::arrange_model()
// TODO: from Sasha from GUI // TODO: from Sasha from GUI
hint.type = arr::BedShapeType::WHO_KNOWS; hint.type = arr::BedShapeType::WHO_KNOWS;
arr::arrange(*model_, arr::arrange(*m_model,
min_obj_distance, min_obj_distance,
bed, bed,
hint, hint,
false, // create many piles not just one pile false, // create many piles not just one pile
[this, pind, count](unsigned rem) { [this, pind, &ctl, count](unsigned rem) {
if(pind) if(pind)
pind->update(count - rem, L("Arranging objects...")); pind->update(count - rem, L("Arranging objects..."));
process_events(); ctl->process_events();
}, [this] () { return !arranging_.load(); }); }, [this] () { return !m_arranging.load(); });
} catch(std::exception& e) { } catch(std::exception& e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
report_issue(IssueType::ERR, ctl->report_issue(IssueType::ERR,
L("Could not arrange model objects! " L("Could not arrange model objects! "
"Some geometries may be invalid."), "Some geometries may be invalid."),
L("Exception occurred")); L("Exception occurred"));
@ -539,13 +354,13 @@ void AppController::arrange_model()
// Restore previous max value // Restore previous max value
if(pind) { if(pind) {
pind->max(pmax); pind->max(pmax);
pind->update(0, arranging_.load() ? L("Arranging done.") : pind->update(0, m_arranging.load() ? L("Arranging done.") :
L("Arranging canceled.")); L("Arranging canceled."));
pind->on_cancel(/*remove cancel function*/); pind->on_cancel(/*remove cancel function*/);
} }
arranging_.store(false); m_arranging.store(false);
} }
} }

View File

@ -20,6 +20,21 @@ class PrintConfig;
class ProgressStatusBar; class ProgressStatusBar;
class DynamicPrintConfig; class DynamicPrintConfig;
/// A Progress indicator object smart pointer
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
using FilePath = std::string;
using FilePathList = std::vector<FilePath>;
/// Common runtime issue types
enum class IssueType {
INFO,
WARN,
WARN_Q, // Warning with a question to continue
ERR,
FATAL
};
/** /**
* @brief A boilerplate class for creating application logic. It should provide * @brief A boilerplate class for creating application logic. It should provide
* features as issue reporting and progress indication, etc... * features as issue reporting and progress indication, etc...
@ -32,34 +47,12 @@ class DynamicPrintConfig;
* UI toolkit dependencies. We can implement it with any UI framework or make it * UI toolkit dependencies. We can implement it with any UI framework or make it
* a cli client. * a cli client.
*/ */
class AppControllerBoilerplate { class AppControllerBase {
public: public:
/// A Progress indicator object smart pointer using Ptr = std::shared_ptr<AppControllerBase>;
using ProgresIndicatorPtr = std::shared_ptr<ProgressIndicator>;
private: inline virtual ~AppControllerBase() {}
class PriData; // Some structure to store progress indication data
// Pimpl data for thread safe progress indication features
std::unique_ptr<PriData> pri_data_;
public:
AppControllerBoilerplate();
~AppControllerBoilerplate();
using Path = std::string;
using PathList = std::vector<Path>;
/// Common runtime issue types
enum class IssueType {
INFO,
WARN,
WARN_Q, // Warning with a question to continue
ERR,
FATAL
};
/** /**
* @brief Query some paths from the user. * @brief Query some paths from the user.
@ -67,25 +60,30 @@ public:
* It should display a file chooser dialog in case of a UI application. * It should display a file chooser dialog in case of a UI application.
* @param title Title of a possible query dialog. * @param title Title of a possible query dialog.
* @param extensions Recognized file extensions. * @param extensions Recognized file extensions.
* @return Returns a list of paths choosed by the user. * @return Returns a list of paths chosen by the user.
*/ */
PathList query_destination_paths( virtual FilePathList query_destination_paths(
const std::string& title, const std::string& title,
const std::string& extensions) const; const std::string& extensions,
const std::string& functionid = "",
const std::string& hint = "") const = 0;
/** /**
* @brief Same as query_destination_paths but works for directories only. * @brief Same as query_destination_paths but works for directories only.
*/ */
PathList query_destination_dirs( virtual FilePathList query_destination_dirs(
const std::string& title) const; const std::string& title,
const std::string& functionid = "",
const std::string& hint = "") const = 0;
/** /**
* @brief Same as query_destination_paths but returns only one path. * @brief Same as query_destination_paths but returns only one path.
*/ */
Path query_destination_path( virtual FilePath query_destination_path(
const std::string& title, const std::string& title,
const std::string& extensions, const std::string& extensions,
const std::string& hint = "") const; const std::string& functionid = "",
const std::string& hint = "") const = 0;
/** /**
* @brief Report an issue to the user be it fatal or recoverable. * @brief Report an issue to the user be it fatal or recoverable.
@ -97,12 +95,9 @@ public:
* @param brief A very brief description. Can be used for message dialog * @param brief A very brief description. Can be used for message dialog
* title. * title.
*/ */
bool report_issue(IssueType issuetype, virtual bool report_issue(IssueType issuetype,
const std::string& description, const std::string& description,
const std::string& brief); const std::string& brief) = 0;
bool report_issue(IssueType issuetype,
const std::string& description);
/** /**
* @brief Return the global progress indicator for the current controller. * @brief Return the global progress indicator for the current controller.
@ -110,9 +105,9 @@ public:
* *
* Only one thread should use the global indicator at a time. * Only one thread should use the global indicator at a time.
*/ */
ProgresIndicatorPtr global_progress_indicator(); virtual ProgresIndicatorPtr global_progress_indicator() = 0;
void global_progress_indicator(ProgresIndicatorPtr gpri); virtual void global_progress_indicator(ProgresIndicatorPtr gpri) = 0;
/** /**
* @brief A predicate telling the caller whether it is the thread that * @brief A predicate telling the caller whether it is the thread that
@ -122,7 +117,7 @@ public:
* @return Return true for the same caller thread that created this * @return Return true for the same caller thread that created this
* object and false for every other. * object and false for every other.
*/ */
bool is_main_thread() const; virtual bool is_main_thread() const = 0;
/** /**
* @brief The frontend supports asynch execution. * @brief The frontend supports asynch execution.
@ -138,11 +133,9 @@ public:
* @return true if a job or method can be executed asynchronously, false * @return true if a job or method can be executed asynchronously, false
* otherwise. * otherwise.
*/ */
bool supports_asynch() const; virtual bool supports_asynch() const = 0;
void process_events(); virtual void process_events() = 0;
protected:
/** /**
* @brief Create a new progress indicator and return a smart pointer to it. * @brief Create a new progress indicator and return a smart pointer to it.
@ -151,36 +144,169 @@ protected:
* @param firstmsg The message for the first subtask to be displayed. * @param firstmsg The message for the first subtask to be displayed.
* @return Smart pointer to the created object. * @return Smart pointer to the created object.
*/ */
ProgresIndicatorPtr create_progress_indicator( virtual ProgresIndicatorPtr create_progress_indicator(
unsigned statenum, unsigned statenum,
const std::string& title, const std::string& title,
const std::string& firstmsg) const; const std::string& firstmsg = "") const = 0;
};
ProgresIndicatorPtr create_progress_indicator( /**
* @brief Implementation of AppControllerBase for the GUI app
*/
class AppControllerGui: public AppControllerBase {
private:
class PriData; // Some structure to store progress indication data
// Pimpl data for thread safe progress indication features
std::unique_ptr<PriData> m_pri_data;
public:
AppControllerGui();
virtual ~AppControllerGui();
virtual FilePathList query_destination_paths(
const std::string& title,
const std::string& extensions,
const std::string& functionid,
const std::string& hint) const override;
virtual FilePathList query_destination_dirs(
const std::string& /*title*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return {}; }
virtual FilePath query_destination_path(
const std::string& title,
const std::string& extensions,
const std::string& functionid,
const std::string& hint) const override;
virtual bool report_issue(IssueType issuetype,
const std::string& description,
const std::string& brief = std::string()) override;
virtual ProgresIndicatorPtr global_progress_indicator() override;
virtual void global_progress_indicator(ProgresIndicatorPtr gpri) override;
virtual bool is_main_thread() const override;
virtual bool supports_asynch() const override;
virtual void process_events() override;
virtual ProgresIndicatorPtr create_progress_indicator(
unsigned statenum, unsigned statenum,
const std::string& title) const; const std::string& title,
const std::string& firstmsg) const override;
protected:
// This is a global progress indicator placeholder. In the Slic3r UI it can // This is a global progress indicator placeholder. In the Slic3r UI it can
// contain the progress indicator on the statusbar. // contain the progress indicator on the statusbar.
ProgresIndicatorPtr global_progressind_; ProgresIndicatorPtr m_global_progressind;
};
class AppControllerCli: public AppControllerBase {
class CliProgress : public ProgressIndicator {
std::string m_msg, m_title;
public:
virtual void message(const std::string& msg) override {
m_msg = msg;
}
virtual void title(const std::string& title) override {
m_title = title;
}
};
public:
AppControllerCli() {
std::cout << "Cli AppController ready..." << std::endl;
m_global_progressind = std::make_shared<CliProgress>();
}
virtual ~AppControllerCli() {}
virtual FilePathList query_destination_paths(
const std::string& /*title*/,
const std::string& /*extensions*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return {}; }
virtual FilePathList query_destination_dirs(
const std::string& /*title*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return {}; }
virtual FilePath query_destination_path(
const std::string& /*title*/,
const std::string& /*extensions*/,
const std::string& /*functionid*/,
const std::string& /*hint*/) const override { return "out.zip"; }
virtual bool report_issue(IssueType /*issuetype*/,
const std::string& description,
const std::string& brief) override {
std::cerr << brief << ": " << description << std::endl;
return true;
}
virtual ProgresIndicatorPtr global_progress_indicator() override {
return m_global_progressind;
}
virtual void global_progress_indicator(ProgresIndicatorPtr) override {}
virtual bool is_main_thread() const override { return true; }
virtual bool supports_asynch() const override { return false; }
virtual void process_events() override {}
virtual ProgresIndicatorPtr create_progress_indicator(
unsigned /*statenum*/,
const std::string& /*title*/,
const std::string& /*firstmsg*/) const override {
return std::make_shared<CliProgress>();
}
protected:
// This is a global progress indicator placeholder. In the Slic3r UI it can
// contain the progress indicator on the statusbar.
ProgresIndicatorPtr m_global_progressind;
};
class Zipper {
struct Impl;
std::unique_ptr<Impl> m_impl;
public:
Zipper(const std::string& zipfilepath);
~Zipper();
void next_entry(const std::string& fname);
std::string get_name() const;
std::ostream& stream();
void close();
}; };
/** /**
* @brief Implementation of the printing logic. * @brief Implementation of the printing logic.
*/ */
class PrintController: public AppControllerBoilerplate { class PrintController {
Print *print_ = nullptr; Print *m_print = nullptr;
std::function<void()> rempools_; std::function<void()> m_rempools;
protected: protected:
void make_skirt() {}
void make_brim() {}
void make_wipe_tower() {}
void make_perimeters(PrintObject *pobj) {}
void infill(PrintObject *pobj) {}
void gen_support_material(PrintObject *pobj) {}
// Data structure with the png export input data // Data structure with the png export input data
struct PngExportData { struct PngExportData {
std::string zippath; // output zip file std::string zippath; // output zip file
@ -198,20 +324,14 @@ protected:
PngExportData query_png_export_data(const DynamicPrintConfig&); PngExportData query_png_export_data(const DynamicPrintConfig&);
// The previous export data, to pre-populate the dialog // The previous export data, to pre-populate the dialog
PngExportData prev_expdata_; PngExportData m_prev_expdata;
/**
* @brief Slice one pront object.
* @param pobj The print object.
*/
void slice(PrintObject *pobj);
void slice(ProgresIndicatorPtr pri); void slice(ProgresIndicatorPtr pri);
public: public:
// Must be public for perl to use it // Must be public for perl to use it
explicit inline PrintController(Print *print): print_(print) {} explicit inline PrintController(Print *print): m_print(print) {}
PrintController(const PrintController&) = delete; PrintController(const PrintController&) = delete;
PrintController(PrintController&&) = delete; PrintController(PrintController&&) = delete;
@ -238,10 +358,10 @@ public:
/** /**
* @brief Top level controller. * @brief Top level controller.
*/ */
class AppController: public AppControllerBoilerplate { class AppController {
Model *model_ = nullptr; Model *m_model = nullptr;
PrintController::Ptr printctl; PrintController::Ptr printctl;
std::atomic<bool> arranging_; std::atomic<bool> m_arranging;
public: public:
/** /**
@ -258,7 +378,7 @@ public:
* @param model A raw pointer to the model object. This can be used from * @param model A raw pointer to the model object. This can be used from
* perl. * perl.
*/ */
void set_model(Model *model) { model_ = model; } void set_model(Model *model) { m_model = model; }
/** /**
* @brief Set the print object from perl. * @brief Set the print object from perl.

View File

@ -1,5 +1,9 @@
#include "AppController.hpp" #include "AppController.hpp"
#include <wx/stdstream.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <thread> #include <thread>
#include <future> #include <future>
@ -21,40 +25,43 @@
namespace Slic3r { namespace Slic3r {
bool AppControllerBoilerplate::supports_asynch() const bool AppControllerGui::supports_asynch() const
{ {
return true; return true;
} }
void AppControllerBoilerplate::process_events() void AppControllerGui::process_events()
{ {
wxYieldIfNeeded(); wxYieldIfNeeded();
} }
AppControllerBoilerplate::PathList FilePathList AppControllerGui::query_destination_paths(
AppControllerBoilerplate::query_destination_paths(
const std::string &title, const std::string &title,
const std::string &extensions) const const std::string &extensions,
const std::string &/*functionid*/,
const std::string& hint) const
{ {
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) ); wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
dlg.SetWildcard(extensions); dlg.SetWildcard(extensions);
dlg.ShowModal(); dlg.SetFilename(hint);
FilePathList ret;
if(dlg.ShowModal() == wxID_OK) {
wxArrayString paths; wxArrayString paths;
dlg.GetPaths(paths); dlg.GetPaths(paths);
PathList ret(paths.size(), "");
for(auto& p : paths) ret.push_back(p.ToStdString()); for(auto& p : paths) ret.push_back(p.ToStdString());
}
return ret; return ret;
} }
AppControllerBoilerplate::Path FilePath AppControllerGui::query_destination_path(
AppControllerBoilerplate::query_destination_path(
const std::string &title, const std::string &title,
const std::string &extensions, const std::string &extensions,
const std::string &/*functionid*/,
const std::string& hint) const const std::string& hint) const
{ {
wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) ); wxFileDialog dlg(wxTheApp->GetTopWindow(), _(title) );
@ -62,16 +69,16 @@ AppControllerBoilerplate::query_destination_path(
dlg.SetFilename(hint); dlg.SetFilename(hint);
Path ret; FilePath ret;
if(dlg.ShowModal() == wxID_OK) { if(dlg.ShowModal() == wxID_OK) {
ret = Path(dlg.GetPath()); ret = FilePath(dlg.GetPath());
} }
return ret; return ret;
} }
bool AppControllerBoilerplate::report_issue(IssueType issuetype, bool AppControllerGui::report_issue(IssueType issuetype,
const std::string &description, const std::string &description,
const std::string &brief) const std::string &brief)
{ {
@ -89,14 +96,52 @@ bool AppControllerBoilerplate::report_issue(IssueType issuetype,
return ret != wxCANCEL; return ret != wxCANCEL;
} }
bool AppControllerBoilerplate::report_issue( wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent);
AppControllerBoilerplate::IssueType issuetype,
const std::string &description) struct Zipper::Impl {
wxFileName fpath;
wxFFileOutputStream zipfile;
wxZipOutputStream zipstream;
wxStdOutputStream pngstream;
Impl(const std::string& zipfile_path):
fpath(zipfile_path),
zipfile(zipfile_path),
zipstream(zipfile),
pngstream(zipstream)
{ {
return report_issue(issuetype, description, std::string()); if(!zipfile.IsOk())
throw std::runtime_error(L("Cannot create zip file."));
}
};
Zipper::Zipper(const std::string &zipfilepath)
{
m_impl.reset(new Impl(zipfilepath));
} }
wxDEFINE_EVENT(PROGRESS_STATUS_UPDATE_EVENT, wxCommandEvent); Zipper::~Zipper() {}
void Zipper::next_entry(const std::string &fname)
{
m_impl->zipstream.PutNextEntry(fname);
}
std::string Zipper::get_name() const
{
return m_impl->fpath.GetName().ToStdString();
}
std::ostream &Zipper::stream()
{
return m_impl->pngstream;
}
void Zipper::close()
{
m_impl->zipstream.Close();
m_impl->zipfile.Close();
}
namespace { namespace {
@ -107,26 +152,26 @@ namespace {
class GuiProgressIndicator: class GuiProgressIndicator:
public ProgressIndicator, public wxEvtHandler { public ProgressIndicator, public wxEvtHandler {
wxProgressDialog gauge_; wxProgressDialog m_gauge;
using Base = ProgressIndicator; using Base = ProgressIndicator;
wxString message_; wxString m_message;
int range_; wxString title_; int m_range; wxString m_title;
bool is_asynch_ = false; bool m_is_asynch = false;
const int id_ = wxWindow::NewControlId(); const int m_id = wxWindow::NewControlId();
// status update handler // status update handler
void _state( wxCommandEvent& evt) { void _state( wxCommandEvent& evt) {
unsigned st = evt.GetInt(); unsigned st = evt.GetInt();
message_ = evt.GetString(); m_message = evt.GetString();
_state(st); _state(st);
} }
// Status update implementation // Status update implementation
void _state( unsigned st) { void _state( unsigned st) {
if(!gauge_.IsShown()) gauge_.ShowModal(); if(!m_gauge.IsShown()) m_gauge.ShowModal();
Base::state(st); Base::state(st);
if(!gauge_.Update(static_cast<int>(st), message_)) { if(!m_gauge.Update(static_cast<int>(st), m_message)) {
cancel(); cancel();
} }
} }
@ -134,25 +179,25 @@ class GuiProgressIndicator:
public: public:
/// Setting whether it will be used from the UI thread or some worker thread /// Setting whether it will be used from the UI thread or some worker thread
inline void asynch(bool is) { is_asynch_ = is; } inline void asynch(bool is) { m_is_asynch = is; }
/// Get the mode of parallel operation. /// Get the mode of parallel operation.
inline bool asynch() const { return is_asynch_; } inline bool asynch() const { return m_is_asynch; }
inline GuiProgressIndicator(int range, const wxString& title, inline GuiProgressIndicator(int range, const wxString& title,
const wxString& firstmsg) : const wxString& firstmsg) :
gauge_(title, firstmsg, range, wxTheApp->GetTopWindow(), m_gauge(title, firstmsg, range, wxTheApp->GetTopWindow(),
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT), wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT),
message_(firstmsg), m_message(firstmsg),
range_(range), title_(title) m_range(range), m_title(title)
{ {
Base::max(static_cast<float>(range)); Base::max(static_cast<float>(range));
Base::states(static_cast<unsigned>(range)); Base::states(static_cast<unsigned>(range));
Bind(PROGRESS_STATUS_UPDATE_EVENT, Bind(PROGRESS_STATUS_UPDATE_EVENT,
&GuiProgressIndicator::_state, &GuiProgressIndicator::_state,
this, id_); this, m_id);
} }
virtual void state(float val) override { virtual void state(float val) override {
@ -161,33 +206,32 @@ public:
void state(unsigned st) { void state(unsigned st) {
// send status update event // send status update event
if(is_asynch_) { if(m_is_asynch) {
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_); auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, m_id);
evt->SetInt(st); evt->SetInt(st);
evt->SetString(message_); evt->SetString(m_message);
wxQueueEvent(this, evt); wxQueueEvent(this, evt);
} else _state(st); } else _state(st);
} }
virtual void message(const std::string & msg) override { virtual void message(const std::string & msg) override {
message_ = _(msg); m_message = _(msg);
} }
virtual void messageFmt(const std::string& fmt, ...) { virtual void messageFmt(const std::string& fmt, ...) {
va_list arglist; va_list arglist;
va_start(arglist, fmt); va_start(arglist, fmt);
message_ = wxString::Format(_(fmt), arglist); m_message = wxString::Format(_(fmt), arglist);
va_end(arglist); va_end(arglist);
} }
virtual void title(const std::string & title) override { virtual void title(const std::string & title) override {
title_ = _(title); m_title = _(title);
} }
}; };
} }
AppControllerBoilerplate::ProgresIndicatorPtr ProgresIndicatorPtr AppControllerGui::create_progress_indicator(
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, unsigned statenum,
const std::string& title, const std::string& title,
const std::string& firstmsg) const const std::string& firstmsg) const
@ -202,30 +246,23 @@ AppControllerBoilerplate::create_progress_indicator(
return pri; return pri;
} }
AppControllerBoilerplate::ProgresIndicatorPtr
AppControllerBoilerplate::create_progress_indicator(
unsigned statenum, const std::string &title) const
{
return create_progress_indicator(statenum, title, std::string());
}
namespace { namespace {
class Wrapper: public ProgressIndicator, public wxEvtHandler { class Wrapper: public ProgressIndicator, public wxEvtHandler {
ProgressStatusBar *sbar_; ProgressStatusBar *m_sbar;
using Base = ProgressIndicator; using Base = ProgressIndicator;
wxString message_; wxString m_message;
AppControllerBoilerplate& ctl_; AppControllerBase& m_ctl;
void showProgress(bool show = true) { void showProgress(bool show = true) {
sbar_->show_progress(show); m_sbar->show_progress(show);
} }
void _state(unsigned st) { void _state(unsigned st) {
if( st <= ProgressIndicator::max() ) { if( st <= ProgressIndicator::max() ) {
Base::state(st); Base::state(st);
sbar_->set_status_text(message_); m_sbar->set_status_text(m_message);
sbar_->set_progress(st); m_sbar->set_progress(st);
} }
} }
@ -239,11 +276,11 @@ class Wrapper: public ProgressIndicator, public wxEvtHandler {
public: public:
inline Wrapper(ProgressStatusBar *sbar, inline Wrapper(ProgressStatusBar *sbar,
AppControllerBoilerplate& ctl): AppControllerBase& ctl):
sbar_(sbar), ctl_(ctl) m_sbar(sbar), m_ctl(ctl)
{ {
Base::max(static_cast<float>(sbar_->get_range())); Base::max(static_cast<float>(m_sbar->get_range()));
Base::states(static_cast<unsigned>(sbar_->get_range())); Base::states(static_cast<unsigned>(m_sbar->get_range()));
Bind(PROGRESS_STATUS_UPDATE_EVENT, Bind(PROGRESS_STATUS_UPDATE_EVENT,
&Wrapper::_state, &Wrapper::_state,
@ -256,13 +293,13 @@ public:
virtual void max(float val) override { virtual void max(float val) override {
if(val > 1.0) { if(val > 1.0) {
sbar_->set_range(static_cast<int>(val)); m_sbar->set_range(static_cast<int>(val));
ProgressIndicator::max(val); ProgressIndicator::max(val);
} }
} }
void state(unsigned st) { void state(unsigned st) {
if(!ctl_.is_main_thread()) { if(!m_ctl.is_main_thread()) {
auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_); auto evt = new wxCommandEvent(PROGRESS_STATUS_UPDATE_EVENT, id_);
evt->SetInt(st); evt->SetInt(st);
wxQueueEvent(this, evt); wxQueueEvent(this, evt);
@ -272,20 +309,20 @@ public:
} }
virtual void message(const std::string & msg) override { virtual void message(const std::string & msg) override {
message_ = _(msg); m_message = _(msg);
} }
virtual void message_fmt(const std::string& fmt, ...) override { virtual void message_fmt(const std::string& fmt, ...) override {
va_list arglist; va_list arglist;
va_start(arglist, fmt); va_start(arglist, fmt);
message_ = wxString::Format(_(fmt), arglist); m_message = wxString::Format(_(fmt), arglist);
va_end(arglist); va_end(arglist);
} }
virtual void title(const std::string & /*title*/) override {} virtual void title(const std::string & /*title*/) override {}
virtual void on_cancel(CancelFn fn) override { virtual void on_cancel(CancelFn fn) override {
sbar_->set_cancel_callback(fn); m_sbar->set_cancel_callback(fn);
Base::on_cancel(fn); Base::on_cancel(fn);
} }
@ -295,7 +332,8 @@ public:
void AppController::set_global_progress_indicator(ProgressStatusBar *prsb) void AppController::set_global_progress_indicator(ProgressStatusBar *prsb)
{ {
if(prsb) { if(prsb) {
global_progress_indicator(std::make_shared<Wrapper>(prsb, *this)); auto ctl = GUI::get_appctl();
ctl->global_progress_indicator(std::make_shared<Wrapper>(prsb, *ctl));
} }
} }

View File

@ -196,7 +196,11 @@ const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
GLVolume::GLVolume(float r, float g, float b, float a) GLVolume::GLVolume(float r, float g, float b, float a)
: m_offset(Vec3d::Zero()) : m_offset(Vec3d::Zero())
#if ENABLE_MODELINSTANCE_3D_ROTATION
, m_rotation(Vec3d::Zero())
#else
, m_rotation(0.0) , m_rotation(0.0)
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
, m_scaling_factor(1.0) , m_scaling_factor(1.0)
, m_world_matrix(Transform3f::Identity()) , m_world_matrix(Transform3f::Identity())
, m_world_matrix_dirty(true) , m_world_matrix_dirty(true)
@ -255,7 +259,24 @@ void GLVolume::set_render_color()
set_render_color(color, 4); set_render_color(color, 4);
} }
double GLVolume::get_rotation() #if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& GLVolume::get_rotation() const
{
return m_rotation;
}
void GLVolume::set_rotation(const Vec3d& rotation)
{
if (m_rotation != rotation)
{
m_rotation = rotation;
m_world_matrix_dirty = true;
m_transformed_bounding_box_dirty = true;
m_transformed_convex_hull_bounding_box_dirty = true;
}
}
#else
double GLVolume::get_rotation() const
{ {
return m_rotation; return m_rotation;
} }
@ -270,6 +291,7 @@ void GLVolume::set_rotation(double rotation)
m_transformed_convex_hull_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true;
} }
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& GLVolume::get_offset() const const Vec3d& GLVolume::get_offset() const
{ {
@ -327,7 +349,13 @@ const Transform3f& GLVolume::world_matrix() const
{ {
m_world_matrix = Transform3f::Identity(); m_world_matrix = Transform3f::Identity();
m_world_matrix.translate(m_offset.cast<float>()); m_world_matrix.translate(m_offset.cast<float>());
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(2), Vec3f::UnitZ()));
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(1), Vec3f::UnitY()));
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(0), Vec3f::UnitX()));
#else
m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation, Vec3f::UnitZ())); m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation, Vec3f::UnitZ()));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_world_matrix.scale((float)m_scaling_factor); m_world_matrix.scale((float)m_scaling_factor);
m_world_matrix_dirty = false; m_world_matrix_dirty = false;
} }
@ -403,7 +431,13 @@ void GLVolume::render() const
::glCullFace(GL_BACK); ::glCullFace(GL_BACK);
::glPushMatrix(); ::glPushMatrix();
::glTranslated(m_offset(0), m_offset(1), m_offset(2)); ::glTranslated(m_offset(0), m_offset(1), m_offset(2));
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
#else
::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (this->indexed_vertex_array.indexed()) if (this->indexed_vertex_array.indexed())
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
@ -529,7 +563,13 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
::glPushMatrix(); ::glPushMatrix();
::glTranslated(m_offset(0), m_offset(1), m_offset(2)); ::glTranslated(m_offset(0), m_offset(1), m_offset(2));
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
#else
::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (n_triangles > 0) if (n_triangles > 0)
@ -574,7 +614,13 @@ void GLVolume::render_legacy() const
::glPushMatrix(); ::glPushMatrix();
::glTranslated(m_offset(0), m_offset(1), m_offset(2)); ::glTranslated(m_offset(0), m_offset(1), m_offset(2));
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
#else
::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor);
if (n_triangles > 0) if (n_triangles > 0)
@ -698,7 +744,11 @@ std::vector<int> GLVolumeCollection::load_object(
#else #else
v.set_offset(Vec3d(instance->offset(0), instance->offset(1), 0.0)); v.set_offset(Vec3d(instance->offset(0), instance->offset(1), 0.0));
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
v.set_rotation(instance->get_rotation());
#else
v.set_rotation(instance->rotation); v.set_rotation(instance->rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
v.set_scaling_factor(instance->scaling_factor); v.set_scaling_factor(instance->scaling_factor);
} }
} }
@ -2067,12 +2117,30 @@ void _3DScene::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, vo
void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback) void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback)
{ {
#if !ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback); s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
}
void _3DScene::register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback)
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_rotate_3D_callback(canvas, callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} }
void _3DScene::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback) void _3DScene::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback)
{ {
#if !ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_flatten_callback(canvas, callback); s_canvas_mgr.register_on_gizmo_flatten_callback(canvas, callback);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
}
void _3DScene::register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback)
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
s_canvas_mgr.register_on_gizmo_flatten_3D_callback(canvas, callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} }
void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)

View File

@ -256,8 +256,13 @@ public:
private: private:
// Offset of the volume to be rendered. // Offset of the volume to be rendered.
Vec3d m_offset; Vec3d m_offset;
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Rotation around three axes of the volume to be rendered.
Vec3d m_rotation;
#else
// Rotation around Z axis of the volume to be rendered. // Rotation around Z axis of the volume to be rendered.
double m_rotation; double m_rotation;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
// Scale factor of the volume to be rendered. // Scale factor of the volume to be rendered.
double m_scaling_factor; double m_scaling_factor;
// World matrix of the volume to be rendered. // World matrix of the volume to be rendered.
@ -327,8 +332,13 @@ public:
// Sets render color in dependence of current state // Sets render color in dependence of current state
void set_render_color(); void set_render_color();
double get_rotation(); #if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& get_rotation() const;
void set_rotation(const Vec3d& rotation);
#else
double get_rotation() const;
void set_rotation(double rotation); void set_rotation(double rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& get_offset() const; const Vec3d& get_offset() const;
void set_offset(const Vec3d& offset); void set_offset(const Vec3d& offset);
@ -558,7 +568,9 @@ public:
static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback);
static void register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback);
static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
static void register_action_add_callback(wxGLCanvas* canvas, void* callback); static void register_action_add_callback(wxGLCanvas* canvas, void* callback);

View File

@ -1095,6 +1095,9 @@ GLCanvas3D::Mouse::Drag::Drag()
GLCanvas3D::Mouse::Mouse() GLCanvas3D::Mouse::Mouse()
: dragging(false) : dragging(false)
, position(DBL_MAX, DBL_MAX) , position(DBL_MAX, DBL_MAX)
#if ENABLE_GIZMOS_RESET
, ignore_up_event(false)
#endif // ENABLE_GIZMOS_RESET
{ {
} }
@ -1181,9 +1184,11 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent)
return false; return false;
} }
#if !ENABLE_MODELINSTANCE_3D_ROTATION
// temporary disable x and y grabbers // temporary disable x and y grabbers
gizmo->disable_grabber(0); gizmo->disable_grabber(0);
gizmo->disable_grabber(1); gizmo->disable_grabber(1);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo)); m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
@ -1349,6 +1354,18 @@ void GLCanvas3D::Gizmos::update(const Linef3& mouse_ray)
curr->update(mouse_ray); curr->update(mouse_ray);
} }
#if ENABLE_GIZMOS_RESET
void GLCanvas3D::Gizmos::process_double_click()
{
if (!m_enabled)
return;
GLGizmoBase* curr = _get_current();
if (curr != nullptr)
curr->process_double_click();
}
#endif // ENABLE_GIZMOS_RESET
GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const GLCanvas3D::Gizmos::EType GLCanvas3D::Gizmos::get_current_type() const
{ {
return m_current; return m_current;
@ -1421,6 +1438,35 @@ void GLCanvas3D::Gizmos::set_scale(float scale)
reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale); reinterpret_cast<GLGizmoScale3D*>(it->second)->set_scale(scale);
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d GLCanvas3D::Gizmos::get_rotation() const
{
if (!m_enabled)
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoRotate3D*>(it->second)->get_rotation() : Vec3d::Zero();
}
void GLCanvas3D::Gizmos::set_rotation(const Vec3d& rotation)
{
if (!m_enabled)
return;
GizmosMap::const_iterator it = m_gizmos.find(Rotate);
if (it != m_gizmos.end())
reinterpret_cast<GLGizmoRotate3D*>(it->second)->set_rotation(rotation);
}
Vec3d GLCanvas3D::Gizmos::get_flattening_rotation() const
{
if (!m_enabled)
return Vec3d::Zero();
GizmosMap::const_iterator it = m_gizmos.find(Flatten);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_rotation() : Vec3d::Zero();
}
#else
float GLCanvas3D::Gizmos::get_angle_z() const float GLCanvas3D::Gizmos::get_angle_z() const
{ {
if (!m_enabled) if (!m_enabled)
@ -1448,6 +1494,7 @@ Vec3d GLCanvas3D::Gizmos::get_flattening_normal() const
GizmosMap::const_iterator it = m_gizmos.find(Flatten); GizmosMap::const_iterator it = m_gizmos.find(Flatten);
return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_normal() : Vec3d::Zero(); return (it != m_gizmos.end()) ? reinterpret_cast<GLGizmoFlatten*>(it->second)->get_flattening_normal() : Vec3d::Zero();
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object) void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object)
{ {
@ -2385,7 +2432,11 @@ void GLCanvas3D::update_gizmos_data()
m_gizmos.set_position(Vec3d(model_instance->offset(0), model_instance->offset(1), 0.0)); m_gizmos.set_position(Vec3d(model_instance->offset(0), model_instance->offset(1), 0.0));
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
m_gizmos.set_scale(model_instance->scaling_factor); m_gizmos.set_scale(model_instance->scaling_factor);
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_rotation(model_instance->get_rotation());
#else
m_gizmos.set_angle_z(model_instance->rotation); m_gizmos.set_angle_z(model_instance->rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_flattening_data(model_object); m_gizmos.set_flattening_data(model_object);
} }
} }
@ -2394,7 +2445,11 @@ void GLCanvas3D::update_gizmos_data()
{ {
m_gizmos.set_position(Vec3d::Zero()); m_gizmos.set_position(Vec3d::Zero());
m_gizmos.set_scale(1.0f); m_gizmos.set_scale(1.0f);
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_rotation(Vec3d::Zero());
#else
m_gizmos.set_angle_z(0.0f); m_gizmos.set_angle_z(0.0f);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_gizmos.set_flattening_data(nullptr); m_gizmos.set_flattening_data(nullptr);
} }
} }
@ -2757,6 +2812,19 @@ void GLCanvas3D::register_on_gizmo_scale_uniformly_callback(void* callback)
m_on_gizmo_scale_uniformly_callback.register_callback(callback); m_on_gizmo_scale_uniformly_callback.register_callback(callback);
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3D::register_on_gizmo_rotate_3D_callback(void* callback)
{
if (callback != nullptr)
m_on_gizmo_rotate_3D_callback.register_callback(callback);
}
void GLCanvas3D::register_on_gizmo_flatten_3D_callback(void* callback)
{
if (callback != nullptr)
m_on_gizmo_flatten_3D_callback.register_callback(callback);
}
#else
void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback) void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback)
{ {
if (callback != nullptr) if (callback != nullptr)
@ -2768,6 +2836,7 @@ void GLCanvas3D::register_on_gizmo_flatten_callback(void* callback)
if (callback != nullptr) if (callback != nullptr)
m_on_gizmo_flatten_callback.register_callback(callback); m_on_gizmo_flatten_callback.register_callback(callback);
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3D::register_on_update_geometry_info_callback(void* callback) void GLCanvas3D::register_on_update_geometry_info_callback(void* callback)
{ {
@ -3043,6 +3112,41 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_toolbar_action_running = true; m_toolbar_action_running = true;
m_toolbar.do_action((unsigned int)toolbar_contains_mouse); m_toolbar.do_action((unsigned int)toolbar_contains_mouse);
} }
#if ENABLE_GIZMOS_RESET
else if (evt.LeftDClick() && m_gizmos.grabber_contains_mouse())
{
#if ENABLE_GIZMOS_RESET
m_mouse.ignore_up_event = true;
#endif // ENABLE_GIZMOS_RESET
m_gizmos.process_double_click();
switch (m_gizmos.get_current_type())
{
case Gizmos::Scale:
{
m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale());
update_scale_values();
m_dirty = true;
break;
}
case Gizmos::Rotate:
{
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& rotation = m_gizmos.get_rotation();
m_on_gizmo_rotate_3D_callback.call(rotation(0), rotation(1), rotation(2));
#else
m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z());
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
update_rotation_values();
m_dirty = true;
break;
}
default:
{
break;
}
}
}
#endif // ENABLE_GIZMOS_RESET
else if (evt.LeftDown() || evt.RightDown()) else if (evt.LeftDown() || evt.RightDown())
{ {
// If user pressed left or right button we first check whether this happened // If user pressed left or right button we first check whether this happened
@ -3083,6 +3187,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx);
if (m_gizmos.get_current_type() == Gizmos::Flatten) { if (m_gizmos.get_current_type() == Gizmos::Flatten) {
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Rotate the object so the normal points downward:
const Vec3d& rotation = m_gizmos.get_flattening_rotation();
m_on_gizmo_flatten_3D_callback.call(rotation(0), rotation(1), rotation(2));
#else
// Rotate the object so the normal points downward: // Rotate the object so the normal points downward:
Vec3d normal = m_gizmos.get_flattening_normal(); Vec3d normal = m_gizmos.get_flattening_normal();
if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) { if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) {
@ -3090,6 +3199,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
float angle = acos(clamp(-1.0, 1.0, -normal(2))); float angle = acos(clamp(-1.0, 1.0, -normal(2)));
m_on_gizmo_flatten_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2)); m_on_gizmo_flatten_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2));
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} }
m_dirty = true; m_dirty = true;
@ -3272,6 +3382,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
} }
case Gizmos::Rotate: case Gizmos::Rotate:
{ {
#if ENABLE_MODELINSTANCE_3D_ROTATION
// Apply new temporary rotation
Vec3d rotation = m_gizmos.get_rotation();
for (GLVolume* v : volumes)
{
v->set_rotation(rotation);
}
update_rotation_value(rotation);
#else
// Apply new temporary angle_z // Apply new temporary angle_z
float angle_z = m_gizmos.get_angle_z(); float angle_z = m_gizmos.get_angle_z();
for (GLVolume* v : volumes) for (GLVolume* v : volumes)
@ -3279,6 +3398,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
v->set_rotation((double)angle_z); v->set_rotation((double)angle_z);
} }
update_rotation_value((double)angle_z, Z); update_rotation_value((double)angle_z, Z);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
break; break;
} }
default: default:
@ -3377,12 +3497,20 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled()) else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging() && !is_layers_editing_enabled())
{ {
// deselect and propagate event through callback // deselect and propagate event through callback
#if ENABLE_GIZMOS_RESET
if (!m_mouse.ignore_up_event && m_picking_enabled && !m_toolbar_action_running)
#else
if (m_picking_enabled && !m_toolbar_action_running) if (m_picking_enabled && !m_toolbar_action_running)
#endif // ENABLE_GIZMOS_RESET
{ {
deselect_volumes(); deselect_volumes();
_on_select(-1, -1); _on_select(-1, -1);
update_gizmos_data(); update_gizmos_data();
} }
#if ENABLE_GIZMOS_RESET
else if (m_mouse.ignore_up_event)
m_mouse.ignore_up_event = false;
#endif // ENABLE_GIZMOS_RESET
} }
else if (evt.LeftUp() && m_gizmos.is_dragging()) else if (evt.LeftUp() && m_gizmos.is_dragging())
{ {
@ -3416,14 +3544,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
} }
case Gizmos::Rotate: case Gizmos::Rotate:
{ {
#if ENABLE_MODELINSTANCE_3D_ROTATION
const Vec3d& rotation = m_gizmos.get_rotation();
m_on_gizmo_rotate_3D_callback.call(rotation(0), rotation(1), rotation(2));
#else
m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z());
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
break; break;
} }
default: default:
break; break;
} }
m_gizmos.stop_dragging(); m_gizmos.stop_dragging();
Slic3r::GUI::update_settings_value(); update_settings_value();
} }
m_mouse.drag.move_volume_idx = -1; m_mouse.drag.move_volume_idx = -1;
@ -3863,8 +3996,13 @@ void GLCanvas3D::_deregister_callbacks()
m_on_wipe_tower_moved_callback.deregister_callback(); m_on_wipe_tower_moved_callback.deregister_callback();
m_on_enable_action_buttons_callback.deregister_callback(); m_on_enable_action_buttons_callback.deregister_callback();
m_on_gizmo_scale_uniformly_callback.deregister_callback(); m_on_gizmo_scale_uniformly_callback.deregister_callback();
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_on_gizmo_rotate_3D_callback.deregister_callback();
m_on_gizmo_flatten_3D_callback.deregister_callback();
#else
m_on_gizmo_rotate_callback.deregister_callback(); m_on_gizmo_rotate_callback.deregister_callback();
m_on_gizmo_flatten_callback.deregister_callback(); m_on_gizmo_flatten_callback.deregister_callback();
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
m_on_update_geometry_info_callback.deregister_callback(); m_on_update_geometry_info_callback.deregister_callback();
m_action_add_callback.deregister_callback(); m_action_add_callback.deregister_callback();

View File

@ -315,6 +315,9 @@ class GLCanvas3D
bool dragging; bool dragging;
Vec2d position; Vec2d position;
Drag drag; Drag drag;
#if ENABLE_GIZMOS_RESET
bool ignore_up_event;
#endif // ENABLE_GIZMOS_RESET
Mouse(); Mouse();
@ -366,6 +369,9 @@ class GLCanvas3D
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
bool grabber_contains_mouse() const; bool grabber_contains_mouse() const;
void update(const Linef3& mouse_ray); void update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
void process_double_click();
#endif // ENABLE_GIZMOS_RESET
EType get_current_type() const; EType get_current_type() const;
@ -381,11 +387,20 @@ class GLCanvas3D
float get_scale() const; float get_scale() const;
void set_scale(float scale); void set_scale(float scale);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_rotation() const;
void set_rotation(const Vec3d& rotation);
#else
float get_angle_z() const; float get_angle_z() const;
void set_angle_z(float angle_z); void set_angle_z(float angle_z);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_flattening_data(const ModelObject* model_object); #if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_flattening_rotation() const;
#else
Vec3d get_flattening_normal() const; Vec3d get_flattening_normal() const;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_flattening_data(const ModelObject* model_object);
void render_current_gizmo(const BoundingBoxf3& box) const; void render_current_gizmo(const BoundingBoxf3& box) const;
@ -501,8 +516,13 @@ class GLCanvas3D
PerlCallback m_on_wipe_tower_moved_callback; PerlCallback m_on_wipe_tower_moved_callback;
PerlCallback m_on_enable_action_buttons_callback; PerlCallback m_on_enable_action_buttons_callback;
PerlCallback m_on_gizmo_scale_uniformly_callback; PerlCallback m_on_gizmo_scale_uniformly_callback;
#if ENABLE_MODELINSTANCE_3D_ROTATION
PerlCallback m_on_gizmo_rotate_3D_callback;
PerlCallback m_on_gizmo_flatten_3D_callback;
#else
PerlCallback m_on_gizmo_rotate_callback; PerlCallback m_on_gizmo_rotate_callback;
PerlCallback m_on_gizmo_flatten_callback; PerlCallback m_on_gizmo_flatten_callback;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
PerlCallback m_on_update_geometry_info_callback; PerlCallback m_on_update_geometry_info_callback;
PerlCallback m_action_add_callback; PerlCallback m_action_add_callback;
@ -626,8 +646,13 @@ public:
void register_on_wipe_tower_moved_callback(void* callback); void register_on_wipe_tower_moved_callback(void* callback);
void register_on_enable_action_buttons_callback(void* callback); void register_on_enable_action_buttons_callback(void* callback);
void register_on_gizmo_scale_uniformly_callback(void* callback); void register_on_gizmo_scale_uniformly_callback(void* callback);
#if ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_gizmo_rotate_3D_callback(void* callback);
void register_on_gizmo_flatten_3D_callback(void* callback);
#else
void register_on_gizmo_rotate_callback(void* callback); void register_on_gizmo_rotate_callback(void* callback);
void register_on_gizmo_flatten_callback(void* callback); void register_on_gizmo_flatten_callback(void* callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_update_geometry_info_callback(void* callback); void register_on_update_geometry_info_callback(void* callback);
void register_action_add_callback(void* callback); void register_action_add_callback(void* callback);

View File

@ -699,6 +699,21 @@ void GLCanvas3DManager::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* c
it->second->register_on_gizmo_scale_uniformly_callback(callback); it->second->register_on_gizmo_scale_uniformly_callback(callback);
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3DManager::register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_on_gizmo_rotate_3D_callback(callback);
}
void GLCanvas3DManager::register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback)
{
CanvasesMap::iterator it = _get_canvas(canvas);
if (it != m_canvases.end())
it->second->register_on_gizmo_flatten_3D_callback(callback);
}
#else
void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback) void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback)
{ {
CanvasesMap::iterator it = _get_canvas(canvas); CanvasesMap::iterator it = _get_canvas(canvas);
@ -712,6 +727,7 @@ void GLCanvas3DManager::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, v
if (it != m_canvases.end()) if (it != m_canvases.end())
it->second->register_on_gizmo_flatten_callback(callback); it->second->register_on_gizmo_flatten_callback(callback);
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback)
{ {

View File

@ -163,8 +163,13 @@ public:
void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback); void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback);
void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback);
#if ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback);
#else
void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback);
void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback);
void register_action_add_callback(wxGLCanvas* canvas, void* callback); void register_action_add_callback(wxGLCanvas* canvas, void* callback);

View File

@ -759,6 +759,20 @@ void GLGizmoScale3D::on_update(const Linef3& mouse_ray)
do_scale_uniform(mouse_ray); do_scale_uniform(mouse_ray);
} }
#if ENABLE_GIZMOS_RESET
void GLGizmoScale3D::on_process_double_click()
{
if ((m_hover_id == 0) || (m_hover_id == 1))
m_scale(0) = 1.0;
else if ((m_hover_id == 2) || (m_hover_id == 3))
m_scale(1) = 1.0;
else if ((m_hover_id == 4) || (m_hover_id == 5))
m_scale(2) = 1.0;
else if (m_hover_id >= 6)
m_scale = Vec3d::Ones();
}
#endif // ENABLE_GIZMOS_RESET
void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const void GLGizmoScale3D::on_render(const BoundingBoxf3& box) const
{ {
if (m_grabbers[0].dragging || m_grabbers[1].dragging) if (m_grabbers[0].dragging || m_grabbers[1].dragging)
@ -1237,15 +1251,28 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const
::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f);
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
for (const InstanceData& inst : m_instances) {
Vec3d position = inst.position + dragged_offset;
#else
for (Vec3d offset : m_instances_positions) { for (Vec3d offset : m_instances_positions) {
offset += dragged_offset; offset += dragged_offset;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
for (Vec2d offset : m_instances_positions) { for (Vec2d offset : m_instances_positions) {
offset += to_2d(dragged_offset); offset += to_2d(dragged_offset);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
::glPushMatrix(); ::glPushMatrix();
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glTranslated(position(0), position(1), position(2));
::glRotated(inst.rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(inst.rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(inst.rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
::glScaled(inst.scaling_factor, inst.scaling_factor, inst.scaling_factor);
#else
::glTranslated(offset(0), offset(1), offset(2)); ::glTranslated(offset(0), offset(1), offset(2));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f); ::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -1268,13 +1295,25 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const
{ {
::glColor3f(1.0f, 1.0f, picking_color_component(i)); ::glColor3f(1.0f, 1.0f, picking_color_component(i));
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
for (const InstanceData& inst : m_instances) {
#else
for (const Vec3d& offset : m_instances_positions) { for (const Vec3d& offset : m_instances_positions) {
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
for (const Vec2d& offset : m_instances_positions) { for (const Vec2d& offset : m_instances_positions) {
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
::glPushMatrix(); ::glPushMatrix();
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
::glTranslated(inst.position(0), inst.position(1), inst.position(2));
::glRotated(inst.rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0);
::glRotated(inst.rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0);
::glRotated(inst.rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0);
::glScaled(inst.scaling_factor, inst.scaling_factor, inst.scaling_factor);
#else
::glTranslated(offset(0), offset(1), offset(2)); ::glTranslated(offset(0), offset(1), offset(2));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f); ::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -1293,10 +1332,18 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
// ...and save the updated positions of the object instances: // ...and save the updated positions of the object instances:
if (m_model_object && !m_model_object->instances.empty()) { if (m_model_object && !m_model_object->instances.empty()) {
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_instances.clear();
#else
m_instances_positions.clear(); m_instances_positions.clear();
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
for (const auto* instance : m_model_object->instances) for (const auto* instance : m_model_object->instances)
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
m_instances.emplace_back(instance->get_offset(), instance->get_rotation(), instance->scaling_factor);
#else
m_instances_positions.emplace_back(instance->get_offset()); m_instances_positions.emplace_back(instance->get_offset());
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
m_instances_positions.emplace_back(instance->offset); m_instances_positions.emplace_back(instance->offset);
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -1312,8 +1359,10 @@ void GLGizmoFlatten::update_planes()
for (const ModelVolume* vol : m_model_object->volumes) for (const ModelVolume* vol : m_model_object->volumes)
ch.merge(vol->get_convex_hull()); ch.merge(vol->get_convex_hull());
ch = ch.convex_hull_3d(); ch = ch.convex_hull_3d();
#if !ENABLE_MODELINSTANCE_3D_ROTATION
ch.scale(m_model_object->instances.front()->scaling_factor); ch.scale(m_model_object->instances.front()->scaling_factor);
ch.rotate_z(m_model_object->instances.front()->rotation); ch.rotate_z(m_model_object->instances.front()->rotation);
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
m_planes.clear(); m_planes.clear();
@ -1462,8 +1511,10 @@ void GLGizmoFlatten::update_planes()
m_source_data.bounding_boxes.clear(); m_source_data.bounding_boxes.clear();
for (const auto& vol : m_model_object->volumes) for (const auto& vol : m_model_object->volumes)
m_source_data.bounding_boxes.push_back(vol->get_convex_hull().bounding_box()); m_source_data.bounding_boxes.push_back(vol->get_convex_hull().bounding_box());
#if !ENABLE_MODELINSTANCE_3D_ROTATION
m_source_data.scaling_factor = m_model_object->instances.front()->scaling_factor; m_source_data.scaling_factor = m_model_object->instances.front()->scaling_factor;
m_source_data.rotation = m_model_object->instances.front()->rotation; m_source_data.rotation = m_model_object->instances.front()->rotation;
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex(); const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex();
m_source_data.mesh_first_point = Vec3d((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]); m_source_data.mesh_first_point = Vec3d((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]);
} }
@ -1475,9 +1526,13 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
if (m_state != On || !m_model_object || m_model_object->instances.empty()) if (m_state != On || !m_model_object || m_model_object->instances.empty())
return false; return false;
#if ENABLE_MODELINSTANCE_3D_ROTATION
if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size())
#else
if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size() if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size()
|| m_model_object->instances.front()->scaling_factor != m_source_data.scaling_factor || m_model_object->instances.front()->scaling_factor != m_source_data.scaling_factor
|| m_model_object->instances.front()->rotation != m_source_data.rotation) || m_model_object->instances.front()->rotation != m_source_data.rotation)
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
return true; return true;
// now compare the bounding boxes: // now compare the bounding boxes:
@ -1493,11 +1548,22 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
return false; return false;
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d GLGizmoFlatten::get_flattening_rotation() const
{
// calculates the rotations in model space
Eigen::Quaterniond q;
Vec3d angles = q.setFromTwoVectors(m_normal, -Vec3d::UnitZ()).toRotationMatrix().eulerAngles(2, 1, 0);
m_normal = Vec3d::Zero();
return Vec3d(angles(2), angles(1), angles(0));
}
#else
Vec3d GLGizmoFlatten::get_flattening_normal() const { Vec3d GLGizmoFlatten::get_flattening_normal() const {
Vec3d normal = m_model_object->instances.front()->world_matrix(true).matrix().block(0, 0, 3, 3).inverse() * m_normal; Vec3d normal = m_model_object->instances.front()->world_matrix(true).matrix().block(0, 0, 3, 3).inverse() * m_normal;
m_normal = Vec3d::Zero(); m_normal = Vec3d::Zero();
return normal.normalized(); return normal.normalized();
} }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -94,6 +94,10 @@ public:
void update(const Linef3& mouse_ray); void update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
void process_double_click() { on_process_double_click(); }
#endif // ENABLE_GIZMOS_RESET
void render(const BoundingBoxf3& box) const { on_render(box); } void render(const BoundingBoxf3& box) const { on_render(box); }
void render_for_picking(const BoundingBoxf3& box) const { on_render_for_picking(box); } void render_for_picking(const BoundingBoxf3& box) const { on_render_for_picking(box); }
@ -106,6 +110,9 @@ protected:
virtual void on_start_dragging(const BoundingBoxf3& box) {} virtual void on_start_dragging(const BoundingBoxf3& box) {}
virtual void on_stop_dragging() {} virtual void on_stop_dragging() {}
virtual void on_update(const Linef3& mouse_ray) = 0; virtual void on_update(const Linef3& mouse_ray) = 0;
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click() {}
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const = 0; virtual void on_render(const BoundingBoxf3& box) const = 0;
virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0; virtual void on_render_for_picking(const BoundingBoxf3& box) const = 0;
@ -155,6 +162,9 @@ protected:
virtual bool on_init(); virtual bool on_init();
virtual void on_start_dragging(const BoundingBoxf3& box); virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_update(const Linef3& mouse_ray); virtual void on_update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click() { m_angle = 0.0; }
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const;
@ -178,6 +188,10 @@ class GLGizmoRotate3D : public GLGizmoBase
public: public:
explicit GLGizmoRotate3D(GLCanvas3D& parent); explicit GLGizmoRotate3D(GLCanvas3D& parent);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
#else
double get_angle_x() const { return m_gizmos[X].get_angle(); } double get_angle_x() const { return m_gizmos[X].get_angle(); }
void set_angle_x(double angle) { m_gizmos[X].set_angle(angle); } void set_angle_x(double angle) { m_gizmos[X].set_angle(angle); }
@ -186,6 +200,7 @@ public:
double get_angle_z() const { return m_gizmos[Z].get_angle(); } double get_angle_z() const { return m_gizmos[Z].get_angle(); }
void set_angle_z(double angle) { m_gizmos[Z].set_angle(angle); } void set_angle_z(double angle) { m_gizmos[Z].set_angle(angle); }
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
protected: protected:
virtual bool on_init(); virtual bool on_init();
@ -222,6 +237,13 @@ protected:
g.update(mouse_ray); g.update(mouse_ray);
} }
} }
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click()
{
if (m_hover_id != -1)
m_gizmos[m_hover_id].process_double_click();
}
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const virtual void on_render_for_picking(const BoundingBoxf3& box) const
{ {
@ -265,6 +287,9 @@ protected:
virtual void on_start_dragging(const BoundingBoxf3& box); virtual void on_start_dragging(const BoundingBoxf3& box);
virtual void on_stop_dragging() { m_show_starting_box = false; } virtual void on_stop_dragging() { m_show_starting_box = false; }
virtual void on_update(const Linef3& mouse_ray); virtual void on_update(const Linef3& mouse_ray);
#if ENABLE_GIZMOS_RESET
virtual void on_process_double_click();
#endif // ENABLE_GIZMOS_RESET
virtual void on_render(const BoundingBoxf3& box) const; virtual void on_render(const BoundingBoxf3& box) const;
virtual void on_render_for_picking(const BoundingBoxf3& box) const; virtual void on_render_for_picking(const BoundingBoxf3& box) const;
@ -320,8 +345,10 @@ private:
}; };
struct SourceDataSummary { struct SourceDataSummary {
std::vector<BoundingBoxf3> bounding_boxes; // bounding boxes of convex hulls of individual volumes std::vector<BoundingBoxf3> bounding_boxes; // bounding boxes of convex hulls of individual volumes
#if !ENABLE_MODELINSTANCE_3D_ROTATION
float scaling_factor; float scaling_factor;
float rotation; float rotation;
#endif // !ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d mesh_first_point; Vec3d mesh_first_point;
}; };
@ -330,7 +357,19 @@ private:
std::vector<PlaneData> m_planes; std::vector<PlaneData> m_planes;
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
struct InstanceData
{
Vec3d position;
Vec3d rotation;
double scaling_factor;
InstanceData(const Vec3d& position, const Vec3d& rotation, double scaling_factor) : position(position), rotation(rotation), scaling_factor(scaling_factor) {}
};
std::vector<InstanceData> m_instances;
#else
Pointf3s m_instances_positions; Pointf3s m_instances_positions;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
#else #else
std::vector<Vec2d> m_instances_positions; std::vector<Vec2d> m_instances_positions;
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
@ -344,7 +383,11 @@ public:
explicit GLGizmoFlatten(GLCanvas3D& parent); explicit GLGizmoFlatten(GLCanvas3D& parent);
void set_flattening_data(const ModelObject* model_object); void set_flattening_data(const ModelObject* model_object);
#if ENABLE_MODELINSTANCE_3D_ROTATION
Vec3d get_flattening_rotation() const;
#else
Vec3d get_flattening_normal() const; Vec3d get_flattening_normal() const;
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
protected: protected:
virtual bool on_init(); virtual bool on_init();

View File

@ -1,4 +1,5 @@
#include "GUI.hpp" #include "GUI.hpp"
#include "../AppController.hpp"
#include "WipeTowerDialog.hpp" #include "WipeTowerDialog.hpp"
#include <assert.h> #include <assert.h>
@ -1405,4 +1406,23 @@ void desktop_open_datadir_folder()
#endif #endif
} }
namespace {
AppControllerPtr g_appctl;
}
AppControllerPtr get_appctl()
{
return g_appctl;
}
void set_cli_appctl()
{
g_appctl = std::make_shared<AppControllerCli>();
}
void set_gui_appctl()
{
g_appctl = std::make_shared<AppControllerGui>();
}
} } } }

View File

@ -42,6 +42,9 @@ class TabIface;
class PreviewIface; class PreviewIface;
class Print; class Print;
class GCodePreviewData; class GCodePreviewData;
class AppControllerBase;
using AppControllerPtr = std::shared_ptr<AppControllerBase>;
#define _(s) Slic3r::GUI::I18N::translate((s)) #define _(s) Slic3r::GUI::I18N::translate((s))
@ -129,6 +132,10 @@ ProgressStatusBar* get_progress_status_bar();
wxNotebook * get_tab_panel(); wxNotebook * get_tab_panel();
wxNotebook* get_tab_panel(); wxNotebook* get_tab_panel();
AppControllerPtr get_appctl();
void set_cli_appctl();
void set_gui_appctl();
const wxColour& get_label_clr_modified(); const wxColour& get_label_clr_modified();
const wxColour& get_label_clr_sys(); const wxColour& get_label_clr_sys();
const wxColour& get_label_clr_default(); const wxColour& get_label_clr_default();

View File

@ -1802,11 +1802,15 @@ void update_scale_values(double scaling_factor)
void update_rotation_values() void update_rotation_values()
{ {
#if ENABLE_MODELINSTANCE_3D_ROTATION
update_rotation_value((*m_objects)[m_selected_object_id]->instances.front()->get_rotation());
#else
auto og = get_optgroup(ogFrequentlyObjectSettings); auto og = get_optgroup(ogFrequentlyObjectSettings);
auto instance = (*m_objects)[m_selected_object_id]->instances.front(); auto instance = (*m_objects)[m_selected_object_id]->instances.front();
og->set_value("rotation_x", 0); og->set_value("rotation_x", 0);
og->set_value("rotation_y", 0); og->set_value("rotation_y", 0);
og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation))); og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation)));
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
} }
void update_rotation_value(double angle, Axis axis) void update_rotation_value(double angle, Axis axis)
@ -1836,6 +1840,16 @@ void update_rotation_value(double angle, Axis axis)
og->set_value(axis_str, int(Geometry::rad2deg(angle))); og->set_value(axis_str, int(Geometry::rad2deg(angle)));
} }
#if ENABLE_MODELINSTANCE_3D_ROTATION
void update_rotation_value(const Vec3d& rotation)
{
auto og = get_optgroup(ogFrequentlyObjectSettings);
og->set_value("rotation_x", int(Geometry::rad2deg(rotation(0))));
og->set_value("rotation_y", int(Geometry::rad2deg(rotation(1))));
og->set_value("rotation_z", int(Geometry::rad2deg(rotation(2))));
}
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_uniform_scaling(const bool uniform_scale) void set_uniform_scaling(const bool uniform_scale)
{ {
g_is_uniform_scale = uniform_scale; g_is_uniform_scale = uniform_scale;

View File

@ -124,6 +124,9 @@ void update_scale_values(double scaling_factor);
void update_rotation_values(); void update_rotation_values();
// update rotation value after "gizmos" // update rotation value after "gizmos"
void update_rotation_value(double angle, Axis axis); void update_rotation_value(double angle, Axis axis);
#if ENABLE_MODELINSTANCE_3D_ROTATION
void update_rotation_value(const Vec3d& rotation);
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_uniform_scaling(const bool uniform_scale); void set_uniform_scaling(const bool uniform_scale);
void on_begin_drag(wxDataViewEvent &event); void on_begin_drag(wxDataViewEvent &event);

View File

@ -153,19 +153,19 @@ bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, Print* prin
// sets colors for gcode preview extrusion roles // sets colors for gcode preview extrusion roles
std::vector<std::string> extrusion_roles_colors = { std::vector<std::string> extrusion_roles_colors = {
"FFFF66", // Perimeter "Perimeter", "FFFF66",
"FFA500", // External perimeter "External perimeter", "FFA500",
"0000FF", // Overhang perimeter "Overhang perimeter", "0000FF",
"B1302A", // Internal infill "Internal infill", "B1302A",
"D732D7", // Solid infill "Solid infill", "D732D7",
"FF1A1A", // Top solid infill "Top solid infill", "FF1A1A",
"9999FF", // Bridge infill "Bridge infill", "9999FF",
"FFFFFF", // Gap fill "Gap fill", "FFFFFF",
"845321", // Skirt "Skirt", "845321",
"00FF00", // Support material "Support material", "00FF00",
"008000", // Support material interface "Support material interface", "008000",
"B3E3AB", // Wipe tower "Wipe tower", "B3E3AB",
"28CC94" // Custom "Custom", "28CC94"
}; };
m_gcode_preview_data->set_extrusion_paths_colors(extrusion_roles_colors); m_gcode_preview_data->set_extrusion_paths_colors(extrusion_roles_colors);

View File

@ -14,31 +14,31 @@ public:
using CancelFn = std::function<void(void)>; // Cancel function signature. using CancelFn = std::function<void(void)>; // Cancel function signature.
private: private:
float state_ = .0f, max_ = 1.f, step_; float m_state = .0f, m_max = 1.f, m_step;
CancelFn cancelfunc_ = [](){}; CancelFn m_cancelfunc = [](){};
public: public:
inline virtual ~ProgressIndicator() {} inline virtual ~ProgressIndicator() {}
/// Get the maximum of the progress range. /// Get the maximum of the progress range.
float max() const { return max_; } float max() const { return m_max; }
/// Get the current progress state /// Get the current progress state
float state() const { return state_; } float state() const { return m_state; }
/// Set the maximum of the progress range /// Set the maximum of the progress range
virtual void max(float maxval) { max_ = maxval; } virtual void max(float maxval) { m_max = maxval; }
/// Set the current state of the progress. /// Set the current state of the progress.
virtual void state(float val) { state_ = val; } virtual void state(float val) { m_state = val; }
/** /**
* @brief Number of states int the progress. Can be used instead of giving a * @brief Number of states int the progress. Can be used instead of giving a
* maximum value. * maximum value.
*/ */
virtual void states(unsigned statenum) { virtual void states(unsigned statenum) {
step_ = max_ / statenum; m_step = m_max / statenum;
} }
/// Message shown on the next status update. /// Message shown on the next status update.
@ -51,13 +51,13 @@ public:
virtual void message_fmt(const std::string& fmt, ...); virtual void message_fmt(const std::string& fmt, ...);
/// Set up a cancel callback for the operation if feasible. /// Set up a cancel callback for the operation if feasible.
virtual void on_cancel(CancelFn func = CancelFn()) { cancelfunc_ = func; } virtual void on_cancel(CancelFn func = CancelFn()) { m_cancelfunc = func; }
/** /**
* Explicitly shut down the progress indicator and call the associated * Explicitly shut down the progress indicator and call the associated
* callback. * callback.
*/ */
virtual void cancel() { cancelfunc_(); } virtual void cancel() { m_cancelfunc(); }
/// Convenience function to call message and status update in one function. /// Convenience function to call message and status update in one function.
void update(float st, const std::string& msg) { void update(float st, const std::string& msg) {

View File

@ -14,117 +14,117 @@ namespace Slic3r {
ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id): ProgressStatusBar::ProgressStatusBar(wxWindow *parent, int id):
self(new wxStatusBar(parent ? parent : GUI::get_main_frame(), self(new wxStatusBar(parent ? parent : GUI::get_main_frame(),
id == -1? wxID_ANY : id)), id == -1? wxID_ANY : id)),
timer_(new wxTimer(self)), m_timer(new wxTimer(self)),
prog_ (new wxGauge(self, m_prog (new wxGauge(self,
wxGA_HORIZONTAL, wxGA_HORIZONTAL,
100, 100,
wxDefaultPosition, wxDefaultPosition,
wxDefaultSize)), wxDefaultSize)),
cancelbutton_(new wxButton(self, m_cancelbutton(new wxButton(self,
-1, -1,
"Cancel", "Cancel",
wxDefaultPosition, wxDefaultPosition,
wxDefaultSize)) wxDefaultSize))
{ {
prog_->Hide(); m_prog->Hide();
cancelbutton_->Hide(); m_cancelbutton->Hide();
self->SetFieldsCount(3); self->SetFieldsCount(3);
int w[] = {-1, 150, 155}; int w[] = {-1, 150, 155};
self->SetStatusWidths(3, w); self->SetStatusWidths(3, w);
self->Bind(wxEVT_TIMER, [this](const wxTimerEvent&) { self->Bind(wxEVT_TIMER, [this](const wxTimerEvent&) {
if (prog_->IsShown()) timer_->Stop(); if (m_prog->IsShown()) m_timer->Stop();
if(is_busy()) prog_->Pulse(); if(is_busy()) m_prog->Pulse();
}); });
self->Bind(wxEVT_SIZE, [this](wxSizeEvent& event){ self->Bind(wxEVT_SIZE, [this](wxSizeEvent& event){
wxRect rect; wxRect rect;
self->GetFieldRect(1, rect); self->GetFieldRect(1, rect);
auto offset = 0; auto offset = 0;
cancelbutton_->Move(rect.GetX() + offset, rect.GetY() + offset); m_cancelbutton->Move(rect.GetX() + offset, rect.GetY() + offset);
cancelbutton_->SetSize(rect.GetWidth() - offset, rect.GetHeight()); m_cancelbutton->SetSize(rect.GetWidth() - offset, rect.GetHeight());
self->GetFieldRect(2, rect); self->GetFieldRect(2, rect);
prog_->Move(rect.GetX() + offset, rect.GetY() + offset); m_prog->Move(rect.GetX() + offset, rect.GetY() + offset);
prog_->SetSize(rect.GetWidth() - offset, rect.GetHeight()); m_prog->SetSize(rect.GetWidth() - offset, rect.GetHeight());
event.Skip(); event.Skip();
}); });
cancelbutton_->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) { m_cancelbutton->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) {
if(cancel_cb_) cancel_cb_(); if(m_cancel_cb) m_cancel_cb();
m_perl_cancel_callback.call(); m_perl_cancel_callback.call();
cancelbutton_->Hide(); m_cancelbutton->Hide();
}); });
} }
ProgressStatusBar::~ProgressStatusBar() { ProgressStatusBar::~ProgressStatusBar() {
if(timer_->IsRunning()) timer_->Stop(); if(m_timer->IsRunning()) m_timer->Stop();
} }
int ProgressStatusBar::get_progress() const int ProgressStatusBar::get_progress() const
{ {
return prog_->GetValue(); return m_prog->GetValue();
} }
void ProgressStatusBar::set_progress(int val) void ProgressStatusBar::set_progress(int val)
{ {
if(!prog_->IsShown()) show_progress(true); if(!m_prog->IsShown()) show_progress(true);
if(val == prog_->GetRange()) { if(val == m_prog->GetRange()) {
prog_->SetValue(0); m_prog->SetValue(0);
show_progress(false); show_progress(false);
} else { } else {
prog_->SetValue(val); m_prog->SetValue(val);
} }
} }
int ProgressStatusBar::get_range() const int ProgressStatusBar::get_range() const
{ {
return prog_->GetRange(); return m_prog->GetRange();
} }
void ProgressStatusBar::set_range(int val) void ProgressStatusBar::set_range(int val)
{ {
if(val != prog_->GetRange()) { if(val != m_prog->GetRange()) {
prog_->SetRange(val); m_prog->SetRange(val);
} }
} }
void ProgressStatusBar::show_progress(bool show) void ProgressStatusBar::show_progress(bool show)
{ {
prog_->Show(show); m_prog->Show(show);
prog_->Pulse(); m_prog->Pulse();
} }
void ProgressStatusBar::start_busy(int rate) void ProgressStatusBar::start_busy(int rate)
{ {
busy_ = true; m_busy = true;
show_progress(true); show_progress(true);
if (!timer_->IsRunning()) { if (!m_timer->IsRunning()) {
timer_->Start(rate); m_timer->Start(rate);
} }
} }
void ProgressStatusBar::stop_busy() void ProgressStatusBar::stop_busy()
{ {
timer_->Stop(); m_timer->Stop();
show_progress(false); show_progress(false);
prog_->SetValue(0); m_prog->SetValue(0);
busy_ = false; m_busy = false;
} }
void ProgressStatusBar::set_cancel_callback(ProgressStatusBar::CancelFn ccb) { void ProgressStatusBar::set_cancel_callback(ProgressStatusBar::CancelFn ccb) {
cancel_cb_ = ccb; m_cancel_cb = ccb;
if(ccb) cancelbutton_->Show(); if(ccb) m_cancelbutton->Show();
else cancelbutton_->Hide(); else m_cancelbutton->Hide();
} }
void ProgressStatusBar::run(int rate) void ProgressStatusBar::run(int rate)
{ {
if(!timer_->IsRunning()) { if(!m_timer->IsRunning()) {
timer_->Start(rate); m_timer->Start(rate);
} }
} }
@ -141,12 +141,12 @@ void ProgressStatusBar::set_status_text(const wxString& txt)
void ProgressStatusBar::show_cancel_button() void ProgressStatusBar::show_cancel_button()
{ {
cancelbutton_->Show(); m_cancelbutton->Show();
} }
void ProgressStatusBar::hide_cancel_button() void ProgressStatusBar::hide_cancel_button()
{ {
cancelbutton_->Hide(); m_cancelbutton->Hide();
} }
} }

View File

@ -24,9 +24,9 @@ namespace Slic3r {
*/ */
class ProgressStatusBar { class ProgressStatusBar {
wxStatusBar *self; // we cheat! It should be the base class but: perl! wxStatusBar *self; // we cheat! It should be the base class but: perl!
wxTimer *timer_; wxTimer *m_timer;
wxGauge *prog_; wxGauge *m_prog;
wxButton *cancelbutton_; wxButton *m_cancelbutton;
public: public:
/// Cancel callback function type /// Cancel callback function type
@ -42,7 +42,7 @@ public:
void show_progress(bool); void show_progress(bool);
void start_busy(int = 100); void start_busy(int = 100);
void stop_busy(); void stop_busy();
inline bool is_busy() const { return busy_; } inline bool is_busy() const { return m_busy; }
void set_cancel_callback(CancelFn = CancelFn()); void set_cancel_callback(CancelFn = CancelFn());
inline void remove_cancel_callback() { set_cancel_callback(); } inline void remove_cancel_callback() { set_cancel_callback(); }
void run(int rate); void run(int rate);
@ -55,8 +55,8 @@ public:
PerlCallback m_perl_cancel_callback; PerlCallback m_perl_cancel_callback;
private: private:
bool busy_ = false; bool m_busy = false;
CancelFn cancel_cb_; CancelFn m_cancel_cb;
}; };
namespace GUI { namespace GUI {

View File

@ -35,6 +35,12 @@ bool is_windows10()
void set_wxapp(SV *ui) void set_wxapp(SV *ui)
%code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %}; %code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %};
void set_gui_appctl()
%code%{ Slic3r::GUI::set_gui_appctl(); %};
void set_cli_appctl()
%code%{ Slic3r::GUI::set_cli_appctl(); %};
void set_progress_status_bar(ProgressStatusBar *prs) void set_progress_status_bar(ProgressStatusBar *prs)
%code%{ Slic3r::GUI::set_progress_status_bar(prs); %}; %code%{ Slic3r::GUI::set_progress_status_bar(prs); %};

View File

@ -651,6 +651,13 @@ register_on_gizmo_rotate_callback(canvas, callback)
CODE: CODE:
_3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); _3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
void
register_on_gizmo_rotate_3D_callback(canvas, callback)
SV *canvas;
SV *callback;
CODE:
_3DScene::register_on_gizmo_rotate_3D_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
void void
register_on_gizmo_flatten_callback(canvas, callback) register_on_gizmo_flatten_callback(canvas, callback)
SV *canvas; SV *canvas;
@ -658,6 +665,13 @@ register_on_gizmo_flatten_callback(canvas, callback)
CODE: CODE:
_3DScene::register_on_gizmo_flatten_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); _3DScene::register_on_gizmo_flatten_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
void
register_on_gizmo_flatten_3D_callback(canvas, callback)
SV *canvas;
SV *callback;
CODE:
_3DScene::register_on_gizmo_flatten_3D_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback);
void void
register_on_update_geometry_info_callback(canvas, callback) register_on_update_geometry_info_callback(canvas, callback)
SV *canvas; SV *canvas;

View File

@ -364,8 +364,13 @@ ModelMaterial::attributes()
Ref<ModelObject> object() Ref<ModelObject> object()
%code%{ RETVAL = THIS->get_object(); %}; %code%{ RETVAL = THIS->get_object(); %};
#if ENABLE_MODELINSTANCE_3D_ROTATION
double rotation()
%code%{ RETVAL = THIS->get_rotation(Z); %};
#else
double rotation() double rotation()
%code%{ RETVAL = THIS->rotation; %}; %code%{ RETVAL = THIS->rotation; %};
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
double scaling_factor() double scaling_factor()
%code%{ RETVAL = THIS->scaling_factor; %}; %code%{ RETVAL = THIS->scaling_factor; %};
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET
@ -376,8 +381,17 @@ ModelMaterial::attributes()
%code%{ RETVAL = &THIS->offset; %}; %code%{ RETVAL = &THIS->offset; %};
#endif // ENABLE_MODELINSTANCE_3D_OFFSET #endif // ENABLE_MODELINSTANCE_3D_OFFSET
#if ENABLE_MODELINSTANCE_3D_ROTATION
void set_rotation(double val)
%code%{ THIS->set_rotation(Z, val); THIS->get_object()->invalidate_bounding_box(); %};
void set_rotations(Vec3d *rotation)
%code%{ THIS->set_rotation(*rotation); THIS->get_object()->invalidate_bounding_box(); %};
#else
void set_rotation(double val) void set_rotation(double val)
%code%{ THIS->rotation = val; THIS->get_object()->invalidate_bounding_box(); %}; %code%{ THIS->rotation = val; THIS->get_object()->invalidate_bounding_box(); %};
#endif // ENABLE_MODELINSTANCE_3D_ROTATION
void set_scaling_factor(double val) void set_scaling_factor(double val)
%code%{ THIS->scaling_factor = val; THIS->get_object()->invalidate_bounding_box(); %}; %code%{ THIS->scaling_factor = val; THIS->get_object()->invalidate_bounding_box(); %};
#if ENABLE_MODELINSTANCE_3D_OFFSET #if ENABLE_MODELINSTANCE_3D_OFFSET