Hello Jim. Sorry for all the e-mails, but I made a couple of other notable changes I should mention. 1. The optimization I described in one of my other e-mails that allowed Renderer to skip subdivision of curves into monotonic pieces if the curves came from Stroker is gone. There was a bug with round joins and caps (the curves composing them would not be monotonic). I could have fixed this, but there's also the problem that the rest of Stroker's output curves can only be guaranteed to be monotonic in x and y if we can find all points in the non-offset curve where the radius of curvature == linewidth. My algorithm that tries to find these points does so pretty well, but it doesn't always find them all.
2. I changed how the alpha map is managed in PiscesTileGenerator to something that's a bit clearer and uses less memory (the latter comes from changing the +300 in the alpha tile allocation to +1. If there was a good reason for using 300, please tell me). That's all. Regards, Denis. ----- "Jim Graham" <james.gra...@oracle.com> wrote: > Hi Denis, > > On 9/27/2010 7:43 AM, Denis Lila wrote: > > Hi Jim. > >> How much faster? I'm worried about this, especially given our > tiled > >> approach to requesting the data. What was the bottleneck before? > >> (It's been a while since I visited the code - we weren't computing > the > >> crossings for every curve in the path for every tile being > generated > >> were we?) > > > > Not much faster. I'm working on someting better. > > Then hopefully we can get to something with better memory and CPU > costs. > > > I'm not sure about the bottleneck, but what we were doing > before is: > > 1. Flatten (by subdividing) every curve so that we deal only with > lines. > > 2. Add each line to a list sorted by y0. When end_rendering was > called > > for each scanline we found the crossings of the scanline and every > line > > in our line list, which we used to compute the alpha for that > scanline's > > pixel row. All this would be put into RLE encoded temporary storage > and it > > would be read back and converted into tile form by > PiscesTileGenerator. > > > > Speaking of which, would it not be better to get rid of > PiscesCache and > > just keep a buffer with the current tile row in Renderer.java. This > would > > be possible because the specification for AATileGenerator says the > iteration > > is like: for (y...) for (x...);. > > Why is PiscesCache there? It isn't being used as a cache at all. > Could it be? > > Also, why do we output tiles, instead of just pixel rows (which I > guess would > > just be nx1 tiles). Is it because we would like to use > getTypicalAlpha to eliminate > > completely transparent or completely opaque regions as soon as > possible (and the > > longer a tile is the less of a chance it has at being either of > those two)? > > That was basically "cramming what we had into the interface's box". > The > cache existed for something that was being done on mobile, but it > doesn't have much of a place in our APIs so it was just reused for > tile > generation. If we have a much more direct way of doing it then it > would > be great to get rid of it. > > I think we can support "ALL1s" and "ALL0s" reasonably without the > cache. > > >> I can see your points here. I think there are solutions to avoid > much > >> of the untransforming we can consider, but your solution works well > so > >> let's get it in and then we can look at optimizations if we feel > they > >> are causing a measurable problem later. > > > > I should say this isn't quite as bad as I might have made it > seem. Firstly, > > this IO handler class I made elimiinates transformations when > Dasher > > communicates with Stroker. More importantly, no untransforming is > done > > when the transformation is just a translation or is the identity or > is singular > > and when STROKE_CONTROL is off, we only transform the output path. > That's > > because the most important reason for handling transforms the way I > do now > > is because we can't normalize untransformed paths, otherwise > coordinate > > adjustments might be magnified too much. So, we need to transform > paths > > before normalization. But we also can't do the stroking and > widening > > before the normalization. But if normalization is removed we can > just pass > > untransformed paths into Stroker, and transform its output (which is > still > > somewhat more expensive than only trasnforming the input path, > since > > Stroker produces many 3-7 curves for each input curve). > > Can the untransform be eliminated in the case of scaling? (Whether > just > for uniform scaling, or maybe even for non-uniform scaling with no > rotation or shearing?) > > >> I'm not sure I understand the reasoning of the control point > >> calculation. I'll have to look at the code to register an > opinion. > > > > I'm sorry, my explanation wasn't very clear. I attached a > picture that > > will hopefully clarify things. > > But, in a way, the computation I use is forced on us. Suppose we > have a > > quadratic curve B and we need to compute one of its offsets C. > C'(0) > > and C'(1) will be parallel to B'(0) and B'(1) so we need to make > sure > > our computed offset has this property too (or it would look weird > around > > the endpoints). Now, B'(0) and B'(1) are parallel to p2-p1 and > p3-p2 > > where p1,p2,p3 are the 3 control points that define B, so if the > control > > points of C are q1, q2, q3 then q2-q1 and q3-q2 must be parallel to > p2-p1 > > and p3-p2 respectively. At this point, we need more constraint, > since > > our system is underdetermined. We use the constraints that q1 = > C(0) > > and q3 = C(1) (so, the endpoints of the computed offset are equal to > the > > endpoints of the ideal offset). All we have left to compute is q2, > but > > we know the direction of q2-q1 and the direction of q3-q2, so q2 > must > > lie on the lines defined by q1+t*(q2-q1) and q3+t*(q3-q2) so q2 > must > > be the intersection of these lines. > > I agree that if you are creating a parallel curve then intersection is > > the way to go. I guess what I was potentially confused about was > whether there are cases where you need to subdivide at all? > Regardless > of subdivision, when you get down to the final step of creating the > parallel curves then I believe offsetting and finding the intersection > > is correct (though I reserve the possibility that there might still be > a > simpler way - I haven't done any investigation to know if that is > true). > > >> It sounds like you are correct here. What does the closed source > code > >> draw? > > > > I thought closed source java simply didn't draw the round joins > in > > these cases, but I did some more testing and it turns out it does > for > > some curves and it doesn't for others. I've included the results of > a > > test I wrote that tries to draw paths like: > moveTo(0,0);p.lineTo(cos,sin);p.lineTo(0,0); > > where cos and sin are coordinates on a circle (source1.png is the > output > > of closed java. Source2.png is my output). As you can see, my > > version draws the round joins on all tested cases, while closed > java > > is inconsistent. > > You rock then! A bug should be filed on closed JDK. Can you file it > or > send me your test case and I'll do it? > > > That sounds good. Hopefully by the end of today I'll have a > > less memory hungry AA implementation that is also faster. > > Yay! > > > Thank you, > > Ummm... Thank *you*. You're doing all the good work here, I'm just > sitting back, throwing out tiny crumbs of past experience and watching > > the ensuing woodchips fly with awe. I've had on my wish list for some > > time to be able to eliminate these last few closed source holdouts, > but > the quality of the Ductus code was so high that I never got motivated > to > try. Who knows now... ;-) > > ...jim