ObjectCutDialog.pm 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package Slic3r::GUI::Plater::ObjectCutDialog;
  2. use strict;
  3. use warnings;
  4. use utf8;
  5. use Slic3r::Geometry qw(PI X);
  6. use Wx qw(:dialog :id :misc :sizer wxTAB_TRAVERSAL);
  7. use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
  8. use base 'Wx::Dialog';
  9. sub new {
  10. my $class = shift;
  11. my ($parent, %params) = @_;
  12. my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
  13. $self->{model_object_idx} = $params{model_object_idx};
  14. $self->{model_object} = $params{model_object};
  15. $self->{new_model_objects} = [];
  16. # cut options
  17. $self->{cut_options} = {
  18. z => 0,
  19. keep_upper => 1,
  20. keep_lower => 1,
  21. rotate_lower => 1,
  22. };
  23. my $optgroup;
  24. $optgroup = $self->{optgroup} = Slic3r::GUI::OptionsGroup->new(
  25. parent => $self,
  26. title => 'Cut',
  27. on_change => sub {
  28. my ($opt_id) = @_;
  29. $self->{cut_options}{$opt_id} = $optgroup->get_value($opt_id);
  30. $self->_update;
  31. },
  32. label_width => 120,
  33. );
  34. $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
  35. opt_id => 'z',
  36. type => 'slider',
  37. label => 'Z',
  38. default => $self->{cut_options}{z},
  39. min => 0,
  40. max => $self->{model_object}->bounding_box->size->z,
  41. full_width => 1,
  42. ));
  43. {
  44. my $line = Slic3r::GUI::OptionsGroup::Line->new(
  45. label => 'Keep',
  46. );
  47. $line->append_option(Slic3r::GUI::OptionsGroup::Option->new(
  48. opt_id => 'keep_upper',
  49. type => 'bool',
  50. label => 'Upper part',
  51. default => $self->{cut_options}{keep_upper},
  52. ));
  53. $line->append_option(Slic3r::GUI::OptionsGroup::Option->new(
  54. opt_id => 'keep_lower',
  55. type => 'bool',
  56. label => 'Lower part',
  57. default => $self->{cut_options}{keep_lower},
  58. ));
  59. $optgroup->append_line($line);
  60. }
  61. $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new(
  62. opt_id => 'rotate_lower',
  63. label => 'Rotate lower part upwards',
  64. type => 'bool',
  65. tooltip => 'If enabled, the lower part will be rotated by 180° so that the flat cut surface lies on the print bed.',
  66. default => $self->{cut_options}{rotate_lower},
  67. ));
  68. {
  69. my $cut_button_sizer = Wx::BoxSizer->new(wxVERTICAL);
  70. $self->{btn_cut} = Wx::Button->new($self, -1, "Perform cut", wxDefaultPosition, wxDefaultSize);
  71. $cut_button_sizer->Add($self->{btn_cut}, 0, wxALIGN_RIGHT | wxALL, 10);
  72. $optgroup->append_line(Slic3r::GUI::OptionsGroup::Line->new(
  73. sizer => $cut_button_sizer,
  74. ));
  75. }
  76. # left pane with tree
  77. my $left_sizer = Wx::BoxSizer->new(wxVERTICAL);
  78. $left_sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
  79. # right pane with preview canvas
  80. my $canvas;
  81. if ($Slic3r::GUI::have_OpenGL) {
  82. $canvas = $self->{canvas} = Slic3r::GUI::PreviewCanvas->new($self);
  83. $canvas->load_object($self->{model_object});
  84. $canvas->set_bounding_box($self->{model_object}->bounding_box);
  85. $canvas->set_auto_bed_shape;
  86. $canvas->SetSize([500,500]);
  87. $canvas->SetMinSize($canvas->GetSize);
  88. }
  89. $self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
  90. $self->{sizer}->Add($left_sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10);
  91. $self->{sizer}->Add($canvas, 1, wxEXPAND | wxALL, 0) if $canvas;
  92. $self->SetSizer($self->{sizer});
  93. $self->SetMinSize($self->GetSize);
  94. $self->{sizer}->SetSizeHints($self);
  95. # needed to actually free memory
  96. EVT_CLOSE($self, sub {
  97. $self->EndModal(wxID_OK);
  98. $self->Destroy;
  99. });
  100. EVT_BUTTON($self, $self->{btn_cut}, sub { $self->perform_cut });
  101. $self->_update;
  102. return $self;
  103. }
  104. sub _update {
  105. my ($self) = @_;
  106. my $optgroup = $self->{optgroup};
  107. # update canvas
  108. if ($self->{canvas}) {
  109. $self->{canvas}->SetCuttingPlane($self->{cut_options}{z});
  110. $self->{canvas}->Render;
  111. }
  112. # update controls
  113. my $z = $self->{cut_options}{z};
  114. $optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1);
  115. $optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1);
  116. $optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower});
  117. # update cut button
  118. if (($self->{cut_options}{keep_upper} && $have_upper)
  119. || ($self->{cut_options}{keep_lower} && $have_lower)) {
  120. $self->{btn_cut}->Enable;
  121. } else {
  122. $self->{btn_cut}->Disable;
  123. }
  124. }
  125. sub perform_cut {
  126. my ($self) = @_;
  127. # scale Z down to original size since we're using the transformed mesh for 3D preview
  128. # and cut dialog but ModelObject::cut() needs Z without any instance transformation
  129. my $z = $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
  130. my ($new_model) = $self->{model_object}->cut($z);
  131. my ($upper_object, $lower_object) = @{$new_model->objects};
  132. $self->{new_model} = $new_model;
  133. $self->{new_model_objects} = [];
  134. if ($self->{cut_options}{keep_upper} && $upper_object->volumes_count > 0) {
  135. push @{$self->{new_model_objects}}, $upper_object;
  136. }
  137. if ($self->{cut_options}{keep_lower} && $lower_object->volumes_count > 0) {
  138. push @{$self->{new_model_objects}}, $lower_object;
  139. if ($self->{cut_options}{rotate_lower}) {
  140. $lower_object->rotate(PI, X);
  141. }
  142. }
  143. $self->Close;
  144. }
  145. sub NewModelObjects {
  146. my ($self) = @_;
  147. return @{ $self->{new_model_objects} };
  148. }
  149. 1;