Don’t be put off by the title!
I’ve uploaded a new project to http://www.math.ntnu.no/~stacey/HowDidIDoThat/iPad/Codea.html: the cube project. It displays a cube defined by vertices and edges. Main features:
- The cube is stereographically projected onto the screen from an “eye” above the screen.
- The elements are ordered according to how far from the eye they are and placed on the screen in the right order to create the 3D effect (a little shading, using a technique from TikZ/PGF, ensures that over/under looks right).
- As you tilt the iPad, the cube “stays level” in that it adjusts so that the bottom face always appears to be downwards. So if you tilt the iPad up, you look at the top of the cube.
- You can rotate the cube by touching and dragging on the screen. You should imagine a sphere containing the cube and as you drag your finger across the screen, you rotate this sphere. (Then if you further tilt the iPad, it keeps the current orientation relative to the ground.)
Main code features:
- An extended
Vec3 class for holding 3-dimensional vectors. I figured out how to make the
+ and so forth operators work, so things like
u + v just work. I had to be a bit creative:
u * v returns the cross product,
u .. v the dot product, and
#v the length. It also has a crude
applyMatrix function where the matrix is specified as a triple of
Vec3 objects. Many of the operations work with
vec3 objects as well. It has functions for stereographic projection of vectors onto the screen from an “eye”.
- A class
Quaternion for dealing with quaternions. “What’s a quaternion?”, I hear you cry. If you don’t know then think of them as a neat way of encoding rotations. You can apply a quaternion (rotation) to a
Vec3 object by the notation
v^q. Composing rotations corresponds to multiplying quaternions:
q * p.
Things to do:
- The vertical stuff is done by ordering the elements according to their distance from the “eye”. I’d planned on using
zLevel for this but couldn’t get it to work as I expected so went for a manual sort. Now that I know a bit more about
zLevel I could put this back (maybe).
- The vertical stuff can’t cope with this problem: (image included, with the permission of the author, from this blog post which is about something a little similar). This would need more advanced drawing tools, or extremely finickity computation.
- The radius of the “balls” for the vertices varies with the depth, but the calculation is a little crude. This could be improved.
- Adding support for pinch-to-zoom would be super cool!
- The stereographic projection doesn’t do anything sensible with points behind the viewer. This should be possible, though there are a few edge cases to consider.
- Defining the data is fairly abstract, but could be made more so with a 3DObject class.
- The vertices themselves don’t look very 3D.
Other suggestions welcome!
This is insanely awesome. Well implemented quaternions alone will be handy in the long run, as will the operator overloading. (I implemented a c++ class to do them in the distant past when I had been doing everything with Euler angles and hit the dreaded gimbal lock - I won’t pretend I ever fully understood it all, a lot of trial and error and code that worked, eventually, but I couldn’t explain why). Plus - wonderful explanations. Thank you for this whole thing.
Incidentally (since it took me quite some time to find it) the overloading is described in the reference manual at the metatable entry.
(In my background research for this, then I read about the gimbal lock but it just made my brain freeze. If anyone can explain it, I’ll be very grateful! I used quaternions purely and simply because I know about them from my work.)
Left-right dragging (iPad in landscape mode) is wonky for me. (I also deeply appreciate a good trackball controller!)
It’s sad that this basically duplicates most of the functionality of the c++ code I mentioned - sticks and balls in 3d rotatable - in maybe one twentieth of the code, and it took me 6 months. It was a good learning experience, but woof!
I plan on swiping this, with great gusto, for my strategic space game (oft started, never completed - I think I’m on my 10th version now). Yay!
Could you be more precise? “Wonky” is a little … open to interpretation!
I’m not convinced that I have the dragging in its most intuitive fashion, it often takes me a couple of goes to get it right. In particular, I’m not totally sure that I have the interaction between the gravitational rotation and the touch rotation quite right. There was a lot of “try a few things until something looks right” instead of sitting down with a pen and paper (sorry! I mean stylus and ipad) and working out what it ought to be.
Drag up - cube spins away (ie. closest vertex goes up) - good. Down likewise.
Drag right - close vertex moves up and right. Drag left, close vertex goes down and left.
Something is skewed somewhere. This is all with the iPad held steady. Hmm. Ah - orientation matters. I am holding the iPad “screen up” leaning over it. If I hold the screen closer to vertical, the effect is less pronounced. (if I hold it very vertical, the cube disappears)
Hmm, it looks as though I’m not correcting for the tilt when working out the effect of the touches. Ah, well. Back to the drawing-board^H^H^H^H^HiPad.
The cube shouldn’t disappear at any orientation. If you hold it completely flat then it might spin round a bit as it tries to work out what orientation to use (the gravity vector is no longer sufficient when it’s completely flat).
Just spotted another bug which happens when one rotates the iPad all the way around with the rotation lock on (I wonder if we can detect the rotation lock …). Halfway around then some assumption goes false and the gravity vector is in the wrong direction.
Hold the iPad landscape mode in front of you, like a window - at vertical (or close) - no cube.
This is with rotation lock on, as is only right and proper. Non-lockers are a menace to society!
Man I need to go to bed.
I get a strange flicker every now and then as I try to orient it exactly at vertical, but I can’t find a position where it actually vanishes for long enough for me to see.
I’ll have a think and see if I can work out some diagnostics for you to run that might tell me what’s going on, if you’d be prepared to do that for me. (But I need to finish writing a lecture so I won’t do it now … you can go to bed.)
I wonder what your daily job, guys. You both seem to have plenty of free time to play around with Codea. I envy you! I hardly able to pull my iPad from my kids!
Heh - was 2am for me. Just getting up now… 5 hours of sleep is plen.t…y… Zzzzzzzzz
Andrew - I have iPad 1 - maybe you have iPad 2 and it’s a speed thing? Happy to try whatever.
BTW - confirmed, when I set the gravity vector to Vec3(1,0,0,0) - the trackball works perfectly. For my purposes, this is more than sufficient (You see vertexes and lines, or perhaps atoms and molecular bonds - I see planets, and when I’m done a minimal spanning tree connecting them all for my awesome strategic wargame )
Okey-dokey. Glad that’s figured out. For the record, yes I have an iPad 2.
In an ideal world, I’d have a touch-button for turning gravity on and off. Maybe I’ll program that in …
“hardly able to pull my iPad from my kids!” You have to call homework:complete()
This usually returns false then the iPad is yours.
Yes, I was under the misapprehension that it was my iPad as well. Ah, well.
@Andrew: it’s the first outside project I’m trying, and I have to say it’s amazing, both for the learning value as for the potential applications. Thanks for sharing it!
(Also, thanks for the suggestion on your web page to use GoodReader to copy and paste the source code, it was most useful.)
I’ve fixed some bugs, and introduced a fair few new features; mainly to do with interaction.
Pinch-zoom is now implemented. There are two directions: a horizontal pinch changes the scaling after the stereographic projection is done, a vertical pinch changes it before.
Tapping affects gravity. A single tap turns it on or off. A double tap resets everything to its starting configuration (including the zooms).
Data is now abstracted into its own class (Data3d.lua). There’s a new shape, which is cyclohexane in “chair” format (pretty much cut-and-pasted from pubchem).
Touches are also abstracted just a little.
Have a play!
May as well record my ideas for extending this.
- Make vertices and edges objects in their own right. Then add styles (size, colour).
- Figure out the simplest way to specify a molecule from pubchem for input.
- Specify edges by giving each vertex a valency and then forming edges to the nearest other vertices up to the valency.
- Double swipe for translate?
- Add a menu to swap between shapes
- Make it possible to edit the shape by dragging vertices. In a particular view, dragging a vertex moves it parallel to the view. Need to have a toggle button somewhere to say “now I’m in editing mode”, otherwise the gestures get too complicated. One could add/remove edges as well.
- Abstract the “viewport” stuff a little (mainly with regard to the interaction with touches).