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

Allow the rotate function to specify an axis in 2D #4668

Open
1 task
olleicua opened this issue Jul 2, 2020 · 22 comments
Open
1 task

Allow the rotate function to specify an axis in 2D #4668

olleicua opened this issue Jul 2, 2020 · 22 comments

Comments

@olleicua
Copy link

olleicua commented Jul 2, 2020

Most appropriate sub-area of p5.js?

  • Core/Environment/Rendering

Feature enhancement details:

I want to be able to rotate objects in 2D without the center of rotation being the origin. I noticed that it is possible to move the origin using the translate function but this then requires me to reposition objects with respect to the new origin and that won't work if I want different objects to rotate around different centers (for example to make a 2D simulation of a planetary system with moons).

I'm hoping to support the following syntaxes:

rotate(angle, centerX, centerY);
rotate(angle, createVector(x, y));

Implementation

I'm planning to try to implement this myself but any thoughts others have on implementation details are welcome :)

@welcome
Copy link

welcome bot commented Jul 2, 2020

Welcome! 👋 Thanks for opening your first issue here! And to ensure the community is able to respond to your issue, be sure to follow the issue template if you haven't already.

@joemckay5
Copy link

You can translate from your translate if you push without popping. Here's a sun-earth-moon example
https://editor.p5js.org/Joemckay/sketches/GHYH1-ugr

@limzykenneth
Copy link
Member

Hi, if you need help with your own code, please direct your questions to the forum. We use GitHub issues mainly for bug reports and feature requests only. Thanks!

@olleicua
Copy link
Author

olleicua commented Jul 2, 2020

Thanks joemckay5. Using the translate function in this way works but I still find it a bit counter-intuitive because it requires me visualize a rotating frame of reference. I can do this if I have to but I'm not sure it is the easiest way for everyone. Given that part of p5's goal is to be accessible to as many coders as possible I think it would be best to support both the method in your example and the syntax I proposed above. We should be able to accomplish this by internally calling translate before and after the rotation if an axis is passed in.

@limzykenneth I'm working on a PR for this right now. I'm not able to re-open the issue. Is there a formal decision making process for deciding whether a contribution will be accepted? Should I abandon my PR? Please advise.

@limzykenneth
Copy link
Member

In general we don't try to make the library do everything in every way possible so I would not recommend adding the complexity of a special rotate signature that ignores translate (would it ignore rotates as well?).

I would suggest holding off on a PR for now until there is a concensus about whether to add this feature or not.

@limzykenneth limzykenneth reopened this Jul 3, 2020
@olleicua
Copy link
Author

olleicua commented Jul 3, 2020

It wouldn't ignore translate. It would do the translate for you. It would work like the transform-origin css property. Basically the user passes in the coordinates within whatever the current frame of reference is (including any translates that have previously happened) and then internally the library could call translate(x, y) then rotate then translate back with translate(-x, -y). The reference already describes this interface for the 3D case so it seems more consistent to make it work in the 2D case as well. The implementations is pretty simple and I think it would make it a lot easier to use while still being backwards compatible.

@limzykenneth
Copy link
Member

I find in this case the solution suggested by @joemckay5 easier to work around, the reference frame can be prevented from rotating by having a pair of push() pop() around them.

In the 3D case it is different. The rotation origin still stays the same and controlled by translate(). The second argument is the axis in which to rotate (normal to the plane of rotation), not the origin (since there is more degress of freedom in 3D, and there's only one valid axis to rotate around in 2D).

@olleicua
Copy link
Author

olleicua commented Jul 3, 2020

You say here "there's only one valid axis to rotate around in 2D". This is completely false it is possible to rotate a 2D object around any point.

I recognize that there are ways of doing this without my feature. The point I'm trying to make is that for some people the existing ways feel counter-intuitive. Forcing the developer to visualize a transformation of the reference frame in order to rotate one object in an intuitive way (something they may not even consider trying) introduces unnecessary friction. Reading the p5 website and github page gives the impression of a community interested in welcoming anyone and everyone and respecting that different people may have different ways of approaching code. If you are serious about these goals of inclusivity then it seems like rejecting my proposal out of hand might be a mistake.

Let me put it this way: what is the down-side of accepting my PR. It adds minimal complexity. It doesn't break any existing code. I'm offering to write it and test it. Please reconsider.

@joemckay5
Copy link

joemckay5 commented Jul 4, 2020

I'm not fully understanding how your proposed code would make the sun-earth-moon simulation easier.
If you just want the earth to rotate around the sun then rotateAround(locSun, locEarth, angle, radius) makes sense. But then how do you rotate the moon? P5 doesn't have a screenX screenY function like processing, so if you're using translate and rotate how does your rotateAround function return the location of the earth? I can't write rotateAround(locEarth, locMoon, angle, radius) if we don't know the location of the earth. We'd need to nest a rotateAround() inside another rotateAround(), but now we're duplicating the complexity you're seeking to avoid.
The easiest answer is to avoid push, translate, rotate, pop, all together, and just use trig to get the actual locations of all the celestial bodies. But to my thinking, the simplicity of this sketch doesn't beg out for more simplification.
https://editor.p5js.org/Joemckay/sketches/EgMjCFkeY

@olleicua
Copy link
Author

olleicua commented Jul 4, 2020

https://editor.p5js.org/olleicua/sketches/CSpYx_IFS

The above is what I am proposing and it is definitely simpler than the trig solution for someone less familiar with trigonometry as wells as avoiding all of the complications of push/pop that a novice programmer might find more challenging. I really want to emphasize that it isn't really relevant whether you or I feel that a solution we have found begs for simplification. What is relevant is whether the p5 library provides tools that will allow any given novice programmer to build whatever they might want to build. If some people find using translate or trigonometry less intuitive and we are able to provide them with tools they might find more intuitive (without taking away any of the current options) then I see no reason we shouldn't do that. Not to put too fine a point on it but saying "this way works and it makes sense to me" feels dangerously close to code snobbery which I was led to believe we don't do here.

@olleicua
Copy link
Author

olleicua commented Jul 4, 2020

As a side-note, an advantage of the code I linked in my most recent comment is that if you comment out either or both of the calls to proposedRotate you get exactly the result you would expect. This makes debugging easier (something a lot of novice programmers struggle with).

@joemckay5
Copy link

Try drawing anything after you call your function and it will also be rotating. Push and pop are necessary because it resets the rotation as well as the position.
At this point I agree with limzykenneth that this conversation belongs in a different forum. I think a lot of what you're perceiving as snobbishness is due to the context and in another setting people will be more interested and generous in helping you think through your idea. Good luck.

@dhowe
Copy link
Contributor

dhowe commented Jul 4, 2020

Just going to jump here with my two-cents that a version of rotate (in 2d) that takes the point of rotation might actually be rather useful for new students. Each year I have one or more students who need to do a simple rotation in 2d to complete a piece, well before we have done affine transforms and I have to tell them either to wait, or to go ahead to that lesson on their own. For the 2d case at least, the only argument used for rotate in the renderer is the angle, so it would be relatively easy to allow 2nd and 3rd optional args for the point of rotation (not sure what this would require in the 3d renderer to keep the APIs in sync).

@chen-ni
Copy link

chen-ni commented Jul 5, 2020

@olleicua push() and pop() are really powerful and essential to p5. In my understanding, your code is a workaround to avoid using push() and pop(). It does work in some cases and I would even agree that it's more intuitive than using push() and pop(), but at some point down the road, one would have to get used to using push() and pop(). For example, what if one has to simulate the rotation (turning on its own axis) as well as the revolution (moving around another body) in the solar system? What if one has to add another body that moves around the moon? Things like these can be easily done with the help of push() and pop() and could be really tricky otherwise.

So, what I'm suggesting is that instead of inventing some "alternative" to push() and pop(), just get used to them. You will love them.

@montoyamoraga
Copy link
Member

hi @olleicua thank you for your contribution!

i struggle myself with rotation and translation,
and i rely on the documentation we have,
and i use a lot push() and pop()
to not lose track of what i am doing
and i do love the push and pop paradigm :)

maybe a good solution is you can help is to include your function
as an example, or adding it side by side to an example
using the existing combination of push, pop, rotate, translate
so that beginners can grasp these concerts in a better and easier way,
and we can improve our examples and documentation,
without adding more complexity to the library as @limzykenneth suggested :)

i will be checking this discussion so we are all happy about our collective decision ~

@dhowe
Copy link
Contributor

dhowe commented Jul 5, 2020

I think that people are underestimating the conceptual leap for new students moving from basic commands and specific x/y positions (point, line, rect, etc) to matrices/affine-transforms. Better coders should of course understand/use the latter, but there is a case to be made, in line with the p5js philosophy, that we should facilitate learners doing simple rotations in 2d with as little conceptual overhead as possible (we have a circle command after all).

So perhaps what's being proposed here, something like rotate2d(angle, [x], [y]) can be thought of as a convenience function, encapsulating the commands [translate(x,y), rotate(angle), translate(-x,-y)] into something potentially simpler for beginners to use. If so, then we should consider it. If, on the other hand, we think it will create additional confusion later on, or cause unexpected results in combination with others commands, then we shouldn't (@limzykenneth's point about how this would work with pre-existing rotations/translations is relevant)

@joemckay5
Copy link

dhowe, I teach Processing too, and you're right, rotation is a tricky topic. I hope everyone is keeping in mind that the proposed function doesn't alleviate the need to push and pop.

@lmccart
Copy link
Member

lmccart commented Jul 5, 2020

I guess I feel that "moving from basic commands and specific x/y positions (point, line, rect, etc) to matrices/affine-transforms" may not represent a complete beginner student anymore. So while this would be helpful for some, it may not necessarily be working toward our goal of expanding access, especially for those identifying with groups that have been historically marginalized.

@dhowe
Copy link
Contributor

dhowe commented Jul 6, 2020

@lmccart can you clarify what you mean above? I'm not suggesting new people learn the internals of matrices - I only mean using the push/pop, translate, rotate, scale mode of drawing/thinking.

@lmccart
Copy link
Member

lmccart commented Jul 6, 2020

I'm wondering, by the time you get to the point where a student is rotating an object around an axis, if we are beyond the "newbie" barrier to some extent.

@dhowe
Copy link
Contributor

dhowe commented Jul 6, 2020

Probably depends on the case, though often the question comes up (in a first year uni class) when we do simple animations with variables (week 3-4?), well before drawing with transforms (week ~10).

@mkmori
Copy link
Sponsor

mkmori commented Jul 13, 2020

As a mid-level newbie with gaps in my math ed., (like matrix ops!), push()/pop() (pushMatrix()/popMatrix()) is pretty basic to enabling me to handle a whole range of multiple, complex, (incl. recursive!) transformations with any "elegance".

I would also take the opportunity to plug screenX/Y/Z (for "picking" and screen effects) and modelX/Y/Z (for construction)....

These features seem to keep coming up, often tangentially, as a bridge between "friendly" p5 transformation functions, (translate(), rotateX/Y/Z() etc.) and more complex operations, short of directly manipulating transformation matrices.

There seem to be technical limitations and performance issues tracking transformation matrices in a (2D) canvas: I've recently asked elsewhere if the same issues are obstacles in WebGL...?

Would it be feasible/desirable to implement P2D in WebGL, too?

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

No branches or pull requests

9 participants