I've already searched this topic everywhere on the Internet, but nothing.
I'm programming with JAVA and I'm painting in a JPanel some shapes like yellow stars with a sort of spaceship in the center of the screen. My purpose is to make the entire scene, apart from the spaceship which remains stationary at the center, rotate around the center (and of course around the spaceship) when I press a certain button.
Now, when I rotate the stars I make them rotate around the center point wich changes as the spaceship moves, but when I do a rotation, the coordinates system changes and the ship moves diagonally, while I want to rotate the scene keeping possible to move the spaceship vertically and horizontally.
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
// RIEMPIMENTO SFONDO
g2.setColor(new Color(10, 10, 10));
g2.fillRect(0, 0, 1366, 768);
// DEBUGGER
g2.setColor(Color.WHITE);
g2.drawString("|" + posx + "|" + posy + "| " + scale, 1250, 758);
// TRASFORMAZIONE NAVICELLA
AffineTransform at = new AffineTransform();
at.translate(683, 384);
at.scale(scale, scale);
g2.setTransform(at);
AffineTransform backup = g2.getTransform();
// DISEGNO NAVICELLA
g2.setColor(Color.LIGHT_GRAY);
int[] xp = {0, -25, -25, 0, 25, 25};
int[] yp = {-25, 0, 25, 0, 25, 0};
g2.drawPolygon(xp, yp, 6);
// TRASFORMAZIONE SPAZIO
at.translate(posx, posy);
at.rotate(Math.toRadians(rotation), -posx, -posy);
g2.setTransform(at);
// DISEGNO SPAZIO
STAR(g2, 300 + posx, 100 + posy, 200, 200, Color.YELLOW);
STAR(g2, -100 + posx, -200 + posy, 200, 200, Color.YELLOW);
g2.dispose();
}
Related
I am trying to make a program where when you click a check box saying that you want an object to be drawn with a dashed line you can, but when I create a stroke and try to use it my graphics does not acknowledge it. The code is set to double buffer so the image doesn't disappear when you are creating it. I am not sure how to make the objects draw in with the dashed line and would appreciate any help!
Graphics bgg = bg.getGraphics();
if(!jCheckBox1.isSelected()){
bgg.drawImage(fg, jPanel1.getX(), jPanel1.getY()-50, null);
}
else{
Graphics2D g2d = (Graphics2D) bgg;
float[] fa = {10, 10, 10};
BasicStroke bs = new BasicStroke(5, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10, fa, 10);
g2d.setStroke(bs);
g2d.drawImage(fg, jPanel1.getX(), jPanel1.getY()-50, null);
}
In order to draw a rectangle onto your image you will need to use the Graphics.drawRect() method something like this (just off the top of my head with what you've already got):
Graphics bgg = bg.getGraphics();
if(!jCheckBox1.isSelected()){
bgg.drawImage(fg, jPanel1.getX(), jPanel1.getY()-50, null);
}
else{
Graphics2D g2d = (Graphics2D) bgg;
//Draw image into panel...
g2d.drawImage(fg, jPanel1.getX(), jPanel1.getY()-50, null);
//Draw dashed rectagle in center of panel...
int pW = jPanel1.getWidth(); // Get panel Width
int pH = jPanel1.getHeight(); // Get panel Height
float[] fa = {10, 10, 10}; // The dash pattern
// Set Brush thickness (5)
BasicStroke bs = new BasicStroke(5, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 10, fa, 10);
g2d.setStroke(bs);
Dimension rectangle = new Dimension(200, 50); // Our desired rectangle dimensions
// Center locations for rectangle...
int x1 = (pW / 2) - (rectangle.width / 2);
int y1 = (pH / 2) - (rectangle.height / 2);
int x2 = rectangle.width;
int y2 = rectangle.height;
g2d.setColor(Color.RED); // Set the dashed shape line color
g2d.drawRect(x1, y1, x2, y2); // Draw the dashed rectangle
// free resourses
bgg.dispose();
g2d.dispose();
jPanel1.revalidate(); // update panel graphics
}
A brush stroke of 5 makes for a pretty heavy dash :)
The following code is the code that I am using to rotate two rectangles is below
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setColor(Color.WHITE);
//r1
Rectangle2D r1 = new Rectangle2D.Double(0, 0, 50, 4);
g2d.rotate(Math.toRadians(45));
g2d.fill(r1);
//r3
Rectangle2D r3 = new Rectangle2D.Double(0, 25, 50, 4);
g2d.rotate(Math.toRadians(-90));
g2d.fill(r3);
This create something which looks like this
Whereas I am trying to create something which looks like this
This occurs since when the rectangles are rotated, they are both rotated around the point 0,0. To fix that I tried using rotate(double theta, double x, double y). However I am having trouble using that correctly. For example when I have tried
Rectangle2D r3 = new Rectangle2D.Double(0, 25, 50, 4);
g2d.rotate(Math.toRadians(-90), 25, 25);
or
Rectangle2D r3 = new Rectangle2D.Double(0, 25, 50, 4);
g2d.rotate(Math.toRadians(-90), 0, 25);
I get similar undesired results when both the rectangles were being rotated around the point 0,0. I would appreciate any help if fixing my problem.
If you are wondering why I have done it like this, it is because I am hoping to make a effect similar to when you click on the 3 parallel lines seen here by the time I finish coding the graphic
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class Cross extends JPanel {
private Rectangle2D rectangle;
Cross() {
rectangle = new Rectangle2D.Double(0, 0, 50, 4);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setColor(Color.white);
AffineTransform at = g2.getTransform();
g2.translate(5, 5);
g2.rotate(Math.toRadians(45));
g2.fill(rectangle);
g2.setTransform(at);
g2.translate(5, 5 + Math.sqrt(2) * 25);
g2.rotate(Math.toRadians(-45));
g2.fill(rectangle);
g2.setTransform(at);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Cross");
frame.add(new Cross());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(128, 128);
frame.setVisible(true);
}
}
Although I think I might have done mistake somewhere with maths (it looks somewhat odd), this should give you an idea.
So it turns out that this can be done with some relatively simple maths. As the shape I am trying to make is a perfect X.
To work out the position for the rectangle we can use Pythagorean theorem.
The image above shows two steps.
Translation [2√2, 0] from the point [0, 0]
Rotate 45deg from the point [2√2, 0]
Next we need to work out the minimum point of this rectangle. Again we can use Pythagorean theorem.
This tells us where the top point of the second rectangle will be
Difference in height: 4 - 2√2
Bottom of line when straight: [0, 27√2 + (4 - 2√2)] = [0, 4 + 25√2]
Top of line when straight: [0, 25√2]
Finally we can put in the last rectangle starting at [0, 0]
Translation [0, 25√2] from the point [0, 0]
Rotate -45deg from the point [0, 25√2]
Now that the theory is out of the way, what does this look like in code? It looks similar to the code below
//Values
final static double[] r1Points = {2.828427125, 0}; //Equivilant 2√2
final static double[] r3Points = {0, 35.35533906}; //Equivilant 25√2
final static int[] widthNHeight = {50, 4}; //Width then height
final static double angle = 45.0; //Angle to rotate lines
//Declaring the rectangles
Rectangle2D r1 = new Rectangle2D.Double(r1Points[0], r1Points[1], widthNHeight[0], widthNHeight[1]);
Rectangle2D r3 = new Rectangle2D.Double(r3Points[0], r3Points[1], widthNHeight[0], widthNHeight[1]);
//r1
g2d.rotate(Math.toRadians(angle), r1Points[0], r1Points[1]); //Rotates graphic for first rectangle
g2d.fill(r1);
//r3
g2d.rotate(Math.toRadians(-angle), r1Points[0], r1Points[1]); //Rotates the graphic back to straight
g2d.rotate(Math.toRadians(-angle), r3Points[0], r3Points[1]); //Rotates graphic for second rectangle
g2d.fill(r3);
I need to outline in blue 1 rectangle at a time when selected. The code works but I cant see the blue outline very well. what is the easiest way to make the outline thicker. Wither that be drawing another shape over it or something else.
private void displayBlock(Graphics g)
{
for(int i = 0; i < 10; i++)
{
if (occupant[i].equals("Empty"))
{
//Sets the rectangle red to show the room is occupied
g.setColor(emptyColor);
g.fillRect(150+(i*50), 120, aptWidth, aptHeight);
}
else
{
//Sets the rectangle green to show the room is free
g.setColor(Color.red);
g.fillRect(150+(i*50), 120, aptWidth, aptHeight);
}
if (i == selectedApartment)
{
g.setColor(Color.blue);
g.drawRect(150+(i*50), 120, aptWidth, aptHeight);
}
else
{
g.setColor(Color.black);
g.drawRect(150+(i*50), 120, aptWidth, aptHeight);
}
// Draws the numbers in the Corresponding boxes
g.setColor(Color.black);
g.drawString(Integer.toString(i+1), 150+(i*50)+15, 120+25);
}
//Drawing the key allowing the user to see what the colours refer to
g.setFont(new Font("TimesRoman", Font.PLAIN, 14));
g.drawString("Key", 20,120);
g.drawString("Occupied",60,150);
g.drawString("Empty", 60, 170);
// Drawing the boxes to show what the colours mean in the key
g.setColor(Color.red);
g.fillRect(20, 130, 25, 25);
g.setColor(Color.black);
g.drawRect(20, 130, 25, 25);
g.setColor(Color.green);
g.fillRect(20,150,25,25);
g.setColor(Color.black);
g.drawRect(20,150,25,25);
} // End of displayBlock
You can set the thickness of the rectangle by creating a Graphics2D object and setting its stroke.
java.awt.Graphics2D g2 = (java.awt.Graphics2D) g.create();
g2.setStroke(new java.awt.BasicStroke(3)); // thickness of 3.0f
g2.setColor(Color.blue);
g2.drawRect(10,10,50,100); // for example
Maybe you could draw a second rectangle immediately inside the first one. Or multiple of them.
public static void drawRectangle(Graphics g, int x, int y, int width, int height, int thickness) {
g.drawRect(x, y, width, height);
if (thickness > 1) {
drawRectangle(g, x + 1, y + 1, width - 2. height - 2, thickness - 1);
}
}
I'm trying to make a Mastermind in Java. The code isn't really difficult, but I want to have a very good interface. I have a JPanel which take all my JFrame, and I paint this JPanel with surchargind repaint() method:
//method to draw elements on the map
public void paint(Graphics g) {
super.paintComponents(g);
Graphics gr;
gr = MasterMindPane.getGraphics();
img = MasterMindPane.getToolkit().getImage("images/plateau4-8.jpg");
gr.drawImage(img, 0, 0, 600, 720, this);
gr = bouleRougePane.getGraphics();
img = bouleRougePane.getToolkit().getImage("images/bouleRouge.png");
//gr.drawImage(img, 535, 303, 45, 45, this);
gr.drawImage(img, 0, 0, 45, 45, this);
gr = bouleOrangePane.getGraphics();
img = bouleOrangePane.getToolkit().getImage("images/bouleOrange.png");
//gr.drawImage(img, 535, 303, 45, 45, this);
gr.drawImage(img, 0, 0, 45, 45, this);
}
When I click on one image, which have a Panel, I draw a yellow circle like that :
private void bouleRougePaneMouseClicked(java.awt.event.MouseEvent evt) {
Graphics2D g2d = (Graphics2D) MasterMindPane.getGraphics();
for(int i = 0; i<4; i++)
{
g2d.setColor(Color.ORANGE);
g2d.setStroke(new BasicStroke(3));
g2d.drawOval(78+i*70, 106+etape*50, 35, 35);
}
}
And when I select a hole, I want to delete the circle, which only indicates where the gamer can play.
But I don't know how to delete the circle or repaint just a part of my Image because it costs a lot to repaint all.
A very simple way is to use paintImmediately(x,y,w,h);
This repaints only the specified area that starts at pixel (x,y) with width w and height h.
You can set clip Shape to the thick oval and fill it.
Create the big oval Shape via BasicStroke with thick line.
Revised: The problem is to paint a four sided border where each side starts with a solid base color and fades to white inward over the span of the border. The challenge was to make the intersection of the borders look seamless. To accomplish this, one may draw the borders, then use triangles to 'blend' the corners. Two triangles may be used per corner if there is no overlap in the rectangles drawing the broder, or one triangle per corner is sufficient (as shown below) if two parallel border sides extend the full length of the border (ie the rectangles overlap).
private static final int GRADIENT_LENGTH = 29;
private static final int BAR_LENGTH = 25;
public static void paintGradientBorder(Graphics g, Color borderColor) {
Graphics2D g2 = (Graphics2D) g.create();
GradientPaint gradientColorWest = new GradientPaint(0, 0, borderColor,
GRADIENT_LENGTH, 0, Color.WHITE);
GradientPaint gradientColorEast = new GradientPaint(WINDOW_WIDTH - GRADIENT_LENGTH,
0, Color.WHITE, WINDOW_WIDTH, 0, borderColor);
GradientPaint gradientColorNorth= new GradientPaint(0, 0, borderColor, 0,
GRADIENT_LENGTH, Color.WHITE);
GradientPaint gradientColorSouth = new GradientPaint(0, WINDOW_HEIGHT - GRADIENT_LENGTH,
Color.WHITE,0, WINDOW_HEIGHT, borderColor);
//south bar
g2.setPaint(gradientColorSouth);
g2.fillRect(0, WINDOW_HEIGHT - BAR_LENGTH, WINDOW_WIDTH, BAR_LENGTH);
//north bar
g2.setPaint(gradientColorNorth);
g2.fillRect(0, 0, WINDOW_WIDTH, BAR_LENGTH);
//west bar
g2.setPaint(gradientColorWest);
g2.fillRect(0, BAR_LENGTH, BAR_LENGTH, WINDOW_HEIGHT - BAR_LENGTH * 2);
//east bar
g2.setPaint(gradientColorEast);
g2.fillRect(WINDOW_WIDTH - BAR_LENGTH, BAR_LENGTH, WINDOW_WIDTH, WINDOW_HEIGHT - BAR_LENGTH * 2);
//NORTH WEST CORNER
//left triangle
Polygon p = new Polygon();
p.addPoint(0, 0);
p.addPoint(BAR_LENGTH, BAR_LENGTH);
p.addPoint(0, BAR_LENGTH);
g2.setPaint(gradientColorWest);
g2.fillPolygon(p);
//NORTH EAST CORNER
//right triangle
p.reset();
p.addPoint(WINDOW_WIDTH, 0);
p.addPoint(WINDOW_WIDTH - BAR_LENGTH, BAR_LENGTH);
p.addPoint(WINDOW_WIDTH, BAR_LENGTH);
g2.setPaint(gradientColorEast);
g2.fillPolygon(p);
//SOUTH WEST CORNER
//left triangle
p.reset();
p.addPoint(0, WINDOW_HEIGHT);
p.addPoint(0,WINDOW_HEIGHT - BAR_LENGTH);
p.addPoint(BAR_LENGTH, WINDOW_HEIGHT - BAR_LENGTH);
g2.setPaint(gradientColorWest);
g2.fillPolygon(p);
//SOUTH EAST CORNER
//right triangle
p.reset();
p.addPoint(WINDOW_WIDTH, WINDOW_HEIGHT);
p.addPoint(WINDOW_WIDTH, WINDOW_HEIGHT - BAR_LENGTH);
p.addPoint(WINDOW_WIDTH - BAR_LENGTH, WINDOW_HEIGHT - BAR_LENGTH);
g2.setPaint(gradientColorEast);
g2.fillPolygon(p);
g2.dispose();
}
What if you don't intersect the rectangles but instead use a polygon (GeneralPath)?
GeneralPath topBox = new GeneralPath();
topBox.moveTo(0, 0);
// upper right
topBox.lineTo(width, 0);
// lower right; move diagonally down and to the left as in a picture frame
topBox.lineTo(width - (insetX / 2), 0 + (insetY / 2));
// lower left
topBox.lineTo((insetX / 2), 0 + (insetY / 2));
topBox.closePath();
g2.fill(topBox);
That way the rectangles will not overlap, but instead you'll have nice crisp edges between the different segments.
Rather than creating and painting 4 rectangles, I would create a single Shape representing your border area by subtracting an inner rectangle from an outer one using Area:
Area area = new Area(new Rectangle2D.Double(...));
Area inner = new Area(new Rectangle2D.Double(...));
area.subtract(inner);
g2.setPaint(new GradientPaint(...));
g2.fill(area);