I want to draw a circle (with 1 or 2 for loops) using pixels position (starts from top left and ends at bottom right)
I successfully drew a rectangle with this method:
private void drawrect(int width,int height,int x,int y) {
int top=y;
int left=x;
if(top<0){
height+=top;
top=0;
}
if(left<0){
width+=left;
left=0;
}
for (int j = 0; j <width; j++) {
for (int i = 0; i <height; i++) {
pixels[((i+top)*w)+j+left] = 0xffffff;//white color
}
}
}
The pixels array contains the pixel index followed by it's color.
pixels[index]=color;
Before that I use this code for "image" and "pixels" array (if this helps you)
img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
But how can I draw only the white pixels like in this image and ignore the other pixels?
Here is the code for drawing circle with pixels: It uses the formula xend = x + r cos(angle) and yend = y + r sin(angle).
#include <stdio.h>
#include <graphics.h>
#include <stdlib.h>
#include <conio.h>
#include <bios.h>
#include <math.h>
void DrawCircle(int x, int y, int r, int color)
{
static const double PI = 3.1415926535;
double i, angle, x1, y1;
for(i = 0; i < 360; i += 0.1)
{
angle = i;
x1 = r * cos(angle * PI / 180);
y1 = r * sin(angle * PI / 180);
putpixel(x + x1, y + y1, color);
}
}
Reference: http://www.softwareandfinance.com/Turbo_C/DrawCircle.html
You can calculate the minimum angle between two pixels and improve the Kathir solution
...
void DrawCircle(int x, int y, int r, int color)
{
static const double PI = 3.1415926535;
double x1, y1;
// calculates the minimun angle between two pixels in a diagonal.
// you can multiply minAngle by a security factor like 0.9 just to be sure you wont have empty pixels in the circle
double minAngle = acos(1 - 1/r);
for(double angle = 0; angle <= 360; angle += minAngle)
{
x1 = r * cos(angle);
y1 = r * sin(angle);
putpixel(x + x1, y + y1, color);
}
}
Since you already have a BufferedImage, why not create a graphics object for it and use that to draw the circle? That way you don't have to reinvent the wheel:
BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.setColor(Color.WHITE);
g.fillOval(x, y, width, height);
Update
Here is a SSCCE:
public class DrawCircleExample extends Canvas {
private static final int WIDTH = 32;
private static final int HEIGHT = 32;
public static void main(String[] args) {
JFrame f = new JFrame("Draw circle example");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new DrawCircleExample());
f.pack();
f.setVisible(true);
}
private final BufferedImage img;
public DrawCircleExample() {
img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = img.createGraphics();
g.setColor(Color.WHITE);
g.fillOval(8, 8, 14, 14);
}
#Override
public void paint(Graphics g) {
g.drawImage(img, 0, 0, null);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(),img.getHeight());
}
}
It should produce an image like this:
One way to do this would be to test, for each point in the rectangle, whether or not the distance from that pixel to the center of the square is less than the intended radius of the circle. You could then draw the pixels that pass the test and skip the pixels that don't. The ratio of the area of the circle to the area of the total square is π/4, which is about .77, so this actually isn't all that inefficient.
If you want to draw an arbitrary oval that fits in the rectangle, you can use this same idea, but would modify the computation that would determine the distance to the center such that you give proportionally less weight to the long axis of the ellipse.
Hope this helps!
Sorry for the delay
This code works perfectly
private void drawcircle(int x,int y,int radius){
for(int i=x;i<radius*2;i++)
for(int j=x;j<radius*2;j++){
int d= (int) Math.sqrt((i-radius)*(i-radius)+(j-radius)*(j-radius));
if(d<radius)
pixels[i+j*WIDTH]=346346;
}
}
Related
My partner and I are trying to remake Tetris for our final project of the year in my Computer Science class we currently have a for loop that draws individual rectangles in an overwritten paint method.
private final int spacer = 30;
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
for(int i = getHeight()/2 - (spacer * 10); i < getHeight()/2 + (spacer * 10); i += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += (spacer)) {
g.drawRect(x, i, (spacer), (spacer));
}
}
setForeground(Color.black);
}
The method basically takes the width and height of the window and makes a 10 x 20 grid of boxes that are 30 units, pixels I think, wide.
We'd like to make a Grid.java class that takes in color, the spacer int, and an x and y int. The constructor for Grid.java should draw the exact same thing as the code above using the for loop, but when we tried it gave us a white screen that would not resize with the window.
private final int spacer = 30;
private static Grid[][] arr = new Grid[10][20];
public int getSpacer()
{
return spacer;
}
public void paint(Graphics g) {
setBackground(Color.GRAY);
int countY = 0;
int countX = 0;
for(int y = getHeight()/2 - (spacer * 10); y < getHeight()/2 + (spacer * 10); y += spacer) {
for(int x = getWidth()/2 - (spacer * 5); x < getWidth()/2 + (spacer * 5); x += spacer) {
arr[countX][countY] = new Grid(x, y, spacer, g);
countX++;
}
countY++;
}
setForeground(Color.black);
}
*Grid.java Class*
package Tetris_Shapes;
import javax.swing.*;
import java.awt.*;
public class Grid {
private int x;
private int y;
private int side;
private Graphics g;
public Grid(int x, int y, int side, Graphics g) {
// g.drawRect(x, y, spacer, spacer);
this.x = x;
this.y = y;
this.side = side;
this.g = g;
paint(this.g);
}
private void paint(Graphics g) {
g.drawRect(x, y, side, side);
}
}
When we try and run this we get the white box that doesn't resize. My question is does anyone know of a way to get a constructor to draw shapes. Thank you in advance, this is pretty niche so I'm also going to apologize in advance.
Is there any way to bend a BufferedImage in Java?
I thought that if I crop the image into smaller pieces and rotate them then I would essentially bend the image, but it doesn't seem to work.
Here is the method I created:
/**
* This is a recursive method that will accept an image the point where the bending will start and the point where the bending will end, as well as the angle of bending
*
* #param original:the original image
* #param startingPoint: the point where the bending should start
* #param endingPoint: the point where the bending should end
* #param radiands: the angle
* #return the bent image
*/
public static BufferedImage getBentImage(BufferedImage original, int startingPoint, int endingPoint, double radians) {
if (startingPoint >= endingPoint)
return original;
int type = BufferedImage.TYPE_INT_ARGB;
int width = original.getWidth();
int height = original.getHeight();
BufferedImage crop = original.getSubimage(0, 0, startingPoint, height);
BufferedImage crop0 = original.getSubimage(startingPoint, 0, width - startingPoint, height);
BufferedImage bendCrop = new BufferedImage(width, height, type);
BufferedImage image = new BufferedImage(width, height, type);
AffineTransform rotation = new AffineTransform();
rotation.translate(0, 0);
rotation.rotate(radians);
Graphics2D g = bendCrop.createGraphics();
g.drawImage(crop0, rotation, null);
g.dispose();
g = image.createGraphics();
g.drawImage(crop, 0, 0, null);
g.drawImage(bendCrop, startingPoint, 0, null);
g.dispose();
return getBentImage(image, startingPoint + 1, endingPoint, radians);
}
This is the original Image:
And this is the result of this getBentImage(image, 200, 220, Math.toRadians(1)):
I was expecting something closer to:
Any ideas on how to actually implement a getBentImage() method?
As suggested in the comments, a simple approach is to divide the image into 3 parts:
Identical to the original.
Bent according to the bending transformation.
Constant diagonal continuation.
Here is a quick and a bit messy example that shows the original shape and the resulting shape below it. I just used a label icon for the images instead of doing custom painting. (Also I didn't adhere to the Java naming conventions with final variables because it's math and not typical coding.)
Since there are quite a few variables in the calculation code, I added a sketch at the end that shows what the variables represent.
public class Main extends JFrame {
static BufferedImage image;
public static void main(String[] args) {
try {
image = ImageIO.read(ClassLoader.getSystemResource("img.png"));
} catch (IOException e) {
e.printStackTrace();
}
new Main();
}
public Main() {
getContentPane().setLayout(new BorderLayout(5, 10));
BufferedImage img2 = transform(15, 100, 300);
JLabel label1 = new JLabel(new ImageIcon(image));
label1.setHorizontalAlignment(JLabel.LEFT);
label1.setOpaque(true);
label1.setBackground(Color.YELLOW);
add(label1, BorderLayout.NORTH);
JLabel label2 = new JLabel(new ImageIcon(img2));
label2.setHorizontalAlignment(JLabel.LEFT);
label2.setOpaque(true);
label2.setBackground(Color.CYAN);
add(label2);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
static BufferedImage transform(int t, int x1, int x2) {
final double TH = Math.toRadians(t);
final int D = x2 - x1;
final int W = image.getWidth();
final int H = image.getHeight();
final int dD = (int) (D / (2 * TH) * Math.sin(2 * TH));
final int dH = (int) (D / TH * Math.pow(Math.sin(TH), 2));
final int pH = (int) ((W - x2) * Math.tan(2 * TH));
final int width = W - (D - dD);
final int height = (int) (H + dH + pH);
System.out.println(W + " " + H + " -> " + width + " " + height);
BufferedImage img2 = new BufferedImage(width, height, image.getType());
for (int x = 0; x < x1; x++) {
for (int y = 0; y < H; y++) {
int rgb = image.getRGB(x, y);
img2.setRGB(x, y, rgb);
}
}
for (int x = x1; x < x2; x++) {
for (int y = 0; y < H; y++) {
int rgb = image.getRGB(x, y);
int dx = (int) (D / (2 * TH) * Math.sin(2 * (x-x1) * TH / D));
int dy = (int) (D / TH * Math.pow(Math.sin((x-x1) * TH / D), 2));
img2.setRGB(x1 + dx, y + dy, rgb);
}
}
for (int x = x2; x < W; x++) {
for (int y = 0; y < H; y++) {
int rgb = image.getRGB(x, y);
int dp = (int) ((x - x2) * Math.tan(2 * TH));
img2.setRGB(x - (D - dD), y + dH + dp, rgb);
}
}
return img2;
}
}
As for the calculations, I'll leave it for you as homework; it's just geometry/trigonometry which belongs on Math.SE more than on SO. If you can't figure it out I'll give you a direction.
Note that this method might not be fast at all and could certainly be optimized, I'll leave that to you also. Oh, and rounding doubles to ints carelessly, so the result is not pixel-perfect.
I dont know what you mean by bending but essentially you have a rectangle and you break one piece of it and rotate it:
so the algorithm is as follows:
rotate line(x, 0, width-1, 0)
rotate line(x, height-1, width-1, height-1)
connect the pieces
So essentially you are looking for rotate line.
I'm trying to build a User Interface for the RGBike POV:
http://www.instructables.com/id/RGBike-POV-Open-project/
The program will display a bike wheel in form of a grid. The user can click
onto the single squares and changes the colour of these.
I want to build this applet in java. I'm stuck at drawing the wheel in the right way.
I need to have a sort of array of every rectangle, to export the colour later.
The best thing would be to draw a sort of circular table. Drawing each shape
With graphics2D to have each as a single object would be an idea, too. But that would
be around 860 single shapes, little bit too much to update them every time by paint().
Spoke POV has done such a user Interface for their project already:
http://www.ladyada.net/make/spokepov/software.html
But only their old python script is open source.
Be VERY grateful that I have previously generate a "segment" shape in the past ;)
This basically generates each segment individually (does some funky translation into real space) and maintains a cache of shapes which can be checked to see if the mouse falls within there bounds.
This is rather inefficient, but I think you get the idea.
I should also be noted, that I didn't bother with a backing buffer. Not to say it could use one, I just got away without it...
public class TestSpoke {
public static void main(String[] args) {
new TestSpoke();
}
public TestSpoke() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public static final int CIRCLE_COUNT = 16;
public static final int SEGMENT_COUNT = 80;
private Map<Integer, List<Shape>> mapWheel;
private Map<Point, Color> mapColors;
public TestPane() {
mapColors = new HashMap<>(CIRCLE_COUNT * SEGMENT_COUNT);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
Map<Integer, List<Shape>> mapWheel = getWheel();
for (Integer circle : mapWheel.keySet()) {
List<Shape> segments = mapWheel.get(circle);
for (int index = 0; index < segments.size(); index++) {
Shape segment = segments.get(index);
if (segment.contains(e.getPoint())) {
mapColors.put(new Point(circle, index), Color.RED);
repaint();
break;
}
}
}
}
});
}
#Override
public void invalidate() {
mapWheel = null;
super.invalidate();
}
protected float getRadius() {
return Math.min(getWidth(), getHeight());
}
/**
* This builds a wheel (if required) made of segments.
* #return
*/
protected Map<Integer, List<Shape>> getWheel() {
if (mapWheel == null) {
mapWheel = new HashMap<>(CIRCLE_COUNT);
// The current radius
float radius = getRadius();
// The radius of each individual circle...
float circleRadius = radius / CIRCLE_COUNT;
// The range of each segment
float extent = 360f / SEGMENT_COUNT;
for (int circle = 0; circle < CIRCLE_COUNT; circle++) {
float startAngle = 0;
List<Shape> segments = new ArrayList<>(SEGMENT_COUNT);
mapWheel.put(circle, segments);
// Calculate the "translation" to place each segement in the
// center of the screen
float innerRadius = circleRadius * circle;
float x = (getWidth() - innerRadius) / 2;
float y = (getHeight() - innerRadius) / 2;
for (int seg = 0; seg < SEGMENT_COUNT; seg++) {
// Generate a Segment shape
Segment segment = new Segment(circleRadius * circle, circleRadius, startAngle, extent);
startAngle += extent;
// We translate the segment to the screen space
// This will make it faster to paint and check for mouse clicks
PathIterator pi = segment.getPathIterator(AffineTransform.getTranslateInstance(x, y));
Path2D path = new Path2D.Float();
path.append(pi, true);
segments.add(path);
}
}
}
return mapWheel;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Map<Integer, List<Shape>> mapWheel = getWheel();
for (Integer circle : mapWheel.keySet()) {
List<Shape> segments = mapWheel.get(circle);
for (int index = 0; index < segments.size(); index++) {
Shape segment = segments.get(index);
Color color = mapColors.get(new Point(circle, index));
if (color != null) {
g2d.setColor(color);
g2d.fill(segment);
}
g2d.setColor(Color.BLACK);
g2d.draw(segment);
}
}
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public static class Segment extends Path2D.Float {
public Segment(float radius, float thickness, float extent) {
this(radius, thickness, 0f, extent);
}
public Segment(float radius, float thickness, float startAngle, float extent) {
// Basically, we want to draw the outter edge from a to b angle,
// draw the connecting line from the outter to the inner,
// draw the inner from b to a angel and
// draw the connecting line from the inner to out the outter
// We want to span about 30 degrees, with a small gap...
// I want the gap to be a factor of the radius
Arc2D.Float outter = new Arc2D.Float(0, 0, radius, radius, startAngle, extent, Arc2D.OPEN);
Arc2D.Float inner = new Arc2D.Float(thickness / 2f, thickness / 2f, radius - thickness, radius - thickness, startAngle + extent, -extent, Arc2D.OPEN);
append(outter, true);
float angel = startAngle + extent;
Point2D p1 = getPointOnEdge(angel, radius);
Point2D p2 = getPointOnEdge(angel, radius - thickness);
// We need to adjust in for the change in the radius
p2.setLocation(p2.getX() + (thickness / 2f), p2.getY() + (thickness / 2f));
lineTo(p2.getX(), p2.getY());
append(inner, true);
angel = startAngle;
p1 = getPointOnEdge(angel, radius);
p2 = getPointOnEdge(angel, radius - thickness);
p2.setLocation(p2.getX() + (thickness / 2f), p2.getY() + (thickness / 2f));
lineTo(p1.getX(), p1.getY());
closePath();
}
public Point2D getPointOnEdge(float angel, float radius) {
angel -= 90;
float x = radius / 2f;
float y = radius / 2f;
double rads = Math.toRadians((angel + 90));
// This determins the length of tick as calculate from the center of
// the circle. The original code from which this derived allowed
// for a varible length line from the center of the cirlce, we
// actually want the opposite, so we calculate the outter limit first
float fullLength = (radius / 2f);
// Calculate the outter point of the line
float xPosy = (float) (x + Math.cos(rads) * fullLength);
float yPosy = (float) (y - Math.sin(rads) * fullLength);
return new Point2D.Float(xPosy, yPosy);
}
}
}
So far I have a java app where I draw a circle(player) and then draw a green rectangle on top(gun barrel). I have it so when the player moves, the barrel follows with it. I want it to find where the mouse is pointing and then rotate the barrel accordingly. For an example of what I mean look at this video I found http://www.youtube.com/watch?v=8W7WSkQq5SU See how the player image reacts when he moves the mouse around?
Here's an image of what the game looks like so far:
So how do I rotate it like this? Btw I don't like using affinetransform or Graphics2D rotation. I was hoping for a better way. Thanks
Using the Graphics2D rotation method is indeed the easiest way. Here's a simple implementation:
int centerX = width / 2;
int centerY = height / 2;
double angle = Math.atan2(centerY - mouseY, centerX - mouseX) - Math.PI / 2;
((Graphics2D)g).rotate(angle, centerX, centerY);
g.fillRect(...); // draw your rectangle
If you want to remove the rotation when you're done so you can continue drawing normally, use:
Graphics2D g2d = (Graphics2D)g;
AffineTransform transform = g2d.getTransform();
g2d.rotate(angle, centerX, centerY);
g2d.fillRect(...); // draw your rectangle
g2d.setTransform(transform);
It's a good idea to just use Graphics2D anyway for anti-aliasing, etc.
Using AffineTransform, sorry, only way I know how :P
public class RotatePane extends javax.swing.JPanel {
private BufferedImage img;
private Point mousePoint;
/**
* Creates new form RotatePane
*/
public RotatePane() {
try {
img = ImageIO.read(getClass().getResource("/MT02.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(img.getWidth(), img.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
int x = (width - img.getWidth()) / 2;
int y = (height - img.getHeight()) / 2;
g2d.rotate(Math.toRadians(rotation), width / 2, height / 2);
g2d.drawImage(img, x, y, this);
x = width / 2;
y = height / 2;
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.drawLine(x, y, x, y - height / 4);
g2d.dispose();
}
}
Will produce this effect
The red line (point out from the center) will want to follow the cursor.
I want an circular movement of an image in JAVA, i thought I have the solution but it doesn't work and i'm a bit clueless now.
For calculating the points it needs to go im using pythagoras to calculate the height (point B).
if it does one round im satisfied but more rounds would be cool.
The image size is around 500 x 300 pixels.
Here's my code :
package vogel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class Vogel extends Component {
private int x;
private int r;
private int b;
BufferedImage img;
public vogel() {
try {
img = ImageIO.read(new File("F:/JAVA/workspace/School/src/vogel/vogel.png"));
} catch (IOException e) {
}
r = 60;
x = 10;
}
#Override
public void paint(Graphics g) {
for(int i = -x; i <= x; i++) {
b = (int)Math.sqrt(r^2 - i^2);
g.drawImage(img, x, b, this);
}
}
public static void main(String[] args) {
JFrame f = new JFrame("Vogel");
f.setSize(1000,1000);
f.add(new Vogel());
f.setVisible(true);
for (int number = 1; number <= 1500000; number++) {
f.repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
}
}
}
Using your loop in the paint(Graphics) method, it draws 21 birds with one repaint.
You should do it with an angle stored in an object variable and use the Math.sin() and Math.cos() function calculate the x and y position. The angle should be increased with every repaint().
To add:
// To control the radius of moving
private final double MAX_X = 200;
private final double MAX_Y = 200;
private double angle = 0;
#Override
public void paint(Graphics g) {
// increase angle (should be a double value)
angle += 0.1;
// rotate around P(0/0), assuming that 0° is vector (1/0)
int x = (int) (Math.cos(angle) * MAX_X);
int y = (int) (Math.sin(angle) * MAX_Y);
// move P to center of JFrame (width and height = 1000)
x += 500;
y += 500;
// image is 500x300, calc upper left corner
x -= 250;
y -= 150;
// draw
g.drawImage(img, x, y, null);
}
To remove:
private double x, b, r;
So this is the code, try it.
Addition to Sibbo's code to convert angle to rads
private double angle = 0.1;
#Override
public void paint(Graphics g) {
// increase angle (should be a double value
double random = angle * 2.0 * Math.PI/360.0; //this will convert it to rads
// rotate around P(0/0)
int x = (int) (Math.cos(random) * MAX_X);
int y = (int) (Math.sin(random) * MAX_Y);
// move P to center of JFrame (width and height = 1000)
x += 500;
y += 500;
// image is 500x300, calc upper left corner
x -= 250;
y -= 150;
angle++
// draw
g.drawImage(img, x, y, null);
}