I am trying to draw a route over the road using the source code below:
final List<GeoPosition> region = new ArrayList<GeoPosition>();
Painter<JXMapViewer> lineOverlay = new Painter<JXMapViewer>() {
public void paint(Graphics2D g, JXMapViewer map, int w, int h) {
region.add(new GeoPosition(5.42031,100.34389));
region.add(new GeoPosition(5.41984,100.33924));
region.add(new GeoPosition(5.42300,100.33456));
g = (Graphics2D) g.create();
//convert from viewport to world bitmap
Rectangle rect = jXMapKit1.getMainMap().getViewportBounds();
g.translate(-rect.x, -rect.y);
//do the drawing
g.setColor(Color.RED);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2));
int lastX = -1;
int lastY = -1;
for (GeoPosition gp : region.getGpxTrack())
{
//convert geo to world bitmap pixel
Point2D pt = jXMapKit1.getMainMap().getTileFactory().geoToPixel(gp, jXMapKit1.getMainMap().getZoom());
if (lastX != -1 && lastY != -1) {
g.drawLine(lastX, lastY, (int) pt.getX(), (int) pt.getY());
}
lastX = (int) pt.getX();
lastY = (int) pt.getY();
}
System.out.println("I am here");
g.dispose();
}
};
However, I get an error at the line region.getGpxTrack().
I try to use the region only GeoPosition gp : region, it only draw a line between two points. What I want is a road route. Anyone know where I got wrong?
Ok I did the same to see if it works if you replace region.getGpxTrack() with region as I assume in comment. Yes it works. Here is full worked application with that what you are trying to do:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import org.jdesktop.swingx.JXMapKit;
import org.jdesktop.swingx.JXMapKit.DefaultProviders;
import org.jdesktop.swingx.JXMapViewer;
import org.jdesktop.swingx.mapviewer.GeoPosition;
import org.jdesktop.swingx.painter.Painter;
public class Starter {
public static void main(final String[] args) {
final JFrame f = new JFrame();
f.setSize(500, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXMapKit jXMapKit1 = new JXMapKit();
jXMapKit1.setDefaultProvider(DefaultProviders.OpenStreetMaps);
jXMapKit1.setCenterPosition(new GeoPosition(5.41984, 100.33924));
jXMapKit1.setZoom(3);
final List<GeoPosition> region = new ArrayList<GeoPosition>();
region.add(new GeoPosition(5.42031, 100.34389));
region.add(new GeoPosition(5.41984, 100.33924));
region.add(new GeoPosition(5.42300, 100.33456));
final Painter<JXMapViewer> lineOverlay = new Painter<JXMapViewer>() {
#Override
public void paint(Graphics2D g, final JXMapViewer map, final int w, final int h) {
g = (Graphics2D) g.create();
// convert from viewport to world bitmap
final Rectangle rect = jXMapKit1.getMainMap().getViewportBounds();
g.translate(-rect.x, -rect.y);
// do the drawing
g.setColor(Color.RED);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2));
int lastX = -1;
int lastY = -1;
for (final GeoPosition gp : region) {
// convert geo to world bitmap pixel
final Point2D pt = jXMapKit1.getMainMap().getTileFactory().geoToPixel(gp, jXMapKit1.getMainMap().getZoom());
if (lastX != -1 && lastY != -1) {
g.drawLine(lastX, lastY, (int) pt.getX(), (int) pt.getY());
}
lastX = (int) pt.getX();
lastY = (int) pt.getY();
}
g.dispose();
}
};
jXMapKit1.getMainMap().setOverlayPainter(lineOverlay);
f.setContentPane(jXMapKit1);
f.setVisible(true);
}
}
Related
I am developing a navigation system in Java. The map should be drawn in the middle, with indicators on the left and right.
How do I make the map slowly fade out on both sides?
As shown above, the roads are drawn across the entire window via Graphics2D. How can I make a gradient with left and right transparent and center color x?
for(Street street : streets){
g2d.setColor(Color.BLACK);
if(street.distanceToCurrentPosition() * factor < width * 2){
Integer last_x = null;
Integer last_y = null;
street.setupGraphicSettings(g2d);
if(street.getType() != ""){
for(WayPoint wayPoint : street.getWayPoints()){
int waypoint_x = (int) (wayPoint.getDistanceLongitudeTo(current_position) * factor) + middle_x;
int waypoint_y = - (int) (wayPoint.getDistanceLatitudeTo(current_position) * (double) factor) + middle_y;
if(last_x != null || last_y != null){;
g2d.drawLine(waypoint_x, waypoint_y, last_x, last_y);
}
last_x = waypoint_x;
last_y = waypoint_y;
}
}
}else return;
A working code solution
The "basic" idea is to use a combination of LinearGradientPaint and AlphaComposite to apply an alpha based "mask" to the core map image - now, this assumes you have an image based map.
Start by taking a look at:
2D Graphics Trail
Stroking and Filling Graphics Primitives
Compositing Graphics
Basically, we create a alpha based "mask":
BufferedImage alphaMask = new BufferedImage(baseMap.getWidth(), baseMap.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = alphaMask.createGraphics();
Color opaqueColor = new Color(0, 0, 0, 255);
Color alphaColor = new Color(0, 0, 0, 0);
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(baseMap.getWidth(), 0),
new float[]{0f, 0.1f, 0.25f, 0.75f, 0.9f, 1f},
new Color[]{alphaColor, alphaColor, opaqueColor, opaqueColor, alphaColor, alphaColor}
);
g2d.setPaint(lgp);
g2d.fillRect(0, 0, alphaMask.getWidth(), alphaMask.getHeight());
g2d.dispose();
Note, we're not really interested in the color, just there alpha values.
Next, we use a AlphaComposite.DST_IN to "mask" the source image, this done via a utility method...
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
BufferedImage maskedImage = null;
if (sourceImage != null) {
int width = maskImage.getWidth();
int height = maskImage.getHeight();
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth()) / 2;
int y = (height - sourceImage.getHeight()) / 2;
mg.drawImage(sourceImage, x, y, null);
mg.setComposite(AlphaComposite.getInstance(method));
mg.drawImage(maskImage, 0, 0, null);
mg.dispose();
}
return maskedImage;
}
Runnable example
NB: The component's background is set to red to demonstrate the alpha masking
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
try {
frame.add(new TestPane());
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage maskedMap;
public TestPane() throws IOException {
BufferedImage baseMap = ImageIO.read(getClass().getResource("/images/MiddleEarth.jpeg"));
BufferedImage alphaMask = new BufferedImage(baseMap.getWidth(), baseMap.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = alphaMask.createGraphics();
Color opaqueColor = new Color(0, 0, 0, 255);
Color alphaColor = new Color(0, 0, 0, 0);
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(baseMap.getWidth(), 0),
new float[]{0f, 0.1f, 0.25f, 0.75f, 0.9f, 1f},
new Color[]{alphaColor, alphaColor, opaqueColor, opaqueColor, alphaColor, alphaColor}
);
g2d.setPaint(lgp);
g2d.fillRect(0, 0, alphaMask.getWidth(), alphaMask.getHeight());
g2d.dispose();
maskedMap = applyMask(baseMap, alphaMask, AlphaComposite.DST_IN);
// Just to prove the point
setBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return maskedMap == null ? new Dimension(200, 200) : new Dimension(maskedMap.getWidth(), maskedMap.getHeight());
}
public static BufferedImage applyMask(BufferedImage sourceImage, BufferedImage maskImage, int method) {
BufferedImage maskedImage = null;
if (sourceImage != null) {
int width = maskImage.getWidth();
int height = maskImage.getHeight();
maskedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D mg = maskedImage.createGraphics();
int x = (width - sourceImage.getWidth()) / 2;
int y = (height - sourceImage.getHeight()) / 2;
mg.drawImage(sourceImage, x, y, null);
mg.setComposite(AlphaComposite.getInstance(method));
mg.drawImage(maskImage, 0, 0, null);
mg.dispose();
}
return maskedImage;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints hints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON
);
g2d.setRenderingHints(hints);
int x = (getWidth() - maskedMap.getWidth()) / 2;
int y = (getHeight() - maskedMap.getHeight()) / 2;
g2d.drawImage(maskedMap, x, y, this);
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(3f));
// There's a nice and interesting effect ;)
g2d.setComposite(AlphaComposite.SrcOver.derive(0.9f));
int diameter = getWidth() / 4;
x = ((getWidth() / 2) - diameter) / 2;
y = (getHeight() - diameter) / 2;
g2d.fillOval(x, y, diameter, diameter);
x = getWidth() - (((getWidth() / 2) + diameter) / 2);
g2d.fillOval(x, y, diameter, diameter);
g2d.dispose();
}
}
}
I have this Class That Draws a line between specified points or locations in the map And it works
!
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import org.jxmapviewer.JXMapKit;
import org.jxmapviewer.JXMapKit.DefaultProviders;
import org.jxmapviewer.JXMapViewer;
import org.jxmapviewer.painter.Painter;
import org.jxmapviewer.viewer.GeoPosition;
public class Starter {
public static void main(final String[] args) {
final JFrame f = new JFrame();
f.setSize(500, 300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JXMapKit jXMapKit1 = new JXMapKit();
jXMapKit1.setDefaultProvider(DefaultProviders.OpenStreetMaps);
jXMapKit1.setCenterPosition(new GeoPosition(5.41984, 100.33924));
jXMapKit1.setZoom(3);
final List<GeoPosition> region = new ArrayList<GeoPosition>();
region.add(new GeoPosition(5.42031, 100.34389));
region.add(new GeoPosition(5.41984, 100.33924));
region.add(new GeoPosition(5.42300, 100.33456));
final Painter<JXMapViewer> lineOverlay = new Painter<JXMapViewer>() {
#Override
public void paint(Graphics2D g, final JXMapViewer map, final int w, final int h) {
g = (Graphics2D) g.create();
// convert from viewport to world bitmap
final Rectangle rect = jXMapKit1.getMainMap().getViewportBounds();
g.translate(-rect.x, -rect.y);
// do the drawing
g.setColor(Color.RED);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(2));
int lastX = -1;
int lastY = -1;
for (final GeoPosition gp : region) {
// convert geo to world bitmap pixel
final Point2D pt = jXMapKit1.getMainMap().getTileFactory().geoToPixel(gp, jXMapKit1.getMainMap().getZoom());
if (lastX != -1 && lastY != -1) {
g.drawLine(lastX, lastY, (int) pt.getX(), (int) pt.getY());
}
lastX = (int) pt.getX();
lastY = (int) pt.getY();
}
g.dispose();
}
};
jXMapKit1.getMainMap().setOverlayPainter(lineOverlay);
f.setContentPane(jXMapKit1);
f.setVisible(true);
}
}
but I want to draw a route that can follow by car. Not just a straight line that cut across all the building !.
When I select two points on the map, I need to see a suggested path or path to reach, not just a line !
i need like this image
Any Help ?
How do I create a Shape that rensembles the whole Text/String rather than just the outline?
What I got currently from Shape outline = textTl.getOutline(null);
The problem is that I invoke the drawShadowedShape(outline, g2d); on the outline shape, so the shadow is drawn over the font. But I want to invoke the drawShadowedShape(outline, g2d); not on the outline but the Text-Shape as whole thing, so that the shadow is drawn around the Font not like in the example on the outline.
Prior to asking this question I read in the documentiaon about all TextLayout methods that return a Shape object, but I did not find the correct one by my self.
For this snippet to work you just need to supply a valid font here: String fName = "fonts/SugarBomb.ttf";
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.*;
#SuppressWarnings("serial")
public class GradientText extends JPanel {
private static final int PREF_W = 360;
private static final int PREF_H = 200;
private static Font font;
private static final int COLOR_COUNT = 3;
private static final Color BG = Color.ORANGE;
private Paint myPaint;
public GradientText() {
String fName = "fonts/SugarBomb.ttf";
InputStream is = FontTest.class.getResourceAsStream(fName);
try {
font = Font.createFont(Font.TRUETYPE_FONT, is);
font = font.deriveFont(20.0f);
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
setBackground(BG);
setPreferredSize(new Dimension(PREF_W, PREF_H));
float[] fractions = new float[COLOR_COUNT];
Color[] colors = new Color[COLOR_COUNT];
for (int i = 0; i < colors.length; i++) {
fractions[i] = ((float)i) / COLOR_COUNT;
if(i%2==0) {
colors[i] = new Color(248, 57, 1);
}else {
colors[i] = Color.yellow;
}
}
for (int i = 0; i < colors.length; i++) {
System.out.println(colors[i]);
System.out.println(fractions[i]);
}
myPaint = new LinearGradientPaint(0, 0, PREF_W, 0, fractions, colors);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
FontRenderContext frc = g2d.getFontRenderContext();
String s = "Look ma, I'm Stroked";
TextLayout textTl = new TextLayout(s, font, frc);
Shape outline = textTl.getOutline(null);
FontMetrics fm = g2d.getFontMetrics(getFont());
int x = (getWidth() - outline.getBounds().width) / 2;
int y = ((getHeight() - outline.getBounds().height) / 2) + fm.getAscent();
g2d.translate(x, y);
Stroke stroke = g2d.getStroke();
g2d.setPaint(myPaint);
g2d.fill(outline);
g2d.setStroke(new BasicStroke(1.2f));
g2d.setColor(Color.WHITE);
drawShadowedShape(outline, g2d);
g2d.draw(outline);
g2d.dispose();
}
private static void createAndShowGui() {
GradientText mainPanel = new GradientText();
JFrame frame = new JFrame("GradientText");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
public static void drawShadowedShape(Shape shape, Graphics2D g2d) {
Color holdColor = g2d.getColor();
g2d.setColor(Color.black);
AffineTransform holdTransform = g2d.getTransform();
// want the shadow to be one line width pixel offset
float lineWidth = g2d.getStroke() instanceof BasicStroke ? ((BasicStroke) (g2d.getStroke())).getLineWidth()
: 2.0f;
//System.err.println("DrawingUtilities.drawShadowedShape(): lineWidth = "+lineWidth);
g2d.translate(lineWidth, lineWidth);
g2d.draw(shape);
g2d.setColor(holdColor);
g2d.setTransform(holdTransform);
g2d.draw(shape);
}
}
I am trying to design a JButton.
I want the JButton to look like this:
I tried to achieve this using Polygon but I couldn't make the corners be round as seen above.
The one I designed looks like this:
The code that generated this button is below:
public class arcButton extends JButton{
public arcButton() {
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width, size.height);
setPreferredSize(size);
setContentAreaFilled(false);
}
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
g.setColor(Color.CYAN.darker().darker());
} else {
g.setColor(Color.CYAN.darker());
}
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
g.fillPolygon(xPoints, yPoints, xPoints.length);
super.paintComponent(g);
}
protected void paintBorder(Graphics g) {
g.setColor(Color.cyan);
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
Polygon polygon;
public boolean contains(int x, int y) {
if (polygon == null ||
!polygon.getBounds().equals(getBounds())) {
int xPoints[] = {getWidth(), getWidth()/3, getWidth()/3, getWidth()*3/4, getWidth()*3/4, getWidth(), getWidth()*3/4, getWidth()*3/4, 0, 0, getWidth()};
int yPoints[] = {getHeight()*7/9, getHeight()*7/9, getHeight()*3/9, getHeight()*3/9, getHeight()*4/9, getHeight()*2/9, 0, getHeight()/9, getHeight()/9, getHeight(), getHeight()};
polygon = new Polygon(xPoints,yPoints,xPoints.length);
}
return polygon.contains(x, y);
}
}
I tried to draw with arcs but when I use ((Graphics2D)g).draw(arc) in the paintComponent. It kept giving a lot of errors when mouse was on the GUI.
How should I approach this?
I created the following GUI.
Instead of extending a JButton, I created a class to hold two BufferedImages. One for the arrow, and one to signify a pressed button.
I created a test GUI so I could draw the arrow one small piece at a time. I wound up creating two Polygons, one for the semi-circle and one for the arrowhead.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CustonButtonGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CustonButtonGUI());
}
private ButtonImages buttonImages;
public CustonButtonGUI() {
this.buttonImages = new ButtonImages();
}
#Override
public void run() {
JFrame frame = new JFrame("Custom JButton");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
BufferedImage image = buttonImages.getMainImage();
JButton button = new JButton();
button.setPreferredSize(new Dimension(image.getWidth(panel),
image.getHeight(panel)));
button.setIcon(new ImageIcon(image));
button.setPressedIcon(new ImageIcon(buttonImages.getPressedImage()));
panel.add(button);
return panel;
}
private class ButtonImages {
private final BufferedImage mainImage;
private final BufferedImage pressedImage;
public ButtonImages() {
this.mainImage = createMainImage(120, 200);
this.pressedImage = createPressedImage(120, 200);
}
private BufferedImage createMainImage(int width, int height) {
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setColor(Color.BLACK);
g2d.fillPolygon(createArrowPolygon(width, height));
g2d.fillPolygon(createCircularPolygon(width, height));
g2d.dispose();
return image;
}
private Polygon createArrowPolygon(int width, int height) {
Polygon polygon = new Polygon();
int margin = 10;
int arrowWidth = 30;
int x = width - margin;
int y = height - margin;
polygon.addPoint(x, y - arrowWidth);
polygon.addPoint(x - arrowWidth, y - arrowWidth - arrowWidth);
polygon.addPoint(x - arrowWidth, y);
return polygon;
}
private Polygon createCircularPolygon(int width, int height) {
Polygon polygon = new Polygon();
int centerY = height / 2;
int margin = 10;
Point centerPoint = new Point(width - margin - 30, centerY);
double radius = centerY - 55.0;
for (int angle = 90; angle <= 270; angle++) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
polygon.addPoint(x, y);
}
radius += 25.0;
for (int angle = 270; angle >= 90; angle--) {
double theta = Math.toRadians(angle);
int x = (int) Math.round(Math.cos(theta) * radius) + centerPoint.x;
int y = (int) Math.round(Math.sin(theta) * radius) + centerPoint.y;
polygon.addPoint(x, y);
}
return polygon;
}
private BufferedImage createPressedImage(int width, int height) {
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
return image;
}
public BufferedImage getMainImage() {
return mainImage;
}
public BufferedImage getPressedImage() {
return pressedImage;
}
}
}
BEFORE YOU MARK IT AS DUPLICATE
I have searched a lot in the internet for that and tried every solution, but no one does it the same way I do it. In my case the rotation is in a sperate class.
I have created a java class that inherits JLabel class, in my class I have an arrow BufferedImage which I draw using the paintComponent(Graphics g) method.
I am trying to make the arrow point to a specific point (which I get from a different method) but something goes wrong and the arrow rotates to the wrong direction.
I THINK: it doesn't calculate correctly because the imageLocation is relative to the label.
Here is my code:
package pkg1;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public final class ImageLabel extends JLabel {
private float angle = 0.0f; // in radians
private Point imageLocation = new Point();
private File imageFile = null;
private Dimension imageSize = new Dimension(50, 50);
private BufferedImage bi;
private BufferedImage resizeImage(BufferedImage originalImage, int img_width, int img_height) {
int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
BufferedImage resizedImage = new BufferedImage(img_width, img_height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, img_width, img_height, null);
g.dispose();
return resizedImage;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bi == null) {
return;
}
imageLocation = new Point(getWidth() / 2 - bi.getWidth() / 2, getHeight() / 2 - bi.getHeight() / 2);
Graphics2D g2 = (Graphics2D) g;
g2.rotate(angle, imageLocation.x + bi.getWidth() / 2, imageLocation.y + bi.getHeight() / 2);
g2.drawImage(bi, imageLocation.x, imageLocation.y, null);
}
public void rotateImage(float angle) { // rotate the image to specific angle
this.angle = (float) Math.toRadians(angle);
repaint();
}
public void pointImageToPoint(Point target) {
calculateAngle(target);
repaint();
}
private void calculateAngle(Point target) {
// calculate the angle from the center of the image
float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
angle = (float) Math.atan2(deltaY, deltaX);
if (angle < 0) {
angle += (Math.PI * 2);
}
}
}
Okay, so two things jump out at me...
If you take a Point from outside the context of the label, you will have to translate the point into the components coordinate context
The calculateAngle seems wrong
So starting with...
private void calculateAngle(Point target) {
// calculate the angle from the center of the image
float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
angle = (float) Math.atan2(deltaY, deltaX);
if (angle < 0) {
angle += (Math.PI * 2);
}
}
angle = (float) Math.atan2(deltaY, deltaX); should be angle = (float) Math.atan2(deltaX, deltaY); (swap the deltas)
You will find that you need to adjust the result by 180 degrees in order to get the image to point in the right direction
angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
Okay, I'm an idiot, but it works :P
I'd also make use of a AffineTransform to translate and rotate the image - personally, I find it easier to deal with.
In the example, I've cheated a little. I set the translation of the AffineTransform to the centre of the component, I then rotate the context around the new origin point (0x0). I then paint the image offset by half it's height/width, thus making it appear as the if the image is been rotated about it's centre - It's late, I'm tired, it works :P
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private ImageLabel label;
public TestPane() {
setLayout(new GridBagLayout());
label = new ImageLabel();
add(label);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
label.pointImageToPoint(e.getPoint(), TestPane.this);
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public final class ImageLabel extends JLabel {
private double angle = 0;
private Point imageLocation = new Point();
private File imageFile = null;
private Dimension imageSize = new Dimension(50, 50);
private BufferedImage bi;
public ImageLabel() {
setBorder(new LineBorder(Color.BLUE));
bi = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = bi.createGraphics();
g2d.setColor(Color.RED);
g2d.drawLine(25, 0, 25, 50);
g2d.drawLine(25, 0, 0, 12);
g2d.drawLine(25, 0, 50, 12);
g2d.dispose();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(bi.getWidth(), bi.getHeight());
}
protected Point centerPoint() {
return new Point(getWidth() / 2, getHeight() / 2);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bi == null) {
return;
}
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform at = g2d.getTransform();
Point center = centerPoint();
at.translate(center.x, center.y);
at.rotate(angle, 0, 0);
g2d.setTransform(at);
g2d.drawImage(bi, -bi.getWidth() / 2, -bi.getHeight() / 2, this);
g2d.dispose();
}
public void rotateImage(float angle) { // rotate the image to specific angle
this.angle = (float) Math.toRadians(angle);
repaint();
}
public void pointImageToPoint(Point target, JComponent fromContext) {
calculateAngle(target, fromContext);
repaint();
}
private void calculateAngle(Point target, JComponent fromContext) {
// calculate the angle from the center of the image
target = SwingUtilities.convertPoint(fromContext, target, this);
Point center = centerPoint();
float deltaY = target.y - center.y;
float deltaX = target.x - center.x;
angle = (float) -Math.atan2(deltaX, deltaY);
angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
repaint();
}
}
}
I just want to add that using a JLabel for this purpose is overkill, a simple JPanel or JComponent would do the same job and carry a lot less overhead with it, just saying