org.metacsp.utility.UI.PolygonFrame Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of meta-csp-framework Show documentation
Show all versions of meta-csp-framework Show documentation
A Java API for Meta-CSP based reasoning
package org.metacsp.utility.UI;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
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.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;
import java.util.Vector;
import javax.naming.ldap.HasControls;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.metacsp.framework.Constraint;
import org.metacsp.framework.ConstraintNetwork;
import org.metacsp.framework.ConstraintNetworkChangeEvent;
import org.metacsp.framework.ConstraintNetworkChangeListener;
import org.metacsp.framework.Variable;
import org.metacsp.spatial.geometry.GeometricConstraint;
import org.metacsp.spatial.geometry.Polygon;
import org.metacsp.spatial.geometry.Vec2;
public class PolygonFrame extends JFrame implements ConstraintNetworkChangeListener {
private static final long serialVersionUID = 7979735587935134767L;
private final Dimension dim = new Dimension(1024, 768);
private float zoom;
private float zoomInv;
private float deltaX = 0.0f;
private float deltaY = 0.0f;
private float xSpan = 0.0f;
private float ySpan = 0.0f;
private int paddingPixels = 20;
private int originX = 0;
private int originY = 0;
private float canvasStartX;
private float canvasStartY;
private float canvasEndX;
private float canvasEndY;
private HashMap colors = new HashMap();
private HashMap centers = new HashMap();
private HashMap drawablePolys = new HashMap();
private Variable[] polys;
private Constraint[] cons;
private ConstraintNetwork cn;
// private class Pair {
// public Variable from, to;
// public Constraint con;
// public Pair(Variable from, Variable to, Constraint con) {
// this.from = from;
// this.to = to;
// this.con = con;
// }
// public boolean equals(Object o) {
// return ((this.from.equals(((Pair)o).from) && this.to.equals(((Pair)o).to)) || (this.from.equals(((Pair)o).to) && this.to.equals(((Pair)o).from)));
// }
// public int hashCode() {
// return this.from.hashCode() + this.toString().hashCode();
// }
// }
private int[] toScreen(float x, float y) {
// |------ 1024 ------|
//dim.x:spanX=input.x:output.x -> output.x = spanX*input.x/dim.x*
int[] ret = new int[2];
// ret[0] = Math.round(this.zoomInv*xSpan*(x-deltaX+paddingPixels)/dim.width);
// ret[1] = Math.round(this.zoomInv*ySpan*(y-deltaY+paddingPixels)/dim.height);
ret[0] = Math.round(this.zoomInv*(x-deltaX)+paddingPixels);
ret[1] = Math.round(this.zoomInv*(y-deltaY)+paddingPixels);
return ret;
}
private void initialize() {
this.polys = cn.getVariables();
this.cons = cn.getConstraints();
float maxX = Integer.MIN_VALUE;
float minX = Integer.MAX_VALUE;
float maxY = Integer.MIN_VALUE;
float minY = Integer.MAX_VALUE;
for (Variable p : polys) {
if (!((Polygon)p).hasDefaultDomain()) {
Vector vertices = ((Polygon)p).getFullSpaceRepresentation();
for (int i = 0; i < vertices.size(); i++) {
if (vertices.get(i).x > maxX) maxX = vertices.get(i).x;
if (vertices.get(i).y > maxY) maxY = vertices.get(i).y;
if (vertices.get(i).x < minX) minX = vertices.get(i).x;
if (vertices.get(i).y < minY) minY = vertices.get(i).y;
}
}
}
deltaX = minX;
deltaY = minY;
xSpan = Math.abs(maxX-minX);
ySpan = Math.abs(maxY-minY);
canvasStartX = minX;
canvasStartY = minY;
canvasEndX = maxX;
canvasEndY = maxY;
zoom = (float)xSpan/(float)dim.getWidth()*3.0f;
zoomInv = 1/zoom;
}
private void updatePositions() {
Random rand = new Random(1231234);
for (Variable p : polys) {
if (!((Polygon)p).hasDefaultDomain()) {
Vector vertices = ((Polygon)p).getFullSpaceRepresentation();
int[] xCoords = new int[vertices.size()];
int[] yCoords = new int[vertices.size()];
for (int i = 0; i < vertices.size(); i++) {
int[] screenCoords = toScreen(vertices.get(i).x, vertices.get(i).y);
xCoords[i] = screenCoords[0];
yCoords[i] = screenCoords[1];
}
centers.put(((Polygon)p),toScreen(((Polygon)p).getPosition().x,((Polygon)p).getPosition().y));
java.awt.Polygon drawablePoly = new java.awt.Polygon(xCoords, yCoords, xCoords.length);
drawablePolys.put(((Polygon)p),drawablePoly);
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
colors.put(((Polygon)p),new Color(r,g,b));
}
}
}
private void updatePolygonFrame() {
initialize();
repaint();
}
public PolygonFrame(String title, ConstraintNetwork constraintNetwork) {
this.setResizable(true);
this.setTitle(title);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.cn = constraintNetwork;
initialize();
this.cn.addConstraintNetworkChangeListener(this);
this.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent arg0) { }
@Override
public void mouseDragged(MouseEvent arg0) {
//java.awt.Point pStart = arg0.getPoint();
deltaX += (originX-arg0.getX())*zoom;
deltaY += (originY-arg0.getY())*zoom;
originX = arg0.getX();
originY = arg0.getY();
repaint();
}
});
this.addMouseWheelListener(new MouseWheelListener() {
@Override
public void mouseWheelMoved(MouseWheelEvent arg0) {
int rot = arg0.getWheelRotation();
zoom += (0.001*rot);
zoomInv = 1/zoom;
repaint();
}
});
this.addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent arg0) { }
@Override
public void mousePressed(MouseEvent arg0) {
originX = arg0.getX();
originY = arg0.getY();
}
@Override
public void mouseExited(MouseEvent arg0) { }
@Override
public void mouseEntered(MouseEvent arg0) { }
@Override
public void mouseClicked(MouseEvent arg0) { }
});
JPanel p = new JPanel() {
private static final long serialVersionUID = 8429745665836985179L;
//private final int ARR_SIZE = 16;
private final float eccentricityStep = 1.8f;
//Draw arrows
private void drawArrow(Graphics g1, int x1, int y1, int x2, int y2, String label, int num) {
Graphics2D g = (Graphics2D) g1.create();
g.setStroke(new BasicStroke(2));
g.setColor(new Color(0.6f,0.6f,0.6f));
double dx = x2 - x1, dy = y2 - y1;
double angle = Math.atan2(dy, dx);
int len = (int) Math.sqrt(dx*dx + dy*dy);
AffineTransform at = AffineTransform.getTranslateInstance(x1, y1);
at.concatenate(AffineTransform.getRotateInstance(angle));
g.transform(at);
g.setColor(new Color(0.6f,0.6f,0.6f));
java.awt.Point startP = new java.awt.Point(0, 0);
java.awt.Point endP = new java.awt.Point(len, 0);
CurvedArrow ca = new CurvedArrow(startP,endP,num*eccentricityStep);
ca.label = label;
ca.draw(g);
// g.setColor(new Color(0.6f,0.6f,0.6f));
// // Draw horizontal arrow starting in (0, 0)
// g.drawLine(0, 0, len, 0);
// g.fillPolygon(new int[] {len, len-ARR_SIZE, len-ARR_SIZE, len}, new int[] {0, -ARR_SIZE/3, ARR_SIZE/3, 0}, 4);
// g.setFont(new Font("default", Font.BOLD, 16));
// int stringLen = (int)g.getFontMetrics().getStringBounds(label, g).getWidth();
// g.drawString(label, len/2-stringLen/2, -6);
}
private void drawGrid(Graphics g1) {
Graphics2D g = (Graphics2D) g1.create();
g.setStroke(new BasicStroke(1.0f));
g.setColor(new Color(0.7f,0.7f,0.7f));
DecimalFormat df = new DecimalFormat("#.#");
float positionX = canvasStartX;
// System.out.println("StartX = " + canvasStartX);
float interval = xSpan/10.0f;
while(positionX <= canvasEndX+interval) {
int[] p1 = toScreen(positionX,canvasStartY);
int[] p2 = toScreen(positionX,canvasEndY+interval);
g.drawLine(p1[0], p1[1], p2[0], p2[1]);
g.setFont(new Font("default", Font.BOLD, 8));
String label = df.format(positionX);
int stringLen = (int)g.getFontMetrics().getStringBounds(label, g).getWidth();
int stringHeight = (int)g.getFontMetrics().getStringBounds(label, g).getHeight();
g.drawString(label, p1[0]-stringLen/2, p1[1]-stringHeight);
positionX += interval;
}
float positionY = canvasStartY;
while(positionY <= canvasEndY+interval) {
int[] p1 = toScreen(canvasStartX,positionY);
int[] p2 = toScreen(canvasEndX+interval,positionY);
g.drawLine(p1[0], p1[1], p2[0], p2[1]);
g.setFont(new Font("default", Font.BOLD, 8));
String label = df.format(positionY);
int stringLen = (int)g.getFontMetrics().getStringBounds(label, g).getWidth();
int stringHeight = (int)g.getFontMetrics().getStringBounds(label, g).getHeight();
g.drawString(label, p2[0]+stringLen/2, p2[1]+stringHeight/2);
positionY += interval;
}
}
private void drawPolygon(Graphics g, Polygon p) {
g.setColor(colors.get(p));
((Graphics2D)g).setStroke(new BasicStroke(5));
java.awt.Polygon toDraw = drawablePolys.get(p);
if (toDraw != null) g.drawPolygon(toDraw);
g.setFont(new Font("default", Font.BOLD, 16));
if (p != null && centers != null && centers.containsKey(p) && centers.get(p) != null && centers.get(p).length == 2) g.drawString(p.getComponent(), centers.get(p)[0], centers.get(p)[1]);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Compute positions of all polys
updatePositions();
//Draw grid on top
drawGrid(g);
//Draw polys
for (Variable p : polys) if (!((Polygon)p).hasDefaultDomain()) drawPolygon(g, (Polygon)p);
//Draw arrows
Random rand = new Random(125534);
for (Constraint con : cons) {
Polygon from = (Polygon)((GeometricConstraint)con).getFrom();
Polygon to = (Polygon)((GeometricConstraint)con).getTo();
drawArrow(g, centers.get(from)[0], centers.get(from)[1], centers.get(to)[0], centers.get(to)[1], con.getEdgeLabel(), rand.nextInt(10));
}
}
@Override
public Dimension getPreferredSize() {
return dim;
}
};
this.add(p);
this.pack();
this.setVisible(true);
}
@Override
public void stateChanged(ConstraintNetworkChangeEvent event) {
updatePolygonFrame();
}
}