Search code examples
javascriptcssmatrixtransformeuler-angles

Calculate coordinates before (CSS-transform) rotation of point


What I want to do: Give a javascript function the coordinates for a triangle in a 3d-room as parameter and it calculates the svg path and the css transformation angles for this object.

What I've already figured out:

  • to calculate the triangle between the 3 points, I would just need to calculate the lenghts in the room of all 3 sides of it. Then I would be able to draw it in a x-y-coordinate system (angles are calculateable with 3 sides)
  • furthermore, I need the angles with which the triangle has to be rotated to achive my wanted result
  • to do so, I defined one point of the triangle as the origin of the transformation (0|0|0), it can be translated later on.

But then I've failed. I was able to calculate the Z- and Y-angles for a resulting point Pr(x|y|z) with a origin point Po(x|0) on the plane x-y. My thought was to 'fix' one triangle point on the x-axis, and then rotate around the x-axis ... but anyway - it's not working. I thought the x-axis gets rotated first, but thats not the case.


So what I need is the unknown transformation Matrix for given (resulting) point/triangle and its origin triangle, which can be considered as given, where the resulting triangle is located in the three-dimensional room, the origin triangle is in the two-dimensional room (a svg path).

I really don't have a clue, I'm in the 11th grade so it's kind of difficult to figure it out for me.

Thanks a lot for any kind of help! Jonas.


Solution

  • Finally, after a few days with too boring lessons, here my solution!

    1. Actually you can decide which CSS transformation should be applied first: rotateY(~deg) rotateX(~deg) rotates firstly around the Y-axis, then around the x-axis. Caution! The axis of the coordinate system get rotated, together with you object.

    Here an animation to show you what I mean: ext. link. Normally, you would expect that the x-axis is still in place after a Y- and Z- rotation, but it gets rotated with the Object/SVG. So you are rotating around the axis of the object.

    1. There is no need for an transformation matrix: At the end, I calculated the angles for the Y- and Z-rotation to move the first point P1(x|y|z) to P1'(x|0|0). Now with a simple X-rotation I was able to set the z-value of the second point to zero. Applying the X-rotation as the last one, the coordinates of P1 do not change, since it is fixed on the x-axis.

    So here my final code. Intentionally, I will give you the one with debugging logs, so you are probably able to understand it better.

    $(document).ready(function() {
      calcTransf(80, 20, 40, 40, 100, 100);
    });
    
    function calcTransf(x1, y1, z1, x2, y2, z2) {
    
      $(".cube").append('<svg class="C_R0"><path fill="rgba(80, 204, 04, 0.5)" stroke-width="0" d="M0,0 L20,20 L20,0 Z"></path></svg>');
      $(".cube").append('<svg class="C_R1"><path fill="rgba(80, 204, 04, 0.5)" stroke-width="0" d="M0,0 L20,20 L20,0 Z"></path></svg>');
      $(".cube").append('<svg class="C_R2"><path fill="rgba(80, 204, 04, 0.5)" stroke-width="0" d="M0,0 L20,20 L20,0 Z"></path></svg>');
      $(".C_R0").css("transform", "translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)");
      $(".C_R1").css("transform", "translateX(" + x1 + "px) translateY(" + y1 + "px) translateZ(" + z1 + "px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)");
      $(".C_R2").css("transform", "translateX(" + x2 + "px) translateY(" + y2 + "px) translateZ(" + z2 + "px) rotateX(0deg) rotateY(0deg) rotateZ(0deg)");
    
      var Yalpha = -Math.atan2(z1, x1);
      var LX = Math.sqrt(Math.pow(z1, 2) + Math.pow(x1, 2));
    
      x1 = LX;
      y1 = y1;
      z1 = 0;
    
      DEGYalpha = Yalpha / Math.PI * 180;
      console.log("Yalpha " + DEGYalpha);
    
      var Zalpha = Math.atan2(y1, x1);
      var LX = Math.sqrt(Math.pow(y1, 2) + Math.pow(x1, 2));
    
      x1 = LX;
      y1 = 0;
      z1 = 0;
    
      DEGZalpha = Zalpha / Math.PI * 180;
      console.log("Zalpha " + DEGZalpha);
    
      /* -----------------2. Punkt-------------------*/
    
      var x2Ay = x2 * Math.cos(Yalpha) - z2 * Math.sin(Yalpha);
      var z2Ay = z2 * Math.cos(Yalpha) + x2 * Math.sin(Yalpha);
    
      x2 = x2Ay;
      y2 = y2;
      z2 = z2Ay;
    
      console.log("Ay: " + x2 + " " + y2 + " " + z2);
    
      Zalpha = -Zalpha;
      var x2Az = x2 * Math.cos(Zalpha) - y2 * Math.sin(Zalpha);
      var y2Az = y2 * Math.cos(Zalpha) + x2 * Math.sin(Zalpha);
    
      x2 = x2Az;
      y2 = y2Az;
      z2 = z2;
    
      console.log("Az: " + x2 + " " + y2 + " " + z2);
    
      //Winkel z-y
    
      var Xalpha = Math.atan2(z2, y2);
      DEGXalpha = Xalpha / Math.PI * 180;
      console.log("Xalpha " + DEGXalpha);
    
      var z2Ax = z2 * Math.cos(Xalpha) - y2 * Math.sin(Xalpha);
      var y2Ax = y2 * Math.cos(Xalpha) + z2 * Math.sin(Xalpha);
    
      x2 = x2;
      y2 = y2Ax;
      z2 = z2Ax;
    
      console.log("Ax: " + x2 + " " + y2 + " " + z2);
    
      $(".cube").append('<svg class="C_RE"><path fill="rgba(80, 4, 4, 0.5)" stroke-width="0" d="M0,0 L' + x1 + ',0 L' + x2 + ',' + y2 + ' Z"></path></svg>');
      $(".C_RE").css("transform", 'translateX(0px) translateY(0px) translateZ(0px) rotateY(' + DEGYalpha + 'deg) rotateZ(' + DEGZalpha + 'deg) rotateX(' + DEGXalpha + 'deg)');
    
    }
    body {
    	margin: 0; 
    	height: 100%; 
    	width: 100%;
    	perspective: 500px;
    }
    
    .center {
    	transform-style: preserve-3d;
    	transform: translateX(50px) translateY(50px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
    }
    
    .cube {
    	transform-style: preserve-3d;
    	transform: translateX(0px) translateY(0px) translateZ(0px) rotateX(0deg) rotateY(0deg) rotateZ(0deg);
    }
    
    svg {
    	transform-origin: left top;
    	position: absolute;
    	height: 150px;
    	width: 150px;
    }
    <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </head>
    
    <body style="height: 150px; width: 150px;">
    
      <div class="center" style="height: 50px; width: 50px;">
        <div class="cube" style="height: 50px; width: 50px;">
    
        </div>
      </div>
    
    </body>
    
    </html>