Decimals and Measurement System

I know that using decimals with JS is discouraged because of accuracy problems when doing calculations.

Is this valid for Babylon.js also?

I want to create a Metric and Imperial measurement system (Centimeters and inches) and I am considering whether to allow decimals.

In general any tips about this?

I was considering to do something like:

1 unit = 1 CM
1 unit = 1 INCH + decimals

OR INSTEAD use integers to simulate decimals? e.g.

100 units = 1 CM
100 units = 1 INCH

Use toFixed() JS method to restrict the decimal numbers to 2? Because now I get very big numbers with 10+ decimals.

BJS is just JS. So the same computation accuracy.

@jerome so I want to use round/whole numbers then. But not sure how to simulate this when dragging.

Imagine that I have a tube and I can drag the end points to make the tube bigger in length.

While doing so, the length of the tube is currently calculated with decimals. Like this Recording #511

Is there a way to make it go 1-by-1 whole units? Meaning that only round units are used?

For the dragging I use:

scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
                case BABYLON.PointerEventTypes.POINTERDOWN:
                    if(pointerInfo.pickInfo.hit && pointerInfo.pickInfo.pickedMesh != ground) {
                        pointerDown(poinetrInfo.pickInfo.pickedMesh)
                    }
                    break;
                case BABYLON.PointerEventTypes.POINTERUP:
                        pointerUp();
                    break;
                case BABYLON.PointerEventTypes.POINTERMOVE:          
                        pointerMove();
                    break;
            }
}

For the mouse position:

pickResult = scene.pick(scene.pointerX, scene.pointerY);

I hope this makes sense.

Update:

I used Math.floor() on the X and Z coordinates and the numbers are whole when I draw the lines vertically or horizontally. If I draw the lines diagonally the numbers are not whole.

const x = pickResult.pickedPoint.x,
         z = pickResult.pickedPoint.z,
         pickedPoint = new BABYLON.Vector3(
             Math.floor(x),
             0, 
             Math.floor(z)
         );

Any ideas why this happens? See Recording #512

I tried Math.round() also but there is no difference.

Hi.
Like this maybe
return new BABYLON.Vector3(parseFloat(pickinfo.pickedPoint.x.toFixed(2)), 0, parseFloat(pickinfo.pickedPoint.z.toFixed(2)))

No that makes no difference actually.

I ended up rounding down the output of the distance between the 2 vectors.

Its not the most accurate solution but for now it will work. Because the distance between the two vectors is still a float on the actual world coordinates.

1 Like

It seems like Math.round() is a better solution, but it is not! In some cases it will NOT round correctly. Also, toFixed() will NOT round correctly in some cases.

To correct the rounding problem with the previous Math.round() and toFixed(), you can define a custom JavaScript round function that performs a “nearly equal” test to determine whether a fractional value is sufficiently close to a midpoint value to be subject to midpoint rounding. The following function return the value of the given number rounded to the nearest integer accurately.

Number.prototype.roundTo = function(decimal) {
  return +(Math.round(this + "e+" + decimal)  + "e-" + decimal);
}

var num = 9.7654;
console.log( num.roundTo(2)); //output 9.77