Deriving constants that are used to construct an isometric cube

89 Views Asked by At

Problem Overview

I'm working on a website that uses CSS/JS to create this isometric, resizable cube.

enter image description here

Through some "logical" experimentation, I was able to determine the constants that allow for the 3 planes to stay connected together as expected:

enter image description here

Here are the constants used specifically

  • .7049166488
  • .210
  • .494916649 (just the difference of the previous two)

I was wondering what the actual formula of these numbers is, given the fact that the faces are squares skewed on 22.5 degree angles. Any help in deriving them would be appreciated :)

Code Walkthrough & Diagrams

As requested, I've done my best to walk through each of the skews and shifts the code performs on each face. Calculations are as follows:

For a given xWidth x, yWidth y and cube height h (this example is performed with $x = 20, y = 40, h = 60$),

  • Create a $y * x$ rectangle, this is the top face.
  • Create a $x * h$ rectangle, this is the left face.
  • Create a $y * h$ rectangle, this is the right face.
  • Align all rectangles by their top-right corners.

Note: Here, the right face is the darkest, and the top the lightest.

Impact of skews on base rectangles

Then, perform these skews:

  • Skew the top and bottom edges of the left face by 22.5 degrees
  • Skew the top and bottom edges of the right face by -22.5 degrees (sloping upwards instead of downwards)
  • Skew all edges of the top face by 22.5 degrees
  • Rotate the top face 45 degrees

Margin-shifting diagram

Finally, perform these translational operations:

  • Shift the entire block down $h + .7049x + .21y$
  • Shift the top face left $.5x$
  • Shift the left face left $x$
  • Shift the left face down $.4949x + .21y$
  • Shift the right face down $.7049x$

Code

I've provided my code here in case it helps anyone.

JSX:

import './Block.css';

export default function Block ({xWidth, yWidth, height}) {
  return (
    <div class="block" style={{marginTop: -height - xWidth*.7049166488 - yWidth*.210, left: 200, top: 200}}>
      <figure class="top" style={{width:yWidth, height:xWidth, marginLeft:-1*xWidth/2}}></figure>
      <figure class="left" style={{width:xWidth, height:height, marginLeft:-1*xWidth, marginTop:xWidth*(.494916649) + (yWidth)*(.210)}}></figure>
      <figure class="right" style={{width:yWidth, height:height, marginTop:xWidth*(.7049166488)}}></figure>
    </div>
  )
}

CSS:

.block {
  position: absolute;
}

.block > figure {
  position: absolute;
  -webkit-transform-origin: 50% 50% 0;
}

.left {
  transform: skewY(22.5deg);
  margin: 0;
  padding: 0;
  background-color: #00E5BB;
}
.right {
  transform: skewY(-22.5deg);
  margin: 0;
  padding: 0;  
  background-color: #00CBA5;
}
.top {
  transform: rotateZ(-45deg) skew(22.5deg, 22.5deg);
  margin: 0;
  padding: 0;
  background-color: #00FFD0;
}
1

There are 1 best solutions below

1
On BEST ANSWER

Short summary:

  • Your $0.7049166488$ is an approximation of $\sin(45°)=\cos(45°)=\frac12\sqrt2$ and stems from your rotation. A better approximation would be $0.707106781186547524400844362105$.
  • Your $0.210$ is an approximation of $\tfrac12\tan(22.5°)=\tfrac12\left(\sqrt2-1\right)$ and stems from your skew transformations. A better approximation would be $0.207106781186547524400844362105$.
  • Your $0.494916649$ should indeed be the difference between the other two, with an exact value of $\frac12=0.5$.

Long answer:

Throughout this post I'll be writing affine transformations as matrices acting on homogeneous coordinates.

$$ \begin{pmatrix}a&b&c\\d&e&f\\0&0&1\end{pmatrix} \cdot\begin{pmatrix}x\\y\\1\end{pmatrix} =\begin{pmatrix}ax+by+c\\dx+ey+f\\1\end{pmatrix} $$

In this notation the one in the last row is just a tool which enables us to express translations in the same framework. By not treating translations as a separate vector addition operation, we can combine multiple operations by simple matrix multiplication.

My coordinate system will have its origin in the top left corner (because all your items are aligned using top and left measurements) and will have the $y$ direction pointing down as is the convention in computer graphics, not up as the convention in mathematics. I'll write $x,y,h$ instead of xWidth, yWidth, height, and I'll use $t:=\tan(22.5°)=\sqrt2-1$ as another abbreviation.

Let's apply this to the left face, to get it into shape but not translate it yet.

$$ \begin{pmatrix} 1 & 0 & \frac x2 \\ 0 & 1 & \frac h2 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 1 & 0 & 0 \\ t & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 1 & 0 & -\frac x2 \\ 0 & 1 & -\frac h2 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 0 & x & x & 0 \\ 0 & 0 & h & h \\ 1 & 1 & 1 & 1 \end{pmatrix}\\= \begin{pmatrix} 0 & x & x & 0 \\ -\frac t2x & \frac t2x & h+\frac t2x & h-\frac t2x \\ 1 & 1 & 1 & 1 \end{pmatrix} $$

Read this from right to left: the rightmost matrix consists of four columns representing the four corners of the rectangle, with a constant $1$ added in the third row. Then we apply a transformation which shifts the center of the rectangle to the origin of the coordinate system, in line with the default transform-origin (and your explicit webkit setting). Then you apply the skewY using the matrix straight from the documentation, and then you shift the origin back to where it was. The end result is again a matrix with four columns representing the four transformed corners, where you notice a change in the vertical position of all four corners.

Same for the right face:

$$ \begin{pmatrix} 1 & 0 & \frac y2 \\ 0 & 1 & \frac h2 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 1 & 0 & 0 \\ -t & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 1 & 0 & -\frac y2 \\ 0 & 1 & -\frac h2 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 0 & y & y & 0 \\ 0 & 0 & h & h \\ 1 & 1 & 1 & 1 \end{pmatrix}\\= \begin{pmatrix} 0 & y & y & 0 \\ \frac t2y & -\frac t2y & h-\frac t2y & h-\frac t2y \\ 1 & 1 & 1 & 1 \end{pmatrix} $$

And lastly the top face, where you apply a skew followed by a rotate (although you used rotateZ for some reason).

For that one I use yet another abbreviation: $s:=\sin(45°)=\cos(45°)=\frac1{\sqrt2}=\frac12\sqrt2$. With this abbreviation, the matrix for the rotation alone becomes

$$ \begin{pmatrix} \cos(-45°) & -\sin(-45°) & 0 \\ \sin(-45°) & \cos(-45°) & 0 \\ 0 & 0 & 1 \end{pmatrix}= \begin{pmatrix} s & s & 0 \\ -s & s & 0 \\ 0 & 0 & 1 \end{pmatrix} $$

And then transforming four corners of a rectangle in a chain, with skew before rotation because it is written on the right both here in the matrix multiplication and in your transform property:

$$ \begin{pmatrix} 1 & 0 & \frac y2 \\ 0 & 1 & \frac x2 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} s & s & 0 \\ -s & s & 0 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 1 & t & 0 \\ t & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 1 & 0 & -\frac y2 \\ 0 & 1 & -\frac x2 \\ 0 & 0 & 1 \end{pmatrix}\cdot \begin{pmatrix} 0 & y & y & 0 \\ 0 & 0 & x & x \\ 1 & 1 & 1 & 1 \end{pmatrix}\\= \begin{pmatrix} -\frac12\,x & -\frac12\,x+y & \frac12\,x+y & \frac12\,x \\ (1-s)\,x+(-\frac12+s)\,y & (1-s)\,x+(\frac12-s)\,y & s\,x+(\frac12-s)\,y & s\,x+(-\frac12+s)\,y \\ 1 & 1 & 1 & 1 \end{pmatrix} $$

Note that I used the actual values of $s$ and $t$ to combine these and express the above in terms of $s$ only. Done symbolically the $t$ wouldn't simply cancel out, you need the relationship between these two to get rid of one. Specifically $t=\sqrt2-1=2s-1$.

Now we want to align all of these. Since the bottom front corner is to remain fixed, let's make that the origin. So we want the third column (bottom right corner) of the left face to move to that origin, which is a translation by

$$ \begin{pmatrix} -x\\ -h-\tfrac t2x \end{pmatrix} $$

The relevant factor there in front of the $x$ is

$$\tfrac t2=\tfrac12\tan(22.5°)=\tfrac12(\sqrt2-1)\approx 0.2071\approx 0.7049166488-0.494916649$$

So this roughly matches the combined margin-top of the block and left elements, noticing that the yWidth terms in your style cancel each other out.

To move the right face we move the fourth column (bottom left corner) to the origin, using a translation by

$$ \begin{pmatrix} 0 \\ -h+\frac t2y \end{pmatrix} $$

The relevant term in front of the $y$ is again

$$\tfrac t2=\tfrac12\tan(22.5°)=\tfrac12(\sqrt2-1)\approx 0.2071\approx 0.210$$

That is the term you use for the combined margin-top of block and right, noticing that the xWidth terms cancel each other out.

Now for the top face. We want the fourth column (originally the bottom left corner, but bottom corner after the transformations) to move to $(0,-h)$. We achieve that using a translation by

$$ \begin{pmatrix} -\frac12x \\ -h-sx+\left(\tfrac12-s\right)y \end{pmatrix} = \begin{pmatrix} -\frac12x \\ -h-\tfrac12\sqrt2x-\tfrac12(\sqrt2-1)y \end{pmatrix} $$

The factor $\tfrac12(\sqrt2-1)\approx0.210$ we already discussed above. The new term is

$$\tfrac12\sqrt2\approx0.7049166488$$

where the approximate value is from your source; the last number of digits is wrong.

Note that you might be able to avoid a lot of this hassle by picking a transformation origin in such a way that it allows you exact placement of either the top front or the bottom front corner of the cube. Having the origin in the center means you have to account for the transformations for every corner, there is none that remains unaffected.

You might be wondering where the exact equation for $\tan(22.5°)=\sqrt2-1$ is coming from. There are many ways to derive that. https://en.wikipedia.org/wiki/List_of_trigonometric_identities has formulas for half or double angles which you can use. Personally I came from the inscribed angle theorem. The chord on the unit circle between $A=(1,0)$ and $B=(\frac12\sqrt2,\frac12\sqrt2)$ is subtended by a central angle of $45°$. In other words for $O=(0,0)$ you get $\measuredangle AOB=45°$. According to the theorem, the inscribed angle is half that, which you get at any point on the circle, specifically at the point $C=(-1,0)$. So $\measuredangle ACB=22.5°$. Since the edge $AC$ is horizontal, the tangens of that angle is just the slope of the line $CB$ which is

$$t= \frac{\frac12\sqrt2}{1+\frac12\sqrt2}= \frac{\frac12\sqrt2\left(1-\frac12\sqrt2\right)}{\left(1+\frac12\sqrt2\right)\left(1-\frac12\sqrt2\right)}= \frac{\frac12\sqrt2-\frac12}{1-\frac12}= \sqrt2-1$$