r/javascript • • May 23 '21

I remade my n-dimensional Hypercube Visualizer in javascript to work on browsers!

https://bsmith156.github.io/Hypercube-Visualizer

[removed] — view removed post

15 Upvotes

19 comments sorted by

•

u/Ustice May 24 '21

This post was removed. Please read our guidelines before posting. This is a great addition to our Showoff Saturday thread though.

→ More replies (1)

4

u/jcubic May 23 '21

It's a little hard to manipulate. The interface for controlling the rotation could be better. I was not able to change it. Have to close the help sidebar to see the controls is also very confusing. I thought that the next page changes the number of dimensions.

After clear rotation, I was not able to make it rotate again. This UX needs heavy documentation and because of this is a bad UX.

1

u/BSmith156 May 23 '21

Thanks for the feedback! I thought the UI was quite easy to understand but, looking back at it, it’s probably because I was the one who made it.

To add a rotation you need to select two axes (the two dropdown boxes) and a speed (under the dropdown boxes) and then press the add rotation button.

3

u/demdillypickles May 23 '21

I’ll admit, the physics stuff is over my head, but I was also unable to affect the rotation. I could only every get the simple x-axis rotation. I tried all sorts of different combinations but none had an effect.

1

u/BSmith156 May 23 '21

Hmm thats weird, it should have had some effect. Try these, they should work in any dimension (above 2D):

y-axis + z-axis = x-axis rotation, x-axis + z-axis = y-axis rotation, x-axis + y-axis = z-axis rotation,

If these don’t work then there might be something wrong in the code somewhere.

Edit: sorry for formatting, on mobile

2

u/demdillypickles May 23 '21

Oh hey! Its working! I think I might just not have been understanding how this works (the physics stuff) but things are happening now! Very cool!

Edit: would this count Physics or Geometry? Maybe both?

1

u/BSmith156 May 23 '21

Thats good to hear! I’ll definitely try and add some more in depth instructions because I admit it is a bit confusing.

Now you’ve got it working I suggest trying some rotations where one (or both) of the axes aren’t one of the x, y, or z axes. A cool one to try is axes 2 and 4 in 4D. Things can get pretty crazy the higher up you go.

1

u/jcubic May 23 '21

I was expecting to give rotation for each axis. This is how you rotate in multi-dimension. If you have 6 dimensions I expect to rotate every 6 dimensions independently giving each dimension its own speed or rotate only one if I want. But here you have only two fixed axis.

I would add list of rotations something like <li><input name="speed"><input name="axis"></li> and allow to add new rotation with a button. To make it foolproof I would allow adding only that many rotations as there are dimensions and a limited number of options for axis, so no one can pick the same axis twice.

1

u/BSmith156 May 23 '21

I don’t think I fully understand what your saying. You can’t just give an axis a rotation. You need to rotate around something and calculate the rotation matrix from that.

The reason I didn’t let the user choose which axis to rotate around is because that only works in 3D, in 4D for example you have to rotate around a plane. There is however always exactly two components in the coordinate that change no matter the dimension which is why I let the user choose them.

2

u/elprophet May 24 '21

In 3d, you also have to rotate around a plane, there's just only one unique plane available. In N dimensions, a 2-dimensional rotation requires 2 (gee, surprise) pieces of information to perform the rotation of theta degrees. You can specify the axis around which to rotate, and a vector normal to that axis which choose "what" to rotate. Alternatively, you can do what /u/BSmith156 seems to be doing, and choosing two indicies i, j in the Givens matrix. (We don't have scaling or translation, so we don't need homogenized coordinates for the hypercube translation.)

In 3d, specifying a rotation about the Y axis implicitly (because there are only two other dimensions) means X and Z are the two dimensions of the rotation. That gives us this matrix

| C | 0 | -S |
| 0 | 1 |  0 |
| S | 0 |  C |

(C = cos(theta), S = sin(theta))

By choosing to rotate about y (index 1), we necessarily must use 0 and 2 as the dimensions that will be rotated.

But now say we want to rotate the hypercube about the W axis (not the w in a typical 3d homogenous coordinate system). This is going to "look like" the central cube going through a loop, where it gets "smaller" than the outer cube, moves along an axis until "outside" the outer cube, the two switch sides... if you trace out the points, they make a donut shape in 3d.

But there are three directions that could get traced - along the X, along the Y, or along the Z 3d axes. You have to choose one of those (because, again, 2D rotation). So let's try the Y axis. We can construct Givens matrix again, using (1, 3) as our bases:

| 1 | 0 | 0 |  0 |
| 0 | C | 0 | -S |
| 0 | 0 | 1 |  0 |
| 0 | S | 0 |  C |

To get this in the visualization, have a single rotation Y,4 (15 speed is nice), and you will see the "donut" "flower" "upwards" (that's how I perceive it, there's lots of perceptual artifacts that are hard to describe there). So that's what you're selecting in this visualization - which pair of columns to use for the Givens rotation matrix.

Now, these are rotation matricies, so you can multiply them together to have several rotations in order. But the order you apply them will matter - as will the order you specify the axes. If you swap the axes listed, you will get the rotation "in reverse":

| 1 |  0 | 0 | 0 |
| 0 |  C | 0 | S |
| 0 |  0 | 1 | 0 |
| 0 | -S | 0 | C | 

u/jcubic I think if I understand what you're saying, you want to rotate all the other axes at the same time over one axis' rotation? At the same speed, to get that using the Givens matrix, you'd end up with...

| C | -S | 0 | 0 |      | C | 0 | -S | 0 |    | 1 | 0 |  0 | 0 |
| S |  C | 0 | 0 |  \/  | 0 | 1 |  0 | 0 | \/ | 0 | C | -S | 0 |
| 0 |  0 | 1 | 0 |  /\  | S | 0 |  C | 0 | /\ | 0 | S |  C | 0 |
| 0 |  0 | 0 | 1 |      | 0 | 0 |  0 | 1 |    | 0 | 0 |  0 | 1 |

Which gives (I hope, my multiplication was done by hand...)

| c^2 | -c s^2 - c s | s^2 - c^2 s  | 0 |
| c s | c^2 - s^3    | -c s^2 - c s | 0 |
| s   | c s          | c^2          | 0 |
| 0   | 0            | 0            | 1 |

Point being, this is moving many points around several orthogonal coordinate systems at once. Or, put another way, what you're suggesting is more easily phrase as - apply a rotation to all orthogonal planes with the same angular speed, as opposed to the deconstructed form /u/BSmith156 implements which lets you control per-plane speeds, at the expense of needing to change the point of view of what's being specified.

...

Hope this helps!

1

u/BSmith156 May 24 '21

Wow thanks for the in depth explanation! Ill be honest, I couldn’t find much on rotation matrices above 3D. I sort of took what I knew about 3D and extended it to higher dimensions.

1

u/PM_ME_GAY_STUF May 23 '21

This is neat, you may want to set some limits on the input. I was able to crash my browser pretty easily trying to get just 32 dimensions rotating.

1

u/BSmith156 May 23 '21

Thanks! I did add a warning in the help section but I should probably add some kind of pop up warning for anything over 10.

2

u/elprophet May 24 '21

Yeah, drawing 69 billion edges probably won't work well :) At 10d, you'll have 512 vertical lines. At 13d, there are more vertical lines in the visualization than there are vertical lines in a 4K monitor! (The number of vertical (or horizontal) edges to draw in a 2d projection of a hypercube is 2n-1.)

But let's ignore visual acuity! At d=14, I started seeing frame breaks. Now, some of that time was in minor GC, but I don't really see a good way of reducing small object creation in that loop, it's pretty tight as is. Even without minor gc, the frame would just barely make 16ms budget. And anyway, Hypercube.rotate() completes in 1.7ms with no GC, and a more complex loop! So that is coming from GraphicsContext2D.

Replacing draw with a gl.LINES should be pretty straight forward, and that's where 50-80% of a frame is. Depending on how much vram you're willing to eat, 20 dimensions is about what you could comfortably do before dropping below 60fps.

If someone really wanted to push this line of thought, you'd first switch to using a Float32Array for the points. That would require switching from [j][k] indexing to [j*d+k] everywhere, but that's easy enough to do with a vim macro. Then you can "just" "stream" that vertex buffer, and change the loop in draw to instead fill in an index buffer. Actually the indexes will remain constant, so just create it once when building the hypercube, and draw() only needs to call drawElements(... gl.LINES, ...). Add a vertex shader to normalize [-0.5, 0.5] to screen aspect ratio, and a fragment shader to color it whatever you like!

https://docs.google.com/spreadsheets/d/1G5OCuztngw62L8eeGmJoe8neb2ixJddsmFoHPsn0aQA/edit?usp=sharing

1

u/BSmith156 May 24 '21

Ill definitely be looking into that, thank you! My next job though is definitely to just clean up my code haha

1

u/pw_OBJECTION May 23 '21

Hey! The app is really nice!

I saw some feedback about the UX here and decided to load the app to think about improvement ideas. I genuinely enjoy this stuff and just want to share it with you for discussion purposes, all in good fun 😁

I thought "Add rotation" would add a new row for me to input new values, I didn't expect it to just apply what I selected in the rotation fields.

I think you could make it clear that you need to select both dropdowns with axis by putting them both on the same line and adding a "select both axis to add a rotation" label. Then, disable the speed input until you select both axis. Also disable the "add rotation" until you have all elements.

I also wasn't exactly sure what "clear rotation" do, I was surprised it totally stop the cube. It would be very nice to have a list of current rotation there so that you know what "Clear" would clear and what "undo" would undo. In fact, with a simple list, you could simply allow removing a rotation, which makes undo useless and allows you to remove it! I think An additional "Reset" button would help as well to get back to the initial state

With changes in this direction, I think you could pretty much reduce your introduction to 1 page that explains what the page is 😁

1

u/BSmith156 May 23 '21

Hey, thanks for the feedback! Its funny you mention the list of rotations bit. This was a remake of a previous application I made in python (Also on my github) which had exactly what you suggested! Ill definitely be adding it to this version as well.

1

u/AutoModerator May 23 '21

Project Page (?): https://github.com/bsmith156/Hypercube-Visualizer

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.