PDA

View Full Version : Point3 of Polygon


JokerMartini
05-21-2011, 06:18 AM
Calculate the Point3 value of Click”A” and Click”B” of the picked polygon and print it to the listener as well has have the dotted line display between the two clicks. The approach to do this would be similar to the Align to face script. But just print the point 3 value to the listener. For some reason I can just not get this one working. Here is the align to face script it might help. It is a bit weird on how it works.

http://forums.cgsociety.org/attachment.php?attachmentid=162073&stc=1

(
tool AlignToSurfaceTool
(
local somethin=undefined
local OrgPos=undefined
local OrgRot=undefined
local target_mesh=undefined
local StartDragging=0
local posy=undefined
local roty=undefined
local OrgViewY=undefined

fn g_filter o =
(
if o!=somethin then
(
superclassof o == Geometryclass
)
else
(
false
)
)

fn ResetStuff str=
(
somethin.pos = OrgPos
somethin.dir = OrgRot
)

fn DoMyStuff str=
(
local myRay=mapScreenToWorldRay viewPoint -- make a ray from active viewport
local tempRay=intersectRay target_mesh myRay --see if the ray hits the picked object
if tempRay!=undefined then --if we actually hit the picked object set to surface
(
somethin.pos = tempRay.pos
somethin.dir = tempRay.dir
)
else -- otherwise make it reset
(
ResetStuff now
)
str --functions need to return somethin right
)

on start do
(
--if something is selected
if $!=undefined then
(
somethin=$
OrgPos=somethin.pos --save original position
OrgRot=somethin.dir --save original rotation
target_mesh = pickObject message:"Pick Target Surface" forceListenerFocus:false filter:g_filter
)
else -- if nothing is selected
(
messageBox "Start this tool with an object selected"
#stop
)
)

on mouseAbort clicker do
( --reset position and rotation
ResetStuff now
)

on mousePoint clickno do
(
if (clickno == 1 and target_mesh!=undefined)then
(
DoMyStuff now -- function calls dont seem to work without a parameter
)
else
(
#stop --bail
)
)

on freeMove do
(
if target_mesh!=undefined then
(
DoMyStuff now --this way it actually shows it is workin
)
else
(
#stop --bail
)
)

on mouseMove clickno do
(
if StartDragging==0 then
(
posy = somethin.pos -- dont ask why i need this
roty = somethin.rotation -- dont ask why i need this
OrgViewY=viewPoint.y -- store click loc for later
StartDragging=1 -- make sure this dont happen again
)
somethin.rotation = roty -- dont ask why setting rotation moves the object
somethin.pos = posy -- but now we got to move it back... theres got to be a better way
local tempRot = eulerangles 0 0 0 -- make a blank euler
tempRot.z=((viewPoint.y-OrgViewY)/2) -- make it only rotate more or less by initial screen click loc
in coordsys local rotate somethin tempRot -- and finally rotate locally
--somethin.pos = posy
)
)
startTool AlignToSurfaceTool

)

Swordslayer
05-21-2011, 09:25 AM
There are quite a few ways to achieve that, mouseTrack seems to make sense here but for some applications even simple pickPoint can do the job:

(
local previousSnap = snapMode.active
snapMode.active = true
local previousState = snapmode.getOSnapItemActive 5 6
snapMode.setOSnapItemActive 5 6 true

local firstPoint = pickPoint snap:#3d
format "First Point: %\n" firstPoint

if isKindOf firstPoint Point3 do
format "Second Point: %\n" (pickPoint snap:#3d rubberBand:firstPoint)

snapMode.setOSnapItemActive 5 6 previousState
snapMode.active = previousSnap
)

As for the mouseTrack way, without the "rubberband" or in this case rather a connecting line it's much easier and faster but here you have it with a red substitute for the rubberband. If you want to see the difference in performance (or just want to draw some nice patterns in viewport), comment out the completeRedraw() part. Of course you can just have the points array globally accessible and set a viewport redraw callback with the drawLine function and you can make several other tweaks to it, I just wanted to point out some of the issues in this snippet. Btw. you have to have the two objects selected to test it.

(
local clickNum = 0
local startPos
local targetObjs = selection

fn drawLine points =
(
gw.setTransform (matrix3 1)
gw.SetColor #line red
gw.wPolyline points false
gw.enlargeUpdateRect #whole
gw.updateScreen()
)

fn getHitPos msg ir obj faceNum shift ctrl alt =
(
case msg of
(
#freeMove:
(
case clickNum of
(
0: #continue
1: (
drawLine #(startPos,[mouse.pos.x,mouse.pos.y,0])
completeRedraw()
#continue
)
2: (completeRedraw(); #stop)
)
)

#mousePoint:
(
clickNum += 1
startPos = [mouse.pos.x,mouse.pos.y,0]
format "Intersect point %, on node %\n" ir.pos obj
#continue
)

#mouseAbort:
(
pushPrompt "Aborted!"
#stop
)
)
)

if targetObjs.count > 0 do
mouseTrack on:targetObjs trackCallback:getHitPos
)

JokerMartini
05-21-2011, 04:13 PM
Thanks Swordslayer
That works out great. It seemed like a possible thing to do. It seems pretty straight forward and understandable look into the code.

Now is there a way to make it so you don't have to have the objects selected when picking the points?

JokerMartini
05-21-2011, 04:14 PM
I simply just changed the targetObjs = objects instead of seletion.

Now where would I modify the script to print the distance between the two clicks of the mouse?

Swordslayer
05-21-2011, 04:52 PM
I simply just changed the targetObjs = objects instead of seletion.

Note that for complex scenes with many objects, this could become quite slow.

Now where would I modify the script to print the distance between the two clicks of the mouse?

Just put something like if clickNum == 2 then print (distance startPos [mouse.pos.x,mouse.pos.y,0]) else startPos = [mouse.pos.x,mouse.pos.y,0] in the #mousePoint section instead of the line setting the startPos.

JokerMartini
05-21-2011, 06:47 PM
(
local clickNum = 0
local startPos
local targetObjs = objects

fn drawLine points =
(
gw.setTransform (matrix3 1)
gw.SetColor #line green
gw.wPolyline points false
gw.enlargeUpdateRect #whole
gw.updateScreen()
)

fn getHitPos msg ir obj faceNum shift ctrl alt =
(
case msg of
(
#freeMove:
(
case clickNum of
(
0: #continue
1: (
drawLine #(startPos,[mouse.pos.x,mouse.pos.y,0])
completeRedraw()
#continue
)
2: (completeRedraw(); #stop)
)
)

#mousePoint:
(
clickNum += 1
startPos = [mouse.pos.x,mouse.pos.y,0]
format "Intersect point %, on node %\n" ir.pos obj
if clickNum == 2 then
(
print (distance startPos [mouse.pos.x,mouse.pos.y,0])
#stop
)
else
(
startPos = [mouse.pos.x,mouse.pos.y,0]
#continue
)
)

#mouseAbort:
(
pushPrompt "Aborted!"
#stop
)
)
)

if targetObjs.count > 0 do
mouseTrack on:targetObjs trackCallback:getHitPos
)


i dont believe the distance printing is working in world units.

Swordslayer
05-21-2011, 08:13 PM
This is in screen units, to get it in world units, you'd do it like this:

(
local clickNum = 0
local startPos, startPoint
local targetObjs = objects

fn drawLine points =
(
gw.SetColor #line green
gw.wPolyline points false
gw.enlargeUpdateRect #whole
gw.updateScreen()
)

fn getHitPos msg ir obj faceNum shift ctrl alt =
(
case msg of
(
#freeMove:
(
case clickNum of
(
0: #continue
1: (
drawLine #(startPos,[mouse.pos.x,mouse.pos.y,0])
completeRedraw()
#continue
)
2: (completeRedraw(); #stop)
)
)

#mousePoint:
(
local pickedPoint = ir.pos
format "Intersect point %, on node %\n" pickedPoint obj
clickNum += 1

if clickNum == 2 then
format "Distance: %" (distance startPoint pickedPoint)
else
(
startPoint = pickedPoint
startPos = [mouse.pos.x,mouse.pos.y,0]
#continue
)
)

#mouseAbort:
(
pushPrompt "Aborted!"
#stop
)
)
)

if targetObjs.count > 0 do
mouseTrack on:targetObjs trackCallback:getHitPos
)

JokerMartini
05-23-2011, 03:00 PM
Hey! I ended up having to modify the code because it was bugging out when I was trying to run the code consecutively. Meaning I would use to it measure one thing and try to run it again by clicking the button to measure another thing and it wouldn't work.


here is what I ended up with.
Gotta get the green line back in there.

(

local clickNum = 0
local canClick = true
local startPos, startPoint
local targetObjs = objects
local aoMeasure = 0

rollout rlTest "test"
(

button btnMeasure "measure"
label lbMeasureVal

fn drawLine points = -- AO Distance Line
(
gw.SetColor #line green
gw.wPolyline points false
gw.enlargeUpdateRect #whole
gw.updateScreen()
)

fn getHitPos msg ir obj faceNum shift ctrl alt = --AO Distance hits
(
if (msg == #freeMove) then
(
canClick = true
#continue
)
else if ((msg == #mousePoint or msg == #mouseMove) and canClick == true) then
(--#continue
local pickedPoint = ir.pos
format "Intersect point %, on node %\n" pickedPoint obj
clickNum += 1
canClick = false
if (clickNum == 2) then
(
aoMeasure = (distance startPoint pickedPoint)
)
else
(
startPoint = pickedPoint
startPos = [mouse.pos.x,mouse.pos.y,0]
#continue
)
)
else if (msg == #mouseAbort) then
(
pushPrompt "Aborted!"
#stop
)
else
#continue
)


on btnMeasure pressed do
(
if targetObjs.count > 0 do
(
clickNum = 0
canClick = true
mouseTrack on:targetObjs trackCallback:getHitPos
lbMeasureVal.text = aoMeasure as string
)
)
)
createDialog rlTest
)

denisT
05-23-2011, 03:09 PM
does it have to work the same way as pickOffsetDistance ?

JokerMartini
05-23-2011, 03:50 PM
The goal of this tool is to visually pick to points in 3d space and return the distance between those points. Using that distance as a gage of what the ambient occlusion distance should be.

denisT
05-23-2011, 04:44 PM
The goal of this tool is to visually pick to points in 3d space and return the distance between those points. Using that distance as a gage of what the ambient occlusion distance should be.

i see. you need distance between two hit-points.
it's what HeightPick function in Macro_BakeTextures.mcr is doing.

JokerMartini
05-23-2011, 04:59 PM
Is what we have written in this post not something good to use for what I'm trying to do?

denisT
05-23-2011, 05:27 PM
Is what we have written in this post not something good to use for what I'm trying to do?

sorry i haven't read the whole post carefully...

here is my vision how i would do it:

fn pickHitOffset =
(
fn sortByDistance n1 n2 = if n1[3] < n2[3] then -1 else if n1[3] > n2[3] then 1 else 0

local wpos = unsupplied, wray
local nodes, hits = #(), lasthit, hitdist = ""
while wpos != #rightclick and wpos != #escape do
(
wpos = pickpoint snap:#3d rubberband:wpos
if iskindof wpos Point3 do
(
wray = mapScreenToWorldRay mouse.pos
nodes = intersectRayScene wray
nodes = for node in nodes where not node[1].ishidden collect append node (distance node[2].pos wray.pos)
if nodes.count > 0 do
(
qsort nodes sortByDistance pos:wray.pos
node = nodes[1]
select node[1]
if lasthit != undefined do hitdist = distance lasthit node[2].pos
format "node: %\n\thit distance: %\n" node hitdist
lasthit = node[2].pos
append hits node
)
)
)
hits
)
pickHitOffset()


i just don't want to draw my own rubber-band...

you can use your predefined list of nodes to hit. I check all geo nodes.

JokerMartini
05-23-2011, 06:21 PM
Yeah that works great. My only concern on this would be if someone had one object, for example a wall and they wanted to measure the distance from the ground plane and then halfway up the wall. In that case which is most cases for me, this would not work.
That is why I went with the other case.
No is there a better way of doing something like that?

denisT
05-23-2011, 06:41 PM
Yeah that works great. My only concern on this would be if someone had one object, for example a wall and they wanted to measure the distance from the ground plane and then halfway up the wall. In that case which is most cases for me, this would not work.
That is why I went with the other case.
No is there a better way of doing something like that?

my method doesn't need multiple objects. you can measure a distance between an object and any static point, or return Z-position of the hit.
if you want to hit only one node you can call intersectRay. The function returns a ray (pos, dir) or undefined for missed case.

JokerMartini
05-23-2011, 06:58 PM
I saw the selection being highlighted and was quickly testing it and thought it was doing it based off the objects pivot. Scratch that last message I wrote. What you wrote is more or less exactly what I wanted. It simple and is not intense with dense scenes. Thanks for the time spent helping me on this DenisT

denisT
05-23-2011, 07:17 PM
I saw the selection being highlighted

it's just for test only. you don't need it as well as you don't need to print any info or collect hit nodes.

JokerMartini
05-23-2011, 07:55 PM
So when condensing the code and getting rid of what I wouldn't need I would be left with this is then?



fn pickHitOffset =
(
fn sortByDistance n1 n2 = if n1[3] < n2[3] then -1 else if n1[3] > n2[3] then 1 else 0

local wpos = unsupplied, wray
local nodes, hits = #(), lasthit, hitdist = ""
while wpos != #rightclick and wpos != #escape do
(
wpos = pickpoint snap:#3d rubberband:wpos
if iskindof wpos Point3 do
(
wray = mapScreenToWorldRay mouse.pos
nodes = intersectRayScene wray
nodes = for node in nodes where not node[1].ishidden collect append node (distance node[2].pos wray.pos)
if nodes.count > 0 do
(
qsort nodes sortByDistance pos:wray.pos
node = nodes[1]
if lasthit != undefined do hitdist = distance lasthit node[2].pos
lasthit = node[2].pos
append hits node
print hitdist --used in spinner
)
)
)
hits
)
pickHitOffset()

denisT
05-23-2011, 08:09 PM
you don't need to collect all hits. you can leave the function after first successful hit.
i don't do because sometimes it's hard to hit exactly right node. so usually i provide some extra information: print node's name, blink a picked node

denisT
05-23-2011, 08:10 PM
if you know the node(s) that should be hit you don't need to do sorting. just find it in the list.

CGTalk Moderation
05-23-2011, 08:10 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.