SVG performance - whole numbers vs decimals - javascript

I read somewhere that javascript is handling whole numbers better than decimal etc.
Since I am working with SVG a lot I thought hmm SVG is about vectors so its coordinates system could be whatever we want.
Now I built this naive performance test here:
https://jsperf.com/svg-whole-numbers-or-not
Question - the test shows 50% faster processing for the case with whole numbers. Can someone explain if avoiding using non-whole numbers actually give any real benefit?
I basically want to know should I (even if the performance win is small) just by default avoid non-whole numbers when I work with SVG?

The speed difference is largely accounted for by the need to "anti-alias" stroke and fill operations by differentially shading pixels which are adjacent to a path that does not run between adjacent pixels.
While this can occur for horizontal lines, vertical lines and rectangles, it would not generally apply to diagonal lines, curves and arbitrary shapes.
Avoiding non integer values will not benefit general purpose svg drawings. It may speed up a sub class of drawings such as very simple flow diagrams that make use of horizontal and vertical joiners and boxes. Whether the care or editing to use whole number coordinates is worth the time saved is (imho) doubtful.

Related

JavaScript Canvas Complex Shape Collision

I am trying to make a very simple game with the HTML canvas and JavaScript. I have found many tutorials and questions about detecting collisions of basic shapes on a canvas (such as rectangles and circles). But I am wondering is it possible to detect if a complex shape (a shape that is made up of many basic shapes) is colliding with another shape, or even if two complex shapes are colliding. If so, how could this be done? Thanks in advance!
A general algorithm will not provide a better solution than one based specifically on the knowledge of each shape type.
Generally, for complex (i.e. compound) shapes, you would generally try as step #1 and "exit early" test. For optimization reasons, you generally try eliminate false-positives as early in the process as possible.
As simple step #1 is to test for collisions on the "bounding boxes" of each compound shape. If the bounding boxes are NOT overlapping then you can quit early and assume no collision because the compound shapes could not be colliding (see https://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169)
If the bounding-box test cannot eliminate early, you will need to test each sub-shape in turn with algorithms most suitable to the shape (circle-circle, circle-rect etc.) leaving the most "expensive" tests to last - like polygon-polygon.
You might want to also look at this question How do I determine if two convex polygons intersect?

Find text lines in a page (limited image processing resources)

I want to find the text lines in a page of text (like from a book).
Sample image:
One of the problems is that I want to implement this in Javascript and this is the best computer vision library that I found:
http://inspirit.github.io/jsfeat/#imgproc
Therefore I am limited to the algorithms implemented in JSFeat (or another JS library).
I thought of doing feature detection on the page and then doing statistics on the plotted points to find the lines. I'm not sure that's a good idea or how this can be done.
For example this is the output of FAST when applied on that image.
It should work regardless of the font used. Also slight rotation tolerance would be even better.
Help much appreciated!
My approach would be to count the number of vertical edges on each horizontal scanline. Each letter will produce two or more edges.
First, use the sobel operator to calculate x derivative:
Now we have positive and negative edges, but we want to count them both as positive. So take the absolut value:
Now count the edges on each line. This can be done by summing the pixels up, or simply by scaling the image to a width of 1px, leaving the height unchanged. For easy viewing I've plotted the result:
Now you'll need to threshold this result somehow, or maybe find the maxima after running a blur on the 1px-width image. If the font size and the letters per line stay roughly the same, this is easy.
You may want to re-run on different rotations of the original image and then use the result with the highest contrast.

SVG text hit-test

I'm trying to implement collision detection for SVG text elements using client side JavaScript. The hit-test should check if any glyph of a text overlaps any glyph of another text element. Since getBBox and getExtentOfChar are anything than accurate I need a custom solution.
My first approach was to get the colour of each coordinate/pixel of an element and do the hit-testing manually, but this does not work because it isn't possible to get the colour of a coordinate. It would require an additional canvas to get pixel colours -> awful workaround.
Now I'm thinking about converting the text or the glyphs to polygons for hit testing. Is it possible? Or has anyone another approach for glyph based hit testing?
Best Regards
You are really entering a world of pain and cross browser problems. I ended up doing custom path-rendering of fonts only to get the total text length reliable and consistent. I don't even want to think about glyph-hitting.
One problem for example is that firefox (at least 3.6) and iirc also some version of opera has some rounding error when scaling so when you scale the parent-element holding the text and scale the text by the inverse of that scale, then the letter-spacing will be slightly different compared to without any scale. (Because each letter must begin on an even number or something like that, problem can be solved by multiplying both the upscale and downscale with like 10000 but that's another story)
The performance impact by using path compared to text is unfortunately quite noticeable. If your canvas does any form of animated panning or zooming you should switch to pure text-elements during the animation and once static, turn on path rendering for accuracy.
Fortunally converting svg-fonts to paths is very easy, it is plaintext and using the exact same format as the path-element. (beware of font-embedding-licenses though! Also keep file size in mind as you cannot use the fonts from the users system, )
As for the pixel-based hit-testing – if you switch to HTML5 Canvas, then this will become possible. Several projects provide easy transition from SVG to Canvas, e.g. fabric.js. See a comparison table here.
As for the polygon-based approach – possible, but difficult. You can convert text or glyphs to polygons (paths) using some tool (Inkscape's text-to-path for instance). And then there'll be calculations. Making a general solution for any text will require a lot of work. However, if the text doesn't change, then drawing your text manually using paths can be a quick and dirty solution.

Plotting mathematical functions without rendering artefacts

I don't think there's a good answer to this, but I'd like to find out if there's a better way to do this.
I need to plot a mathematical function, which is nearly flat at one end of the display, and nearly vertical at the other end. The bottom left quadrant of a circle would be a good model. I can auto-generate as many points as required.
The problem is, I can't do this without all sorts of artefacts.
I haven't tried Bezier fitting; I don't think this would be even close. My understanding is that Bezier is for one-off manually-constructed pretty graphics, and not for real curve-fitting.
That leaves polylines. There are only 2 things I can do with polylines - I can select the line length (in other words, the number of points I auto-generate), and I can disable anti-aliasing (setAttributeNS(null, "shape-rendering", "crisp-edges").
If I generate lots of points, then I get jaggies everywhere, and the result is unusable. It can also look very much like it's oscillating, which makes it appear that I've incorrectly calculated the function. The anti-aliasing doesn't make any difference, since it doesn't operate across point boundaries.
The only solution I've got is to draw fewer points, so that it's obvious that I'm drawing segments. It's no longer smooth, but at least there are no jaggies or oscillation. I draw this with the default anti-aliasing.
Any ideas?
Edit:
It seems like the only answer to this is actually Bezier curve fitting. You have to preprocess to find the parameters of the required segments, and then plot the results. Google comes up with a number of hits on curve fitting with Beziers.
You have the mathematical function, and can therefore generate as many points as you need.
I assume the problem is that because you do not know the output resolution (SVG is device independent) you do not know how many points to generate. Otherwise you could just create a polyline where each line is approximately 1 pixel long.
Fitting your mathematical function to a bezier curve is (probably) not going to get a perfect match - just like a circle cannot be matched perfectly by a cubic bezier curve. And I think the task of fitting your function to a bezier curve would not be trivial (I've never done this).
Could you rather output your mathematical function to a canvas element? Then you could write some javascript code to plot your mathematical function dependant on the output resolution. Similar to how a graphics system renders a Bezier curve.
Do you know how graphics systems render Bezier curves? They approximate the bezier curve with a polyline, and then measure the error difference between the polyline and the bezier curve. If the difference is greater than a certain tolerance - where the tolerance is determined by the output resolution - the bezier is subdivided and the process repeated for each bezier curve. When the difference between beziers and polylines is below the tolerance, the polylines are drawn. http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Computer_graphics
I suppose you want to draw y=f(x) over a certain interval [a,b]
A classical solution is to take N points uniformly distributed over [a,b], to compute f over these points and draw lines (or polynoms).
It of course doesn't work in your case, since y is nearly vertical in certain area. But why don't you take more points in these areas (and less points where the function is nearly horizontal) ?
You can compute the derivative of your function (or approximate this derivative with (f(x+h)-f(x))/h and h small) and determine the step between two successive points with this derivative

Merging pixels to minimize paint operations on Html canvas

Hi I'm painting an image onto a canvas (html5) and I want to reduce the number of fillRect calls I'm making in the hope of making the process more efficient.
Note: I'm calling canvas.fillRect to paint individual pixels and pixels can be 1x1 or other size rectangle depending on resolution I'm painting in (So I know that they are not called pixels but my image vocab is limited).
What I would like to do is find and merge individual pixels if they are the same colour. This will reduce the number of calls to fillRect and hopefully be faster than what I currently have.
So lets say I have a bit map like this:
[fff, fff, fff]
[f00, f00, f00]
[00f, 00f, 00f]
Instead of making 9 calls to fillRect I would like to make 3.
So my questions are:
1) What is this process called (so I can do some more intelligent research, as googling 'merging pixels', 'merging rectangles', etc, yields no useful results).
2) Anyone aware of any open source library that implements this (does not have to be javascript)
3) Does anyone think that adding this pre-processing step will actually make the code slower in JS?
Thanks All
Guido Tapia
I would agree with #Jakub that doing this kind of analysis in Javascript is likely to take a lot longer than the time you save by filling fewer rectangles (usually a very fast operation for a graphics card). That is unless you have to paint the same set of rectangles many thousands of times.
As for what it's called, the closest thing I can come up with is run-length encoding, which admittedly is one-dimensional rather than two.

Categories

Resources