-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
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
SVGLoader: Implement ellipse transformations. #24750
Conversation
Code style clean up.
@yomboprime Does this look good to you? |
Yes. I've read the commit and seems good. Although I can't verify the maths in depth. |
examples/jsm/loaders/SVGLoader.js
Outdated
function isTransformSkewed( m ) { | ||
|
||
const te = m.elements; | ||
const basisDot = te[ 0 ] * te[ 3 ] + te[ 1 ] * te[ 4 ]; | ||
return basisDot !== 0; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is testing if the columns are orthogonal. Is this function reliable in practice given there will be round off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will give false positives, probably only will return false if the matrix is identity. The only solution I think of is testing against a very small angle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case of a false-positive it will cause the compute-intensive branch which, nevertheless, gives the correct results for full circles and ellipses.
In practice, for a pure rotation it does not give false-positives since rotation matrices have their conjugate-diagonal set to sin θ -sin θ
.
The only case to worry about is a long chain of nested group matrix multiplications. If we should handle it, I can update the PR to test against some Epsilon, not zero. Is it a good idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think any arbitrary rotation can seem as skewed currently.
It is not elegant to introduce deltas but I guess the skewing can be detected with a big angle (1 or 2 degrees) as it is a very specific use case only for the ellipse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. I’ve added a tolerance a new commit. Please, take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm inclined to think 1/100 of a degree would be more appropriate. I do not think you are going to get 1 degree round off error.
@Mugen87 What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would normally start to test against Number.EPSILON
unless there is a need for a greater threshold. I'm not sure I understand why this is the case for isTransformSkewed()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible errors can be estimated with some hard-core math and reasoning and I don’t think I’m able to do it. However, yes it sounds that an error should be a magnitude lower than 1°.
I’ve committed a comparison against Number.EPSILON
. EPSILON
is of order 1e-16, 1°/100 is of order 1e-8.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just ran this test. It always gets success. With or without random increments, and variations testing against EPSILON or 0, indicates that a matrix constructed with m.rotate() always has basisDot
equal to 0.
So the conclusion is that using Number.EPSILON as threshold works just fine.
const m = new Matrix3();
let error = false;
const useRandom = 1;
for ( let a = 0; a < 2.1 * Math.PI; a += 0.00000001 + Math.random() * 0.00000001 * useRandom ) {
m.identity().rotate( a );
if ( isTransformSkewed( m ) ) {
error = true;
break;
}
}
console.log( error ? "Error." : "Success." );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! So, are we ready for the merge?
Related issue: #21330
Currently the following is not implemented:
This PR implements points (1), (2), and (3), leaving (4) unimplemented yet. I’m not smart enough to solve this math riddle 🤯 However, this fourth case is arguably quite rare and in any case the improvement is purely additive.
Test fixture (Inkscape)
Before
After
The coral pacmans (skewed 30° by X) are still more like Kandinsky art, but the full-circle and full-ellipse are correct. Other groups are correct too.