I use KineticJS to make a lot of transformations. Like the following:
var baseX = pos.x;
var baseY = pos.y;
var w = self.getWidth();
var h = self.getHeight();
var halfW = w / 2;
var halfH = h / 2;
var aspectRadian = Math.atan2(halfH, halfW);
Pretty quickly you int numbers turn into double numbers. So how do I deal with it? For example when I have to set a position of a Rect. I do
rect.x(10);
Since there are no half pixel the following does not make any sense:
rect.x(10.3);
I guess that KineticJS makes a rounding internally or may be it works with double numbers.
Is it better to use int numbers or double when working with KineticJS? Does one or the other solution leads to performance problems or rounding errors? Should I use double all the time to be as precise as possible?
If you just plan on making calculations that use only pixels, then sticking to float (or double) is fine and shouldn't produce any issues (except for minor anti-aliasing, if that's an issue at all for you). But if, say, you're going to try to convert pixels into different measurements (e.g. inches), then you might find Javascript's floating point precision working against you.
Related
I am trying to achieve what was asked in this question. In most scenarios, it is working fine by using the following code:
Math.round(num * 100) / 100
But I encountered a situation where it fails due to a very odd behavior. The number I'm trying to round is 1.275. I am expecting this to be rounded to 1.28, but it is being rounded to 1.27. The reason behind this is the fact that num * 100 is resulting in 127.49999999999999 instead of 127.5.
Why is this happening and is there a way around it?
EDIT
Yes, this question is probably the root cause of the issue I'm facing, but the suggested solutions of the selected answer are not working for me. The desired end result is a rounded number that is displayed correctly. So basically I'm trying to achieve what that question is instructing (check below) but I cannot figure out how.
If you just don’t want to see all those extra decimal places: simply
format your result rounded to a fixed number of decimal places when
displaying it.
You can use toFixed to ensure the precision that you're looking for:
var x = 1.275;
var y = x * 100;
y = y.toFixed(1); // y = 127.5
I am creating three angles. These angles creates a triangle.I want to show calculated angle in my canvas, for that I am calculating angle and rounding off for showing.While calculating the angle's , I am rounding off the decimal digits using Math.round().
So if I got 65.25, 70.36, 44.39 degree as value of three angles and after rounding off it will be 65,70,44,which become 179 degree instead of 180 degree(One degree is missing here).How can I solve this problem ?
Here are some images for reference
One approach is to compute the third angle (rounded) based upon the other two, rather than simply rounding them all as you have done. For instance:
var th0 = 65.25;
var th1 = 70.36;
var th2 = 44.39;
var th0r = Math.round(th0);
var th1r = Math.round(th1);
var th2r = 180.0 - th0r - th1r;
This will force th0r + th1r + th2r to always sum to 180. You can become a little more sophisticated by picking the best angle to compute from the other two, but this will probably suffice for most applications.
Hey i've made a rotation function in Javascript for rotating some 2D vector(point).
The Y output of the function works as expected, however the X value is outputting some crazy number, can anyone point out the floor in my logic?
Vector2.prototype.rotate = function(degrees){
var angle = degrees * TO_RADIANS; //Convert to radians.
var x = (this.getX() * Math.cos(angle)) - (this.getY() * Math.sin(angle));
var y = (this.getX() * Math.sin(angle)) + (this.getY() * Math.cos(angle));
return new Vector2(x,y);
};
Inputting Vector(1,0) into this function with a rotation of 90 degrees outputs 6.someDecimalPlaces e-17; which is obviously incorrect.
The outputted Y value however works as expected and returns 1.
Thanks in advance
The "6.someDecimalPlaces e-17" you're seeing is due to Javascript's handling of floating point numbers. What you're seeing is a rounding error in converting back from binary floating point to decimal. There's no easy fix for this although there are libraries that attempt to overcome the problem.
If you want rounded numbers for pixel perfect CSS manupilation you're best bet is to round the numbers coming out of this function or cast them to integer.
I am trying to create a custom linear congruential generator (LCQ) in JavaScript (the one used in glibc).
Its properties as it's stated on Wikipedia are: m=2^31 , a=1103515245 , c=12345.
Now I am getting next seed value with
x = (1103515245 * x + 12345) % 0x80000000 ; // (The same as &0x7fffffff)
Although the generator seems to work, but when the numbers are tested on canvas:
cx = (x & 0x3fffffff) % canvasWidth; // Coordinate x (the same for cy)
They seem to be horribly biased: http://jsfiddle.net/7VmR9/3/show/
Why does this happen? By choosing a different modulo, the result of a visual test looks much better.
The testing JSFiddle is here: http://jsfiddle.net/7VmR9/3/
Update
At last I fixed the transformation to canvas coordinates as in this formula:
var cx = ((x & 0x3fffffff)/0x3fffffff*canvasWidth)|0
Now the pixel coordinates are not so much malformed as when used the modulo operation.
Updated fiddle: http://jsfiddle.net/7VmR9/14/
For the generator the formula is (you forgot a modulus in the first part):
current = (multiplier * current * modul + addend) % modulus) / modulus
I realize that you try to optimize it so I updated the fiddle with this so you can use it as a basis for the optimizations:
http://jsfiddle.net/AbdiasSoftware/7VmR9/12/
Yes, it looks like you solved it. I've done the same thing.
A linear congruential generator is in the form:
seed = (seed * factor + offset) % range;
But, most importantly, when obtaining an actual random number from it, the following does not work:
random = seed % random_maximum;
This won't work because the second modulus seems to counteract the effect of the generator. Instead, you need to use:
random = floor (seed / range * random_maximum);
(This would be a random integer; remove the floor call to obtain a random float.)
Lastly, I will warn you: In JavaScript, when working with numbers that exceed the dword limit, there is a loss of precision. Thus, the random results of your LCG may be random, but they most likely won't match the results of the same LCG implemented in C++ or another low-level language that actually supports dword math.
Also due to imprecision, the cycle of the LCG is highly liable to be greatly reduced. So, for instance, the cycle of the glibc LCG you reference is probably 4 billion (that is, it will generate over 4 billion random numbers before starting over and re-generating the exact same set of numbers). This JavaScript implementation may only get 1 billion, or perhaps far less, due to the fact that when multiplying by the factor, the number surpasses 4 billion, and loses precision in doing so.
I have used this code to exactly try to have the RGB code of color:
var huePixel = HueCanvas.css('background-color').match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);//["rgb(0, 70, 255", "0", "70", "255"]
var svPixel = SVCanvas.get(0).getContext("2d").getImageData(satPos,valPos,1,1).data;
//opacity*original + (1-opacity)*background = resulting pixel
var opacity =(svPixel[3]/255);
var r =parseInt((opacity*svPixel[0])+((1-opacity)*huePixel[1]));
var g =parseInt((opacity*svPixel[1])+((1-opacity)*huePixel[2]));
var b =parseInt((opacity*svPixel[2])+((1-opacity)*huePixel[3]));
The problem is that in some pixels , the RGB is not exactly the same . If i use Math.round than parseInt there is more problems , and more pixels have little changes than real ones.
I know that the problem is in var opacity =(svPixel[3]/255); , but i dont know how to put the equation to not have that problems.
Thanks for your attention.
I don't know the definite answer to your question (I'm not even sure I understand the question itself), but I'll take a shot.
It appears that you're trying to calculate the RGB value that you see when something else (the browser?) blends a non-opaque canvas on top of opaque background. (Are you sure this is the right thing to do at all?)
First, please don't use parseInt to round a number. It's used to parse strings and you should use it to convert huePixel[i] to an integer: parseInt(huePixel[i], 10) (note that I specify the radix explicitly to avoid numbers being parsed as octal).
To round values, you should use Math methods: Math.round (to closest integer), Math.ceil (round up) or Math.floor (round down).
Maybe the problem you're having is caused by rounding errors (hard to say without the specific inputs and expected outputs of the calculation). To minimize the rounding errors, you could try rewriting the formula like this:
(opacity * svPixel[0]) + ((1-opacity) * huePixel[1]) =
huePixel[1] + opacity * (svPixel[0]-huePixel[1]) =
huePixel[1] + svPixel[3] * (svPixel[0]-huePixel[1]) / 255