package nars.gui.input.image;
import automenta.vivisect.swing.NWindow;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import nars.NAR;
public class SketchPointCloudPanel extends Panel implements MouseListener, MouseMotionListener, ActionListener {
public static void main(String[] args) {
NWindow w = new NWindow("Sketch", new SketchPointCloudPanel(null));
w.setSize(500, 500);
w.setVisible(true);
}
public NAR nar;
static final int GESTURE_PROCESSED = 0;
static final int STROKE_COMPLETE = 2;
static final int STROKE_IN_PROGRESS = 1;
static final String DEFAULT_USER_DEFINED_STRING = "";
int state = GESTURE_PROCESSED;
int _currentStrokeId = 0;
PointCloudLibrary _library = PointCloudLibrary.getDemoLibrary();
ArrayList<PointCloudPoint> _currentGesture = new ArrayList<>();
Label caption = new Label();
Button clearCanvas = new Button();
Button deleteUserDefined = new Button();
Button addUserDefined = new Button();
Button addStandard = new Button();
Button addInput = new Button("Add Input");
TextField userDefinedName = new TextField();
Choice standardNames = new Choice();
String name = "";
double score = 0;
Image offScreen;
Color[] lineColors = new Color[30];
Color defaultColor = Color.WHITE;
Color backColor=new Color(50,50,50);
public SketchPointCloudPanel(NAR nar) {
super(new BorderLayout());
this.nar=nar;
for (int i = 0; i < lineColors.length; i++) {
lineColors[i] = new Color((float) Math.random(), (float) Math.random(), (float) Math.random());
}
String[] s = _library.getNames().toArray(new String[0]);
for (int i = 0; i < s.length; i++) {
standardNames.add(s[i]);
}
setLayout(new BorderLayout());
Panel tempContainer = new Panel();
tempContainer.setLayout(new BorderLayout());
tempContainer.add(caption, BorderLayout.CENTER);
clearCanvas.setLabel("Clear");
clearCanvas.addActionListener(this);
tempContainer.add(addInput,BorderLayout.LINE_START);
caption.setBackground(backColor);
tempContainer.setBackground(backColor);
clearCanvas.setBackground(backColor);
tempContainer.setForeground(Color.WHITE);
clearCanvas.setForeground(Color.WHITE);
addInput.addActionListener(this);
addInput.setBackground(backColor);
addInput.setForeground(Color.WHITE);
deleteUserDefined.setBackground(backColor);
deleteUserDefined.setForeground(Color.WHITE);
tempContainer.add(clearCanvas, BorderLayout.EAST);
add(tempContainer, BorderLayout.NORTH);
tempContainer = new Panel();
tempContainer.setLayout(new GridLayout(3, 1));
Panel veryTempContainer = new Panel();
veryTempContainer.setLayout(new FlowLayout());
//veryTempContainer.add(new Label("Add as example of existing type:"));
//veryTempContainer.add(standardNames);
//addStandard.setLabel("Add");
//addStandard.setEnabled(false);
// addStandard.addActionListener(this);
//veryTempContainer.add(addStandard);
// veryTempContainer.add(addInput);
//tempContainer.add(veryTempContainer);
veryTempContainer = new Panel();
veryTempContainer.setLayout(new FlowLayout());
veryTempContainer.add(new Label("Add as example of type:"));
veryTempContainer.setForeground(Color.WHITE);
veryTempContainer.setBackground(backColor);
userDefinedName.setColumns(10);
userDefinedName.setText(DEFAULT_USER_DEFINED_STRING);
veryTempContainer.add(userDefinedName);
userDefinedName.setBackground(Color.BLACK);
userDefinedName.setForeground(Color.WHITE);
addUserDefined.setLabel("Add");
//addUserDefined.setEnabled(false);
addUserDefined.addActionListener(this);
addUserDefined.setForeground(Color.WHITE);
addUserDefined.setBackground(backColor);
veryTempContainer.add(addUserDefined);
tempContainer.add(veryTempContainer);
veryTempContainer = new Panel();
veryTempContainer.setLayout(new FlowLayout());
veryTempContainer.add(new Label("Delete all types:"));
veryTempContainer.add(new Label(" "));
veryTempContainer.setBackground(backColor);
veryTempContainer.setForeground(Color.WHITE);
deleteUserDefined.setLabel("Delete");
deleteUserDefined.addActionListener(this);
veryTempContainer.add(deleteUserDefined);
tempContainer.add(veryTempContainer);
add(tempContainer, BorderLayout.SOUTH);
resize(400, 400);
offScreen = createImage(getSize().width, getSize().height);
addMouseListener(this);
addMouseMotionListener(this);
}
public String lastdrawing="";
public String drawing="";
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearCanvas) {
clearCanvas();
return;
}
if(e.getSource() == addInput && !drawing.equals("")) {
nar.addInput("<"+drawing.replace(" ","-")+" --> drawn>. :|:");
if(lastdrawing!=null && !lastdrawing.equals("")) {
if(Math.abs(coordx-lastcoordx)>10) {
String direction=coordx-lastcoordx > 0 ? "left" : "right";
String opdirection=coordx-lastcoordx > 0 ? "right" : "left";
nar.addInput("<(*,"+drawing.replace(" ","-")+","+lastdrawing.replace(" ","-")+") --> "+direction+">. :|:");
nar.addInput("<(*,"+lastdrawing.replace(" ","-")+","+drawing.replace(" ","-")+") --> "+opdirection+">. :|:");
}
if(Math.abs(coordy-lastcoordy)>10) {
String direction=coordy-lastcoordy > 0 ? "up" : "down";
String opdirection=coordy-lastcoordy > 0 ? "down" : "up";
nar.addInput("<(*,"+drawing.replace(" ","-")+","+lastdrawing.replace(" ","-")+") --> "+direction+">. :|:");
nar.addInput("<(*,"+lastdrawing.replace(" ","-")+","+drawing.replace(" ","-")+") --> "+opdirection+">. :|:");
}
}
nar.step(1);
}
if (e.getSource() == deleteUserDefined) {
_library.clear();
caption.setText("All user defined gestures have been cleared");
return;
}
if (e.getSource() == addStandard) {
String name = standardNames.getSelectedItem();
_library.addPointCloud(new PointCloud(name, _currentGesture));
caption.setText("Gesture added as additional version of " + name);
return;
}
if (e.getSource() == addUserDefined) {
drawing="";
String name = userDefinedName.getText();
if (name.equals(DEFAULT_USER_DEFINED_STRING)) {
caption.setText("You must enter a name for the gesture");
} else {
_library.addPointCloud(new PointCloud(name, _currentGesture));
caption.setText("Gesture added with name " + name);
userDefinedName.setText(DEFAULT_USER_DEFINED_STRING);
}
return;
}
}
private void clearCanvas() {
_currentGesture = new ArrayList<>();
_currentStrokeId = 0;
caption.setText("");
addUserDefined.setEnabled(false);
addStandard.setEnabled(false);
repaint();
coordx=0;
coordy=0;
lastcoordx=-1;
lastcoordy=-1;
lastdrawing="";
}
public void mouseEntered(MouseEvent e) //mouse entered canvas
{
}
public void mouseExited(MouseEvent e) //mouse left canvas
{
}
public void mouseClicked(MouseEvent e) //mouse pressed-depressed (no motion in between), if there's motion -> mouseDragged
{
if(e.getButton()==MouseEvent.BUTTON3) {
_currentStrokeId++;
}
if(e.getButton()==MouseEvent.BUTTON2) {
_currentStrokeId++;
}
}
public void update(MouseEvent e) {
// if(e.getX()<coordx) {
coordx=e.getX();
coordy=e.getY();
// }
PointCloudPoint p = new PointCloudPoint(e.getX(), e.getY(), _currentStrokeId);
_currentGesture.add(p);
repaint();
e.consume();
}
int coordx=0;
int coordy=0;
int lastcoordx=-1;
int lastcoordy=-1;
public void mousePressed(MouseEvent e) {
int button = e.getButton();
switch (button) {
case MouseEvent.BUTTON1: {
if (state == GESTURE_PROCESSED) {
//_currentGesture = new ArrayList<PointCloudPoint>();
lastcoordx=coordx;
lastcoordy=coordy;
coordx=0;
coordy=0;
}
state = STROKE_IN_PROGRESS;
caption.setForeground(lineColors[_currentStrokeId]);
caption.setText("Capturing stroke: " + (_currentStrokeId + 1));
update(e);
return;
}
case MouseEvent.BUTTON3: {
_currentStrokeId++;
if (state != STROKE_COMPLETE) {
return;
}
PointCloud c = new PointCloud("input gesture", _currentGesture);
ArrayList<PointCloudPoint> pts = c.getPoints();
PointCloudMatchResult r = _library.originalRecognize(c);
name = r.getName();
score = r.getScore();
caption.setForeground(defaultColor);
caption.setText("Result: " + name + " (" + round(score, 2) + ")");
lastdrawing=drawing;
drawing=name;
state = GESTURE_PROCESSED;
_currentStrokeId = 0;
addUserDefined.setEnabled(true);
addStandard.setEnabled(true);
_currentStrokeId++;
return;
}
default: {
_currentStrokeId++;
return;
}
}
}
public void mouseReleased(MouseEvent e) {
int button = e.getButton();
_currentStrokeId++;
switch (button) {
case MouseEvent.BUTTON1: {
state = STROKE_COMPLETE;
caption.setForeground(lineColors[_currentStrokeId]);
caption.setText("Stroke " + (_currentStrokeId + 1) + " recorded");
update(e);
return;
}
default: {
_currentStrokeId++;
return;
}
}
}
public void mouseMoved(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
state = STROKE_IN_PROGRESS;
update(e);
if(e.getButton()==MouseEvent.BUTTON3 || e.getButton()==MouseEvent.BUTTON2)
_currentStrokeId++;
}
public void paint(Graphics _g) {
Graphics2D g = (Graphics2D)_g;
int pointCount = _currentGesture.size();
if (pointCount < 2) {
return;
}
int lineColorIndex = 0;
g.setColor(lineColors[lineColorIndex]);
g.setStroke(new BasicStroke(4));
for (int i = 0; i < pointCount - 1; i++) {
PointCloudPoint p1 = _currentGesture.get(i);
PointCloudPoint p2 = _currentGesture.get(i + 1);
if (p1.getID() == p2.getID()) {
g.drawLine((int) p1.getX(), (int) p1.getY(), (int) p2.getX(), (int) p2.getY());
//g.drawOval((int) p1.getX(), (int) p1.getY(), 4, 4); //only works like this, others one creates a wrong line
} else {
i++;
g.setColor(lineColors[++lineColorIndex]);
continue;
}
}
}
private double round(double n, double d) // round 'n' to 'd' decimals
{
d = Math.pow(10, d);
return Math.round(n * d) / d;
}
}