In this program, I am trying to get dot drawn onto the hypotenuse. If the line is diagonal, it seems to work fine. But the more vertical or horizontal the line gets, the dots are more sparse. If the line is completely vertical or horizontal, I get no dots. Also the longer the red line, dots are drawn further away from it.
This question here seems to be similar to what I'm asking, but I don't understand the answer.
How to check if a point (int - Coordinates) is within the hypotenuse of a triangle
I need a dot drawn at every pixel on the red line, but not too far away from it (1 or 2 pixels at most)
This code is for Processing.
int sx,sy,ex,ey;
void setup(){
sx=150;
sy=150;
ex=550;
ey=550;
size(600,600);
}
void draw(){
background(255);
stroke(#ff0000);
fill(0);
line(sx,sy,ex,ey);
stroke(0);
for(int y=0;y<height;y++){
for(int x=0;x<width;x++){
if(((x<=sx && x>=ex) || (x>=sx && x<=ex)) && ((y<=sy && y>=ey) || (y>=sy && y<=ey))){
double xdiff=ex-sx;
double ydiff=ey-sy;
double xpos=(x-sx)/xdiff;
double ypos=(y-sy)/ydiff;
double diff=xpos-ypos;
if(diff>-0.01 && diff < 0.01) ellipse(x,y,3,3);
}
}
}
}
void mousePressed() {
if(mouseButton == LEFT){
ex=mouseX;
ey=mouseY;
}else{
sx=mouseX;
sy=mouseY;
}
}
Can you just follow the line itself instead of testing every pixel?
int sx,sy,ex,ey;
void setup(){
size(600,600); //size() should always be the first line of setup()
sx=150;
sy=150;
ex=550;
ey=550;
background(255);
}
void draw(){}
void mousePressed(){
background(255);
fill(0);
stroke(0);
if(mouseButton == LEFT){
ex=mouseX;
ey=mouseY;
}else{
sx=mouseX;
sy=mouseY;
}
line(sx,sy,ex,ey);
float dx = (ex-sx);
float dy = (ey-sy);
float numDots = sqrt(pow(ey-sy,2) + pow(ex-sx,2));
for(int i = 0; i < numDots; i++){
ellipse(sx + i*dx/numDots, sy + i*dy/numDots,3,3);
}
}
Or, using Processing's PVector class:
PVector start,end;
void setup(){
size(600,600); //size() should always be the first line of setup()
start = new PVector(150,150);
end = new PVector(550,500);
background(255);
}
void draw(){}
void mousePressed(){
background(255);
fill(0);
stroke(0);
if(mouseButton == LEFT)
end.set(mouseX,mouseY);
else
start.set(mouseX,mouseY);
line(start.x,start.y,end.x,end.y);
PVector slope = new PVector(end.x-start.x,end.y-start.y);
float numDots = end.dist(start);
for(int i = 0; i < numDots; i++){
ellipse(start.x + i*slope.x/numDots, start.y + i*slope.y/numDots,3,3);
}
}
Related
so I'm creating an interactive story, and I want to switch between scenes by clicking buttons (like a standard old pokemon game except there isn't movement, just clicking).
I should probably use a switch statement right? But I don't know how to implement the changing of scenes and loading scenes into the cases. I also don't know if I would need to use 'if' statements within the cases.
This might be confusing, because it is very confusing to me. I'd appreciate any help you guys offer! I am desperate ;)
Code so far is below:
//PImages
PImage startScreen;
PImage[] waves = new PImage[3];
PImage[] scenes = new PImage[1];
int switchVariable;
//Objects
Button play;
void setup() {
size(750, 600);
background(#A3E9EA);
//Initialising Objects
play = new Button(50, 480, 330);
//loading wave images
waves[0] = loadImage("wave1.png");
waves[1] = loadImage("wave2.png");
waves[2] = loadImage("wave3.png");
//loading start image
startScreen = loadImage("start-screen.png");
//loading scenes
scenes[0] = loadImage("scene-one.png");
//setting frame rate
frameRate(6);
}
void draw() {
background(#A3E9EA);
frameCount++;
println (frameCount);
//drawing wave animation
if (frameCount < 5) {
image(waves[0], 0, 0);
}
else {
image(waves[1], 0, 0);
}
if (frameCount < 15 & frameCount > 10) {
background(#A3E9EA);
image(waves[2], 0, 0);
frameCount = 0;
}
//drawing start screen
image(startScreen, 0, 0);
//displaying play button
if (play.visible) play.buttonDisplay();
}
void mousePressed() {
if (play.visible) {
float d = dist(play.x+110, play.y+22, mouseX, mouseY);
if (d <= play.radius){
background(#A3E9EA);
image(scenes[0], 0, 0);
}
}
}
Button Class:
class Button {
float radius;
float x;
float y;
PImage[] buttonImage = new PImage[2];
boolean visible;
Button(float _radius, float _x, float _y) {
radius = _radius;
visible = true;
x = _x;
y = _y;
buttonImage[0] = loadImage("play-game-button.png");
}
void buttonDisplay() {
image(buttonImage[0], x, y);
}
}
The source code below shows one possible approach to your question. It does not rely on ‘switch’ but instead uses a custom control with up and down buttons similar to a Java stepper. The stepper control value corresponds with images in the scenes array and the background() is set accordingly. A separate button class is required and code for this follows the demo.
color BLUE = color(64, 124, 188);
color LTGRAY = color(185, 180, 180);
color YELLOW = color(245, 250, 13);
color RED = color(255, 0, 0);
color BLACK = color(0, 0, 0);
color WHITE = color(255, 255, 255);
color GREEN = color(0, 255, 0);
color ORANGE = color(247, 168, 7);
PFont font;
PImage[] scenes = new PImage[6];
// **** Up/Down Buttons init, min, max values **** //
final int _initValue = 2;
final int _maxValue = 5;
final int _minValue = 0;
int stepperValue = 0;
Button _up;
Button _dwn;
Button _quit;
final int _displayX = 160;
final int _displayY = 30;
final int _displayW = 100;
final int _displayH = 24;
final int _txtSize = 18;
void stepperValueDisplay(int value) {
fill(WHITE); // background color
noStroke();
rect(_displayX, _displayY, _displayW, _displayH, 0);
fill(BLACK); // text color
textSize(_txtSize);
textAlign(CENTER);
String str = String.format("Scene %d", value);
text(str, _displayX, _displayY, _displayW, _displayH);
}
void scene_0(){
background(RED);
save("scene0.png");
}
void scene_1(){
background(GREEN);
save("scene1.png");
}
void scene_2(){
background(BLACK);
save("scene2.png");
}
void scene_3(){
background(YELLOW);
save("scene3.png");
}
void scene_4(){
background(LTGRAY);
save("scene4.png");
}
void scene_5(){
background(ORANGE);
save("scene5.png");
}
void setup() {
size(600, 600);
background(BLUE);
font = createFont("Menlo-Bold", 20);
_dwn = new Button( _displayX - 40, _displayY, 40, 24, "--", LTGRAY, BLACK);
_up = new Button( _displayX + _displayW, _displayY, 40, 24, "++", LTGRAY, BLACK);
stepperValue = _initValue;
_quit = new Button(width - 60, 20, 30, 24, "Q", LTGRAY, BLACK);
scene_0();
scene_1();
scene_2();
scene_3();
scene_4();
scene_5();
scenes[0] = loadImage("scene0.png");
scenes[1] = loadImage("scene1.png");
scenes[2] = loadImage("scene2.png");
scenes[3] = loadImage("scene3.png");
scenes[4] = loadImage("scene4.png");
scenes[5] = loadImage("scene5.png");
}
void draw() {
background(scenes[stepperValue]);
_up.display();
_dwn.display();
_quit.display();
stepperValueDisplay(stepperValue);
}
void mousePressed() {
if (mouseX > _quit.x && mouseX < _quit.x + _quit.w && mouseY > _quit.y && mouseY < _quit.y + _quit.h) {
exit();
}
if (mouseX > _up.x && mouseX < _up.x + _up.w && mouseY > _up.y && mouseY < _up.y + _up.h) {
stepperValue++;
if (stepperValue > _maxValue) {
stepperValue = _maxValue;
}
stepperValueDisplay(stepperValue);
}
if (mouseX > _dwn.x && mouseX < _dwn.x + _dwn.w && mouseY > _dwn.y && mouseY < _dwn.y + _dwn.h) {
stepperValue--;
if (stepperValue < _minValue) {
stepperValue = _minValue;
}
stepperValueDisplay(stepperValue);
}
}
Button Class:
int _btnTxtSize = 18;
class Button {
float x, y, w, h;
String title;
color bkgrndColor;
color txtColor;
// Constructor
Button(int xpos, int ypos, float wt, float ht, String titleStr, color background, color textColor) {
x = xpos;
y = ypos;
w = wt;
h = ht;
title = titleStr;
bkgrndColor = background;
txtColor = textColor;
}
void display(){
fill(bkgrndColor);
noStroke();
rect( x, y, w, h, 0);
fill(txtColor);
textSize(_btnTxtSize);
textAlign(CENTER);
text(title, x, y, w, h);
}
}
I would like to implement some kind of eraser,so in my render method I make the upper layer transparent.
#Override
public void render () {
cam.update();
Gdx.gl.glClearColor(1, 1, 1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isTouched()) {
pos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
pixmap.setColor(new Color(1, 1, 1, 0.5f)); //transparency
pixmap.fillCircle((int)pos.x, (int)pos.y, 10);
}
texture3.draw(pixmap, 0, 0);
batch.begin();
batch.draw(texture, 0, 0);
batch.draw(texture3, 0, 0);
batch.end();
}
But I got points when make swipes. It requires to do very slow speed to make lines instead of dots.
So I expect continuous line instead of dots.
Can you advice something please?
Dots instead of line
This is caused because of the frequency at which the input state is updated, the solution here would be to manually calculate the missing points needed to make a line, you could do this with a linear interpolation between each pair of dots, additionally you could calculate how many extra dots are necessary depending on how far is the newest dot from the previous one, in my example I use an arbitrary number of extra dots (20) like so:
public class TestDraw extends Game {
private Pixmap pixmap;
private Texture texture;
private SpriteBatch batch;
private Vector2 lastPos;
#Override
public void create() {
pixmap = new Pixmap(1000, 1000, Pixmap.Format.RGBA8888);
texture = new Texture(pixmap);
batch = new SpriteBatch();
lastPos = new Vector2();
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isTouched()) {
pixmap.setColor(new Color(1, 1, 1, 0.5f)); //transparency
int newX = Gdx.input.getX();
int newY = Gdx.input.getY();
pixmap.setColor(Color.RED);
pixmap.fillCircle(newX, newY, 10);
// If the distance is too far, fill with extra dots
if (lastPos.dst(newX, newY) > 10) { // Here far is 10, you can adjust as needed
int extraDots = 20; // How many extra dots to draw a line, I use 20, adjust as needed or calculate according to distance (for example lastPos.dst(newX,newY) * 5)
for (int i = 0; i < extraDots; i++) {
float progress = (1f / extraDots) * i;
int dotX = (int) MathUtils.lerp(lastPos.x, newX, progress);
int dotY = (int) MathUtils.lerp(lastPos.y, newY, progress);
pixmap.setColor(Color.BLUE);
pixmap.fillCircle(dotX, dotY, 10);
}
}
// Store last position for next render() call
lastPos.set(newX, newY);
}
texture.draw(pixmap, 0, 0);
batch.begin();
batch.draw(texture, 0, 0);
batch.end();
}
}
Adecuate to your code as needed, I didn't know what was texture3 so I didn't include in my example
Also another option which I don't like too much because of rendering and storage cost is using a Polygon to draw the lines.
I'm coding in Processing for the first time (previously familiar with Java) and I'm trying to make a grid of triangles where when I click one, it changes the fill and stroke to a different color. The fill is changing but the stroke remains the default color. Here is my code:
void setup() {
size(800, 600); // size of canvas
triangles = new ArrayList<TriangleClass>(); // Create an empty ArrayList
int L = 50; // length of triangle side
double halfStep = L * Math.sqrt(3);
// all the code about making the grid
}
void draw() {
background(0);
TriangleClass myCurrentTriangle;
for (int i = 0; i < triangles.size(); i++) {
// get object from ArrayList
myCurrentTriangle = triangles.get(i);
myCurrentTriangle.display();
}
}
void mouseClicked () {
TriangleClass myCurrentTriangle ;
for (int i=0; i < triangles.size(); i++) {
// get object from ArrayList
myCurrentTriangle = triangles.get(i);
myCurrentTriangle.mouseOver();
}
}
class TriangleClass {
double x1, y1, x2, y2, x3, y3; // points
color fill; // fill color
color stroke; // stroke color
float mouseSensorX, mouseSensorY;// check point for dist to mouse
// constructor
TriangleClass(
// ...
stroke = color(174, 208, 234);
fill = color(249, 249, 249);
mouseSensorX = (float) (x1+x2+x3 )/ 3;
mouseSensorY = (float) (y1+y2+y3 )/ 3;
}
void mouseOver() {
if (dist(mouseX, mouseY, mouseSensorX, mouseSensorY) < 17) {
if (fill == color(249, 249, 249)) {
stroke = color(251, 84, 84);
fill = color(251,84,84);
// ... repeated for other colors
}
}
void display() {
// show triangle
stroke(stroke);
fill(fill);
triangle((float) x1, (float) y1, (float) x2, (float) y2, (float) x3, (float) y3);
}
}
// =====================================================================
I believe the problem is the stroke weight. All you need to do it have this line of code at the end of your setup function:
strokeWeight(3);
The larger the number, the larger the outline.
I am using processing-3.2.2 for audio visualization. I have the code to play the visualiser but I don't know how to save it as a video(.mp4) file.
Here's what I wrote:
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioPlayer player;
AudioMetaData meta;
BeatDetect beat;
int r = 200;
float rad = 70;
void setup()
{
size(500, 500);
//size(600, 400);
minim = new Minim(this);
player = minim.loadFile("son_final.mp3");
meta = player.getMetaData();
beat = new BeatDetect();
player.play();
//player.play();
background(-1);
noCursor();
}
void draw()
{
float t = map(mouseX, 0, width, 0, 1);
beat.detect(player.mix);
fill(#1A1F18,50);
noStroke();
rect(0, 0, width, height);
translate(width/2, height/2);
noFill();
fill(-2, 10);
if (beat.isOnset()) rad = rad*0.9;
else rad = 70;
ellipse(0, 0, 2*rad, 2*rad);
stroke(-1, 50);
int bsize = player.bufferSize();
for (int i = 0; i < bsize - 1; i+=5)
{
float x = (r)*cos(i*2*PI/bsize);
float y = (r)*sin(i*2*PI/bsize);
float x2 = (r + player.left.get(i)*100)*cos(i*2*PI/bsize);
float y2 = (r + player.left.get(i)*100)*sin(i*2*PI/bsize);
line(x, y, x2, y2);
}
beginShape();
noFill();
stroke(-1, 50);
for (int i = 0; i < bsize; i+=30)
{
float x2 = (r + player.left.get(i)*100)*cos(i*2*PI/bsize);
float y2 = (r + player.left.get(i)*100)*sin(i*2*PI/bsize);
vertex(x2, y2);
pushStyle();
stroke(-5);
strokeWeight(2);
point(x2, y2);
popStyle();
}
endShape();
if (flag) showMeta();
}
void showMeta() {
int time = meta.length();
textSize(50);
textAlign(CENTER);
text( (int)(time/1000-millis()/1000)/60 + ":"+ (time/1000-millis()/1000)%60, -7, 21);
}
boolean flag =false;
void mousePressed() {
if (dist(mouseX, mouseY, width/2, height/2)<150) flag =!flag;
}
void keyPressed() {
if(key=='e')exit();
}
I know I can import MovieMaker library but I don't know how to use it in this code. Please suggest some changes.
Thank you.
You can use the Video Export library for that. More info here: http://funprogramming.org/VideoExport-for-Processing/
Then all you'd do is create an instance of VideoExport and then call videoExport.saveFrame() at the end of your draw() function.
import com.hamoid.*;
VideoExport videoExport;
void setup() {
size(600, 600);
videoExport = new VideoExport(this, "basic.mp4");
}
void draw() {
background(#224488);
rect(frameCount * frameCount % width, 0, 40, height);
videoExport.saveFrame();
}
There are a ton of resources online. I recommend googling "Processing video export" for a ton of results. Then try something out and post an MCVE (not your entire project) showing exactly where you're stuck.
I would like to dynamically set the stroke-width of an SVG curve from within a ProcessingJS sketch.
So far, the only solution that I have found is to use disableStyle() on the SVG shape and then manually set all of the style attributes like Fill(), stroke(), strokeJoin() and strokeWeight(). However, the opacity of the line seems to render differently when executed this way.
Is there some way to access and modify only the stroke-width and leave the other styles unchanged?
Here is the code that I have so far. It seems to work okay, but it would be nice not to have to manually reset all the style attributes that were in the original svg file.
/* #pjs preload="frog_trajs.svg"; */
PShape trajs;
float zoom_factor = 1.0;
float imgW;
float ingH;
float lineWeight = 1.00;
//panning variables
float centerX;
float centerY;
boolean active = false;
PFont f;
void setup()
{
size(900, 600);
frameRate(20);
centerX = width/2;
centerY = height/2;
trajs = loadShape("frog_trajs.svg");
trajs.disableStyle();
imgW = trajs.width;
imgH = trajs.height;
}
void draw()
{
background(255);
//here, the styles are reset, with lineWeight dynamically updated by mouseScrolled()
shapeMode(CENTER);
strokeJoin(ROUND);
strokeWeight(lineWeight);
stroke(#EF25B2,170);
noFill();
shape(trajs,centerX,centerY,imgW,imgH);
}
void mouseScrolled()
{
if(active){
if(mouseScroll > 0)
{
//zoom out;
zoom_factor = 1 - mouseScroll*0.01;
}
else
{
//zoom in;
zoom_factor = 1 - mouseScroll*0.01;
}
lineWeight = lineWeight/zoom_factor;
}
}
void mouseOver(){
active = true;
}
void mouseOut(){
active = false;
}