[Closed] Position within range
I want to be able to find out where a position is relative to 2 other points. In the 2 diagrams: On the left because point A and B are right above each other, I can just use the Z position to figure that point C is about 71.4% of the way to b on the z plane. But what if the position of point A and B are offset. I can’t figure how to calculate the same value when the measuring angle is not aligned to the world. I have a rough idea that I’ll have to build a transform matrix out of the vector from A to B and somehow figure another vector that helps me get a right angle from the green axis (yellow line) that’s also inline with point C.
I’m stuck at the start trying to build a useful matrix from one axis.
Cheers,
Cg.
You don’t need a matrix at all, for projection there’s dot product: normalize the vector you are projecting to, get the dotproduct which will give you the projected distance, then multiply it by the normalized vector and add to the vector origin:
pA + (vA * (dot (pC - pA) vA))
where pA is the position of A, vA is the NORMALIZED vector (B – A) and pC is the position of C.
Hey Swordslayer thanks for your reply. I’m not sure whether I don’t understand your answer properly, or I didn’t explain myself properly. But I’ve tried this and not getting the result I was looking for. In the code below, I make the 3 points (A,B and C) and then make a root point to link them all to. I do the calculation as you have supplied, then I rotate the root point 45 degrees on y then do the calculation again.
With this setup, I was looking for was a value of 50 units if it’s measuring the distance from A or 150 if it’s returning distance from B. Or if it’s returning percentage it’d be 25% from A or 75% from B.
But as well as not returning a value that I was expecting, when I rotate the whole thing 45 degrees on the Y axis, I was expecting the same result because the relationships between points A B and C haven’t changed. But as you can see if you run the code, I first get a value of:
[0,0,50]
And then after the rotation, it returns a value of:
[35.3554,0,35.3554]
(
clearlistener()
delete Objects
fn calcPos PointA PointB PointC =
(
pA = PointA.transform.row4
pB = PointB.transform.row4
pC = PointC.transform.row4
vA = normalize(pB - pA)
pA + (vA * (dot (pC - pA) vA))
)
PointA = point name:"PointA" size:20 cross:on box:off
PointB = instance PointA
PointB.name = "PointB"
PointB.pos = [0,0,200]
PointC = instance PointA
PointC.name = "PointC"
PointC.pos = [100,0,50]
PointRoot = point name:"PointRoot" size:50 cross:off box:on
PointRoot.wirecolor = blue
PointA.wirecolor = PointB.wirecolor = PointC.wirecolor = red
PointA.parent = PointB.parent = PointC.parent = PointRoot
format "%
"(calcPos PointA PointB PointC)
PointRoot.transform = (matrix3 [0.707107,0,-0.707107] [0,1,0] [0.707107,0,0.707107] [0,0,0])
format "%
"(calcPos PointA PointB PointC)
)
Well, since all your source positions are in world space, it will be a point in space in world coordinates as well. It would be the same value only if you rotated about it or if you supplied the positions in parent space. If you want it in a different coordsys, transform it accordingly, for example for the PointRoot:
(calcPos PointA PointB PointC) * inverse PointRoot.transform
Btw. instead of guessing if the values are what you expected, why not create a point there?
Point pos:(calcPos PointA PointB PointC)
I just looked up vector projection and found this link at khan academy.
I didn’t even get half way through the vid before it all clicked into place and I realised that all I need to do was measure the distance from pointA to the returned value to get what I need.
Thanks again.
Cg.
Just to make sure you don’t make it unnecessarily complicated, by ‘measure the distance to the returned point’, you don’t mean really measure the distance, right? The distance is the dot product part:
dot (pC – pA) vA
Yup, I get it now. No distance needed. Just length of returned vector.
Thanks for your persistence.
Cg.
Here’s a version of the code that returns both ways. vector length and distance tested.
Not sure if one is better than the other.
Your help is much appreciated.
(
clearlistener()
delete Objects
fn calcPos PointA PointB PointC =
(
pA = PointA.transform.row4
pB = PointB.transform.row4
pC = PointC.transform.row4
vA = normalize(pB - pA)
projVec = (pA + (vA * (dot (pC - pA) vA)))
#((length (projVec - pA)),(distance projVec pA))
)
PointA = point name:"PointA" size:20 cross:on box:off
PointB = instance PointA
PointB.name = "PointB"
PointB.pos = [0,0,200]
PointC = instance PointA
PointC.name = "PointC"
PointC.pos = [100,0,50]
PointRoot = point name:"PointRoot" size:50 cross:off box:on
PointRoot.wirecolor = blue
PointA.wirecolor = PointB.wirecolor = PointC.wirecolor = red
PointA.parent = PointB.parent = PointC.parent = PointRoot
PointRoot.pos = [20,40,60]
format "%
"(calcPos PointA PointB PointC)
PointRoot.transform = (matrix3 [0.707107,0,-0.707107] [0,1,0] [0.707107,0,0.707107] [20,40,60])
format "%
"(calcPos PointA PointB PointC)
)
try this little toy:
try (destroydialog RelativePoint) catch()
rollout RelativePoint "Relative Point" width:200
(
--checkbox use_scale_ch "Use Scale"
button create_bt "Create" width:180 align:#center
button reset_bt "Reset" width:180 align:#center
local targets = #()
local rpoint = undefined
local ini_tm = matrix3 1
local rel_tm = matrix3 1
local scl_unit = 1
fn makeMatrix a b =
(
front = normalize (b.pos - a.pos)
up = z_axis
side = cross front up
matrix3 front side up a.pos
)
fn updatePoint use_scale:on = try
(
scl = distance targets[1] targets[2]
tm = makeMatrix targets[1] targets[2]
if use_scale do prescale tm ([1,1,1] * scl / scl_unit)
rpoint.pos = (rel_tm * tm).pos
)
catch()
fn setupUpdate =
(
deleteAllChangeHandlers id:#RelativePoint
when transform targets change id:#RelativePoint do updatePoint()
)
on reset_bt pressed do --undo "Reset" on
(
a = targets[1]
b = targets[2]
c = rpoint
scl_unit = distance a b
ini_tm = makeMatrix a b
rel_tm = c.transform * inverse ini_tm
setupUpdate()
)
on create_bt pressed do undo "Create" on
(
delete objects
targets[1] = point name:#A pos:(random [100,100,0] -[100,100,0]) wirecolor:green size:10
targets[2] = point name:#B pos:(random [100,100,0] -[100,100,0]) wirecolor:green size:10
rpoint = point name:#C pos:(random [100,100,0] -[100,100,0]) wirecolor:yellow size:15
reset_bt.pressed()
)
on RelativePoint open do
(
setupUpdate()
)
)
createdialog RelativePoint
ALL POINTS LIVE IN XY WORLD
OK, I just re-read and understand that the returned point was made by getting the distance and figuring out the ratio of the original vector and then offsetting it by point A. So yes I was still over complicating it.
This is working perfectly
(
clearlistener()
delete Objects
fn calcPos PointA PointB PointC =
(
pA = PointA.transform.row4
pB = PointB.transform.row4
pC = PointC.transform.row4
vA = normalize(pB - pA)
dot (pC - pA) vA
)
PointA = point name:"PointA" size:20 cross:on box:off
PointB = instance PointA
PointB.name = "PointB"
PointB.pos = [0,0,200]
PointC = instance PointA
PointC.name = "PointC"
PointC.pos = [100,0,50]
PointRoot = point name:"PointRoot" size:50 cross:off box:on
PointRoot.wirecolor = blue
PointA.wirecolor = PointB.wirecolor = PointC.wirecolor = red
PointA.parent = PointB.parent = PointC.parent = PointRoot
PointRoot.pos = [20,40,60]
format "%
"(calcPos PointA PointB PointC)
PointRoot.transform = (matrix3 [0.707107,0,-0.707107] [0,1,0] [0.707107,0,0.707107] [20,40,60])
format "%
"(calcPos PointA PointB PointC)
)