Notifications
Clear all

[Closed] problem with compare two face normals

I wrote a function to get the item number of the same item in array
for example
:

[i]aaa=#(1,3,5,2,3)

fn myfinditem myarray item=
(
local myarray_copy=for i in myarray collect i
local myarray01=#()
if finditem myarray_copy item!=0 then
(
while finditem myarray_copy item!=0 do
(
append myarray01 (finditem myarray_copy item)
myarray_copy[finditem myarray_copy item]=undefined
)
myarray01
)
else return false
)[/i]

myfinditem aaa 3

Output;#(2, 5)

It’s runs ok in many situation,except when I use it to find the same normal value.
I collect several face normal in this array
:
bbb=#([0,0,1], [0,0,1], [0.219251,0.279046,0.934913], [0.219251,0.279046,0.934913], [0.219251,0.279046,0.934913], [-0.573886,-0.303822,0.760492], [-0.218346,-0.973074,-0.0738424], [0,0,1], [0,0,1], [0,0,1], [0,0,1], [0,0,1])

it output :#(3, 4, 5, 6, 7)
it seems as if bbb[3] equals bbb[4] and alse bbb[5] but when i test it
,it output false.

I notice that i may have some problem in precision ,but how to solve the problem. Anyone can help me ?

4 Replies

I used your code and your array and got #(3, 4, 5) as expected.

In the case of normals, you might want to implement a separate function that uses a simple loop and compares using the angle between the two normals and a small threshold like 0.1 degrees or something like that to avoid precision problems:


fn compareNormals theArray theNormal theThreshold =
(
result = #()
for i = 1 to theArray.count do
(
theAngle = acos (dot (normalize theArray[i]) (normalize theNormal))
if theAngle <= theThreshold do append result i
)
result 
)

bbb=#([0,0,1], [0,0,1], [0.219251,0.279046,0.934913], [0.219251,0.279046,0.934913], [0.219251,0.279046,0.934913], [-0.573886,-0.303822,0.760492], [-0.218346,-0.973074,-0.0738424], [0,0,1], [0,0,1], [0,0,1], [0,0,1], [0,0,1])

compareNormals bbb [0.219251,0.279046,0.934913] 0.1

--> #(3, 4, 5)

Just so you know, you are hitting a precision problem really hard with the vectors you are using. As you can see, they ARE identical. But the decimal precision is too high for MAXScript to handle without an error:

–The two values ARE equal:
[0.219251,0.279046,0.934913] == [0.219251,0.279046,0.934913]
–>true

–The two values ARE normalized:
normalize [0.219251,0.279046,0.934913] == [0.219251,0.279046,0.934913]
–>true

–But the angle that MAXScript calculates is not 0.0:
acos (dot [0.219251,0.279046,0.934913] [0.219251,0.279046,0.934913])
–>0.0197823

–Even if you make sure they are normalized:
acos (dot (normalize [0.219251,0.279046,0.934913]) (normalize [0.219251,0.279046,0.934913]))
–>0.0197823

–BUT removing one decimal place helps!
acos (dot (normalize [0.21925,0.27904,0.93491]) (normalize [0.21925,0.27904,0.93491]))
–>0.0

This is why in my function I used a threshold of 0.1.
It looks like you could just use an == comparison, but if the two normals are IN FACT slightly different, the function I posted first could help you decide whether to assume them as identical or not…

Thank you very much for such a faithful and particular instruction.

not only in angle compare , but also in any numeric value compare , the absolutely equal is almost not exist.