Changing camera view
CorySimon opened this issue · 3 comments
In my attempt to replicate the examples/mof.html
, my MOF is rotated at a very awkward angle when I first open it. Is it easy to change the default view, through an up vector and view vector? First, for the example in examples/mof.html
. Second, in the IPython Notebook, this would be nice too. Such as:
imolecule.draw("IRMOF-1.cif", show_save=True, up_vector=[1, 0, 0], view_vector=[0, 1, 0])
In javascript, you can grab the camera with imolecule.camera
. It's an
instance of THREE.Camera
, which has all sorts of properties. Something
like imolecule.camera.rotation.set(0, 0, 0);
will set the rotation.
There's also position vectors and rotation matrices to play with.
Personally, I've found it cleaner to rotate the molecule I'm rendering with
a throwaway script instead of the camera. It makes it easier to switch
between molecules in a UI (like the MOF examples).
Regarding the python bindings, I'm hesitant to complicate the API for minor
improvements. I could see the benefit of squeezing this into a **kwargs
,
but I (at least currently) prefer to avoid it.
On Monday, November 9, 2015, Cory Simon notifications@github.com wrote:
In my attempt to replicate the examples/mof.html, my MOF is rotated at a
very awkward angle when I first open it. Is it easy to change the default
view, through an up vector and view vector? First, for the example in
examples/mof.html. Second, in the IPython Notebook, this would be nice
too. Such as:imolecule.draw("IRMOF-1.cif", show_save=True, up_vector=[1, 0, 0], view_vector=[0, 1, 0])
—
Reply to this email directly or view it on GitHub
#27.
Thanks. One cannot change the camera angle in the IPython notebook because camera
is not an attribute of the module imolecule
.
In three.js, it seems that a rotation is possible via:
camera.rotation.y = 90 * Math.PI / 180
However, in your MOF example .html, I modified as:
<script type="text/javascript">
imolecule.create('.molecule');
imolecule.camera.rotation.y = 40 * Math.PI / 180;
$.getJSON('IRMOF1.json', function (mof) {
imolecule.draw(mof);
});
</script>
but the rotation did not work. I also tried adding the line imolecule.camera.rotation.y = 40 * Math.PI / 180;
at different points.
Can you give an example of what you mean by using a throwaway script?
You want to think about the molecule as the origin, and the camera as an object around it. By default, the camera is positioned at (0, 0, z)
, where z
is calculated to fit the molecule into the viewing window. The camera is also tied to looking at the origin by default, so rotating it won't do much - especially if you're rotating around a symmetric molecule like a MOF.
Instead, try setting the position.
Regarding the molecule rotation comment, I find it cleaner to bake the rotation into the JSON versus setting custom camera parameters. You can use whatever rotation algorithm you wish. Here's an example:
def rotate(v, axis, angle):
"""Rotates using axis-angle parameters."""
# This is the Euler-Rodrigues rotation formula
# http://en.wikipedia.org/wiki/Euler%E2%80%93Rodrigues_formula
# http://stackoverflow.com/questions/6802577/python-rotation-of-3d-
# vector
a = np.cos(angle / 2)
b, c, d = -axis * np.sin(angle / 2)
rotation_vector = np.array([[a*a+b*b-c*c-d*d, 2*(b*c-a*d), 2*(b*d+a*c)],
[2*(b*c+a*d), a*a+c*c-b*b-d*d, 2*(c*d-a*b)],
[2*(b*d-a*c), 2*(c*d+a*b), a*a+d*d-b*b-c*c]])
return np.dot(v, rotation_vector)
Then, iterate through your JSON and apply this to the locations. Here's an untested throwaway script example:
import numpy as np
import json # or `import imolecule.json_formatter as json` to get a more molfile-like output
with open(your_file) as in_file:
molecule = json.load(in_file)
for atom in molecule['atoms']:
atom['location'] = rotate(np.array(atom['location']), axis, np.pi / 2).tolist()
print(json.dumps(molecule))
Something like that should work.
Finally, regarding the notebook, there's no global imolecule
instance. There is an imolecule
variable buried in there, but I'd instead recommend injecting code into the javascript string before rendering. I tested this one going off of the "Advanced Usage" example in the sample notebook:
from IPython.display import display, HTML
script = imolecule.draw('c1ccccc1', display_html=False).splitlines()
script.insert(11, '$d.imolecule.camera.position.set(5, 5, 5);')
display(HTML('\n'.join(script)))
Proof:
Even with this, I'd still recommend baking the rotation into your JSON. I think clean code is worth the effort of a rotation script.