New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: undo to rotate, flip, split, cut #3265

Closed
mrvn opened this Issue Mar 8, 2016 · 8 comments

Comments

Projects
None yet
5 participants
@mrvn

mrvn commented Mar 8, 2016

Sometimes I hit the wrong button/menu entry or more often give the wrong angle on rotation and then have to figure out what the reverse action is to undo. Or delete and re-add the object. It would be ncie if there were an undo button for this.

@alranel

This comment has been minimized.

Member

alranel commented Mar 13, 2016

I agree. Cut would be more complicated to undo because it's a destructive operation and the only way to get back to the previous state would require keeping the previous mesh in memory.

@Patola

This comment has been minimized.

Patola commented Jan 13, 2017

Maybe get up to speed with this feature by implementing it only to translate, rotate, flip, scale which would be only a case of changing coordinates and transformation matrices, and in the future try and extend that for for cut and split by saving the state before these transformations in a cache.

When you apply a transformation matrix, you also add their inverse to a stack. So every time the user selects undo or press ctrl-Z, the matrix on the stack is popped and applied to the object.

Just a random reference about inverse matrices: http://mathworld.wolfram.com/MatrixInverse.html

@alranel alranel added the Low Effort label Mar 18, 2017

@singh1114

This comment has been minimized.

Contributor

singh1114 commented Mar 24, 2017

I was reading about rotation, translation, and scaling. We must be using composite transformation to do the various operations similarly we can use composite transformations to roll back the transformation that had already happened. We will keep on saving the instances of the models whenever the user changes something major in the model.

Now if the user requests for an undo we will go to the previous instance.

For example: Say a user applies a composite operation to the model in the following order.

  1. Rotation by angle 30.
  2. A scale of 400.

Now the user wants to apply an undo command. Then these operations will happen:

  1. Scaling by -400.
  2. Rotation by -30.

We know the change matrix of these transformations, therefore the reapplying the negative matrix is not that difficult.

Can this work?

@alranel

This comment has been minimized.

Member

alranel commented Mar 26, 2017

Yeah. We don't use matrices for transformation but we do like this:

  • For XY translations, Z rotations, uniform scaling, we modify the attributes of the ModelInstance objects (these are reversible by restoring the previous attributes).
  • For XY rotations, non-uniform scaling, flip we call the relevant methods on the ModelObject objects because we actually apply a transformation the mesh coordinates (these are reversible by applying the inverse transformation).
  • For cut and split we actually modify the meshes in a destructive way and we add/remove objects from plater (these are much more complicated to reverse and potentially memory-intensive). I suggest to skip these for now.

I think you just need to create a class representing an undoable operation, holding all the relevant information (object and instance to apply the transformation, kind of operation, values). These objects would be added to a stack. Whenever an object or instance is removed from the plater, all the related undoable operations should be removed from the stack. That's it.

wxWidgets provides a built-in facility for undo, but I'm not sure we actually need it (and I'm not sure it's available in wxPerl).

@alranel

This comment has been minimized.

Member

alranel commented Mar 26, 2017

I suggest to put the actual operations in the stack, and only calculate the inverse when the Undo command is actually called.

@singh1114

This comment has been minimized.

Contributor

singh1114 commented Mar 27, 2017

I want to share the data structures using which we can implement: Please also refer to the pseudo code that I have written below. I have implemented it using the comments of @alexrj:

First of all, we will keep adding all the operations to the stack. An array in a class will save all the valid operations that can be undone. Whenever the user clicks the undo button it will request a subroutine to tell whether the operation is undone. If it returns true we can go forward and apply the reverse operations saved in the class.

#class to check the operations that are transformable.

package Undoable;

@undoOperations = ('XYtranslations', 'Zrotation', 'linearScaling', 'XYrotation', 'nonUniformScaling', 'flip');

sub isUndo{
  my($operation) = @_;
  foreach $var (@undoOperations){
    if($operation == $var){
      return 1;
    }
    else{
      return 0;
    }
  }
}

sub xytranslation{
  #....

}

sub z_rotation{
  #.....
}

1;


# Stack:

@stack = Add all the operations to the stack.

When undo key is pressed{
  # get the top of the stack
  $operation = @stack;

  # create the object of the class Undoable
  my $obj = new Undoable();

  $obj->isUndo($operation);

  # if the subroutine returns true
  if($obj){
    pop @stack;
    
    # Apply the reversible operations.
  }
  
}

Please share your views about this. I have tried to write it in perl but as my perl is week, please correct the syntax too if I am wrong somewhere.

@Samir55 Samir55 referenced this issue Aug 28, 2017

Merged

Undo/Redo to rotate, miror, split, cut, etc #4100

10 of 10 tasks complete

lordofhyphens added a commit that referenced this issue Sep 12, 2017

Undo/Redo to rotate, miror, split, cut, etc (#4100)
* * Add UndoOperations package in Plater.pm
* Add undo/redo options to the plater menu with their icons.
* Add the 2 undo/redo stacks to Slic3r::GUI::Plater package.
* Add add_undo_operation, undo & redo sub routines to Slic3r::GUI::Plater.
* Add objet identifier variable to each newly created Slic3r::GUI::Plater::Object to keep track of objects referenced in the stacks of undo/redo.
* Add undo/redo to rotate, mirror, increase, remove.

* * Add undo/redo to cut operation.

* * Add undo/redo to split, decrease, change scale and reset.
* Fix pop and push error.a

* * Refactoring undo/redo functions.

* * Some fixes to undo/redo for  reset and decrease functions

* Some Fixes to undo/redo split, reset and cut operations.

* Improve undo/redo menu items sync.

* * limit the undo stack operations to save RAM.

* Remove debugging lines.

* Add undo/redo to Add models.

* Some Refactoring and some fixes.

* Some Refactoring.

Fixes #3265

@lordofhyphens lordofhyphens added this to the 1.3.0 milestone Sep 12, 2017

@lordofhyphens

This comment has been minimized.

Member

lordofhyphens commented Sep 12, 2017

Thanks to @Samir55 for the PR.

Enjoy @mrvn

@singh1114

This comment has been minimized.

Contributor

singh1114 commented Sep 12, 2017

@lordofhyphens The reference made there to is wrong. I have no hand in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment