does Java 5SE has chaikin function to create smooth graph?
Not that I know of. The smooth curve classes are Arc2D, CubicCurve2D and QuadCurve2D.
is there any example how to use it.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
public class Chaikin {
ChaikinPanel chaikinPanel;
PointGenerator generator;
GraphicController controller;
private JPanel getContent() {
generator = new PointGenerator();
chaikinPanel = new ChaikinPanel(generator);
controller = new GraphicController(chaikinPanel);
chaikinPanel.addMouseListener(controller);
chaikinPanel.addMouseMotionListener(controller);
return chaikinPanel;
}
private JPanel getPointControls() {
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2,2,2,2);
// row 1
final JRadioButton add= new JRadioButton("add", true);
final JRadioButton move= new JRadioButton("move");
final JRadioButton remove = new JRadioButton("remove");
ButtonGroup group = new ButtonGroup();
group.add(add);
group.add(move);
group.add(remove);
ActionListener rbl = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JRadioButton rb = (JRadioButton)e.getSource();
int mode = -1;
if(rb == add)
mode = GraphicController.ADD;
if(rb == move)
mode = GraphicController.MOVE;
if(rb == remove)
mode = GraphicController.REMOVE;
controller.setMode(mode);
}
};
add.addActionListener(rbl);
move.addActionListener(rbl);
remove.addActionListener(rbl);
JButton clear = new JButton("clear");
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
chaikinPanel.clear();
}
});
JPanel topPanel = new JPanel(gridbag);
gbc.weightx = 0;
topPanel.add(new JLabel("points:"), gbc);
gbc.weightx = 1.0;
topPanel.add(add, gbc);
topPanel.add(move, gbc);
topPanel.add(remove, gbc);
topPanel.add(clear, gbc);
// row 2
final JCheckBox curve = new JCheckBox("curve");
final JCheckBox polyline= new JCheckBox("polyline");
final JCheckBox controlPoints = new JCheckBox("control points");
ActionListener cbl = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox)e.getSource();
if(checkBox == curve)
chaikinPanel.setShowCurve(curve.isSelected());
if(checkBox == polyline)
chaikinPanel.setShowPolyline(polyline.isSelected());
if(checkBox == controlPoints)
chaikinPanel.setShowControlPoints(controlPoints.isSelected());
}
};
curve.addActionListener(cbl);
polyline.addActionListener(cbl);
controlPoints.addActionListener(cbl);
// assembly
JPanel panel = new JPanel(gridbag);
gbc.insets = new Insets(0,0,0,0);
gbc.fill = gbc.HORIZONTAL;
gbc.gridwidth = gbc.REMAINDER;
panel.add(topPanel, gbc);
gbc.gridwidth = 1;
gbc.fill = gbc.NONE;
gbc.insets = new Insets(2,2,2,2);
gbc.weightx = 0;
panel.add(new JLabel("display:"), gbc);
gbc.weightx = 1.0;
panel.add(curve, gbc);
panel.add(polyline, gbc);
gbc.gridwidth = gbc.REMAINDER;
panel.add(controlPoints, gbc);
return panel;
}
private JPanel getCurveControls() {
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2,2,2,2);
// row 1
final JRadioButton open= new JRadioButton("open", true);
final JRadioButton closed= new JRadioButton("closed");
final JRadioButton interpolate = new JRadioButton("interpolate");
ButtonGroup group = new ButtonGroup();
group.add(open);
group.add(closed);
group.add(interpolate);
ActionListener rbl = new ActionListener() {
public void actionPerformed(ActionEvent e) {
JRadioButton rb = (JRadioButton)e.getSource();
int style = -1;
if(rb == open)
style = PointGenerator.OPEN;
if(rb == closed)
style = PointGenerator.CLOSED;
if(rb == interpolate)
style = PointGenerator.INTERPOLATE;
generator.setStyle(style);
chaikinPanel.repaint();
}
};
open.addActionListener(rbl);
closed.addActionListener(rbl);
interpolate.addActionListener(rbl);
// row 2
SpinnerNumberModel levelModel = new SpinnerNumberModel(3, 0, 9, 1);
final JSpinner levelSpinner = new JSpinner(levelModel);
SpinnerNumberModel weightModel = new SpinnerNumberModel(3.0, 0, 8.0, 0.1);
final JSpinner weightSpinner = new JSpinner(weightModel);
Dimension d = weightSpinner.getPreferredSize();
d.width = 45;
weightSpinner.setPreferredSize(d);
generator.setLevel(levelModel.getNumber().intValue());
generator.setWeight(weightModel.getNumber().doubleValue());
ChangeListener cl = new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSpinner spinner = (JSpinner)e.getSource();
Object value = spinner.getValue();
if(spinner == levelSpinner)
generator.setLevel( ((Integer)value).intValue() );
if(spinner == weightSpinner)
generator.setWeight( ((Double)value).doubleValue() );
chaikinPanel.repaint();
}
};
levelSpinner.addChangeListener(cl);
weightSpinner.addChangeListener(cl);
JPanel loPanel = new JPanel(gridbag);
gbc.weightx = 0;
loPanel.add(new JLabel("algorithm:"), gbc);
gbc.weightx = 1.0;
addComponents(new JLabel("level"), levelSpinner, loPanel, gbc);
addComponents(new JLabel("weight"), weightSpinner, loPanel, gbc);
// assembly
JPanel panel = new JPanel(gridbag);
gbc.anchor = gbc.CENTER;
gbc.weightx = 0;
panel.add(new JLabel("end points:"), gbc);
gbc.weightx = 1.0;
panel.add(open, gbc);
panel.add(closed, gbc);
gbc.gridwidth = gbc.REMAINDER;
panel.add(interpolate, gbc);
gbc.insets = new Insets(0,0,0,0);
gbc.gridwidth = 4;
gbc.fill = gbc.HORIZONTAL;
panel.add(loPanel, gbc);
return panel;
}
private void addComponents(Component c1, Component c2, Container c,
GridBagConstraints gbc) {
gbc.anchor = gbc.EAST;
c.add(c1, gbc);
gbc.anchor = gbc.WEST;
c.add(c2, gbc);
}
public static void main(String[] args) {
Chaikin chaikin = new Chaikin();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(chaikin.getPointControls(), "First");
f.getContentPane().add(chaikin.getContent());
f.getContentPane().add(chaikin.getCurveControls(), "Last");
f.setSize(500,500);
f.setLocation(515,225);
f.setVisible(true);
}
}
class ChaikinPanel extends JPanel {
PointGenerator pointGenerator;
List<Point2D> polyPoints;
boolean showCurve;
boolean showPolyline;
boolean showControlPoints;
public ChaikinPanel(PointGenerator pg) {
pointGenerator = pg;
polyPoints = new ArrayList<Point2D>();
setBorder(BorderFactory.createEtchedBorder());
showCurve = false;
showPolyline = false;
showControlPoints = false;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if(showPolyline) {
connectPoints(polyPoints.toArray(new Point2D[0]), Color.blue, g2);
}
g2.setPaint(Color.red);
for(Point2D p : polyPoints) {
g2.fill(new Ellipse2D.Double(p.getX()-2, p.getY()-2, 4, 4));
}
if(showCurve) {
Point2D[] points = pointGenerator.getControlPoints();
connectPoints(points, Color.orange, g2);
}
if(showControlPoints) {
g2.setPaint(Color.green.darker());
for(Point2D p : pointGenerator.getControlPoints())
g2.fill(new Ellipse2D.Double(p.getX()-2, p.getY()-2, 4, 4));
}
}
private void connectPoints(Point2D[] points, Color color, Graphics2D g2) {
g2.setPaint(color);
int length = pointGenerator.style == PointGenerator.CLOSED ? points.length
: points.length-1;
for(int j = 0, k; j < length; j++) {
k = (j+1) % points.length;
double x1 = points[j].getX();
double y1 = points[j].getY();
double x2 = points[k].getX();
double y2 = points[k].getY();
g2.draw(new Line2D.Double(x1, y1, x2, y2));
}
}
public void setShowCurve(boolean show) {
showCurve = show;
repaint();
}
public void setShowPolyline(boolean show) {
showPolyline = show;
repaint();
}
public void setShowControlPoints(boolean show) {
showControlPoints = show;
repaint();
}
public void addPoint(Point p) {
polyPoints.add(p);
pointGenerator.generateControlPoints(polyPoints);
repaint();
}
public void movePoint(Point2D p, double x, double y) {
p.setLocation(x, y);
pointGenerator.generateControlPoints(polyPoints);
repaint();
}
public void removePoint(Point2D p) {
polyPoints.remove(p);
pointGenerator.generateControlPoints(polyPoints);
repaint();
}
public void clear() {
polyPoints.clear();
pointGenerator.clear();
repaint();
}
}
class PointGenerator {
Point2D[] controlPoints;
List<Point2D> points;
int level;
double weight;
static final int OPEN= 0;
static final int CLOSED= 1;
static final int INTERPOLATE = 2;
int style = OPEN;
public PointGenerator() {
controlPoints = new Point2D[0];
}
public void generateControlPoints(List<Point2D> points) {
this.points = points;
if(points.size() < 2) {
return;
}
Point2D[] p = points.toArray(new Point2D[0]);
for(int j = 0; j < level; j++) {
p = getLevelPoints(p);
}
controlPoints = p;
}
private Point2D[] getLevelPoints(Point2D[] points) {
int nPoints = 2*(points.length-1);
int index = 0;
switch(style) {
case OPEN:
// default
break;
case CLOSED:
nPoints += 2;
break;
case INTERPOLATE:
nPoints += 2;
index = 1; // skip the first point
}
Point2D[] levelPoints = new Point2D[nPoints];
for(int j = 0, k; j < nPoints/2; j++) {
if(style == INTERPOLATE && j == nPoints/2-1) {
break;// skip the last point
}
k = (j+1) % points.length;
Point2D[] p = getPoints(points[j], points[k]);
levelPoints[index++] = p[0];
levelPoints[index++] = p[1];
}
// add the first and last points
if(style == INTERPOLATE) {
levelPoints[0] = points[0];
levelPoints[levelPoints.length-1] = points[points.length-1];
}
return levelPoints;
}
/**
* Q{i} = P(i)*3/4 + P(i+1)/4
*
* R(i) = P(i)/4 + P(i+1)*3/4
*/
private Point2D[] getPoints(Point2D p1, Point2D p2) {
Point2D[] pts = new Point2D[2];
double dx = p2.getX() - p1.getX();
double dy = p2.getY() - p1.getY();
double x1 = p1.getX() + dx/(1.0+weight);
double y1 = p1.getY() + dy/(1.0+weight);
double x2 = p1.getX() + dx*weight/(1.0+weight);
double y2 = p1.getY() + dy*weight/(1.0+weight);
pts[0] = new Point2D.Double(x1, y1);
pts[1] = new Point2D.Double(x2, y2);
return pts;
}
public Point2D[] getControlPoints() { return controlPoints; }
public void setLevel(int level) {
this.level = level;
if(points != null)
generateControlPoints(points);
}
public void setWeight(double weight) {
this.weight = weight;
if(points != null)
generateControlPoints(points);
}
public void setStyle(int style) {
this.style = style;
generateControlPoints(points);
}
public void clear() {
controlPoints = new Point2D[0];
}
}
class GraphicController extends MouseInputAdapter {
ChaikinPanel chaikinPanel;
Point2D selectedPoint;
Point2D.Double offset;
boolean dragging;
final double MIN_DISTANCE = 5.0;
static final int ADD= 0;
static final int MOVE= 1;
static final int REMOVE = 2;
int mode = ADD;
public GraphicController(ChaikinPanel cp) {
chaikinPanel = cp;
offset = new Point2D.Double();
dragging = false;
}
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
switch(mode) {
case ADD:
chaikinPanel.addPoint(p);
break;
case MOVE:
Point2D target = getTarget(p);
if(target != null) {
selectedPoint = target;
offset.x = p.x - target.getX();
offset.y = p.y - target.getY();
dragging = true;
}
break;
case REMOVE:
target = getTarget(p);
if(target != null)
chaikinPanel.removePoint(target);
break;
default:
System.out.printf("unexpected GraphicController mode %d%n",
mode);
}
}
private Point2D getTarget(Point p) {
Point2D[] points = chaikinPanel.polyPoints.toArray(new Point2D[0]);
for(int j = 0; j < points.length; j++) {
if(points[j].distance(p) < MIN_DISTANCE) {
return points[j];
}
}
return null;
}
public void mouseReleased(MouseEvent e) {
dragging = false;
}
public void mouseDragged(MouseEvent e) {
if(dragging) {
double x = e.getX() - offset.x;
double y = e.getY() - offset.y;
chaikinPanel.movePoint(selectedPoint, x, y);
}
}
public void setMode(int mode) {
this.mode = mode;
}
}