Open attentionbydesign opened 1 week ago
Not easy, because still need a way to toggle back.
Prior to even moving the models into lineup view, gotta save their current state. This means something like remembering
When reverting back, you get the current centroid and axis, and calculate the transformation that got it there. In theory applying the inverse of that should revert the position and orientation.
So far, this seems to work fine with translations. However, rotations might be complicated by how the COFR is defined. If using the major axes as defined by the atoms of the structure, imagine if an arrow shaped model pointing up (ie positive y) positioned far from the origin is turned 90 degrees about the z-axis so that it is now pointing to the right (positive x) with cofr as center of the model (i.e. chimera defines as center of the bounding sphere of displayed and active atoms of a model, not necessarily the centroid). So you try and revert its orientation by rotating -90 about an axis perpendicular to the initial arrow and current arrow direction. In this case, that should potentially work, but model is far from the origin, so its centroid pt will get translated up and to the left as it is rotated -90 (more like revolved around) about the global Z axis.
In theory, shouldn't it be fine as long as you translate it after rotating?
For some reason, it simply is not working...
Some things to try for rotation:
[x] is there a m.openState.localXform? does this work better?
[x] maybe some inspiration from whatever source code is responsible for Tools > Movement > Undo ? After all, this is essentially the goal, but leave out the camera movements, and allow looping through a whole selection instead of a global record of all movements.
localXform is problematic in that any transformations are based on the local coordinate system, in which the axes might not be defined the same (e.g., rotating about X in local could be Y or Z in global).
Issue with using bestLine from StructMeasure was that the sign/polarity of a given axis can randomly flip with certain orientations. i.e., even slightly rotating (<20 degrees) might randomly flip the sign, which means the direction of rotation would be flipped randomly.
Went back to the idea of calculating the transformation matrix between two different sets of atom coordinates using numpy. Converted this back to a chimera Xform object, then broke it down to substituent rotation and translation operations, then combined them back into the one function revertSpatialConfig(mol, saved_coords).
Further Tasks:
[ ] Only works as expected when model is the only only one activated when you move it around relative to the saved position. If you activate all, and then move things around, then saved position remains fixed within the viewing window while the shared coordinate frame of all active models moves. This means that reverting the spatial configuration might move the model back to where it was on the screen, but now the orientation and position relative to all of the other models might be altered. This might not be an issue if all of the models are reverted, but begs the question: how do you revert back relative to a given model or more? Like, if you moved a ligand away from the main protein, then turned the whole view to look at another side of the protein and didn't want to mess up that view but also wanted to move the ligand back? That would probably take an additional layer of saved coordinates, perhaps.
[x] To toggle lineup mode, need to loop through and save the current orientations of all selected models - perhaps will use a dictionary of model:coord pairs. Then
saved_coords = { <model:coord pairs> }
for m in sel:
revertSpatialConfig(m, saved_coords[m])
This should probably not have any issues with sequence/order, as they will each be based on the global coordinate system which doesn't shift or rotate. The camera merely zooms in or out, but moving all models is the proxy for panning; not sure if the camera actually can pan.
Saving coordinates to a dictionary worked! See second to last commit for today.
Some issues / potential improvements:
[ ] All models SHOWN by default for lineup_models(): the function as it is now gets the current selection by default; but if there is nothing selected, why not just default to all models that are SHOWN?
[ ] All models (regardless if shown or not) by default for save_positions: Instead of specifying True or False for selection=, it would make sense to save all currently open models by default. When you go to revert_positions(), you can still select a subset of all the models to revert. However, you might have to fix the global vs. all models vs. single model reference frame issue mentioned in the first comment. Regardless, set sel=None, then use if current_selection(): to see if anything is selected. If so, then loop through that selection, otherwise loop through openModels.list().
[ ] Inspiration from reversion method for volumes: to get a volume back, you need it's current transformation from the origin (vxf2) and it's original transformation from the origin (vxf1). You simply apply the inverse of vxf2 to get it back to the origin, then apply vxf1 forward to get it back to that original position.
In the case of moving a subset of models back relative to all models, regardless of the global: you can first revert that subset, then apply the inverse of whatever transformation would have reverted the other models.
Example: By default , models #1-5 are pointing their local y axes in the positive Z direction of global, as with most volumes. This position is saved into init_p. You rotate by 90 about X to align the Y axes. Then you move model #3 away from the rest in the +X direction. Then you rotate it about Z to look at its different sides.
To reset without ending up all the way back at initial_p, you only initially revert #3 back to its position in inital_p, but then you get the transformation that would have reverted #1-2,4-5 and apply its inverse to #3.
Arithmetic Analogy: Within initial_p, say #3 was at position A, and #5 was at position B. You move them to C and D respectively, where C-D does not equal A-B. You move #3 C +(A-C) = A. Then, move it fr@om A: A+(D-B)=E. Subtract D from both sides: E-D = A-B. So regardless of what C and D are, you can always get #3 to position E which is the same distance from D as A was from B.
[ ] Saved positions cache file? instead of remembering to save the current positions prior to running lineup_models(), how about saving them to a text file that can be read in using r2d? That way, you can store multiple positions. And perhaps a function to delete all of them open closing session for sake of memory management. Also allows for save_positions() to be nested within any function that moves models, such that the most recent is saved prior to moving. Currently, you have to actually assign save_positions() to a variable outside of the local space of the moving function such as lineup_models(). If you did so within lineup_models() the variable would be only within that context, so revert_positions() will be unable to find the saved positions if you pass it in as an argument.
[ ] Create selection option for OrientModels?: currently orients all models, without any alternative.
Would be nice to apply the same idea of all models by default, but if something is selected, then orient that selection to origin
Also, what if you don't want to move it to the origin? Needs an option to orient it relative to a reference model with default being that with the lowest model ID.
And how about an option to orient without translating? Or to recenter without rotating? The former applies well to lineup_view while cofr is independent. Like if you got the grid of volumes slanted each one of them, but want by them all straight again.
Should be an easy fix, already got an empty toggle_lineup function or something similar in custom accelerators that can help edited