-
Notifications
You must be signed in to change notification settings - Fork 138
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
Path and multiple shapes ordering (solves #9) #39
base: master
Are you sure you want to change the base?
Conversation
…dered" This reverts commit d4fe4c1.
Conflicts: js/path.js
I'd like to eventually replace Thanks for all the hard work you've put into this, by the way. Reading your code is a lot of fun. |
We can definitely do that, performance is not a limitation anymore (except if we have a very high number of path, but there is still room for code optimization) First option : we don't change how Second option : each object Guess which option I would vote for 😜 |
ok I implemented "option 2" from my previous post. |
ok it works. |
Following a suggestion by jdan, now it manages backward-compatibility. If you want the new features, you can write it like :
The option |
*/ | ||
Isomer.prototype.add = function (item, baseColor) { | ||
Isomer.prototype.add = function (item, baseColor, expertMode, name) { | ||
var expertModeValid = (typeof expertMode === 'number') ? expertMode : 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.
Why expertMode
isn't a boolean?
IMHO, something like this is more suitable:
expertMode = !!expertMode;
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.
ok !
Okay I think adding shapes & paths one-by-one and then calling "render" at the end would work. This way we could bucket drawing operations and maybe even optimize them (later down the road). So let's change this new "addOrdered" to a simple "add" and then a "render" method will actually draw everything. How does that sound? |
That's what I implemented in the last commits (see my comment above, the one that begins with "Following a suggestion by jdan") |
With regards to doing hit detection, this approach sounds like it will take O(n) to do a hit test, while testing against a background lookup canvas will be O(1) (unless I've misunderstood something). Is that right? |
You're perfectly right, and there is a solution : By the way, with expertMode, each time you need to refresh the canvas (for example with animations), you have to empty this.paths (this.paths.length = 0) |
canvas API will support hit regions at some point, might be better to use |
There is a benchmark here : |
I'm going to change Isomer to use Three.js as a backend, instead of attempting to write my own graphics hacks. I really do appreciate the work you've put into this pull request, but unfortunately I can't proceed in this direction and attempt to tackle more graphics problems that have already been solved in very elegant ways. |
I'd like to revisit this if you don't mind! After some thought I've realized that bringing in Three.js as a requirement for proper shape ordering is pretty unacceptable. You've done some amazing work here, and I'd really like to see it make its way into master. Any interest in addressing some comments? I'll leave them - but if you're totally done with this library then no worries. |
/** | ||
* List of {path, color, shapeName} to draw | ||
*/ | ||
this.paths = []; |
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.
How about we call this scene
or some sort?
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.
Ok it's a better name
Of course I don't mind, |
*/ | ||
Path.prototype.closerThan = function(pathA, observer) { | ||
var result = pathA._countCloserThan(this, observer) - this._countCloserThan(pathA, observer); | ||
return result; |
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.
Indentation is kinda messy in this function...
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.
Yeah I've already address that above :) They'll fix!
I agree that there's definitely value in this work. I'm looking forward to seeing the solution to this problem. I have come across need for a solution this same problem before, and was never successful. It makes me happy that someone is able to finally nail this one down. 😸 |
I built a thing that suffers a great deal from the issue described in #9: http://cutecity.meteor.com/edit/new I tried using a build from @Mysterix's repo, and I'm using the expertMode argument in addition to the draw method. It seems to work well, but it doesn't detect for whether a shape should be overwritten. That'd be something I'd like to explore, perhaps by keeping an object literal with a sort of domain-specific hash notation (such as Should there also be a method to reset the scene? I know it's as easy as writing |
Feel free to branch off and offer up those changes in a separate diff :) Sounds like a good idea to me! jordan scales On Fri, Mar 27, 2015 at 7:17 PM, Hunter Trujillo [email protected]
|
First, good news : it can't break anything, as I only added functions (for the moment), and changed none.
The function to use is addOrdered, you can see examples here http://rdelav.fr/isomer/isomer3.html (and the following numbers)
addOrdered takes as input as list of {shape:yourShape, color:yourColor}, and display all the path of all the shapes of the input and display them in the correct order, according to their relative positions.
The algorithm used is the following :
We put all the paths of every shape in a big array
For every couple of path, we considerer their projection on the canvas (which are two 2D-polygons).
If their intesection is non-empty [see note 1], we add the rule that the one which is in front [see note 2] must be drawn after the other one.
To match all those rules, we sort the path using a topological sort.
Note1 : to know if the intesection is not empty, we compute if one edge of the first cuts an edge of the other, or if a vertex of one is contained in the other
Note2 : to know which one is is front of the other between two intesecting paths, we look at the percentage of vertices of one which are one the same side of the plane defined by the other than the observer. (I will show a drawing for that)
Note3 : we need to check that the projection of the paths is intersecting, otherwise you have common situation where A is in front of B which is in front of C which is in front of A (I will show a drawing for that too)
Note 4 : other problems I didn't think of initially : rounding approximations, and the exact position of the observer.
Note 5 : I found so many special cases and exceptions during my tests (that work in this version) that there may be cases I didn't think of, sorry for that.
In the future, instead of a function addOrdered, we can also have two functions, one to add a shape, and one to flush and draw all the added shapes.