mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Refactor cutting logic, don't slice in 3DScene
This commit is contained in:
		
							parent
							
								
									025a508de2
								
							
						
					
					
						commit
						f7e97f7e9b
					
				
					 2 changed files with 89 additions and 71 deletions
				
			
		| 
						 | 
					@ -13,7 +13,6 @@ use Slic3r::Geometry::Clipper qw(offset_ex intersection_pl);
 | 
				
			||||||
use Wx::GLCanvas qw(:all);
 | 
					use Wx::GLCanvas qw(:all);
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
__PACKAGE__->mk_accessors( qw(_quat _dirty init
 | 
					__PACKAGE__->mk_accessors( qw(_quat _dirty init
 | 
				
			||||||
                              enable_cutting
 | 
					 | 
				
			||||||
                              enable_picking
 | 
					                              enable_picking
 | 
				
			||||||
                              enable_moving
 | 
					                              enable_moving
 | 
				
			||||||
                              on_viewport_changed
 | 
					                              on_viewport_changed
 | 
				
			||||||
| 
						 | 
					@ -319,7 +318,9 @@ sub bed_bounding_box {
 | 
				
			||||||
    my ($self) = @_;
 | 
					    my ($self) = @_;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    my $bb = Slic3r::Geometry::BoundingBoxf3->new;
 | 
					    my $bb = Slic3r::Geometry::BoundingBoxf3->new;
 | 
				
			||||||
 | 
					    if ($self->bed_shape) {
 | 
				
			||||||
        $bb->merge_point(Slic3r::Pointf3->new(@$_, 0)) for @{$self->bed_shape};
 | 
					        $bb->merge_point(Slic3r::Pointf3->new(@$_, 0)) for @{$self->bed_shape};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return $bb;
 | 
					    return $bb;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -402,26 +403,20 @@ sub select_volume {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sub SetCuttingPlane {
 | 
					sub SetCuttingPlane {
 | 
				
			||||||
    my ($self, $z) = @_;
 | 
					    my ($self, $z, $expolygons) = @_;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    $self->cutting_plane_z($z);
 | 
					    $self->cutting_plane_z($z);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    # perform cut and cache section lines
 | 
					    # grow slices in order to display them better
 | 
				
			||||||
    my @verts = ();
 | 
					 | 
				
			||||||
    foreach my $volume (@{$self->volumes}) {
 | 
					 | 
				
			||||||
        foreach my $volume (@{$self->volumes}) {
 | 
					 | 
				
			||||||
            next if !$volume->mesh;
 | 
					 | 
				
			||||||
            my $expolygons = $volume->mesh->slice([ $z - $volume->origin->z ])->[0];
 | 
					 | 
				
			||||||
    $expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1);
 | 
					    $expolygons = offset_ex([ map @$_, @$expolygons ], scale 0.1);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    my @verts = ();
 | 
				
			||||||
    foreach my $line (map @{$_->lines}, map @$_, @$expolygons) {
 | 
					    foreach my $line (map @{$_->lines}, map @$_, @$expolygons) {
 | 
				
			||||||
        push @verts, (
 | 
					        push @verts, (
 | 
				
			||||||
            unscale($line->a->x), unscale($line->a->y), $z,  #))
 | 
					            unscale($line->a->x), unscale($line->a->y), $z,  #))
 | 
				
			||||||
            unscale($line->b->x), unscale($line->b->y), $z,  #))
 | 
					            unscale($line->b->x), unscale($line->b->y), $z,  #))
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    $self->cut_lines_vertices(OpenGL::Array->new_list(GL_FLOAT, @verts));
 | 
					    $self->cut_lines_vertices(OpenGL::Array->new_list(GL_FLOAT, @verts));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -999,7 +994,6 @@ sub load_object {
 | 
				
			||||||
                bounding_box    => $mesh->bounding_box,
 | 
					                bounding_box    => $mesh->bounding_box,
 | 
				
			||||||
                color           => $color,
 | 
					                color           => $color,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            $v->mesh($mesh) if $self->enable_cutting;
 | 
					 | 
				
			||||||
            if ($self->select_by eq 'object') {
 | 
					            if ($self->select_by eq 'object') {
 | 
				
			||||||
                $v->select_group_id($obj_idx*1000000);
 | 
					                $v->select_group_id($obj_idx*1000000);
 | 
				
			||||||
            } elsif ($self->select_by eq 'volume') {
 | 
					            } elsif ($self->select_by eq 'volume') {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@ use warnings;
 | 
				
			||||||
use utf8;
 | 
					use utf8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Slic3r::Geometry qw(PI X);
 | 
					use Slic3r::Geometry qw(PI X);
 | 
				
			||||||
use Wx qw(:dialog :id :misc :sizer wxTAB_TRAVERSAL);
 | 
					use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL);
 | 
				
			||||||
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
 | 
					use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
 | 
				
			||||||
use base 'Wx::Dialog';
 | 
					use base 'Wx::Dialog';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,9 @@ sub new {
 | 
				
			||||||
            my ($opt_id) = @_;
 | 
					            my ($opt_id) = @_;
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            $self->{cut_options}{$opt_id} = $optgroup->get_value($opt_id);
 | 
					            $self->{cut_options}{$opt_id} = $optgroup->get_value($opt_id);
 | 
				
			||||||
 | 
					            wxTheApp->CallAfter(sub {
 | 
				
			||||||
                $self->_update;
 | 
					                $self->_update;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        label_width  => 120,
 | 
					        label_width  => 120,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					@ -95,7 +97,6 @@ sub new {
 | 
				
			||||||
    my $canvas;
 | 
					    my $canvas;
 | 
				
			||||||
    if ($Slic3r::GUI::have_OpenGL) {
 | 
					    if ($Slic3r::GUI::have_OpenGL) {
 | 
				
			||||||
        $canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
 | 
					        $canvas = $self->{canvas} = Slic3r::GUI::3DScene->new($self);
 | 
				
			||||||
        $canvas->enable_cutting(1);
 | 
					 | 
				
			||||||
        $canvas->load_object($self->{model_object}, undef, [0]);
 | 
					        $canvas->load_object($self->{model_object}, undef, [0]);
 | 
				
			||||||
        $canvas->set_auto_bed_shape;
 | 
					        $canvas->set_auto_bed_shape;
 | 
				
			||||||
        $canvas->SetSize([500,500]);
 | 
					        $canvas->SetSize([500,500]);
 | 
				
			||||||
| 
						 | 
					@ -112,7 +113,16 @@ sub new {
 | 
				
			||||||
    $self->{sizer}->SetSizeHints($self);
 | 
					    $self->{sizer}->SetSizeHints($self);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    EVT_BUTTON($self, $self->{btn_cut}, sub {
 | 
					    EVT_BUTTON($self, $self->{btn_cut}, sub {
 | 
				
			||||||
        $self->perform_cut(1);
 | 
					        if ($self->{new_model_objects}{lower}) {
 | 
				
			||||||
 | 
					            if ($self->{cut_options}{rotate_lower}) {
 | 
				
			||||||
 | 
					                $self->{new_model_objects}{lower}->rotate(PI, X);
 | 
				
			||||||
 | 
					                $self->{new_model_objects}{lower}->center_around_origin;  # align to Z = 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if ($self->{new_model_objects}{upper}) {
 | 
				
			||||||
 | 
					            $self->{new_model_objects}{upper}->center_around_origin;  # align to Z = 0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        $self->EndModal(wxID_OK);
 | 
					        $self->EndModal(wxID_OK);
 | 
				
			||||||
        $self->Close;
 | 
					        $self->Close;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -125,25 +135,62 @@ sub new {
 | 
				
			||||||
sub _update {
 | 
					sub _update {
 | 
				
			||||||
    my ($self) = @_;
 | 
					    my ($self) = @_;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    my $optgroup = $self->{optgroup};
 | 
					    {
 | 
				
			||||||
 | 
					        # scale Z down to original size since we're using the transformed mesh for 3D preview
 | 
				
			||||||
 | 
					        # and cut dialog but ModelObject::cut() needs Z without any instance transformation
 | 
				
			||||||
 | 
					        my $z = $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            my ($new_model) = $self->{model_object}->cut($z);
 | 
				
			||||||
 | 
					            my ($upper_object, $lower_object) = @{$new_model->objects};
 | 
				
			||||||
 | 
					            $self->{new_model} = $new_model;
 | 
				
			||||||
 | 
					            $self->{new_model_objects} = {};
 | 
				
			||||||
 | 
					            if ($self->{cut_options}{keep_upper} && $upper_object->volumes_count > 0) {
 | 
				
			||||||
 | 
					                $self->{new_model_objects}{upper} = $upper_object;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($self->{cut_options}{keep_lower} && $lower_object->volumes_count > 0) {
 | 
				
			||||||
 | 
					                $self->{new_model_objects}{lower} = $lower_object;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        # update canvas
 | 
					        # update canvas
 | 
				
			||||||
        if ($self->{canvas}) {
 | 
					        if ($self->{canvas}) {
 | 
				
			||||||
 | 
					            # get volumes to render
 | 
				
			||||||
            my @objects = ();
 | 
					            my @objects = ();
 | 
				
			||||||
            if ($self->{cut_options}{preview}) {
 | 
					            if ($self->{cut_options}{preview}) {
 | 
				
			||||||
            $self->perform_cut;
 | 
					                push @objects, values %{$self->{new_model_objects}};
 | 
				
			||||||
            push @objects, @{$self->{new_model_objects}};
 | 
					 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                push @objects, $self->{model_object};
 | 
					                push @objects, $self->{model_object};
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					            # get section contour
 | 
				
			||||||
 | 
					            my @expolygons = ();
 | 
				
			||||||
 | 
					            foreach my $volume (@{$self->{model_object}->volumes}) {
 | 
				
			||||||
 | 
					                next if !$volume->mesh;
 | 
				
			||||||
 | 
					                next if $volume->modifier;
 | 
				
			||||||
 | 
					                my $expp = $volume->mesh->slice([ $z + $volume->mesh->bounding_box->z_min ])->[0];
 | 
				
			||||||
 | 
					                push @expolygons, @$expp;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            foreach my $expolygon (@expolygons) {
 | 
				
			||||||
 | 
					                $self->{model_object}->instances->[0]->transform_polygon($_)
 | 
				
			||||||
 | 
					                    for @$expolygon;
 | 
				
			||||||
 | 
					                $expolygon->translate(map Slic3r::Geometry::scale($_), @{ $self->{model_object}->instances->[0]->offset });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
            $self->{canvas}->reset_objects;
 | 
					            $self->{canvas}->reset_objects;
 | 
				
			||||||
            $self->{canvas}->load_object($_, undef, [0]) for @objects;
 | 
					            $self->{canvas}->load_object($_, undef, [0]) for @objects;
 | 
				
			||||||
        $self->{canvas}->SetCuttingPlane($self->{cut_options}{z});
 | 
					            $self->{canvas}->SetCuttingPlane(
 | 
				
			||||||
 | 
					                $self->{cut_options}{z},
 | 
				
			||||||
 | 
					                [@expolygons],
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
            $self->{canvas}->Render;
 | 
					            $self->{canvas}->Render;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    # update controls
 | 
					    # update controls
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        my $z = $self->{cut_options}{z};
 | 
					        my $z = $self->{cut_options}{z};
 | 
				
			||||||
 | 
					        my $optgroup = $self->{optgroup};
 | 
				
			||||||
        $optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1);
 | 
					        $optgroup->get_field('keep_upper')->toggle(my $have_upper = abs($z - $optgroup->get_option('z')->max) > 0.1);
 | 
				
			||||||
        $optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1);
 | 
					        $optgroup->get_field('keep_lower')->toggle(my $have_lower = $z > 0.1);
 | 
				
			||||||
        $optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower});
 | 
					        $optgroup->get_field('rotate_lower')->toggle($z > 0 && $self->{cut_options}{keep_lower});
 | 
				
			||||||
| 
						 | 
					@ -157,34 +204,11 @@ sub _update {
 | 
				
			||||||
            $self->{btn_cut}->Disable;
 | 
					            $self->{btn_cut}->Disable;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
sub perform_cut {
 | 
					 | 
				
			||||||
    my ($self, $final) = @_;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    # scale Z down to original size since we're using the transformed mesh for 3D preview
 | 
					 | 
				
			||||||
    # and cut dialog but ModelObject::cut() needs Z without any instance transformation
 | 
					 | 
				
			||||||
    my $z = $self->{cut_options}{z} / $self->{model_object}->instances->[0]->scaling_factor;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    my ($new_model) = $self->{model_object}->cut($z);
 | 
					 | 
				
			||||||
    my ($upper_object, $lower_object) = @{$new_model->objects};
 | 
					 | 
				
			||||||
    $self->{new_model} = $new_model;
 | 
					 | 
				
			||||||
    $self->{new_model_objects} = [];
 | 
					 | 
				
			||||||
    if ($self->{cut_options}{keep_upper} && $upper_object->volumes_count > 0) {
 | 
					 | 
				
			||||||
        $upper_object->center_around_origin if $final;  # align to Z = 0
 | 
					 | 
				
			||||||
        push @{$self->{new_model_objects}}, $upper_object;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if ($self->{cut_options}{keep_lower} && $lower_object->volumes_count > 0) {
 | 
					 | 
				
			||||||
        push @{$self->{new_model_objects}}, $lower_object;
 | 
					 | 
				
			||||||
        if ($self->{cut_options}{rotate_lower} && $final) {
 | 
					 | 
				
			||||||
            $lower_object->rotate(PI, X);
 | 
					 | 
				
			||||||
            $lower_object->center_around_origin;  # align to Z = 0
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sub NewModelObjects {
 | 
					sub NewModelObjects {
 | 
				
			||||||
    my ($self) = @_;
 | 
					    my ($self) = @_;
 | 
				
			||||||
    return @{ $self->{new_model_objects} };
 | 
					    return values %{ $self->{new_model_objects} };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1;
 | 
					1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue