Reputation: 782
I'm trying to draw a diamond (for a composition UML relationship). Right now, I am making a triangle like this:
but I want to make something like this:
And I do the triangle with this code:
private void drawArrowHead(Graphics2D g2, Point tip, Point tail,
Color color) {
g2.setPaint(color);
double dy = tip.y - tail.y;
double dx = tip.x - tail.x;
double theta = Math.atan2(dy, dx);
double x, y, rho = theta + phi;
Point p1 = new Point();
Point p2 = new Point();
p1.setLocation(tip.x - barb * Math.cos(rho), tip.y - barb * Math.sin(rho));
rho = theta - phi;
p2.setLocation(tip.x - barb * Math.cos(rho), tip.y - barb * Math.sin(rho));
int[] xPoints = new int[5];
int[] yPoints = new int[5];
xPoints[0] = tip.x;
xPoints[1] = p1.x;
xPoints[2] = p2.x;
yPoints[0] = tip.y;
yPoints[1] = p1.y;
yPoints[2] = p2.y;
g2.setPaint(Color.BLACK);
Shape shape = new Polygon(xPoints, yPoints, 3);
g2.fill(shape);
//tip.x - barb * Math.cos(rho);
//y = tip.y - barb * Math.sin(rho);
}
Does anyone have an idea on how to make a diamond out of this? Thanks :)
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawArrows {
public static void main(String[] args) {
new DrawArrows();
}
public DrawArrows() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager
.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new UMLWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(30, 30, 1000, 700);
frame.getContentPane().setBackground(Color.white);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
});
}
public static class UMLWindow extends JFrame {
Shapes shapeList = new Shapes();
Panel panel;
private static final long serialVersionUID = 1L;
public UMLWindow() {
addMenus();
panel = new Panel();
}
public void addMenus() {
getContentPane().add(shapeList);
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JMenuItem lineMenuItem = new JMenuItem("New Line");
lineMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("adding line");
shapeList.addLine();
}
});
JMenuBar menubar = new JMenuBar();
menubar.add(lineMenuItem);
setJMenuBar(menubar);
}
}
public static class Shapes extends JPanel {
private static final long serialVersionUID = 1L;
private List<Line2D.Double> lines = new ArrayList<Line2D.Double>();
private Boolean drawing = false;
private Point lineStartingPoint = new Point();
private Point lineEndingPoint = new Point();
private Line2D.Double linePath;
double phi = Math.toRadians(40);
int barb = 20;
public Shapes() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
this.setOpaque(true);
this.setBackground(Color.WHITE); // set canvas color
}
public void addLine() {
drawing = true;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(2));
if (drawing) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(2));
g2.drawLine(lineStartingPoint.x, lineStartingPoint.y,
lineEndingPoint.x, lineEndingPoint.y);
drawArrowHead(g2, lineEndingPoint, lineStartingPoint,
Color.BLACK);
}
for (Line2D line : lines) {
g2.setColor(Color.BLACK);
Point sw = new Point((int) line.getX1(), (int) line.getY1());
Point ne = new Point((int) line.getX2(), (int) line.getY2());
g2.draw(line);
drawArrowHead(g2, ne, sw, Color.BLACK);
}
}
public Rectangle2D drawRect(int x, int y) {
return new Rectangle2D.Double(x - 4, y - 4, 8, 8);
}
private void drawArrowHead(Graphics2D g2, Point tip, Point tail,
Color color) {
g2.setPaint(color);
double dy = tip.y - tail.y;
double dx = tip.x - tail.x;
double theta = Math.atan2(dy, dx);
double x, y, rho = theta + phi;
Point p1 = new Point();
Point p2 = new Point();
p1.setLocation(tip.x - barb * Math.cos(rho), tip.y - barb * Math.sin(rho));
rho = theta - phi;
p2.setLocation(tip.x - barb * Math.cos(rho), tip.y - barb * Math.sin(rho));
int[] xPoints = new int[5];
int[] yPoints = new int[5];
xPoints[0] = tip.x;
xPoints[1] = p1.x;
xPoints[2] = p2.x;
yPoints[0] = tip.y;
yPoints[1] = p1.y;
yPoints[2] = p2.y;
g2.setPaint(Color.BLACK);
Shape shape = new Polygon(xPoints, yPoints, 3);
g2.fill(shape);
//tip.x - barb * Math.cos(rho);
//y = tip.y - barb * Math.sin(rho);
}
class MyMouseAdapter extends MouseAdapter {
int currentIndex;
Point2D.Double startPoint = new Point2D.Double();
Point2D.Double endPoint = new Point2D.Double();
Boolean resizing = false;
@Override
public void mousePressed(MouseEvent e) {
if (drawing) {
lineStartingPoint = e.getPoint();
lineEndingPoint = lineStartingPoint;
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (drawing) {
lineEndingPoint = e.getPoint();
repaint();
System.out.println(lines.size());
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (drawing) {
drawLine(e);
}
drawing = false;
}
@Override
public void mouseMoved(MouseEvent e) {
}
public void drawLine(MouseEvent e) {
drawing = false;
lineEndingPoint = e.getPoint();
linePath = new Line2D.Double(lineStartingPoint.getX(),
lineStartingPoint.getY(), lineEndingPoint.getX(),
lineEndingPoint.getY());
lines.add(linePath);
repaint();
}
}
}
}
Upvotes: 0
Views: 1564
Reputation: 347194
Personally, I would focus on generating the shape and the using the Graphics2D
API to perform the translation and transformation...
The Shape
API makes it really easy to generate complex shapes, for example, this is the diamond shape used in the following example...
public class DiamondShape extends Path2D.Double {
public DiamondShape(int width, int height) {
moveTo(width / 2, 0);
lineTo(width, height / 2);
lineTo(width / 2, height);
lineTo(0, height / 2);
closePath();
}
}
It's short, simple and (for the most part), easy to understand...
"But it needs to rotate" I hear you say, but of course, the Graphics
API provides awesome and simple functionality to achieve that, let it do the heavy lifting. However, if you need to only transform the shape, the Shape
API can do that to (transform the shape itself)
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.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FollowMe {
public static void main(String[] args) {
new FollowMe();
}
public FollowMe() {
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 Point mousePoint;
private DiamondShape head;
public TestPane() {
head = new DiamondShape(10, 20);
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
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;
}
g2d.rotate(Math.toRadians(rotation), width / 2, height / 2);
int x = width / 2;
int y = height / 2;
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.drawLine(x, y, x, y - height / 4);
y -= height / 4 + (head.getBounds().height);
x -= head.getBounds().width / 2;
g2d.fill(head.createTransformedShape(AffineTransform.getTranslateInstance(x, y)));
g2d.dispose();
g2d.dispose();
}
}
public class DiamondShape extends Path2D.Double {
public DiamondShape(int width, int height) {
moveTo(width / 2, 0);
lineTo(width, height / 2);
lineTo(width / 2, height);
lineTo(0, height / 2);
closePath();
}
}
}
Upvotes: 4