I have a component that returns me a value from 0 to 360 degrees, I need to pass that value to units, for example from 0 to 100.
I have the following function but it seems ugly
function degToValue( deg )
{
var unit = Math.ceil( ( deg * 100 ) / 360 );
if ( unit === 0 ) unit = 100;
if ( deg < 1.6 && deg > 0 ) unit = 0;
return unit;
}
Do you know a more elegant way?
You can divide by 3.6 and use modulus to make this much prettier:
function degToValue( deg )
{
var unit = (deg / 3.6) % 100;
return (unit === 0 ? 100 : unit);
}
console.log( degToValue( 360 )); //100
console.log( degToValue( 0 )); //100
console.log( degToValue( 355 )); //98.61
console.log( degToValue( 719 )); //99.72
Related
import {DesignItem} from "../../../entities/FDDesign";
import {AbstractMode} from "./AbstractMode";
import FDMath from "../../../helpers/FDMath";
import RotationRaster from "../../../helpers/RotationRaster";
export default class RotateMode extends AbstractMode {
/**
*
* #param clientX
* #param clientY
* #param rasterRotation
*/
public run(clientX: number, clientY: number, rasterRotation: boolean): DesignItem {
console.log("xyz",clientX,clientY,rasterRotation);
const newAngle = Math.atan2(
clientX - this.itemCenterOnTransformedPage.x,
clientY - this.itemCenterOnTransformedPage.y,
);
const baseAngle = Math.atan2(
this.transformStartClientX - this.itemCenterOnTransformedPage.x,
this.transformStartClientY - this.itemCenterOnTransformedPage.y,
);
const rotation = this.applyRotation(
FDMath.normalizeAngle(
this.item.rotation +
FDMath.radToDeg(baseAngle - newAngle),
),
rasterRotation
);
//its a number consider it as angle for 90,180,270 then again 0 for rotation but it starts from 0..1..2.3.4 with floting values like 1.5..1.6..1.7..1.9 .2 .2.1.2.2 etc
console.log("rotationIn ",rotation);
return {
...this.item,
rotation,
};
}
/**
*
* #param rotation
* #param rasterRotation
*/
private applyRotation = (rotation: number, rasterRotation: boolean) => {
console.log("RotationNumber", rotation);
//i am trying this but its work for clockwise and when i rotate-back its creating problem how to to it for antiClockwise.The mouse is fast i cannot stop on 0 degree once i start rotating it. its hard to come-back to its original position (check image plz)
if(rotation >= 89.6 && rotation <=90.6){
return 90;
}else if(rotation >= 179.6 && rotation <= 180.6){
return 180;
}else if(rotation >= 269.6 && rotation <= 270.6){
return 270;
}else if(rotation >= 359 && rotation <= 360){
return 0;
}
else{
return rotation
};
if (rasterRotation) {
const raster = RotationRaster.getRaster(90);
console.log("Roter", rotation);
console.log("raster",raster);
raster.forEach(
(r) => {
if (
r.from > r.to
? rotation >= r.from || (rotation >= 0 && rotation <= r.to) // raster around 0
: rotation >= r.from && rotation <= r.to
) {
rotation = r.angle;
}
},
);
}
return rotation
}
}
I built a small compass project that is able to calculate the devices heading. SO what I got is a function that returns a value between 0° and 360° for the current heading.
What I like to get is a matching value for the current heading direction from an array like this: (["North", "North-East", "East", "South-East", "South", "South-West", "West", "North-West"])
(keep in mind: North = 0° / 359°)
However I got no idea how to get a result like this & this few lines below are all that I got so far but it doesn't seems working:
var directions = ["North", "North-East", "East", "South-East", "South", "South-West", "West", "North-West"]
function getDirection(heading) {
var index = Math.round((heading/8)/5,625)
return directions[index]
}
Any help would be very appreciated, thanks in advance.
This solution should take all possible scenarios in consideration:
var index = Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8;
function getDirection(angle) {
var directions = ['North', 'North-East', 'East', 'South-East', 'South', 'South-West', 'West', 'North-West'];
var index = Math.round(((angle %= 360) < 0 ? angle + 360 : angle) / 45) % 8;
return directions[index];
}
console.log( getDirection(0) );
console.log( getDirection(45) );
console.log( getDirection(180) );
console.log( getDirection(99) );
console.log( getDirection(275) );
console.log( getDirection(-120) );
console.log( getDirection(587) );
So I have a variable containing rotation in degrees, and I have an ideal rotation, and what I want is the percentage of accuracy within 20 degrees in either direction.
var actualRotation = 215
var idealRotation = 225
var accuracy = magicFunction(actualRotation, idealRotation)
In this case, the actualRotation is 10 degrees off from idealRotation, so with a 20 degree threshold in either direction, that's a 50% accuracy. So the value of accuracy would be 0.5.
var accuracy = magicFunction(225, 225) // 1.0
var accuracy = magicFunction(225, 210) // 0.25
var accuracy = magicFunction(245, 225) // 0.0
var accuracy = magicFunction(90, 225) // 0.0
How can I achieve this?
var actualRotation = 215
var idealRotation = 225
var diff = abs(actualRotation - idealRotation);
if (diff > 20)
console.log(0);
else{
accuracy = 1 - (diff/ 20);
console.log(accuracy);
}
Try this (just run code snippet):
function magicFunction(actualRotation , idealRotation ) {
var diff = Math.abs(actualRotation - idealRotation);
var accurrancy = 1 - (diff / 20);
accurrancy = accurrancy < 0 ? 0 : accurrancy;
return accurrancy;
}
console.log("225, 225: ", magicFunction(225, 225));
console.log("225, 210: ", magicFunction(225, 210));
console.log("245, 225: ", magicFunction(245, 225));
console.log("90, 225: ", magicFunction(90, 225));
The previous answers were good, but they don't handle the case where the difference crosses the zero-singularity.
E.g. when the angles are 5 and 355, you expect a difference of 10, but a simple subtraction gives 350. To rectify this, subtract the angle from 360 if it is bigger than 180.
For the above to work, you also need the angles to be in the range [0, 360). However this is a simple modulo calculation, as below.
Code:
function normalize(angle) {
if (angle < 0)
return angle - Math.round((angle - 360) / 360) * 360;
else if (angle >= 360)
return angle - Math.round(angle / 360) * 360;
else
return angle;
}
function difference(angle1, angle2) {
var diff = Math.abs(normalize(angle1) - normalize(angle2));
return diff > 180 ? 360 - diff : diff;
}
function magicFunction(actualRotation, idealRotation, limit) {
var diff = difference(actualRotation, idealRotation);
return diff < limit ? 1.0 - (diff / limit) : 0.0;
}
// tests
console.log(difference(10, 255)); // 115 (instead of the incorrect answer 245)
console.log(magicFunction(5, 355, 20)); // 0.5 (instead of 0 as would be returned originally)
EDIT: a graphical illustration of why the previous method would be insufficient:
I'm trying to port some code that I made in openFrameworks into THREE.JS. The code generates a landscape using perlin noise. I made it so that first a static index array is created, and then the positions of the vertices are placed out in a square grid each displaced by a specified distance. This is so that the positions of the vertices within the array can be shifted (up, down, left or right) so that when the camera moves the landscape can be updated and new strip of landscape generated based on the direction of the camera movement.
For each vertex, 6 indices are added to the index array which refer to two adjacent triangles. I didn't want to waste memory storing duplicates of each vertex for each triangle.
For example e.g.
v12 v11 v10
*----*----*
|\ |\ |
| \ | \ |
| \ | \ |
| \| \|
*----*----*
v02 v01 v00
so e.g. at vertex v00, the indices {v00, v10, v11} and {v00, v11, v01} are added, etc.
In my openFrameworks code, this all works perfectly! After a lot of trouble I finally got things working in THREE.js, but have noticed that as soon as I increase the amount of vertices everything starts getting weird - the triangles are connecting (what seems) all over the place, and a large chunk of vertices start to become skipped. At the moment anything up to and including a grid size of 256*256 works fine, but as soon as I increase any higher I start to see all the artefacts.
I'm thinking this is probably an issue with offsetting, but I don't really understand what this means, or how to implement it with my code. I've seen other people use it successfully when they define their indices in order (0, 1, 2, 3, ... ) and instead use 3 individual vertices for each triangle (and add each three vertices for each triangle in sequence). I can't seem to get the same kind of thing to work.
Any ideas? I've got my code below just in case it helps. You can see the parts where I commented out the ofsetting.
var landscape =
{
size: 0,
chunkSize: 21845,
distance: 0,
geometry: null,
mesh: null,
positions: null,
normals: null,
colors: null,
indices: null,
generateVertex: function( r, c )
{
var pos, color;
// Set position
pos = new THREE.Vector3();
pos.x = this.distance * c;
pos.z = this.distance * r;
pos.y = -2 + 5*simplex.noise2D( 0.1*pos.x, 0.1*pos.z );
// Set color
color = new THREE.Color();
color.setRGB( Math.random(1), 0, 0 );
this.vertices.setXYZ( r * this.size + c, pos.x, pos.y, pos.z );
this.colors.setXYZ( r * this.size + c, color.r, color.g, color.b );
},
generateIndices: function( i, r, c )
{
this.indices[ i ] = ( r * this.size ) + c;
this.indices[ i + 1 ] = ( ( r + 1 ) * this.size ) + c;
this.indices[ i + 2 ] = ( ( r + 1 ) * this.size ) + ( c + 1 );
this.indices[ i + 3 ] = ( r * this.size ) + c;
this.indices[ i + 4 ] = ( ( r + 1 ) * this.size ) + ( c + 1 );
this.indices[ i + 5 ] = ( r * this.size ) + ( c + 1 );
/*this.indices[ i ] = ( ( r * this.size ) + c ) % ( 3 * this.chunkSize );
this.indices[ i + 1 ] = ( ( ( r + 1 ) * this.size ) + c ) % ( 3 * this.chunkSize );
this.indices[ i + 2 ] = ( ( ( r + 1 ) * this.size ) + ( c + 1 ) ) % ( 3 * this.chunkSize );
this.indices[ i + 3 ] = ( ( r * this.size ) + c ) % ( 3 * this.chunkSize );
this.indices[ i + 4 ] = ( ( ( r + 1 ) * this.size ) + ( c + 1 ) ) % ( 3 * this.chunkSize );
this.indices[ i + 5 ] = ( ( r * this.size ) + ( c + 1 ) ) % ( 3 * this.chunkSize ); */
},
generatePoint: function( x, z )
{
},
generate: function( size, distance )
{
var sizeSquared, i;
sizeSquared = size * size;
i = 0;
this.size = size;
this.distance = distance;
// Create buffer geometry
this.geometry = new THREE.BufferGeometry();
this.indices = new Uint16Array( 6*(size-1)*(size-1) );
this.vertices = new THREE.BufferAttribute( new Float32Array( sizeSquared * 3 ), 3 );
this.colors = new THREE.BufferAttribute( new Float32Array( sizeSquared * 3 ), 3 );
// Generate points
for( var r = 0; r < size; r = r + 1 )
{
for( var c = 0; c < size; c = c + 1 )
{
this.generateVertex( r, c );
if( (r < size - 1) && (c < size - 1) )
{
this.generateIndices( i, r, c );
i = i + 6;
}
}
}
// Set geometry
this.geometry.addAttribute( 'index', new THREE.BufferAttribute( this.indices, 1 ) );
this.geometry.addAttribute( 'position', this.vertices );
this.geometry.addAttribute( 'color', this.colors );
//
/*this.geometry.offsets = [];
var triangles = 2 * ( size - 1 ) * ( size - 1 );
var offsets = triangles / this.chunkSize;
for( var j = 0; j < offsets; j = j + 1 )
{
var offset =
{
start: j * this.chunkSize * 3,
index: j * this.chunkSize * 3,
count: Math.min( triangles - ( j * this.chunkSize ), this.chunkSize ) * 3
};
this.geometry.offsets.push( offset );
}*/
var material = new THREE.MeshBasicMaterial( {vertexColors: THREE.VertexColors} );
//var material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors });
this.geometry.computeBoundingSphere();
this.mesh = new THREE.Mesh( this.geometry, material );
scene.add( this.mesh );
}
WebGL is based on OpenGL ES 2.0 which does not support 32 bit index buffers, so as soon as you have more than 256 * 256 vertices, the index buffer can no longer address them all.
From the OpenGL ES 2.0 Standard (section 2.8 Vertex Arrays):
Indexing support with ubyte and ushort indices is supported. Support
for uint indices is not required by OpenGL ES 2.0. If an
implementation supports uint indices, it will export the OES element
index - uint extension.
Assuming that's the issue you can enable 32bit index buffers by getting and checking for the OES_element_index_uint extension.
var uintExt = gl.getExtension("OES_element_index_uint");
if (!uintExt) {
alert("Sorry, this app needs 32bit indices and your device or browser doesn't appear to support them");
return;
}
According to webglstats.com 93.5% of machines support the extension.
You will need to change your generate function to create a 32 bit array:
this.indices = new Uint16Array( 6*(size-1)*(size-1) );
should be:
this.indices = new Uint32Array( 6*(size-1)*(size-1) );
I had a quick delve inside the source of three.js's renderer, and it looks like it checks the type of the index array and will pass gl.UNSIGNED_INT to glDrawElements if you use a Uint32Array.
Can someone give me an idea how can i round off a number to the nearest 0.5.
I have to scale elements in a web page according to screen resolution and for that i can only assign font size in pts to 1, 1.5 or 2 and onwards etc.
If i round off it rounds either to 1 decimal place or none.
How can i accomplish this job?
Write your own function that multiplies by 2, rounds, then divides by 2, e.g.
function roundHalf(num) {
return Math.round(num*2)/2;
}
Here's a more generic solution that may be useful to you:
function round(value, step) {
step || (step = 1.0);
var inv = 1.0 / step;
return Math.round(value * inv) / inv;
}
round(2.74, 0.1) = 2.7
round(2.74, 0.25) = 2.75
round(2.74, 0.5) = 2.5
round(2.74, 1.0) = 3.0
Just a stripped down version of all the above answers:
Math.round(valueToRound / 0.5) * 0.5;
Generic:
Math.round(valueToRound / step) * step;
To extend the top answer by newtron for rounding on more than only 0.5
function roundByNum(num, rounder) {
var multiplier = 1/(rounder||0.5);
return Math.round(num*multiplier)/multiplier;
}
console.log(roundByNum(74.67)); //expected output 74.5
console.log(roundByNum(74.67, 0.25)); //expected output 74.75
console.log(roundByNum(74.67, 4)); //expected output 76
Math.round(-0.5) returns 0, but it should be -1 according to the math rules.
More info: Math.round()
and Number.prototype.toFixed()
function round(number) {
var value = (number * 2).toFixed() / 2;
return value;
}
var f = 2.6;
var v = Math.floor(f) + ( Math.round( (f - Math.floor(f)) ) ? 0.5 : 0.0 );
function roundToTheHalfDollar(inputValue){
var percentile = Math.round((Math.round(inputValue*Math.pow(10,2))/Math.pow(10,2)-parseFloat(Math.trunc(inputValue)))*100)
var outputValue = (0.5 * (percentile >= 25 ? 1 : 0)) + (0.5 * (percentile >= 75 ? 1 : 0))
return Math.trunc(inputValue) + outputValue
}
I wrote this before seeing Tunaki's better response ;)
These answers weren't useful for me, I wanted to always round to a half (so that drawing with svg or canvas is sharp).
This rounds to the closest .5 (with a bias to go higher if in the middle)
function sharpen(num) {
const rem = num % 1
if (rem < 0.5) {
return Math.ceil(num / 0.5) * 0.5 + 0.5
} else {
return Math.floor(num / 0.5) * 0.5
}
}
console.log(sharpen(1)) // 1.5
console.log(sharpen(1.9)) // 1.5
console.log(sharpen(2)) // 2.5
console.log(sharpen(2.5)) // 2.5
console.log(sharpen(2.6)) // 2.5
The highest voted answer above fails for:
roundHalf(0.6) => returns 0.5
roundHalf(15.27) => returns 15.5
The fixed one is as follows:
const roundHalf = (num) => {
return Math.floor(Math.ceil(num * 2) / 2)
}
As a bit more flexible variation of the good answer above.
function roundNumber(value, step = 1.0, type = 'round') {
step || (step = 1.0);
const inv = 1.0 / step;
const mathFunc = 'ceil' === type ? Math.ceil : ('floor' === type ? Math.floor : Math.round);
return mathFunc(value * inv) / inv;
}