I'm trying to create a script that drawls a curve through 'n' vertexes equally spaced around the center of an ellipse.
The reason I'm not just drawling an ellipse around the center ellipse is because I eventually want to connect a micro-controller to Processing where the data points acquired from the 'n' amount of sensors will vary the height ('y') of each vertex, creating constantly changing, irregular curves around the center ellipse such as this possible curve:
Essentially, this is supposed to be a data visualizer, but I cannot figure out why this is not working or how to achieve this effect after going through examples and the documentation on https://processing.org/reference/.
Here is my code:
color WHITE = color(255);
color BLACK = color(0);
void setup() {
size(500, 500);
}
void draw() {
background(WHITE);
translate(width/2, height/2); // move origin to center of window
// center ellipse
noStroke();
fill(color(255, 0, 0));
ellipse(0, 0, 10, 10); // center point, red
fill(BLACK);
int n = 10;
int y = 100;
float angle = TWO_PI / n;
beginShape();
for (int i = 0; i < n; i++) {
rotate(angle);
curveVertex(0, y);
}
endShape();
}
The matrix operations like rotate do not transform the single vertices in a shape. The current matrix is applied to the entire shape when it is draw (at endShape). You've to calculate all the vertex coordinates:
Create a ArrayList of PVector, fill it with points and draw it in a loop:
color WHITE = color(255);
color BLACK = color(0);
ArrayList<PVector> points = new ArrayList<PVector>();
void setup() {
size(500, 500);
int n = 10;
int radius = 100;
for (int i = 0; i <= n; i++) {
float angle = TWO_PI * (float)i/n;
points.add(new PVector(cos(angle)*radius, sin(angle)*radius));
}
}
void draw() {
background(WHITE);
translate(width/2, height/2);
noFill();
stroke(255, 0, 0);
beginShape();
PVector last = points.get(points.size()-1);
curveVertex(last.x, last.y);
for (int i = 0; i < points.size(); i++) {
PVector p = points.get(i);
curveVertex(p.x, p.y);
}
PVector first = points.get(0);
curveVertex(first.x, first.y);
endShape();
}
Related
I am trying to make a program where there are lines in a grid pointing towards the mouse like magnets. I am a beginner in Processing, can someone point me towards a tutorial on how to do that or give me some code and explain what it does?
int x1 = 0;
int x2 = 0;
int y1 = 0;
int y2 = 0;
void setup() {
size(200, 200);
}
void draw() {
background(255, 255, 0);
x1 = (mouseX + 100) / 2;
y1 = (mouseY + 100) / 2;
x2 = -1 * x1 + 200;
y2 = -1 * y1 + 200;
line(x1, y1, x2, y2);
}
There's plenty of solutions for this project. One of the easiest is to use Processing's PVector class.
The PVector class can be used for two or three dimensional vectors. A vector is an entity that has both magnitude and direction. The PVector class, however, stores the components of the vector (x,y for 2D, and x,y,z for 3D). The magnitude and direction are calculated from the components and can be accessed via the methods mag() and heading().
A two dimensional vector in Processing is defined through x and y components:
PVector v = new PVector(xComponent, yComponent);
With some mathematical formulae, you can determine magnitude and direction using the x- and y-components. But we don't need to determine these.
Below, I've attached completed solution code. Most of it should make sense to you. But it's worth understanding what is going on with PVector.
A nested for loop within void draw() contains x and y variables that represent the coordinates of each grid vertex.
We first define PVector v as a vector given by an x-component of mouseX - x, or the difference between the x-positions of the mouse and each grid point. Similarly, the y-component given by mouseY - y has the same difference.
Creating a variable PVector u initialized from v.setMag(15) holds a PVector that has the same direction as v, but with a length of just 15.
Now to draw the lines. Vectors represent an offset, not a position (in this case), so drawing a line from a grid point to an offset of a grid point is key.
Hence line(x, y, x + u.x, y + u.y), where u.x and u.y are the x- and y-components of the vector u.
void setup() {
size(600, 600); // Set the size of the canvas to 600x600.
}
void draw() {
background(255);
stroke(200); // Set the stroke color to black
int distVertLine = width / 10; // This variable defines the distance between each subsequent vertical line.
for(int i = 0; i < width; i += distVertLine) {
line(i, 0, i, height); // Draw a line at x=i starting at the top of the canvas (y=0) and going to the bottom (y=height)
}
int distHorizLine = height / 10; // This variable defines the distance between each subsequent vertical line.
for(int i = 0; i < width; i += distHorizLine) {
line(0, i, width, i); // Draw a line at y=i starting at the left of the canvas (x=0) and going to the right (x=width)
}
stroke(0); // Set the stroke to black.
// Use a nested for loop to iterate through all grid vertices.
for(int x = 0; x <= width; x += width/10) {
for(int y = 0; y <= height; y += height/10) {
PVector v = new PVector(mouseX - x, mouseY - y); // Define a vector that points in the direction of the mouse from each grid point.
PVector u = v.setMag(15); // Make the vector have a length of 15 units.
line(x, y, x + u.x, y + u.y); // Draw a line from the grid vertex to the terminal point given by the vector.
}
}
}
The answer already given by Ben Myers is excellent! The code below has a few small modifications:
the two for loops for the grid lines have been combined (since width and height are equal);
the construction of the vector is combined with setting the magnitude;
some minor changes to colors and comments.
Modified code:
void setup() {
// Set the size of the canvas to 600x600 pixels.
size(600, 600);
}
void draw() {
// There are 10x10 grid cells that each have a size of 60x60 pixels.
int gridSize = width / 10;
// Set the background color to anthracite and the stroke color to orange.
background(56, 62, 66);
stroke(235, 113, 52);
// Draw vertical and horizontal grid lines.
for (int lineIndex = 0; lineIndex < gridSize; lineIndex++) {
line(lineIndex * gridSize, 0, lineIndex * gridSize, height);
line(0, lineIndex * gridSize, width, lineIndex * gridSize);
}
// Set the stroke color to blue.
stroke(0, 139, 225);
// Use a nested for loop to iterate through all grid cells.
for (int x = 0; x <= width; x += gridSize) {
for (int y = 0; y <= height; y += gridSize) {
// Define a vector that points in the direction of the mouse from
// each grid point and set the vector length to 15 units.
PVector vector = new PVector(mouseX - x, mouseY - y).setMag(15);
// Draw a line from the grid point to the end point using the vector.
line(x, y, x + vector.x, y + vector.y);
}
}
}
My problem is wherever i click a node appears and for the second click another node appears with connected edge...so i want that When i click at any location, the node should be generated at the closest grid intersection point. I tried using loops.
and i'm trying to do that without "class"
int n_partition=10;
int length = 101;
PVector[] position = new PVector[length];
int BallNum;
void setup() {
size(600, 360);
background(255);
}
void draw() {
fill(255);
grid();
fill(0);
}
void mousePressed(){
stroke(0);
BallNum++;
position[BallNum]= new PVector(mouseX, mouseY);
circle(position[BallNum].x, position[BallNum].y, 10);
if (BallNum > 1) {
line(position[BallNum].x,position[BallNum].y,position[BallNum-
1].x,position[BallNum-1].y);
line(position[1].x,position[1].y,position[BallNum].x,position[BallNum] .y);
}
for (int i = 0; i < position[BallNum].length; ++ i) {
position[BallNum] = position[BallNum].get(i);
position[BallNum] = position[BallNum].get((i+1) % position[BallNum].length);
line(position[BallNum].x, position[BallNum].y,
position[BallNum].x, position[BallNum].y);
}
}
I EXPECT THE NODE SHOULD GO TO THE CLOSEST INTERSECTION.
You've to calculate the nearest position of the mouse to a point on the grid. For that you've to know the width (tile_width) and the height (tile_height) of cell.
The index of the cell can be calculated by the dividing the mouse position to the size of a tile and round() the result to an integral value (e.g. round(mouseX / (float)tile_width)).
Don't draw anything in int the mousePressed callback. The only thing you've to do there is to add a pint to the list:
void mousePressed(){
int tile_width = width / n_partition; // adapt this for your needs
int tile_height = height / n_partition;
int x = round(mouseX / (float)tile_width) * tile_width;
int y = round(mouseY / (float)tile_height) * tile_height;
position[BallNum]= new PVector(x, y);
BallNum++;
}
All the drawing has to be done in draw(). Draw the lines and points in separate loops:
void draw() {
background(255);
grid();
// draw the lines in a loop
strokeWeight(3);
stroke(0, 0, 255);
for (int i = 0; i < BallNum; ++ i) {
int i2 = (i+1) % BallNum;
line(position[i].x, position[i].y, position[i2].x, position[i2].y);
}
// draw balls in a loop
strokeWeight(1);
stroke(0, 0, 0);
fill (255, 0, 0);
for (int i = 0; i < BallNum; ++i) {
circle(position[i].x, position[i].y, 10);
}
}
Note, the scene is consecutively redrawn in every frame. Before the scene is drawn, the entire window has to be "cleared" by background().
See the result:
I have written a program in which a UFO (in essence, a gray ellipse) appears from the center of the screen and flies to the edge. There is a laser that appears when the mouse is pressed, and disappears when the mouse is released. I want to make it so that the UFO disappears when the mouse clicks on it/the laser touches it.
I've made it as far as to make the UFO class and create variables that determine its movements and speed, and I was able to get the laser to appear directly on the cursor. I thought of making an 'if' statement to check if the cursor is within the radius (or diameter) of the UFO, and placing it inside of the for loop I created for the UFOs. However, I am not sure how to achieve the proper syntax to make it happen.
Note: You may need to wait a few seconds for the first circle to appear after you play the sketch.
UFO[] ufos = new UFO[3];
void setup() {
size(700, 700);
for (int j = 0; j < ufos.length; j++) {
ufos[j] = new UFO();
}
}
//UFO class
//Class setup ends on line 61
class UFO {
float a;
float b;
float c;
float sa;
float sb;
float d;
UFO() {
//declare float a/b/c value
a = random(-width/2, width/2);
b = random(-height/2, width/2);
c = random(width);
}
//UFO movement
void update() {
//float c will serve as a speed determinant of UFOs
c = c - 1;
if (c < 5) {
c = width;
}
}
//UFO setup
void show() {
//moving x/y coordinates of UFO
float sa = map(a / c, 0, 1, 0, width);
float sb = map(b / c, 0, 1, 0, height);
float d = map(c, 0, width, 50, 0);
//UFO drawing shapes
//ellipse is always sa (or sb) / c to allow UFO to appear
//as if it is moving through space
fill(200);
ellipse((sa / c), (sb / c), d + 5, d+5);
//Hides UFO way off the screen
//and replaces it with a black-filled ellipse until
//it forms into a full circle
//When radius d becomes 50, the UFO flies from the
//center of the screen to off of the screen
if (d < 50) {
fill(0);
ellipse(-5, -10, 90, 90);
sa = 10000;
sb = 10000;
}
}
}
void draw() {
//Background
background(0);
//Translated the screen so that the UFOs appear to fly from
//the center of the screen
translate(width/2, height/2);
//UFO draw loop, make UFO visible on screen
for (int j = 0; j < ufos.length; j++) {
ufos[j].update();
ufos[j].show();
//mouse-click laser
if (mousePressed == true) {
fill(200,0,0);
ellipse(mouseX - 352,mouseY - 347,50,50);
}
}
}
Like I said on the Happy Coding forum:
Basically, if your UFO is a series of circles, then you just need to use the dist() function to check whether the distance from the mouse to the center of the circle is less than the radius of the circle. If it is, then the mouse is inside the circle. Here's a small example:
float circleX = 50;
float circleY = 50;
float circleDiameter = 20;
boolean showCircle = true;
void draw(){
background(0);
if(showCircle){
ellipse(circleX, circleY, circleDiameter, circleDiameter);
}
}
void mousePressed(){
if(dist(mouseX, mouseY, circleX, circleY) < circleDiameter/2){
showCircle = false;
}
}
If your UFO is multiple circles, then you need to apply this logic to each circle. Please try something and post a small example like this one (not your whole sketch) if you get stuck. Good luck.
i have made this code,with a 3d model,the model starts dismorph after 100 frames.I have a box shape that is moved with mouse,i want when ever the vertices be inside the box,to reset their position to the original position,and reconstruct the model,while the others dismorph. Always resetting the position when they are in the box,and move when they are not.Can anyone help me.Until now what it happens,is that when the vertices are inside the box they stop moving.
Thanks in Advance
import peasy.*;
import saito.objloader.*;
OBJModel model ;
OBJModel tmpmodel ;
PeasyCam cam;
float easing = 0.005;
float r;
float k =0.00001;
int VertCount;
PVector[] Verts;
PVector Mouse;
void setup()
{
size(800, 800, P3D);
frameRate(30);
noStroke();
model = new OBJModel(this, "Model2.obj", "absolute", TRIANGLES);
model.enableDebug();
model.scale(100);
model.translateToCenter();
tmpmodel = new OBJModel(this, "Model2.obj", "absolute", TRIANGLES);
tmpmodel.enableDebug();
tmpmodel.scale(100);
tmpmodel.translateToCenter();
cam = new PeasyCam(this, width/2, height/2, 0, 994);
}
void draw()
{
background(129);
lights();
int VertCount = model.getVertexCount ();
PVector[] Verts = new PVector[VertCount];
PVector[] locas = new PVector[VertCount];
float r =80;
PVector Mouse = new PVector(mouseX-width/2, mouseY-height/2, 0);
cam.setMouseControlled(true);
//println(frameCount);
pushMatrix();
translate(width/2, height/2, 0);
for (int i = 0; i < VertCount; i++) {
//PVector orgv = model.getVertex(i);
Verts[i]= model.getVertex(i);
arrayCopy(Verts, locas);
//PVector tmpv = new PVector();
if (frameCount> 100) {
float randX = random(-5, 5);
float randY = random(-5, 5);
float randZ = random(-5, 5);
PVector Ran = new PVector(randX, randY, randZ);
//float norX = abs(cos(k)) * randX;
//float norY = abs(cos(k)) * randY;
//float norZ = abs(cos(k)) * randZ;
if (Verts[i].x > Mouse.x - r/2 && Verts[i].x < Mouse.x + r/2) {
if (Verts[i].x > Mouse.y - r/2 && Verts[i].x < Mouse.y + r/2) {
if (Verts[i].x > Mouse.z - r/2 && Verts[i].x < Mouse.z + r/2) {
arrayCopy(locas, Verts);
}
}
} else {
Verts[i].x+=Ran.x;
Verts[i].y+=Ran.y;
Verts[i].z+=Ran.z;
if (Verts[i].x > width/2 || Verts[i].x < -width/2) {
Verts[i].x+=-Ran.x;
}
if (Verts[i].y > height/2 || Verts[i].y < -height/2) {
Verts[i].y+=-Ran.y;
}
if (Verts[i].z < -800/2 || Verts[i].z > 800/2) {
Verts[i].z+=-Ran.z;
}
}
tmpmodel.setVertex(i, Verts[i].x, Verts[i].y, Verts[i].z);
}
k+=0.0001;
}
pushMatrix();
translate(Mouse.x, Mouse.y, Mouse.z);
noFill();
stroke(255);
box(r);
popMatrix();
noStroke();
tmpmodel.draw();
popMatrix();
pushMatrix();
translate(width/2, height/2, 0);
noFill();
stroke(255);
box(width, height, 600);
popMatrix();
}
if you want to run it use the model from the saito obj example or the PshapeObj example.
There are a few things about your code that don't make a ton of sense (some comments might have helped with that). Why are you copying the array like that?
In any case, I would start simpler if I were you. I would adopt an object oriented approach, where you create a class that encapsulates a point's original position as well as its current position.
Here's an example that does this in two dimensions, but this approach generalizes to three dimensions:
ArrayList<MovingPoint> points = new ArrayList<MovingPoint>();
float circleDiameter = 200;
void setup(){
size(500, 500);
for(int i = 0; i < 100; i++){
points.add(new MovingPoint());
}
}
void draw(){
background(0);
noFill();
stroke(255, 0, 0);
ellipse(mouseX, mouseY, circleDiameter, circleDiameter);
fill(255);
stroke(255);
MovingPoint previousPoint = null;
for(MovingPoint mp : points){
mp.draw();
if(previousPoint != null){
line(previousPoint.current.x, previousPoint.current.y, mp.current.x, mp.current.y);
}
previousPoint = mp;
}
}
class MovingPoint{
PVector original;
PVector current;
public MovingPoint(){
original = new PVector(random(width), random(height));
current = original.copy();
}
void draw(){
if(dist(current.x, current.y, mouseX, mouseY) < circleDiameter/2){
//inside circle, reset position
current = original.copy();
}
else{
//outside circle, move randomly
current.x += random(-5, 5);
current.y += random(-5, 5);
}
ellipse(current.x, current.y, 10, 10);
}
}
You shouldn't have to go through the rigmarole of copying arrays. Just use a class that remembers each point's original and current positions, and then switch between them depending on the mouse position.
If you still can't get it working, please post another question that works from this example instead of your entire sketch. It's hard to help if we don't have access to the libraries you're using, so you're better off getting rid of them and narrowing the problem down to as few lines as possible. Good luck.
I'm coding an Android game and I'm trying to put the character in the middle of the screen (X axis).
In order to get the middle of the screen I get the screen width withe the following command:
int phoneWidth = Resources.getSystem().getDisplayMetrics().widthPixels;
Then I divide phoneWidth by two and hoped that the character would appear in the middle of the screen but it appears slightly to the right.
This is the code that I use:
public void drawCharacter() {
charImg = new Texture("pika.PNG");
charSprite = new Sprite(charImg);
float ahaha = Gdx.graphics.getWidth();
charPosX = (float)phoneWidth/ 2;
}
#Override
public void render() {
ch.stop();
double elapsedSeconds = ch.getSeconds();
checkLevel();
handleObstacles();
scrollTimer = scrollTimer + Gdx.graphics.getDeltaTime() / 2;
if (scrollTimer > 1.0f)
scrollTimer = 0.0f;
sprite.setV(scrollTimer);
sprite.setV2(scrollTimer + 2);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
charSprite.setPosition(charPosX, charPosY);
for (int i = 0; i < obstacles.size(); i++) {
obstacleSprites.get(i).setPosition(obstacles.get(i).getPosX(), obstacles.get(i).getPosY());
}
spriteBatch.begin();
sprite.draw(spriteBatch);
charSprite.draw(spriteBatch);
for (int i = 0; i < obstacleSprites.size(); i++) {
obstacleSprites.get(i).draw(spriteBatch);
}
spriteBatch.end();
moveCharacter();
moveObstacle();
}
Does anyone know where this error come from?
The left-hand edge of your sprite will be in the middle of the screen.
Subtract half the sprite width from half the screen width to draw the sprite centered horizontally.