Point within rotated coordinates (Vector math)

So I have something like this, a rotated “plane”. Let’s give Vector3s a (X, Z) notation. The relative top left point is coordinates (0, 0), the relative bottom right point is (2, 1). The arrow signifies the lookVector of the CFrame of the plane that’s given.

Pretend the Y rotation (0°)/position is static, (non-existent).

INTENDED GOAL

I want to achieve something like, when you a put in a point (1, .5) or any arbitrary point, it would return a Vector3 like this.

But I’m getting a Vector3 like this. Because I can’t properly put Rotation into the aspect.

How would I achieve the intended goal?
Edit: may I also see the reverse process for plugging in a Vector3 and getting the coordinates? Thanks.

2 Likes

define unit vectors along your axis.
axis j = (0.5, 0.87)
axis k = (0.87,-0.5)
and remap
j,k – (2, 3)
x,y – 2*(0.5, 0.87) + 3*(0.87,-0.5)

or you can just use the angle of rotation and use trig everytime.
sin(angle), cos(angle)
+/- depending on direction

1 Like

First you want to get all other corners of your rectangle.
Since you’re rotating around the top left corner you can get the “real” position of 0, 1 and 2, 0 first. Assuming rotation is clockwise (the rotation shown should be negative in that case) you’ll want to “travel” in the direction of rotation by width to get the real position of 2, 0.

First you’ll want the slope of your line. You can use some trigonometry for this. 2 (the width) should be your hypotenuse. Now you’ll want to find the Y offset from the origin of rotation’s y coordinate. You can use sin to do this: Y/width = sin(radiansOfRotation)

Now you multiply the sin value by with to get the Y offset from the origin’s Y coordinate.

You can then get the X offset using the Pythagorean formula like so: A^2 + Y^2 = width^2
So your X offset should be this: sqrt(A) = sqrt(width^2 - Y^2)

You can now repeat this process for 0, 1 by increasing the rotation value by 90 degrees (the angle of your corners).

Now you can use the offsets of the other two corners to know where the last corner is.

Once you have all of your corners you can find the midpoint and you’re done.

I already know all the corner’s real positions! I’m asking for relative position given a point. (and reverse)

In that case you can simply average the corner positions to get the midpoint.

For this specific case, you can probably use some CFrame math. In order to do that, we will need to do one thing, split into three things:

  • turning the part on its corner
    • getting to the corner
    • turning by an angle modeled after a slope of 1/2
    • going back to center

Getting to a corner is as easy as getting the part’s size and dividing by two. We then translate by that from the part’s starting CFrame.

For turning by the slope of 1/2, math.atan returns an angle equivalent to Y/X, rise over run, same as slope, so math.atan(slope).

We would then clean it up by returning back to the center by translating by a negative of the corner CFrame.

code
-- returns a corner when multiplied by part size
-- negate x and/or z for other corners
local TransformV3 = Vector3.new(1,0,1) / 2
local rotatedPosition = (
    -- start with part's CFrame
    part.CFrame * 
    -- move to corner
    CFrame.new(part.Size * TransformV3) * 
    -- turn by slope Y/X, might need to be negated
    CFrame.Angles(0,math.atan(0.5),0) * 
    -- move back to center
    CFrame.new(-part.Size * TransformV3)
-- return position
).Position

For other use-cases, I would essentially need to know what can change, and how the formula needs to be mutated.

Here’s some code for my earlier answer.
This assumes you have the angle of rotation and point of rotation(origin for new vector space)

Example Script
local origin = Vector3.new(3,2,-1)
local angle = 30

--because, truncation
local int = {
[1] = math.cos(math.rad(angle)),
[2] = -math.sin(math.rad(angle)),
[3] = math.cos(math.rad(angle-90)),
[4] = -math.sin(math.rad(angle-90)),
[5] = math.cos(math.rad(-angle)),
[6] = -math.sin(math.rad(-angle)),
[7] = math.cos(math.rad(-angle-90)),
[8] = -math.sin(math.rad(-angle-90)),
}

for i,v in pairs(int) do
  v = v*1000
  v = math.floor(v)
  int[i] = v/1000
end

--axis units mapped to alternate vector space
local mUnitVec = Vector3.new(int[1],0,int[2])
local oUnitVec = Vector3.new(int[3],0,int[4])
local xUnitVec = Vector3.new(int[5],0,int[6])
local zUnitVec = Vector3.new(int[7],0,int[8])

--base grid is x,y,z y static
--new grid is m,n,o n static

function toMNO(XYZ)
  local XYZNoOffset = XYZ-origin
  local x = XYZNoOffset.X
  local z = XYZNoOffset.Z
  return (x*xUnitVec + z*zUnitVec)
end

function toXYZ(MNO)
  local m = MNO.X
  local o = MNO.Z
  return ((m*mUnitVec+o*oUnitVec)+origin)
end

--setup info
print("Origin of MNO on XYZ: ", origin)
print("Angle in Degrees(CounterClockwise: "..angle)

--unit vectors
print("M axis unit in xyz:",mUnitVec)
print("O axis unit in xyz:",oUnitVec)
print("X axis unit in mno:",xUnitVec)
print("Z axis unit in mno:",zUnitVec)

--tests
print("(0,0,1) -> ",toMNO(toXYZ(Vector3.new(0,0,1))))
print("(3,0,1) -> ",toMNO(toXYZ(Vector3.new(3,0,1))))
print("(1,0,1) -> ",toMNO(toXYZ(Vector3.new(1,0,1))))
print("(2,0,1) -> ",toMNO(toXYZ(Vector3.new(2,0,1))))
print("(7,0,1) -> ",toMNO(toXYZ(Vector3.new(7,0,1))))
print("(4,0,4) -> ",toMNO(toXYZ(Vector3.new(4,0,4))))
print("(1,0,0.5) -> ",toMNO(toXYZ(Vector3.new(1,0,0.5))))

--rounding to 1/100 would be pretty accurate or you can just increase accuracy by changing the 1000 up there to 1000000 :P