📄 curveapplet.java
字号:
// Chapter 18 Exercise 6
/*
Most of the work was done in the previous exercise solution. Here, all we need
to do is ensure that moving markers does not make the curve discontinuous.
When a control marker is moved, we need to ensure that the control markers either
side of a defining point remain be the same distance from the defining point
and the control markers and the defining point are collinear.
When a defining point is moved, we must ensure that the control markers that apply
to the segment(s) either side of the point are moved the same distance.
One limitation on function here is that you can't change the first or last control
points because they are hidden by the defining points. A simple send-to-back
operation would fix this though.
*/
import javax.swing.JApplet;
import javax.swing.JComponent;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.event.MouseInputAdapter;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.BorderFactory;
import javax.swing.border.EtchedBorder;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.util.Vector;
public class CurveApplet extends JApplet {
// Initialize the applet
public void init() {
pane = new CurvePane(); // Create pane containing curves
Container content = getContentPane(); // Get the content pane
// Add the pane displaying the curves to the content pane for the applet
content.add(pane); // BorderLayout.CENTER is default position
MouseHandler handler = new MouseHandler(); // Create the listener
pane.addMouseListener(handler); // Monitor mouse button presses
pane.addMouseMotionListener(handler); // as well as movement
// Create the panel to hold the buttons
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout());
buttonPane.setBackground(Color.DARK_GRAY);
buttonPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED,
Color.BLUE,
Color.CYAN));
// Create and add the button to clear the display
JButton button = new JButton("Clear Pane");
button.setBorder(BorderFactory.createRaisedBevelBorder());
button.addActionListener(new ActionListener(){ // Action listener for the button
public void actionPerformed(ActionEvent e) {
clearPane();
}
});
buttonPane.add(button);
// Create and add the button to end the definition of the curve
button = new JButton("End Curve");
button.setBorder(BorderFactory.createRaisedBevelBorder());
button.addActionListener(new ActionListener(){ // Action listener for the button
public void actionPerformed(ActionEvent e) {
curveComplete = true;
pane.repaint();
}
});
buttonPane.add(button);
content.add(buttonPane, BorderLayout.SOUTH);
}
// Method to clear the screen ready for a new set of points
private void clearPane() {
pointMarkers = new Vector(); // Remove the point markers
curveSegments = null; // and the array of curve segments
curveComplete = false; // Reset curve complete flag
repaint();
}
private void createCurves() {
// Create the curves
int n = pointMarkers.size();
Point2D.Double[] points = new Point2D.Double[n];
// Extract the points from the vector of Marker objects
for(int i = 0 ; i<n ; i++)
points[i] = ((Marker)(pointMarkers.elementAt(i))).getCenter();
int m = (n - 2); // Number of coeffients for calculating control vectors
double[] f = new double[m+1]; // Array used to calculate coefficients, a
f[0] = 1.0;
f[1] = -4 + n%2 ; // -3 when n is odd and -4 when n is even
for(int j = 2 ; j<f.length ; j++)
f[j] = -4.0*f[j-1] - f[j-2];
// Calculate the coefficients. This array could be limited to 5 elements
// since the values of elements of a beyond a[4] are very small.
double[] a = new double[m];
double factor = 1.0/f[f.length-1];
for(int j = 0 ; j<a.length ; j++)
a[j] = -f[m-j-1]*factor;
// Calculate control vectors, one for each point. The control points
// for the curve are calculated by adding and/or subtracting the control
// vector from the corresponding curve point.
controlVec = new Point2D.Double[n];
controlVec[0] = new Point2D.Double(0.0, 0.0);
controlVec[n-1] = controlVec[0];
for(int i = 1 ; i<n-1; i++) {
double x = 0.0;
double y = 0.0;
int n1 = 0;
int n2 = 0;
for(int k = 0 ; k<a.length ; k++) {
n1 = (i+k+1)%n;
n2 = Math.abs(i-k-1);
x += a[k]*(points[n1].x - points[n2].x);
y += a[k]*(points[n1].y - points[n2].y);
}
controlVec[i] = new Point2D.Double(x, y);
}
// Define the curve segments using the defining points and control points
// created using the vectors in the controlVec array
curveSegments = new CubicCurve2D.Double[n-1];
controlMarkers = new Marker[2*curveSegments.length];
Point2D.Double controlPt1 = null;
Point2D.Double controlPt2 = null;
int j = 0;
for(int i = 0 ; i<curveSegments.length; i++) {
curveSegments[i] = new CubicCurve2D.Double();
controlPt1 = new Point2D.Double(points[i].x+controlVec[i].x,
points[i].y+controlVec[i].y);
controlPt2 = new Point2D.Double(points[i+1].x-controlVec[i+1].x,
points[i+1].y-controlVec[i+1].y);
curveSegments[i].setCurve(points[i], controlPt1, controlPt2, points[i+1]);
controlMarkers[j++] = new Marker(controlPt1, Color.RED);
controlMarkers[j++] = new Marker(controlPt2, Color.RED);
}
}
// Class defining a pane on which to draw
class CurvePane extends JComponent {
// Constructor
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D)g; // Get a 2D device context
// If there are any curves, draw them in green
if(curveSegments != null) {
g2D.setColor(Color.GREEN);
for (int i = 0; i<curveSegments.length ; i++)
g2D.draw(curveSegments[i]);
}
// Draw the point markers
for(int i = 0 ; i<pointMarkers.size() ; i++) {
((Marker)(pointMarkers.elementAt(i))).draw(g2D);
}
// If the curve is finished, draw the control markers and tangents
if(curveComplete) {
for(int i = 0 ; i<controlMarkers.length ; i++)
controlMarkers[i].draw(g2D);
// Draw the tangent lines
Line2D.Double tangent = null;
g2D.setColor(Color.RED);
for(int i = 0 ; i<curveSegments.length ; i++) {
tangent = new Line2D.Double(curveSegments[i].getP1(),curveSegments[i].getCtrlP1());
g2D.draw(tangent);
tangent = new Line2D.Double(curveSegments[i].getP2(),curveSegments[i].getCtrlP2());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -