[Closed] Nodes facing each other
I want to calculate if two nodes are facing each other within a given angle threshold.
I’ve gotten a start on it but I’m not entirely sure if this method is an ideal solution. I was hoping to get some feedback from the community and see their thoughts.
fn GetPointVector ptA ptB =
(
return (Dot ptA ptB)
)
fn IsNodeFacing nodeA:undefined nodeB:undefined axis:#X angleThreshold:0 =
(
-- if dot == 1 then directly facing each other
val = case axis of
(
#X: (GetPointVector nodeA.transform.row1 nodeB.transform.row1)
#Y: (GetPointVector nodeA.transform.row2 nodeB.transform.row2)
#Z: (GetPointVector nodeA.transform.row3 nodeB.transform.row3)
)
-- if val == 0 then the node is perpendicular
-- if val is negative then they are facing each other
-- if val is positive then they are facing away from each other
--(Dot(nodeA.transform.X, nodeB.transform.X) < -0.8)
)
IsNodeFacing nodeA:selection[1] nodeB:selection[2]
What do you mean by ‘two nodes facing each other’? Their local axis pointing each other?
Perhaps you can use the ‘intersectRay’ function, creating the ray following the object desired axis.
With the distance between the two nodes and the angle threshold, you can easily create a temporary plane and check the intersection in both directions.
Check this simple example out. Perhaps you can get something useful out of it.
(
local viewAngle = 45
local viewDistance = 150
fn BuildScene =
(
delete objects
center = dummy()
obj1 = converttomesh (ngon radius:15 cornerRadius:0 nsides:3 pos:[0,0,0] wirecolor:red name:"OBJ1")
meshop.chamferVerts obj1 #{2,3} 10
obj2 = copy obj1 pos:[100,0,0] wirecolor:green name:"OBJ2" parent:center
view1 = arc radius:viewDistance from:(360-(viewAngle/2.0)) to:(viewAngle/2.0) pie:on pos:[0,0,0] wirecolor:black name:"VIEW1" parent:obj1
view2 = copy view1 pos:[100,0,0] name:"VIEW2" parent:obj2
with animate on
(
for j = 1 to 2 do at time (j*50)
(
rotate obj1 (angleaxis 180 [0,0,1])
rotate obj2 (angleaxis -180 [0,0,1])
rotate center (angleaxis -180 [0,0,1])
)
)
for j in #(obj1,obj2,center) do
(
for i = 1 to 3 do
(
j.rotation.controller.Z_Rotation.controller.keys[i].inTangentType = #slow
j.rotation.controller.Z_Rotation.controller.keys[i].outTangentType = #slow
)
)
)
fn IsNodeAFacingNodeB nodeA nodeB angleThreshold:0 =
(
ang = dot nodeA.transform.row1 (normalize (nodeA.pos-nodeB.pos))
return (acos (ang * -1) <= (angleThreshold/2.0))
)
fn RunTest =
(
isFacingA = IsNodeAFacingNodeB $OBJ1 $OBJ2 angleThreshold:viewAngle
isFacingB = IsNodeAFacingNodeB $OBJ2 $OBJ1 angleThreshold:viewAngle
if isFacingA and isFacingB then
(
$VIEW1.wirecolor = $VIEW2.wirecolor = yellow
)else(
if isFacingA then $VIEW1.wirecolor = red else $VIEW1.wirecolor = black
if isFacingB then $VIEW2.wirecolor = green else $VIEW2.wirecolor = black
)
)
BuildScene()
unRegisterTimeCallback RunTest
registerTimeCallback RunTest
playAnimation()
)
Here is a minor update, a little better as it does not use the Time Callback and you can change the View Angle in real time.
Aditionally the IsNodeAFacingNodeB() function takes any vector as direction, not just X, Y or Z.
It would be better to use Controllers, but the code wouldn’t be as easy to read.
(
local viewAngle = 45
local viewDistance = 150
local obj1, obj2, view1, view2, cone1, cone2
fn BuildScene =
(
delete objects
center = dummy()
obj1 = converttomesh (ngon radius:15 cornerRadius:0 nsides:3 pos:[0,0,0] wirecolor:red name:"OBJ1")
meshop.chamferVerts obj1 #{2,3} 10
obj2 = copy obj1 pos:[100,0,0] wirecolor:green name:"OBJ2" parent:center
view1 = arc radius:viewDistance from:(360-(viewAngle/2.0)) to:(viewAngle/2.0) pie:on pos:[0,0,-1] wirecolor:black name:"VIEW1" parent:obj1
view2 = copy view1 pos:[100,0,-1] wirecolor:black name:"VIEW2" parent:obj2
cone1 = cone heightsegs:1 capsegs:1 sides:20 height:viewDistance radius1:0 radius2:((tan (viewAngle/2.0))*viewDistance)wirecolor:black name:"CONE1" parent:obj1 isHidden:true
cone2 = copy cone1 pos:[100,0,0] wirecolor:black name:"CONE2" parent:obj2 isHidden:true
rotate cone1 (angleaxis 90 [0,1,0])
rotate cone2 (angleaxis 90 [0,1,0])
with animate on
(
for j = 1 to 2 do at time (j*50)
(
rotate obj1 (angleaxis 180 [0,0,1])
rotate obj2 (angleaxis -180 [0,0,1])
rotate center (angleaxis -180 [0,0,1])
)
)
for j in #(obj1,obj2,center) do
(
for i = 1 to 3 do
(
j.rotation.controller.Z_Rotation.controller.keys[i].inTangentType = #slow
j.rotation.controller.Z_Rotation.controller.keys[i].outTangentType = #slow
)
)
slidertime = 0
)
fn IsNodeAFacingNodeB nodeA nodeB vector:[1,0,0] angleThreshold:0 useNodeCenter:false =
(
if useNodeCenter then
(
posA = nodeA.center
posB = nodeB.center
)else(
posA = nodeA.pos
posB = nodeB.pos
)
tm = nodeA.transform
tm.row4 = [0,0,0]
ang = dot (vector * tm) (normalize (posA-posB))
return (acos (ang * -1) <= (angleThreshold/2.0))
)
fn RunTest =
(
isFacingA = IsNodeAFacingNodeB obj1 obj2 angleThreshold:viewAngle
isFacingB = IsNodeAFacingNodeB obj2 obj1 angleThreshold:viewAngle
if isFacingA and isFacingB then
(
#(view1, view2, cone1, cone2).wirecolor = yellow
)else(
if isFacingA then #(view1,cone1).wirecolor = red else #(view1,cone1).wirecolor = black
if isFacingB then #(view2,cone2).wirecolor = green else #(view2,cone2).wirecolor = black
)
)
BuildScene()
try destroydialog ::RO_FACING_NODES catch()
rollout RO_FACING_NODES "Facing Nodes" width:146 height:100
(
spinner spn_fps "FPS:" pos:[46,8] fieldwidth:56 range:[1,30,15] scale:1
spinner spn_angle "View Angle:" pos:[12,36] fieldwidth:56 range:[0,180,45] scale:1
checkbutton bt_play "Play" pos:[8,60] width:128 height:32
timer tm_player "" interval:66 active:false
local end = animationrange.end
on tm_player tick do
(
if currenttime == end do slidertime = 0
slidertime += 1
RunTest()
)
on bt_play changed arg do
(
tm_player.active = not tm_player.active
if arg then bt_play.text = "Stop" else bt_play.text = "Play"
)
on spn_fps changed arg do tm_player.interval = 1000.0 / arg
on spn_angle changed arg do
(
viewAngle = arg
view1.from = 360-(viewAngle/2.0)
view1.to = viewAngle/2.0
view2.from = 360-(viewAngle/2.0)
view2.to = viewAngle/2.0
)
)
createdialog RO_FACING_NODES
)