package org.openpnp.vision.experiments; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.geom.AffineTransform; import java.util.Random; import javax.swing.JComponent; import javax.swing.JFrame; import org.openpnp.model.Board; import org.openpnp.model.LengthUnit; import org.openpnp.model.Location; import org.openpnp.model.Point; import org.openpnp.util.HslColor; import org.openpnp.util.Utils2D; public class BottomVisionTest extends JComponent { private static final Random random = new Random(0xdeadbeef); Location boardLocation = new Location(LengthUnit.Millimeters, 500, 350, 0, 15); Location placementLocation = new Location(LengthUnit.Millimeters, 50, 50, 0, 20); Location bottomVisionOffsets = new Location(LengthUnit.Millimeters, 30, 30, 0, 10); Location nozzleLocation = calculateNozzlePosition(boardLocation, placementLocation, bottomVisionOffsets); int partSize = 50; public BottomVisionTest() { addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { Random r = new Random(); boardLocation = new Location( LengthUnit.Millimeters, rand(200, 600), rand(100, 500), 0, rand(0, 90)); placementLocation = new Location( LengthUnit.Millimeters, rand(10, 100), rand(10, 100), 0, rand(0, 90)); bottomVisionOffsets = new Location( LengthUnit.Millimeters, rand(10, 100), rand(10, 100), 0, rand(0, 45)); nozzleLocation = calculateNozzlePosition(boardLocation, placementLocation, bottomVisionOffsets); repaint(); } }); addMouseMotionListener(new MouseAdapter() { @Override public void mouseDragged(MouseEvent e) { nozzleLocation = nozzleLocation.derive((double) e.getX(), (double) (getHeight() - e.getY()), 0d, null); System.out.println(nozzleLocation); repaint(); } }); addMouseWheelListener(new MouseWheelListener() { @Override public void mouseWheelMoved(MouseWheelEvent e) { nozzleLocation = nozzleLocation.subtractWithRotation(new Location(LengthUnit.Millimeters, 0, 0, 0, e.getWheelRotation() * 0.1)); System.out.println(nozzleLocation); repaint(); } }); } private static int rand(int min, int max) { return random.nextInt(max) + min; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; AffineTransform tx = g2d.getTransform(); g2d.translate(0, getHeight()); g2d.scale(1, -1); g2d.setColor(new Color(0.9f, 0.9f, 0.9f)); g2d.fillRect(0, 0, getWidth(), getHeight()); g2d.setColor(new Color(0.8f, 0.8f, 0.8f)); // draw horizontal lines for (int y = 0; y < getHeight(); y += 10) { g2d.drawLine(0, y, getWidth(), y); } // draw vertical lines for (int x = 0; x < getWidth(); x += 10) { g2d.drawLine(x, 0, x, getHeight()); } g2d.setStroke(new BasicStroke(2)); // do work drawBoard(g2d); drawNozzle(g2d, nozzleLocation, Color.orange); // end work g2d.setTransform(tx); } private static Location calculateNozzlePosition(Location boardLocation, Location placementLocation, Location bottomVisionOffsets) { // The calculated global placement location Location placementFinalLocation = Utils2D.calculateBoardPlacementLocation(boardLocation, Board.Side.Top, 0, placementLocation); // Rotate the point 0,0 using the bottom offsets as a center point by the angle that is // the difference between the bottom vision angle and the calculated global placement angle. Location location = new Location(LengthUnit.Millimeters).rotateXyCenterPoint( bottomVisionOffsets, placementFinalLocation.getRotation() - bottomVisionOffsets.getRotation()); // Set the angle to the difference mentioned above, aligning the part to the same angle as // the placement. location = location.derive(null, null, null, placementFinalLocation.getRotation() - bottomVisionOffsets.getRotation()); // Add the placement final location to move our local coordinate into global space location = location.add(placementFinalLocation); // Subtract the bottom vision offsets to move the part to the final location, instead of // the nozzle. location = location.subtract(bottomVisionOffsets); return location; } private void drawBoard(Graphics2D g) { AffineTransform tx = g.getTransform(); // draw the board location drawCrossHair(g, boardLocation, Color.green); g.translate(boardLocation.getX(), boardLocation.getY()); g.rotate(Math.toRadians(boardLocation.getRotation())); // draw the placement location drawCrossHair(g, placementLocation, Color.white); drawRectangle(g, placementLocation, partSize, partSize, Color.red); g.setTransform(tx); } private void drawNozzle(Graphics2D g, Location location, Color color) { AffineTransform tx = g.getTransform(); // draw the nozzle drawCrossHair(g, location, color); drawCircle(g, location, partSize, color); g.translate(location.getX(), location.getY()); g.rotate(Math.toRadians(location.getRotation())); // draw the part drawCrossHair(g, bottomVisionOffsets, new HslColor(color).getComplementary()); drawRectangle(g, bottomVisionOffsets, partSize, partSize, new HslColor(color).getComplementary()); g.setTransform(tx); } private void drawCircle(Graphics2D g, Location location, double diameter, Color color) { g.setColor(color); double x = location.getX(); double y = location.getY(); g.drawArc((int) (x - diameter / 2), (int) (y - diameter / 2), (int) diameter, (int) diameter, 0, 360); } private void drawCrossHair(Graphics2D g, Location location, Color color) { int size = 20; Point p1; Point p2; g.setColor(color); p1 = Utils2D.rotatePoint(new Point(-size, 0), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(size, 0), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); p1 = Utils2D.rotatePoint(new Point(0, -size), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(0, size), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); g.setColor(Color.red); p1 = Utils2D.rotatePoint(new Point(0, size), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(0, 0), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); } private void drawRectangle(Graphics2D g, Location location, double width, double height, Color color) { g.setColor(color); Point p1, p2; p1 = Utils2D.rotatePoint(new Point(-width / 2, height / 2), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(width / 2, height / 2), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); p1 = Utils2D.rotatePoint(new Point(width / 2, height / 2), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(width / 2, -height / 2), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); p1 = Utils2D.rotatePoint(new Point(width / 2, -height / 2), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(-width / 2, -height / 2), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); p1 = Utils2D.rotatePoint(new Point(-width / 2, -height / 2), location.getRotation()); p2 = Utils2D.rotatePoint(new Point(-width / 2, height / 2), location.getRotation()); g.drawLine((int) (location.getX() + p1.getX()), (int) (location.getY() + p1.getY()), (int) (location.getX() + p2.getX()), (int) (location.getY() + p2.getY())); } public static void main(String[] args) throws Exception { JFrame frame = new JFrame("Bottom Vision Test"); frame.setSize(1024, 768); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().setLayout(new BorderLayout()); frame.getContentPane().add(new BottomVisionTest()); frame.setVisible(true); } }