package org.openpnp.machine.reference.camera;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.Action;
import org.openpnp.CameraListener;
import org.openpnp.ConfigurationListener;
import org.openpnp.gui.support.Wizard;
import org.openpnp.machine.reference.ReferenceCamera;
import org.openpnp.machine.reference.wizards.ReferenceCameraConfigurationWizard;
import org.openpnp.model.Configuration;
import org.openpnp.model.Footprint;
import org.openpnp.model.Length;
import org.openpnp.model.LengthUnit;
import org.openpnp.model.Location;
import org.openpnp.model.Part;
import org.openpnp.spi.Head;
import org.openpnp.spi.Machine;
import org.openpnp.spi.MachineListener;
import org.openpnp.spi.Nozzle;
import org.openpnp.spi.PropertySheetHolder;
import org.simpleframework.xml.Root;
@Root
public class SimulatedUpCamera extends ReferenceCamera implements Runnable {
protected int width = 640;
protected int height = 480;
protected int fps = 10;
private Thread thread;
private Map<Nozzle, Part> nozzleParts = new HashMap<>();
private Location offsets = new Location(LengthUnit.Millimeters);
public SimulatedUpCamera() {
setUnitsPerPixel(new Location(LengthUnit.Millimeters, 0.0234375D, 0.0234375D, 0, 0));
Configuration.get().addListener(new ConfigurationListener.Adapter() {
@Override
public void configurationComplete(Configuration configuration) throws Exception {
configuration.getMachine().addListener(machineListener);
}
});
}
@Override
public BufferedImage internalCapture() {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) image.getGraphics();
AffineTransform tx = g.getTransform();
// invert the image in Y so that Y+ is up
g.translate(0, height);
g.scale(1, -1);
g.translate(width / 2, height / 2);
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
// figure out our physical viewport size
Location phySize = getUnitsPerPixel().convertToUnits(LengthUnit.Millimeters).multiply(width,
height, 0, 0);
double phyWidth = phySize.getX();
double phyHeight = phySize.getY();
// and bounds
Location location = getLocation().convertToUnits(LengthUnit.Millimeters);
Rectangle2D.Double phyBounds = new Rectangle2D.Double(location.getX() - phyWidth / 2,
location.getY() - phyHeight / 2, phyWidth, phyHeight);
// determine if there are any nozzles within our bounds and if so render them
for (Head head : Configuration.get().getMachine().getHeads()) {
for (Nozzle nozzle : head.getNozzles()) {
Location l = nozzle.getLocation().convertToUnits(LengthUnit.Millimeters);
if (phyBounds.contains(l.getX(), l.getY())) {
drawNozzle(g, nozzle);
}
}
}
g.setTransform(tx);
g.dispose();
return image;
}
private void drawNozzle(Graphics2D g, Nozzle nozzle) {
// g.setColor(Color.white);
// Location l = nozzle.getLocation().convertToUnits(LengthUnit.Millimeters);
//
// Location upp = getUnitsPerPixel().convertToUnits(LengthUnit.Millimeters);
// Location scale =
// new Location(LengthUnit.Millimeters, 1D / upp.getX(), 1D / upp.getY(), 0, 0);
// l = l.multiply(scale);
//
// g.fillOval((int) (l.getX() - 20), (int) (l.getY() - 20), 40, 40);
g.setStroke(new BasicStroke(1f));
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.white);
Part part = nozzleParts.get(nozzle);
if (part == null) {
return;
}
org.openpnp.model.Package pkg = part.getPackage();
Footprint footprint = pkg.getFootprint();
if (footprint == null) {
return;
}
Shape shape = footprint.getShape();
if (shape == null) {
return;
}
Location upp = getUnitsPerPixel().convertToUnits(LengthUnit.Millimeters);
// Determine the scaling factor to go from Outline units to
// Camera units.
Length l = new Length(1, footprint.getUnits());
l = l.convertToUnits(upp.getUnits());
double unitScale = l.getValue();
// Create a transform to scale the Shape by
AffineTransform tx = new AffineTransform();
// First we scale by units to convert the units and then we scale
// by the camera X and Y units per pixels to get pixel locations.
tx.scale(unitScale, unitScale);
tx.scale(1.0 / upp.getX(), 1.0 / upp.getY());
tx.translate(offsets.getX(), offsets.getY());
// AffineTransform rotates positive clockwise, so we invert the value.
tx.rotate(Math.toRadians(offsets.getRotation()));
// Transform the Shape and draw it out.
shape = tx.createTransformedShape(shape);
g.fill(shape);
}
@Override
public synchronized void startContinuousCapture(CameraListener listener, int maximumFps) {
start();
super.startContinuousCapture(listener, maximumFps);
}
@Override
public synchronized void stopContinuousCapture(CameraListener listener) {
super.stopContinuousCapture(listener);
if (listeners.size() == 0) {
stop();
}
}
private synchronized void stop() {
if (thread != null && thread.isAlive()) {
thread.interrupt();
try {
thread.join();
}
catch (Exception e) {
}
thread = null;
}
}
private synchronized void start() {
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
while (!Thread.interrupted()) {
BufferedImage frame = internalCapture();
broadcastCapture(frame);
try {
Thread.sleep(1000 / fps);
}
catch (InterruptedException e) {
return;
}
}
}
@Override
public Wizard getConfigurationWizard() {
return new ReferenceCameraConfigurationWizard(this);
}
@Override
public String getPropertySheetHolderTitle() {
return getClass().getSimpleName() + " " + getName();
}
@Override
public PropertySheetHolder[] getChildPropertySheetHolders() {
// TODO Auto-generated method stub
return null;
}
private MachineListener machineListener = new MachineListener.Adapter() {
@Override
public void machineHeadActivity(Machine machine, Head head) {
for (Nozzle nozzle : head.getNozzles()) {
Part part = nozzleParts.get(nozzle);
if (part == null || part != nozzle.getPart()) {
nozzleParts.put(nozzle, nozzle.getPart());
Random r = new Random();
offsets = new Location(LengthUnit.Millimeters, Math.random() * 2 - 1,
Math.random() * 2 - 1, 0, Math.random() * 30 - 15);
}
}
}
};
}