Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vector2/3/4: Avoid divide-by-zero #11253

Merged
merged 1 commit into from
Jun 15, 2017
Merged

Conversation

WestLangley
Copy link
Collaborator

As discussed in #11241.

This leave the zero-vector unchanged under these methods --and does so without warning.

I am not sure I feel that comfortable with it, but it appears by consensus to be an acceptable trade-off.

/ping @Mugen87 for review

@mrdoob
Copy link
Owner

mrdoob commented Apr 27, 2017

/ping @brianchirls @mattdesl

@brianchirls
Copy link
Contributor

Looks good.

@aardgoose
Copy link
Contributor

FWIW - I was hit by this in two cases because of a model with 0 length line segments. One case being raycasting silently breaking and producing incorrect results.

@WestLangley
Copy link
Collaborator Author

Like I said, this change will hide errors: if you normalize the zero-vector, you will get the zero-vector.

Raycaster will generate incorrect results with a zero-length direction vector. Direction vectors must be unit-length in three.js.

@WestLangley
Copy link
Collaborator Author

/ping @bhouston Do you have an opinion one way or the other? I am indifferent to merging this, or leaving the code as-is.

/ping @mattdesl

@WestLangley
Copy link
Collaborator Author

/ping @bhouston @mattdesl

I would like to know what you guys think. I proposed this out of courtesy, not because I am in favor of it.

I will defer to the consensus and either merge it or close it.

@bhouston
Copy link
Contributor

bhouston commented May 5, 2017

We should protect against divide by zeros when normalizing in a similar way to how it is handled in Industrial Light and Magic's Imath library:

https://github.com/openexr/openexr/blob/develop/IlmBase/Imath/ImathVec.h#L1191

I am confused why we are calling the more complex divideScalar( length || 1 ), everywhere instead of the higher level normalize() that has the divide by zero check inside of it. I like to have the check inside normalize() and just use that function everywhere it makes sense.

I think most of these divideScalar( length || 1 )s can be replaced with normalize().

@WestLangley
Copy link
Collaborator Author

OK, closing this.

@WestLangley WestLangley closed this May 7, 2017
@WestLangley WestLangley deleted the dev-vector-math branch May 7, 2017 23:59
@brianchirls
Copy link
Contributor

@WestLangley: wait, why is this closed? It seems like there's some consensus here that a change should be made, even if there's some slight disagreement over the exact implementation.

@WestLangley
Copy link
Collaborator Author

@brianchirls The original issue is still open. :)

@mrdoob
Copy link
Owner

mrdoob commented Jun 13, 2017

@WestLangley said:

OK, closing this.

Hmm... As far as I understand, @bhouston was in agreement with this PR?

@WestLangley
Copy link
Collaborator Author

My understanding was that @bhouston suggested a divide-by-zero check should go in normalize() instead.

Also, as I said, I was not a fan of my own PR anyway... I know that is somewhat unusual. :)

@mrdoob
Copy link
Owner

mrdoob commented Jun 14, 2017

Hmm...

normalize: function () {

	return this.divideScalar( this.length() || 1 );

}

Isn't that, effectively, a divide-by-zero check in normalize()? Or do you mean throwing an error?

@WestLangley
Copy link
Collaborator Author

Isn't that, effectively, a divide-by-zero check in normalize()?

Yes, but it silently returns an incorrect answer if length is zero. I think throwing an error or warning is better.

I am confused why we are calling the more complex divideScalar( length || 1 ), everywhere ...
I think most of these divideScalar( length || 1 )s can be replaced with normalize().

I understand @bhouston's confusion now. We are not calling it everywhere -- only in methods that need to reuse the value of length. It is also being called in normalize(), as @bhouston suggests.

At the cost of some inefficiency, the test can be localized to normalize() only.

@Ludobaka
Copy link
Contributor

@WestLangley said :

I understand @bhouston's confusion now. We are not calling it everywhere -- only in methods that need to reuse the value of length. It is also being called in normalize(), as @bhouston suggests.

I've already seen some 3D engine having length as a return value of normalize(). It has no side effect in any ThreeJS current code and allows to avoid using divideScalar(length || 1) when you need to keep the length for later computations. Latest example I've seen is Ogre3D, a C++ library.

With this, we could keep the test on normalize() and even improve code readability.

As the discussion seems to continue, I await your approval before contributing on this to avoid making various pull requests about the same problem. For now, I will just patch my fork.

@WestLangley
Copy link
Collaborator Author

@Ludobaka We return this so the methods can be chained.

It has no side effect in any ThreeJS current code

We use this pattern in the library:

vector.normalize().multiplyScalar( value );

Changing the return value at this point would lead to backward-compatibility issues.

@WestLangley WestLangley restored the dev-vector-math branch June 15, 2017 02:52
@WestLangley WestLangley reopened this Jun 15, 2017
@WestLangley
Copy link
Collaborator Author

WestLangley commented Jun 15, 2017

@mrdoob Restored deleted branch and reopened. If you would like to merge this, I can make any additional changes you request in a follow-up PR.

@mrdoob
Copy link
Owner

mrdoob commented Jun 15, 2017

Looks good!

@mrdoob mrdoob merged commit c282b17 into mrdoob:dev Jun 15, 2017
@mrdoob
Copy link
Owner

mrdoob commented Jun 15, 2017

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants