A typical random walk does not care about direction changes. Each iteration generates a new direction. But if you imagine a point animated on a random walk, it will mostly jump around. So, the goal is to have a smoother curve depending on the previously calculated points.
How to adjust a random walk function to have smoother directional changes?
My main idea is to have a method that generates a new point with x and y coordinates, but looks after the previous step and decreases the size of the next step (const radius), if the rotation (directional change) comes closer to 180°.
Therefore, I am using D3js to randomly take a new step in any x and y direction. At the end I'll get an array of all past steps limited by the maximum amount of steps. The radius gives an orientation how long an average step should be taking on the x and y axis'.
const history = [];
const steps = 10;
const radius = 1;
let point = {
x: 0,
y: 0,
radians: null
};
for (let i = 0; i < steps; i++) {
console.log(point);
history.push(point);
const previousPoint = Object.assign({}, point);
point.x += radius * d3.randomNormal(0, 1)();
point.y += radius * d3.randomNormal(0, 1)();
point.radians = Math.atan2(
point.y - previousPoint.y,
point.x - previousPoint.x
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.js"></script>
Instead of using a coordinates based random walk, I decided to randomly generate each iteration a new radians. So the new and previous radians can be compared to each others to decide with velocity the new point will get. Depending on the minimum range between these radians' the volicity will be set. Afterwards a simple sine and cosine calculation have to be down to generate the coordinates of the new point.
At least I've achieved my final goal: https://beta.observablehq.com/#nextlevelshit/gentlemans-random-walk-part-3
const steps = 10;
const stepSize = 10;
let point = {
x: 0,
y: 0,
radians: randomRadians(),
velocity: 0
};
for (let i = 0; i < steps; i++) {
console.log(point);
const radians = randomRadians();
const velocity = 1 - minimumDifference(radians, point.radians) / Math.PI;
point = {
// Coordinates calculated depending on random radians and velocity
x: Math.sin(radians * Math.PI) * stepSize * velocity + point.x,
y: Math.cos(radians * Math.PI) * stepSize * velocity + point.y,
radians: radians, // Randomly generated radians
velocity: velocity // Velocity in comparison to previous point
};
}
function randomRadians() {
return randomFloat(- Math.PI, Math.PI);
}
function randomFloat(min, max) {
return Math.random() * (max - min) + min;
}
function minimumDifference(x, y) {
return Math.min((2 * Math.PI) - Math.abs(x - y), Math.abs(x - y));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.js"></script>
Related
I have a 2D equirectangular depth map that is a 1024 x 512 array of floats, each ranging between 0 to 1. Here example (truncated to grayscale):
I want to convert it to a set of 3D points but I am having trouble finding the right formula to do so - it's sort of close - pseudocode here (using a vec3() library):
for(var y = 0; y < array_height; ++y) {
var lat = (y / array_height) * 180.0 - 90.0;
var rho = Math.cos(lat * Math.PI / 180.0);
for(var x = 0; x < array_width; ++x) {
var lng = (x / array_width) * 360.0 - 180.0;
var pos = new vec3();
pos.x = (r * Math.cos(lng * Math.PI / 180.0));
pos.y = (Math.sin(lat * Math.PI / 180.0));
pos.z = (r * Math.sin(lng * Math.PI / 180.0));
pos.norm();
var depth = parseFloat(depth[(y * array_width) + x] / 255);
pos.multiply(depth);
// at this point I can plot pos as an X, Y, Z point
}
}
What I end up with isn't quite right and I can't tell why not. I am certain the data is correct. Can anyone suggest what I am doing wrong.
Thank you.
Molly.
Well looks like the texture is half-sphere in spherical coordinates:
x axis is longitude angle a <0,180> [deg]
y axis is latitude angle b <-45,+45> [deg]
intensity is radius r <0,1> [-]
So for each pixel simply:
linearly convert x,y to a,b
in degrees:
a = x*180 / (width -1)
b = -45 + ( y* 90 / (height-1) )
or in radians:
a = x*M_PI / (width -1)
b = -0.25*M_PI + ( 0.5*y*M_PI / (height-1) )
apply spherical to cartesian conversion
x=r*cos(a)*cos(b);
y=r*sin(a)*cos(b);
z=r* sin(b);
Looks like you have wrongly coded this conversion as latitude angle should be in all x,y,z not just y !!! Also you should not normalize the resulting position that would corrupt the shape !!!
store point into point cloud.
When I put all together in VCL/C++ (sorry do not code in javascript):
List<double> pnt; // 3D point list x0,y0,z0,x1,y1,z1,...
void compute()
{
int x,y,xs,ys; // texture positiona and size
double a,b,r,da,db; // spherical positiona and angle steps
double xx,yy,zz; // 3D point
DWORD *p; // texture pixel access
// load and prepare BMP texture
Graphics::TBitmap *bmp=new Graphics::TBitmap;
bmp->LoadFromFile("map.bmp");
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
xs=bmp->Width;
ys=bmp->Height;
/*
// 360x180 deg
da=2.0*M_PI/double(xs-1);
db=1.0*M_PI/double(ys-1);
b=-0.5*M_PI;
*/
// 180x90 deg
da=1.0*M_PI/double(xs-1);
db=0.5*M_PI/double(ys-1);
b=-0.25*M_PI;
// proces all its pixels
pnt.num=0;
for ( y=0; y<ys; y++,b+=db)
for (p=(DWORD*)bmp->ScanLine[y],a=0.0,x=0; x<xs; x++,a+=da)
{
// pixel access
r=DWORD(p[x]&255); // obtain intensity from texture <0..255>
r/=255.0; // normalize to <0..1>
// convert to 3D
xx=r*cos(a)*cos(b);
yy=r*sin(a)*cos(b);
zz=r* sin(b);
// store to pointcloud
pnt.add(xx);
pnt.add(yy);
pnt.add(zz);
}
// clean up
delete bmp;
}
Here preview for 180x90 deg:
and preview for 360x180 deg:
Not sure which one is correct (as I do not have any context to your map) but the first option looks more correct to me ...
In case its the second just use different numbers (doubled) for the interpolation in bullet #1
Also if you want to remove the background just ignore r==1 pixels:
simply by testing the intensity to max value (before normalization) in my case by adding this line:
if (r==255) continue;
after this one
r=DWORD(p[x]&255);
In your case (you have <0..1> already) you should test r>=0.9999 or something like that instead.
I started a project using the raycasting technique GitHub Project
To find the length of the ray (distance from players pos to wall) I just increment by one. But there are several problems with that, its time consuming, inaccurate & will be difficult for texturing.
I tried to implement the daa algorithm, which doesnt just increments by 1 -> he goes through the grids and returns exact positions.
http://www.geeksforgeeks.org/dda-line-generation-algorithm-computer-graphics/
Has anyone experience with that or any tips?
No algorithm way:
for(let resolution = 0; resolution < display.width / 2; resolution++){ //every 2nd px gets scanned
let ray = this.pov + (-this.fov / 2 + this.fov / (display.width / 2) * resolution);
let distance = 0, hit = false;
/*ugly way of raycasting!*/
do{
let x = this.x + distance * Math.cos(ray * (Math.PI / 180));
let y = this.y + distance * Math.sin(ray * (Math.PI / 180));
if(map[Math.floor(x / block)][Math.floor(y / block)]){
distance = Math.sqrt(Math.pow(this.x - x, 2) + Math.pow(this.y - y, 2));
hit = true
}
distance += 1;
}while(!hit);
distance = convert / distance;
canvas.fillStyle = "#fff";
canvas.fillRect(resolution * 2, display.height / 2 - distance / 2, 2, distance);
}
You don't need DDA or Bresenham algorithm to find intersections of the ray with walls.
If you need one intersection with given border (or box edges) - just calculate it with ray equation and border position.
If you want to get intersections with grid cells - use voxelization algorithm like Amanatides-Woo
I have one circle, which grows and shrinks by manipulating the radius in a loop.
While growing and shrinking, I draw a point on that circle. And within the same loop, increasing the angle for a next point.
The setup is like this:
let radius = 0;
let circleAngle = 0;
let radiusAngle = 0;
let speed = 0.02;
let radiusSpeed = 4;
let circleSpeed = 2;
And in the loop:
radius = Math.cos(radiusAngle) * 100;
// creating new point for line
let pointOnCircle = {
x: midX + Math.cos(circleAngle) * radius,
y: midY + Math.sin(circleAngle) * radius
};
circleAngle += speed * circleSpeed;
radiusAngle += speed * radiusSpeed;
This produces some kind of flower / pattern to be drawn.
After unknown rotations, the drawing line connects to the point from where it started, closing the path perfectly.
Now I would like to know how many rotations must occure, before the line is back to it's beginning.
A working example can be found here:
http://codepen.io/anon/pen/RGKOjP
The console logs the current rotations of both the circle and the line.
Full cycle is over, when both radius and point returns to the starting point. So
speed * circleSpeed * K = 360 * N
speed * radiusSpeed * K = 360 * M
Here K is unknown number of turns, N and M are integer numbers.
Divide the first equation by the second
circleSpeed / radiusSpeed = N / M
If speed values are integers, divide them by LCM to get minimal valid N and M values, if they are rational, multiply them to get integer proportion.
For your example minimal integers N=1,M=2, so we can get
K = 360 * 1 / (0.02 * 2) = 9000 loop turns
I was working on a fun project that implicates creating "imperfect" circles by drawing them with lines and animate their points to generate a pleasing effect.
The points should alternate between moving away and closer to the center of the circle, to illustrate:
I think I was able to accomplish that, the problem is when I try to render it in a canvas half the render jitters like crazy, you can see it in this demo.
You can see how it renders for me in this video. If you pay close attention the bottom right half of the render runs smoothly while the top left just..doesn't.
This is how I create the points:
for (var i = 0; i < q; i++) {
var a = toRad(aDiv * i);
var e = rand(this.e, 1);
var x = Math.cos(a) * (this.r * e) + this.x;
var y = Math.sin(a) * (this.r * e) + this.y;
this.points.push({
x: x,
y: y,
initX: x,
initY: y,
reverseX: false,
reverseY: false,
finalX: x + 5 * Math.cos(a),
finalY: y + 5 * Math.sin(a)
});
}
Each point in the imperfect circle is calculated using an angle and a random distance that it's not particularly relevant (it relies on a few parameters).
I think it's starts to mess up when I assign the final values (finalX,finalY), the animation is supposed to alternate between those and their initial values, but only half of the render accomplishes it.
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I can't figure it out, thanks in advance!
Is the math wrong? Is the code wrong? Or is it just that my computer can't handle the rendering?
I Think that your animation function has not care about the elapsed time. Simply the animation occurs very fast. The number of requestAnimationFrame callbacks is usually 60 times per second, So Happens just what is expected to happen.
I made some fixes in this fiddle. This animate function take care about timestamp. Also I made a gradient in the animation to alternate between their final and initial positions smoothly.
ImperfectCircle.prototype.animate = function (timestamp) {
var factor = 4;
var stepTime = 400;
for (var i = 0, l = this.points.length; i < l; i++) {
var point = this.points[i];
var direction = Math.floor(timestamp/stepTime)%2;
var stepProgress = timestamp % stepTime * 100 / stepTime;
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);
}
}
Step by Step:
based on comments
// 1. Calculates the steps as int: Math.floor(timestamp/stepTime)
// 2. Modulo to know if even step or odd step: %2
var direction = Math.floor(timestamp/stepTime)%2;
// 1. Calculates the step progress: timestamp % stepTime
// 2. Convert it to a percentage: * 100 / stepTime
var stepProgress = timestamp % stepTime * 100 / stepTime;
// if odd invert the percentage.
stepProgress = (direction == 0 ? stepProgress: 100 -stepProgress);
// recompute position based on step percentage
// factor is for fine adjustment.
point.x = point.initX + (Math.cos(point.angle) * stepProgress/100 * factor);
point.y = point.initY + (Math.sin(point.angle) * stepProgress/100 * factor);
Is there a way to translate into javascript a piece of code that will allow me to show map pins around a point taking in consideration a radius ?
var data=[
{long:3,lat:2},
{long:5,lat:2},
{long:2,lat:3}
];
aCoord={long:1,lat:2};
for(var i=0;i<data.length;i++){
if (data[i] is 30 kms far from aCoord)
myMap.addPin(data[i]);
}
myMap.autozoom();
Thank you,
Regards
I came up with this example so you have an idea on how to calculate the points. You'll need to figure out how to do any necessary conversions for lat/lon.
/**
* Returns coordinates for N points around a circle with a given radius from
* the center.
*
* center: array [x, y]
* radius: int
* num_points: int
*/
function get_points_on_circle(center, radius, num_points) {
if (!num_points) num_points = 10;
var interval = Math.PI * 2 / num_points;
points = [];
i = -1;
while (++i < num_points) {
var theta = interval * i,
point = [Math.cos(theta) * radius + center[0], Math.sin(theta) * radius + center[1]];
points.push(point);
}
return points;
}
// Sample usage
var center = [250, 250],
radius = 100,
num_points = 10;
var points = get_points_on_circle(center, radius, num_points);
Test it out (uses Raphael for plotting)
If you are interested in learning a little about the logic:
A radian is a unit of measure for angles. There are a total of 2*PI radians in a circle. Using that fact, you can calculate the angle interval of any number of points on a circle by performing 2*PI/num_points.
When you know the angle interval, you can calculate the angle (theta) of a point on a circle. Once you have theta (the angle), you have polar coordinates (radius,angle). For that to be of any use to us in this problem, you need to convert the polar coordinates into Cartesian coordinates (x,y). You can do that by using the following formulas:
x = cos(theta) * radius
y = sin(theta) * radius
That's pretty much it in a nutshell.