I’m trying to make 6 dots along a line(0, random(height), width, random(height)). The dots should be evenly spaced.
You can use lerp(start, end, t) to linearly interpolate between to values by specifying t: where in between the start/end values you'd like the result to be.
This t value is between 0.0 and 1.0 (normalised value). You can think if of it as percentage. (e.g. 0.0 is at the start (0%) value, 1.0 is at the end value(100%), 0.5 is 50% between the start and end value).
In your case, you would:
store the randomly generated values first (before interpolation)
iterate 6 times, and for each iteration
for each iteration, map the iteration index to the normalised value (t)
Finally, use lerp() by plugging in the from/to values and the t value at the current iteration.
Here's a basic example:
float fromX = 0;
float fromY = random(height);
float toX = width;
float toY = random(height);
int numPoints = 6;
for(int i = 0 ; i < numPoints; i++){
float interpolationAmount = map(i, 0, numPoints - 1, 0.0, 1.0);
float interpolatedX = lerp(fromX, toX, interpolationAmount);
float interpolatedY = lerp(fromY, toY, interpolationAmount);
ellipse(interpolatedX, interpolatedY, 9, 9);
}
Alternatively you can use PVector's lerp() to easiely interpolate between points in 2D (or 3D), without having to interpolate every component:
PVector start = new PVector(0 , random(height));
PVector end = new PVector(width, random(height));
for(float t = 0.0 ; t <= 1.0 ; t += 1.0 / 5){
PVector inbetween = PVector.lerp(start, end, t);
ellipse(inbetween.x, inbetween.y, 9, 9);
}
Update
The slope is the ratio (division) between the difference on Y axis (called rise, Δy = y2 - y1 (E.g. toY - fromY)) and the difference on the X axis (called run, Δx = x2 - x1 (e.g. toX - fromY)).
You can use this difference between start and end points (defining the slope) to draw the points in between.
If you divide this difference into equal sections, each for a point you'd like to draw, then you can multiply it as you iterate and simply translate/offset it from the start position:
// start point
float fromX = 0;
float fromY = random(height);
// end point
float toX = width;
float toY = random(height);
// difference between each component
float diffY = toY - fromY;
float diffX = toX - fromX;
// slope = ratio between Y and X difference
float slope = diffY / diffX;
println("slope as ratio", slope, "as degrees", degrees(atan2(diffY, diffX) + PI));
// start drawing 6 points
int numPoints = 6;
// precalculate a sixth
float sectionIncrement = 1.0 / (numPoints - 1);
for(int i = 0 ; i < 6; i++){
// a sixth incremented (e.g. 1/6 * 0, * 1, *2, ...)
float section = sectionIncrement * i;
// a sixth incremented and mulitplied to the difference
// e.g. 1/6 of slope difference, 2/6 of slope / etc.
// to which we offset the start location (fromX, fromY +)
float x = fromX + (diffX * section);
float y = fromY + (diffY * section);
// render
ellipse(x, y, 9, 9);
}
point(0, random(height))
point(width/5, random(height))
point(width/5*2, random(height))
point(width/5*3, random(height))
point(width/5*4, random(height))
point(width, random(height))
Related
I need to loop through a array in circle in arc shape with a small radius (like draw a circle pixel by pixel), but all algorithm i tried, checks duplicate indexes of array (it's got the same x and y several times).
I have a radius of 3, with a circle form of 28 elements (not filled), but the algorithm iterate 360 times. I can check if x or y change before i do something, but it's lame.
My code now:
for (int radius = 1; radius < 6; radius++)
{
for (double i = 0; i < 360; i += 1)
{
double angle = i * System.Math.PI / 180;
int x = (int)(radius * System.Math.Cos(angle)) + centerX;
int y = (int)(radius * System.Math.Sin(angle)) + centerY;
// do something
// if (array[x, y]) ....
}
}
PS: I can't use midpoint circle, because i need to increment radius starting from 2 until 6, and not every index is obtained, because his circle it's not real (according trigonometry)
EDIT:
What i really need, is scan a full circle edge by edge, starting by center.
360 steps (it's get all coordinates):
Full scan
for (int radius = 2; radius <= 7; radius++)
{
for (double i = 0; i <= 360; i += 1)
{
double angle = i * System.Math.PI / 180;
int x = (int)(radius * System.Math.Cos(angle));
int y = (int)(radius * System.Math.Sin(angle));
print(x, y, "X");
}
}
Using Midpoint Circle or other algorithm skipping steps (missing coordinates):
Midpoint Circle Algorithm
for (int radius = 2; radius <= 7; radius++)
{
int x = radius;
int y = 0;
int err = 0;
while (x >= y)
{
print(x, y, "X");
print(y, x, "X");
print(-y, x, "X");
print(-y, x, "X");
print(-x, y, "X");
print(-x, -y, "X");
print(-y, -x, "X");
print(y, -x, "X");
print(x, -y, "X");
y += 1;
err += 1 + 2 * y;
if (2 * (err - x) + 1 > 0)
{
x -= 1;
err += 1 - 2 * x;
}
}
}
There are two algorithmic ideas in play here: one is rasterizing a circle. The OP code presents a couple opportunities for improvement on that front: (a) one needn't sample the entire 360 degree circle, realizing that a circle is symmetric across both axes. (x,y) can be reflected in the other three quadrants as (-x,y), (-x,-y), and (x,-y). (b) the step on the loop should be related to the curvature. A simple heuristic is to use the radius as the step. So...
let step = MIN(radius, 90)
for (double i=0; i<90; i += step) {
add (x,y) to results
reflect into quadrants 2,3,4 and add to results
}
With these couple improvements, you may no longer care about duplicate samples being generated. If you still do, then the second idea, independent of the circle, is how to hash a pair of ints. There's a good article about that here: Mapping two integers to one, in a unique and deterministic way.
In a nutshell, we compute an int from our x,y pair that's guaranteed to map uniquely, and then check that for duplicates...
cantor(x, y) = 1/2(x + y)(x + y + 1) + y
This works only for positive values of x,y, which is just what you need since we're only computing (and then reflecting) in the first quadrant. For each pair, check that they are unique
let s = an empty set
int step = MIN(radius, 90)
for (double i=0; i<90; i += step) {
generate (x,y)
let c = cantor(x,y)
if (not(s contains c)) {
add (x,y) to results
reflect into quadrants 2,3,4 and add to results
add c to s
}
}
Got it!
It's not beautiful, but work for me.
int maxRadius = 7;
for (int radius = 1; radius <= maxRadius; radius++)
{
x = position.X - radius;
y = position.Y - radius;
x2 = position.X + radius;
y2 = position.Y + radius;
for (int i = 0; i <= radius * 2; i++)
{
if (InCircle(position.X, position.Y, x + i, y, maxRadius)) // Top X
myArray[position, x + i, y]; // check array
if (InCircle(position.X, position.Y, x + i, y2, maxRadius)) // Bottom X
myArray[position, x + i, y2]; // check array
if (i > 0 && i < radius * 2)
{
if (InCircle(position.X, position.Y, x, y + i, maxRadius)) // Left Y
myArray[position, x, y + i]; // check array
if (InCircle(position.X, position.Y, x2, y + i, maxRadius)) // Right Y
myArray[position, x2, y + i]; // check array
}
}
}
public static bool InCircle(int originX, int originY, int x, int y, int radius)
{
int dx = Math.Abs(x - originX);
if (dx > radius) return false;
int dy = Math.Abs(y - originY);
if (dy > radius) return false;
if (dx + dy <= radius) return true;
return (dx * dx + dy * dy <= radius * radius);
}
Consider this binary image:
A normal edge detection algorithm (Like Canny) takes the binary image as input and results into the contour shown in red. I need another algorithm that takes a point "P" as a second piece of input data. "P" is the black point in the previous image. This algorithm should result into the blue contour. The blue contours represents the point "P" lines-of-sight edge of the binary image.
I searched a lot of an image processing algorithm that achieve this, but didn't find any. I also tried to think about a new one, but I still have a lot of difficulties.
Since you've got a bitmap, you could use a bitmap algorithm.
Here's a working example (in JSFiddle or see below). (Firefox, Chrome, but not IE)
Pseudocode:
// part 1: occlusion
mark all pixels as 'outside'
for each pixel on the edge of the image
draw a line from the source pixel to the edge pixel and
for each pixel on the line starting from the source and ending with the edge
if the pixel is gray mark it as 'inside'
otherwise stop drawing this line
// part 2: edge finding
for each pixel in the image
if pixel is not marked 'inside' skip this pixel
if pixel has a neighbor that is outside mark this pixel 'edge'
// part 3: draw the edges
highlight all the edges
At first this sounds pretty terrible... But really, it's O(p) where p is the number of pixels in your image.
Full code here, works best full page:
var c = document.getElementById('c');
c.width = c.height = 500;
var x = c.getContext("2d");
//////////// Draw some "interesting" stuff ////////////
function DrawScene() {
x.beginPath();
x.rect(0, 0, c.width, c.height);
x.fillStyle = '#fff';
x.fill();
x.beginPath();
x.rect(c.width * 0.1, c.height * 0.1, c.width * 0.8, c.height * 0.8);
x.fillStyle = '#000';
x.fill();
x.beginPath();
x.rect(c.width * 0.25, c.height * 0.02 , c.width * 0.5, c.height * 0.05);
x.fillStyle = '#000';
x.fill();
x.beginPath();
x.rect(c.width * 0.3, c.height * 0.2, c.width * 0.03, c.height * 0.4);
x.fillStyle = '#fff';
x.fill();
x.beginPath();
var maxAng = 2.0;
function sc(t) { return t * 0.3 + 0.5; }
function sc2(t) { return t * 0.35 + 0.5; }
for (var i = 0; i < maxAng; i += 0.1)
x.lineTo(sc(Math.cos(i)) * c.width, sc(Math.sin(i)) * c.height);
for (var i = maxAng; i >= 0; i -= 0.1)
x.lineTo(sc2(Math.cos(i)) * c.width, sc2(Math.sin(i)) * c.height);
x.closePath();
x.fill();
x.beginPath();
x.moveTo(0.2 * c.width, 0.03 * c.height);
x.lineTo(c.width * 0.9, c.height * 0.8);
x.lineTo(c.width * 0.8, c.height * 0.8);
x.lineTo(c.width * 0.1, 0.03 * c.height);
x.closePath();
x.fillStyle = '#000';
x.fill();
}
//////////// Pick a point to start our operations: ////////////
var v_x = Math.round(c.width * 0.5);
var v_y = Math.round(c.height * 0.5);
function Update() {
if (navigator.appName == 'Microsoft Internet Explorer'
|| !!(navigator.userAgent.match(/Trident/)
|| navigator.userAgent.match(/rv 11/))
|| $.browser.msie == 1)
{
document.getElementById("d").innerHTML = "Does not work in IE.";
return;
}
DrawScene();
//////////// Make our image binary (white and gray) ////////////
var id = x.getImageData(0, 0, c.width, c.height);
for (var i = 0; i < id.width * id.height * 4; i += 4) {
id.data[i + 0] = id.data[i + 0] > 128 ? 255 : 64;
id.data[i + 1] = id.data[i + 1] > 128 ? 255 : 64;
id.data[i + 2] = id.data[i + 2] > 128 ? 255 : 64;
}
// Adapted from http://rosettacode.org/wiki/Bitmap/Bresenham's_line_algorithm#JavaScript
function line(x1, y1) {
var x0 = v_x;
var y0 = v_y;
var dx = Math.abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
var dy = Math.abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
var err = (dx>dy ? dx : -dy)/2;
while (true) {
var d = (y0 * c.height + x0) * 4;
if (id.data[d] === 255) break;
id.data[d] = 128;
id.data[d + 1] = 128;
id.data[d + 2] = 128;
if (x0 === x1 && y0 === y1) break;
var e2 = err;
if (e2 > -dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
for (var i = 0; i < c.width; i++) line(i, 0);
for (var i = 0; i < c.width; i++) line(i, c.height - 1);
for (var i = 0; i < c.height; i++) line(0, i);
for (var i = 0; i < c.height; i++) line(c.width - 1, i);
// Outline-finding algorithm
function gb(x, y) {
var v = id.data[(y * id.height + x) * 4];
return v !== 128 && v !== 0;
}
for (var y = 0; y < id.height; y++) {
var py = Math.max(y - 1, 0);
var ny = Math.min(y + 1, id.height - 1);
console.log(y);
for (var z = 0; z < id.width; z++) {
var d = (y * id.height + z) * 4;
if (id.data[d] !== 128) continue;
var pz = Math.max(z - 1, 0);
var nz = Math.min(z + 1, id.width - 1);
if (gb(pz, py) || gb(z, py) || gb(nz, py) ||
gb(pz, y) || gb(z, y) || gb(nz, y) ||
gb(pz, ny) || gb(z, ny) || gb(nz, ny)) {
id.data[d + 0] = 0;
id.data[d + 1] = 0;
id.data[d + 2] = 255;
}
}
}
x.putImageData(id, 0, 0);
// Draw the starting point
x.beginPath();
x.arc(v_x, v_y, c.width * 0.01, 0, 2 * Math.PI, false);
x.fillStyle = '#800';
x.fill();
}
Update();
c.addEventListener('click', function(evt) {
var x = evt.pageX - c.offsetLeft,
y = evt.pageY - c.offsetTop;
v_x = x;
v_y = y;
Update();
}, false);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
<center><div id="d">Click on image to change point</div>
<canvas id="c"></canvas></center>
I would just estimate P's line of sight contour with ray collisions.
RESOLUTION = PI / 720;
For rad = 0 To PI * 2 Step RESOLUTION
ray = CreateRay(P, rad)
hits = Intersect(ray, contours)
If Len(hits) > 0
Add(hits[0], lineOfSightContour)
https://en.wikipedia.org/wiki/Hidden_surface_determination with e.g. a Z-Buffer is relatively easy. Edge detection looks a lot trickier and probably needs a bit of tuning. Why not take an existing edge detection algorithm from a library that somebody else has tuned, and then stick in some Z-buffering code to compute the blue contour from the red?
First approach
Main idea
Run an edge detection algorithm (Canny should do it just fine).
For each contour point C compute the triplet (slope, dir, dist), where:
slope is the slope of the line that passes through P and C
dir is a bit which is set if C is to the right of P (on the x axis) and reset if it is to the left; it used in order to distinguish in between points having the same slope, but on opposite sides of P
dist is the distance in between P and C.
Classify the set of contour points such that a class contains the points with the same key (slope, dir) and keep the one point from each such class having the minimum dist. Let S be the set of these closest points.
Sort S in clockwise order.
Iterate once more through the sorted set and, whenever two consecutive points are too far apart, draw a segment in between them, otherwise just draw the points.
Notes
You do not really need to compute the real distance in between P and C since you only use dist to determine the closest point to P at step 3. Instead you can keep C.x - P.x in dist. This piece of information should also tell you which of two points with the same slope is closest to P. Also, C.x - P.x swallows the dir parameter (in the sign bit). So you do not really need dir either.
The classification in step 3 can ideally be done by hashing (thus, in linear number of steps), but since doubles/floats are subject to rounding, you might need to allow small errors to occur by rounding the values of the slopes.
Second approach
Main idea
You can perform a sort of BFS starting from P, like when trying to determine the country/zone that P resides in. For each pixel, look at the pixels around it that were already visited by BFS (called neighbors). Depending on the distribution of the neighbor pixels that are in the line of sight, determine if the currently visited pixel is in the line of sight too or not. You can probably apply a sort of convolution operator on the neighbor pixels (like with any other filter). Also, you do not really need to decide right away if a pixel is for sure in the line of sight. You could instead compute some probability of that to be true.
Notes
Due to the fact that your graph is a 2D image, BFS should be pretty fast (since the number of edges is linear in the number of vertices).
This second approach eliminates the need to run an edge detection algorithm. Also, if the country/zone P resides in is considerably smaller than the image the overall performance should be better than running an edge detection algorithm solely.
I am trying to draw a Gaussian curve with mean = 0 and standard deviation = 1 using processing, but when my code runs, nothing is drawn to the screen (not even the background).
Here is my code:
float x, y, mu, sigma;
void setup() {
size(900, 650);
background(255);
stroke(0);
strokeWeight(1);
mu = 0.0;
sigma = 1.0;
for(int i = -4; i < 4; i += 0.5) {
x = i;
y = (1/(sigma * sqrt(2 * PI)))*(exp((-1 * sq(x - mu)) / (2 * sq(sigma)) ));
x = map(x, -4, 4, 0, width);
y = map(y, 0, 1, 0, height);
point(x, y);
}
}
void draw() {
}
In your for loop, you are using an int as the counter, but you're incrementing it by 0.5. When i is positive and it is incremented, that 0.5 gets truncated and i remains what is was before-- so the loop runs forever. It's a fun observation that i does increase when it is negative-- truncation works towards zero, so adding 0.5 ends up adding 1. Changing the declaration of i from int i = -4 to float i = -4 fixed it on my computer. You may also want to increase the stroke weight, at least temporarily, to verify that the points are being drawn (they were hard to see for me and I wasn't sure it was working at first).
I am trying to make some objects, say 12, to rotate in an ellipse path continuously in Processing. I got a sketch which does rotation in a circle and I want to make it to rotate in a ellipse. I have some pointer from processing forum but the code from the pointer is different from the code that I posted and I couldn't understand yet (weak in trigonometry).
I googled a bit and found a post trying to achieve this with this algorithm:
You need to define your ellipse with a few parameters:
x, y: center of the ellipse
a, b: semimajor and semiminor axes
If you want to move on the elipses this means that you change the
angle between the major axes and your position on the ellipse. Lets
call this angle alpha.
Your position (X,Y) is:
X = x + (a * Math.cos(alpha));
Y = y + (b * Math.sin(alpha));
In order to move left or right you need to increase/decrease alpha and
then recalculate your position. Source:
http://answers.unity3d.com/questions/27620/move-object-allong-an-ellipsoid-path.html
How do I integrate it into my sketch? Thank you.
Here's my sketch:
void setup()
{
size(1024, 768);
textFont(createFont("Arial", 30));
}
void draw()
{
background(0);
stroke(255);
int cx = 500;
int cy = 350;
int r = 300; //radius of the circle
float t = millis()/4000.0f; //increase to slow down the movement
ellipse(cx, cy, 5, 5);
for (int i = 1 ; i <= 12; i++) {
t = t + 100;
int x = (int)(cx + r * cos(t));
int y = (int)(cy + r * sin(t));
line(cx, cy, x, y);
textSize(30);
text(i, x, y);
if (i == 10) {
textSize(15);
text("x: " + x + " y: " + y, x - 50, y - 20);
}
}
}
Replace
int r = 300; //radius of the circle
with
int a = 350; // major axis of ellipse
int b = 250; // minor axis of ellipse
and replace
int x = (int)(cx + r * cos(t));
int y = (int)(cy + r * sin(t));
with
int x = (int)(cx + a * cos(t));
int y = (int)(cy + b * sin(t));
first post here, and probably an easy one.
I've got the code from Processing's reference site:
float a = 0.0;
float inc = TWO_PI/25.0;
for(int i=0; i<100; i=i+4) {
line(i, 50, i, 50+sin(a)*40.0);
a = a + inc;
}
http://processing.org/reference/sin_.html
However, what I need is a line that follows the curve of a Sin wave, not lines representing points along the curve and ending at the 0 axis. So basically I need to draw an "S" shape with a sin wave equation.
Can someone run me through how to do this?
Thank you in advance,
-Askee
To draw a curve you need to store the previous point's position.
float a = 0.0;
float inc = TWO_PI/25.0;
float prev_x = 0, prev_y = 50, x, y;
for(int i=0; i<100; i=i+4) {
x = i;
y = 50 + sin(a) * 40.0;
line(prev_x, prev_y, x, y);
prev_x = x;
prev_y = y;
a = a + inc;
}