Im using de DDA (Digital Diferential Analizer) to make a line, and thought I know maybe using de DrawLine the way I am, just run along with it. Im trying to make different types of lines like dashed or dotted, etc. Im thinking in makeing the for from below jump some numbers to make a dotted line. But I cant still find a way todo it. This is what I have so far:
public void paint(Graphics g) {
super.paint(g);
int dot=0;
int x1 = pointStart.x;
int x2 = pointEnd.x;
int y1 = pointStart.y;
int y2 = pointEnd.y;
float dx, dy, m, y, x;
if (x1>x2){
int ax = x2;
int ay = y2;
x2 = x1;
x1 = ax;
y2 = y1;
y1 = ay;
}
dx = x2 - x1;
dy = y2 - y1;
m = dy/dx;
if (m>=-1&&m<=1){
dot = (int)dx/4;
y = y1;
System.out.println(m);
for (x = x1 ; x <= x2;x++){
//if (x>=dot&&x<=dot+10||x>=dot*2&&x<=dot*2+10||x>=dot*3&&x<=dot*3+10){
g.drawLine((int)x, (int)Math.round(y), (int)x, (int)Math.round(y));
y+=m;
//}
}
}
else{
x = x1;
System.out.println(m);
for (y = y1 ; y <= y2;y++){
g.drawLine((int)Math.round(x), (int)y, (int)Math.round(x), (int)y);
x+=1/m;
}
}
/*if (pointStart != null) {
if (x1>)
g.setColor(Color.RED);
//g.drawLine(pointStart.x, pointStart.y, pointEnd.x, pointEnd.y);
g.drawLine(x1, y1, x1, y1);
}*/
}
Any ideas?
you need draw line function (in your case g.drawline(x0,y0,x1,y1); ).
dont care about color (you can play with it later)
you need definition of your pattern (size of lines and spaces in pixels)
for example int pattern[]={10,-5,0} (10px line, then 5px space, 0 means repeat from beginning) ... -values are spaces + values are lines
you need 'global' state (actual index in pattern and actual pixel length drawed) also you can have global pattern pointer or encapsulate all in class/struct.
ok so the basic idea is to segmentate any line to selected pattern for example like this:
//---------------------------------------------------------------------------
// pattern draw state
int _pattern_ix=0; // actual index in pattern need to reset it to zero before any pattern change
double _pattern_l=0; // already drawed or skipped pixels from actual pattern[_pattern_ix]
// predefined patterns
int _pattern_dash_dash[]={ 10,-10, 0 };
int _pattern_dash_dot[] ={ 10,- 5, 1,- 5,0 };
int _pattern_dot_dot[] ={ 1,- 5, 0 };
//---------------------------------------------------------------------------
// draw line function
void drawline(int x0,int y0,int x1,int y1)
{
// this is just borland GDI access to draw line function
Form1->Canvas->MoveTo(x0,y0);
Form1->Canvas->LineTo(x1,y1);
}
//---------------------------------------------------------------------------
void pattern_line(int x0,int y0,int x1,int y1,int *pattern)
{
int p;
double x,y,xx,yy,dx,dy,dl,t,dt;
dx=x1-x0;
dy=y1-y0;
dl=sqrt((dx*dx)+(dy*dy));
dx/=dl; dy/=dl;
for (t=0.0,dt=0.0;dl>=0.5;)
{
p=pattern[_pattern_ix];
if (p<0) // skip
{
dt=-p-_pattern_l; // t=space to skip [px]
if (dt>dl) { _pattern_l+=dl; return; } // space is bigger then rest of line
dl-=dt; t+=dt; _pattern_l=0.0; // update line params and continue to next pattern entry
}
else // draw
{
dt=+p-_pattern_l; // t=space to draw [px]
x=x0+double(t*dx); // actual point pos
y=y0+double(t*dy); // space is bigger then rest of line
if (dt>dl) { _pattern_l+=dl; drawline(x,y,x1,y1); return; }
dl-=dt; t+=dt; _pattern_l=0.0; // update line params
xx=x0+double(t*dx); // actual point pos
yy=y0+double(t*dy);
drawline(x,y,xx,yy); // draw line and continue to next pattern entry
}
_pattern_ix++;
if (!pattern[_pattern_ix]) _pattern_ix=0;
}
}
//---------------------------------------------------------------------------
void main()
{
// borland GDI clear screen and color settings
Canvas->Brush->Color=clBlack;
Canvas->Pen->Color=clWhite;
Canvas->FillRect(ClientRect);
// draw dash-dot-ed rectangle
int x0,x1,y0,y1;
x0=30; x1=200;
y0=30; y1=100;
pattern_line(x0,y0,x1,y0,_pattern_dash_dot);
pattern_line(x1,y0,x1,y1,_pattern_dash_dot);
pattern_line(x1,y1,x0,y1,_pattern_dash_dot);
pattern_line(x0,y1,x0,y0,_pattern_dash_dot);
}
//---------------------------------------------------------------------------
and do not forget to reset pattern ix,l to zero before any pattern style change.
Code is not optimized so its pretty slow but simple enough to understand i hope.
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);
}
}
}
Im trying to create a slope in java. I can use the DrawLine function and it'll create a perfect one but I dont want to use that but rather create my own function for it. The problem is that it has gaps between the dots.
import java.applet.Applet;
import java.awt.Graphics;
public class slope extends Applet{
public void drawLine(int x1, int y1, int x2, int y2, Graphics g) {
double m = (y2 - y1) / (double)(x2-x1);
double y = y1;
for (int x =x1; x < x2; x++) {
drawPoint(x,(int)y,g);
y +=m;
}
}
public void paint(Graphics g) {
drawLine(20, 10, 300, 700, g); //has spaces between the dots
g.drawLine(20, 10, 300, 700); //this is perfect
}
private void drawPoint(int x, int y, Graphics g) {
g.drawLine(x, y, x, y);
}
}
Two loops: you loop over x++ only when deltaX > deltaY.
else you loop over y++ only.
Dual stepping x and y in the same loop, deciding which should be incremented (assuming you have x as a function of y too) could lead to slower drawing due to extra tests and adjacent pixels may look like a dot in the line. You'd need to play with color intensity to do antialiasing by hand (gold plating). Two loops is much simpler.
fyi, you are trying to generate an image, you could also just set ints in a matrix and make an offscreen raw image (BufferedImage and it's .setRGB() method), which you draw later. That would likely be faster and avoid visible painting delays.
Generally this is done by using an algorithm that doesn't step only along the x or y axis, but adjust the update increment by a variable amount, such that each dot is at most sqrt(2) away from each other.
So, if you think you have a point at the x value, but when you calculate it, you find that it is 3.5 pixels away (because the slope is very steep), you fall into a routine that calculates (typically recursively) an intermediate pixel between that x step
(x, y)
(0, 0) to (1, 5) distance 5.09
-> fill routine
(0, 0) to (0.5, 2.5) distance 2.69
-> fill routine
(0, 0) to (0.25, 1.25) distance 1.34 < 1.41
(0.25, 1.25) to (0.5, 2.5) distance 1.34 < 1.41
(0.5, 2.5) to (0.75, 3.75) distance 1.34 < 1.41
(0.75, 3.75) to (1, 5) distance 1.34 < 1.41
(1, 5) to (2, 10) etc...
The reason one uses 1.41 (sqrt(2)) as the maximum distance allowed is because a of pixels at a 45 degree angle from the bottom of the screen would still appear connected.
Now, in your plotting, you'll need to round the values to align to the exact pixels. There are a number of ways to do this. The simplest is just to round to the next valid value, and this works most of the time. It does have one unfortunate side effect, that is your line will appear to have jagged steps (where the rounding is moving the pixel more, the step will appear more jagged). This jaggedness is called "aliasing" as the true point is presenting through a non-true representation of the point (the alias).
A second approach is to alternatively darken both pixels proportionally, based on how close the point is. A point that is at (0.5) on the x axis would darken both pixels by 50% while a point that is at (0.25) would darken the 0 pixel by 75% and the 1 pixel by 25%. This is anti-aliasing, and may result in a line that is slightly more fuzzy, but appears to be straighter. This fuzziness can be somewhat combated by drawing a thicker line.
I hope this gives you some idea of the math behind many of the higher quality drawing routines, and certainly there are approaches that are even more sophisticated than the one I just presented.
Based on the Bresenham Algorithm, here is a java implementation that
assumes x2 > x1 and y2 > y1 and uses integer arithmetic
import java.applet.Applet;
import java.awt.*;
public class Slope extends Applet{
private int x1 = 20, y1 = 10;
private int x2 = 300, y2 = 700;
#Override
public void paint(Graphics g) {
drawLine(x1, y1, x2, y2, g);
//g.drawLine(x1, y1, x2, y2, g);
}
private void drawPoint(int x, int y, Graphics g) {
g.drawLine(x,y,x,y);
}
#Override
public void init(){
this.setSize(500,700);
}
private void drawLine(int x1,int y1,int x2,int y2,Graphics g){
int dx = x2 - x1;
int dy = y2 - y1;
int xi = 1;
int D = 2*dx - dy;
int x = x1;
for(int y = y1; y <y2; y++) {
drawPoint(x,y,g);
if(D > 0) {
x = x + xi;
D = D - 2 * dy;
}
D = D + 2 * dx;
}
}
}
I just need to get this code working. I know it's not good form or very efficient but I just need it to draw the Sierpinski's Triangle, recursively. It reaches the first recursive call, but never gets past it and only draws part of the triangle. I know I'm being stupid and the answer will be obvious but I haven't coded in a long time. Thank you for any help!
import javax.swing.*;
import java.awt.*;
public class recursiveTriangle18 extends JApplet
{
private final int APPLET_WIDTH = 800;
private final int APPLET_HEIGHT = 800;
/*
//x is accross and y is down
point 1 - Right A x[0],y[0] (720,600)
point 2 - Left B x[1],y[1]
point 3 - Top C x[2],y[2]
point 4 draws back to point 1 to complete triangle
*/ private int[] xPos = {720, 80, 400, 720};
private int[] yPos = {600, 600, 40, 600};
//-----------------------------------------------------------------
// Sets up the basic applet environment.
//-----------------------------------------------------------------
public void init()
{
setBackground (Color.white);
setSize (APPLET_WIDTH, APPLET_HEIGHT);
}
//-----------------------------------------------------------------
// Draws a rocket using polygons and polylines.
//-----------------------------------------------------------------
public void paint (Graphics page)
{
page.setColor (Color.BLUE);
page.drawPolyline (xPos, yPos, xPos.length);
Triangle(xPos,yPos, 0, page);
}//end of paint
public void Triangle(int[] xPos, int[] yPos, int flag, Graphics page)
{
//Find the distance between 2 points ex. - x,y & x1,y1
int x = xPos[0];
int x1 = xPos[1];
int x2 = xPos[2];
int x3 = xPos[3];
int y = yPos[0];
int y1 = yPos[1];
int y2 = yPos[2];
int y3 = yPos[3];
double dist = Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1));
//find the mid points of each line segment
while (dist >= 100){
int midpointx = ((x+x1)/2);
int midpointy = ((y+y1)/2);
int midpointx1 = ((x1+x2)/2);
int midpointy1 = ((y1+y2)/2);
int midpointx2 = ((x2+x3)/2);
int midpointy2 = ((y2+y3)/2);
//make the x and y array (3 points + first point to finish triangle)
//create x,y Array using the midpoints you calculated
int [] xpoints = {midpointx2, midpointx, midpointx2};
int [] ypoints = {midpointy2,y, midpointy, midpointy2};
int [] xpoints1 = {midpointx, midpointx1, x1, midpointx};
int [] ypoints1 = {midpointy, midpointy1, y1, midpointy};
int [] xpoints2 = {midpointx1, midpointx2,x2,midpointx1};
int [] ypoints2 = {midpointy1, midpointy2,y2,midpointy1};
page.drawPolyline(xpoints1, ypoints1, xpoints1.length);
page.drawPolyline(xpoints2, ypoints2, xpoints2.length);
page.drawPolyline(xpoints, ypoints, xpoints.length);
//if the segment/distance is 300 or so, good length to stop
// Recursive calls for each section of triangle
Triangle(xpoints, ypoints, flag, page);
Triangle(xpoints2, ypoints2, flag, page); // how to get here?
Triangle(xpoints1, ypoints1, flag, page);
}
}
//end of Triangle
}
Triangle(xpoints, ypoints, flag, page);
Triangle(xpoints2, ypoints2, flag, page); // how to get here?
Every Triangle call is making another call to Triangle, so it's an infinite recursion that never returns. You need an if (stop condition) block around the recursive calls to tell it when to stop recursing.
There's also another issue:
double dist = Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1));
//find the mid points of each line segment
while (dist >= 100){
You never update the value of dist, so this is an infinite loop.
I looked up how to draw a star in Java, and I found the following code:
public void paint(Graphics g) {
drawStar(g,Color.BLACK,5,300,300,100,1…
drawStar(g,Color.RED,6,100,100,20,20);
drawStar(g,Color.BLUE,9,200,400,40,40)…
drawStar(g,Color.YELLOW,27,400,200,10,…
drawStar(g,Color.GREEN,400,300,300,250…
}
public double circleX(int sides, int angle) {
double coeff = (double)angle/(double)sides;
return Math.cos(2*coeff*Math.PI-halfPI);
}
public double circleY(int sides, int angle) {
double coeff = (double)angle/(double)sides;
return Math.sin(2*coeff*Math.PI-halfPI);
}
public void drawStar(Graphics g, Color c, int sides, int x, int y, int w, int h) {
Color colorSave = g.getColor();
g.setColor(c);
for(int i = 0; i < sides; i++) {
int x1 = (int)(circleX(sides,i) * (double)(w)) + x;
int y1 = (int)(circleY(sides,i) * (double)(h)) + y;
int x2 = (int)(circleX(sides,(i+2)%sides) * (double)(w)) + x;
int y2 = (int)(circleY(sides,(i+2)%sides) * (double)(h)) + y;
g.drawLine(x1,y1,x2,y2);
}
}
}
halfPI is defined as a private static variable outside the body
I don't quite get the logic behind these methods. Could someone offer an explanation?
You can follow the graphics object carefully line by line and see what happens to it. It looks like the writer's algorithm uses sine and cosine the evenly split the circle at the same sized angles depending on the number of sides. Then for each side, it draws the line. It is a good beginner program to test and make it work and don't worry if you can't make the basic math work, those are just rather easy trigonometric expressions depending on the arguments that are passed to the drawing method and the helper methods.
I'm making my first game using Java on Android. I need to draw a lot of pixels which together should create a line. My first approach was to make a large array of booleans, create a loop, and draw a pixel when the associated boolean was true.
It wasn't a good idea of course (the array is about 200x300). Now I remember only the position of the first pixel of the line, and every next pixel has to remember his follower. It works pretty well, but when the line gets longer (but still not very long), the efficiency is bad (<20 fps after 4000 frames).
This is the function that I use to draw a line (only one for now). Can anybody help me improve its efficiency?
public void drawLine(Canvas canvas, int beginx, int beginy) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
int x = beginx;
int y = beginy;
while(C.mGrid[x][y].nx != -1) {
//canvas.drawLine(x, y, C.mGrid[x][y].nx, C.mGrid[x][y].ny, paint);
canvas.drawPoint(x, y, paint);
Grid temp = C.mGrid[x][y];
if ((C.mGrid[x][y].nx == x) && (C.mGrid[x][y].ny == y)) break;
x = temp.nx;
y = temp.ny;
}
}
and Grid.java:
package com.qwak.achtung;
public float x = 0,y = 0;
public int px = -1, py = -1, nx = -1, ny = -1;
public Grid(float x, float y) {
this.x = x;
this.y = y;
}
public void set(int px, int py, int nx, int ny) {
this.px = px;
this.py = py;
this.nx = nx;
this.ny = ny;
}
public void setp(int px, int py) {
this.px = px;
this.py = py;
}
public void setn(int nx, int ny) {
this.nx = nx;
this.ny = ny;
}
PS: It looks like this http://c.wrzuta.pl/wi10559/11f7d10b00110e504e25ebd3/0/andek 14 is fps (on my phone (samsung Spica) it run better - 40 but after a while it decreases to 20 and even less) and 983 is number of frames at all.
There is a drawLine method in the canvas object.
Use the example here: How to draw a line in android
canvas.drawLine(0, 0, 20, 20, paint);
If you want to draw a curve. Find the function of the curve. A Parabola for example is x=y^2. You can get points from the curve: 1 = 1, 2 = 4, 3 = 9, 4 = 16... etc.. If your drawing pixel by pixel you can plug in your x and get your y and draw it.
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
for(int i = beginx; i < CanvasWidth; i++)
{
int x = i;
int y = i * i; //x=y^2
canvas.drawPoint(x, y, paint);
}
To keep a record of points that were visited you could do the following:
class Point
{
int x;
int y;
}
List<Point> points = new List<Point>();
onMove(int newX, int newY)
{
Point p = new Point();
p.x = newX;
p.y = newY;
points.add(p);
}
onDraw()
{
for(Point p : points)
{
canvas.drawPoint(p.x, p.y, paint);
}
}
You want to look into the bresenham algorithm. A bresenham algorithm is a method to draw or rasterize a line. It's a bit different from the subdivision of a grid in a certain angle for example a morton-curve. It's a bit like compute the scalar product for every angle like recall here Traversing a 2D array in an angle.