Note: A parametric curve is a curve defined by a parametric equation, which is a method for defining a relation among parameters. For example, a parabola that is conventionally expressed as y = x^2 can be expressed parametrically as x = t; y = t^2, where t is a parameter that takes on any value.
|
java.awt.geom.QuadCurve2D's inner Double or Float subclass via one of the following
constructors:
QuadCurve2D.Double(double x1, double y1, double ctrlx,
double ctrly, double x2, double y2)
QuadCurve2D.Float(float x1, float y1, float ctrlx,
float ctrly, float x2, float y2)
For either constructor, (x1, y1) defines the start point, (x2, y2) defines the end point, and (ctrlx, ctrly) defines the control point. If you prefer to create a curve where all three points are initialized to zero, call the QuadCurve2D.Double() or QuadCurve2D.Float() constructor.
Invoke QuadCurve2D.Double's void setCurve(double x1, double y1, double ctrlx, double ctrly, double x2, double y2) or QuadCurve2D.Float's void setCurve(float x1, float y1, float ctrlx, float ctrly, float x2, float y2) method to redefine the curve with new points.
| Note: Each subclass also provides various getter methods for returning the values of the various points. |
Listing 1 presents the source code to an applet that demonstrates quadratic curve creation and manipulation.
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.geom.QuadCurve2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class QuadCurveDemo extends Applet
{
// Number of anchors (square rectangles) that are centered under the
// curve's start, control, and end points.
final static int NANCHORS = 3;
// Initial start, control, and end point values.
final static double ISX = 50.0;
final static double ISY = 30.0;
final static double ICX = 100.0;
final static double ICY = 260.0;
final static double IEX = 250.0;
final static double IEY = 260.0;
// Anchor width and height. Each value must be an odd number.
final static double AWIDTH = 7.0;
final static double AHEIGHT = 7.0;
Rectangle2D.Double[] anchors;
QuadCurve2D curve = new QuadCurve2D.Double(ISX, ISY, ICX, ICY, IEX, IEY);
boolean[] inDrag = new boolean[] {false, false, false};
int dragIndex = -1, dragX, dragY;
Graphics bg;
Image imBuffer;
@Override
public void init()
{
// Setup a background buffer and obtain its graphics context to achieve
// double buffering.
imBuffer = createImage(getWidth(), getHeight());
bg = imBuffer.getGraphics();
anchors = new Rectangle2D.Double[NANCHORS];
// Specify the start anchor such that it's centered around initial start
// point (ISX, ISY).
anchors[0] = new Rectangle2D.Double(ISX-AWIDTH/2, ISY-AHEIGHT/2,
AWIDTH, AHEIGHT);
// Specify the control anchor such that it's centered around initial
// control point (ICX, ICY).
anchors[1] = new Rectangle2D.Double(ICX-AWIDTH/2, ICY-AHEIGHT/2,
AWIDTH, AHEIGHT);
// Specify the end anchor such that it's centered around initial end
// point (IEX, IEY).
anchors[2] = new Rectangle2D.Double(IEX-AWIDTH/2, IEY-AHEIGHT/2,
AWIDTH, AHEIGHT);
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent me)
{
for (int i = 0; i < NANCHORS; i++)
if (anchors[i].contains(me.getX(), me.getY()))
{
dragIndex = i;
// Obtain mouse coordinates at the start of
// the drag for use in calculating a
// displacement that's used to offset an
// anchor's upper-left corner.
dragX = me.getX();
dragY = me.getY();
return;
}
}
public void mouseReleased(MouseEvent me)
{
dragIndex = -1;
}
});
addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged(MouseEvent me)
{
if (dragIndex == -1)
return;
// Calculate new location of dragged
// anchor.
double x = anchors[dragIndex].getX()+
me.getX()-dragX;
double y = anchors[dragIndex].getY()+
me.getY()-dragY;
anchors[dragIndex].setRect(x, y, AWIDTH,
AHEIGHT);
// Reposition curve in accordance with
// modified anchor such that the affected
// curve start, control, or end point is
// located at the center of the anchor.
curve.setCurve(anchors[0].getX()+
AWIDTH/2,
anchors[0].getY()+
AHEIGHT/2,
anchors[1].getX()+
AWIDTH/2,
anchors[1].getY()+
AHEIGHT/2,
anchors[2].getX()+
AWIDTH/2,
anchors[2].getY()+
AHEIGHT/2);
repaint();
dragX = me.getX();
dragY = me.getY();
}
});
}
@Override
public void paint(Graphics g)
{
bg.setColor(Color.WHITE);
bg.fillRect(0, 0, getWidth(), getHeight());
Graphics2D g2 = (Graphics2D) bg;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
bg.setColor(Color.BLACK);
for (int i = 0; i < NANCHORS; i++)
g2.fill(anchors[i]);
bg.setColor(Color.RED);
g2.draw(curve);
g.drawImage(imBuffer, 0, 0, this);
}
@Override
public void update(Graphics g)
{
paint(g);
}
}
Listing 1: QuadCurveDemo.java
Listing 1 describes an applet that renders start, a single control, and end points (which are all stored as Rectangle2D objects in the anchors array) via Graphics2D's void fill(Shape s) method; and also renders a quadratic curve (via this class's void draw(Shape s) method. The points are rendered as rectangular anchors (the actual point is in the middle of the anchor) to make it easier to drag them around.
Note: To prevent screen flicker, which occurs when the same pixel is painted more than once during a drawing operation, the applet draws the curve and control points into a buffer and then paints this buffer to the screen, which is known as double buffering. Also, because the Abstract Window Toolkit invokes the void update(Graphics g) method in response to repaint();, and because this method clears the applet's drawing area to the background color before invoking void paint(Graphics g), update(Graphics) is overridden to invoke paint(Graphics) directly without first clearing the drawing area.
|
Listing 2 presents the contents of this applet's QuadCurveDemo.html file.
<applet code="QuadCurveDemo.class" width=350 height=350> </applet>
Listing 2: QuadCurveDemo.html
After compiling this source code, execute appletviewer QuadCurveDemo.html to run this applet. Figure 1 shows the initially displayed quadratic curve.
Figure 1: Drag the quadratic curve's start, end, and control anchors to manipulate the curve.
java.awt.geom.CubicCurve2D's inner Double or Float subclass via one of the following constructors:
CubicCurve2D.Double(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, double ctrly2,
double x2, double y2)
CubicCurve2D.Float(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2,
float x2, float y2)
For either constructor, (x1, y1) defines the start point, (x2, y2) defines the end point, and (ctrlx1, ctrly1) and (ctrlx2, ctrly2) define the control points. If you prefer to create a curve where all four points are initialized to zero, call the
CubicCurve2D.Double() or CubicCurve2D.Float() constructor.
Invoke CubicCurve2D.Double's void setCurve(double x1, double y1, double ctrlx1, double ctrly1, double ctrlx2, double ctrly2, double x2, double y2) or CubicCurve2D.Float's void setCurve(float x1, float y1, float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x2, float y2) method to redefine the curve with new
points.
| Note: Each subclass also provides various getter methods for returning the values of the various points. |
Listing 3 presents the source code to an applet that demonstrates cubic curve creation and manipulation.
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Rectangle2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class CubicCurveDemo extends Applet
{
// Number of anchors (square rectangles) that are centered under the
// curve's start, two control, and end points.
final static int NANCHORS = 4;
// Initial start, two control, and end point values.
final static double ISX = 50.0;
final static double ISY = 30.0;
final static double ICX1 = 100.0;
final static double ICY1 = 260.0;
final static double ICX2 = 200.0;
final static double ICY2 = 40.0;
final static double IEX = 250.0;
final static double IEY = 260.0;
// Anchor width and height. Each value must be an odd number.
final static double AWIDTH = 7.0;
final static double AHEIGHT = 7.0;
Rectangle2D.Double[] anchors;
CubicCurve2D curve = new CubicCurve2D.Double(ISX, ISY, ICX1, ICY1, ICX2,
ICY2, IEX, IEY);
boolean[] inDrag = new boolean[] {false, false, false};
int dragIndex = -1, dragX, dragY;
Graphics bg;
Image imBuffer;
@Override
public void init()
{
// Setup a background buffer and obtain its graphics context to achieve
// double buffering.
imBuffer = createImage(getWidth(), getHeight());
bg = imBuffer.getGraphics();
anchors = new Rectangle2D.Double[NANCHORS];
// Specify the start anchor such that it's centered around initial start
// point (ISX, ISY).
anchors[0] = new Rectangle2D.Double(ISX-AWIDTH/2, ISY-AHEIGHT/2,
AWIDTH, AHEIGHT);
// Specify the first control anchor such that it's centered around
// initial first control point (ICX1, ICY1).
anchors[1] = new Rectangle2D.Double(ICX1-AWIDTH/2, ICY1-AHEIGHT/2,
AWIDTH, AHEIGHT);
// Specify the second control anchor such that it's centered around
// initial second control point (ICX2, ICY2).
anchors[2] = new Rectangle2D.Double(ICX2-AWIDTH/2, ICY2-AHEIGHT/2,
AWIDTH, AHEIGHT);
// Specify the end anchor such that it's centered around initial end
// point (IEX, IEY).
anchors[3] = new Rectangle2D.Double(IEX-AWIDTH/2, IEY-AHEIGHT/2,
AWIDTH, AHEIGHT);
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent me)
{
for (int i = 0; i < NANCHORS; i++)
if (anchors[i].contains(me.getX(), me.getY()))
{
dragIndex = i;
// Obtain mouse coordinates at the start of
// the drag for use in calculating a
// displacement that's used to offset an
// anchor's upper-left corner.
dragX = me.getX();
dragY = me.getY();
return;
}
}
public void mouseReleased(MouseEvent me)
{
dragIndex = -1;
}
});
addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged(MouseEvent me)
{
if (dragIndex == -1)
return;
// Calculate new location of dragged
// anchor.
double x = anchors[dragIndex].getX()+
me.getX()-dragX;
double y = anchors[dragIndex].getY()+
me.getY()-dragY;
anchors[dragIndex].setRect(x, y,AWIDTH,
AHEIGHT);
// Reposition curve in accordance with
// modified anchor such that the affected
// curve start, control, or end point is
// located at the center of the anchor.
curve.setCurve(anchors[0].getX()+
AWIDTH/2,
anchors[0].getY()+
AHEIGHT/2,
anchors[1].getX()+
AWIDTH/2,
anchors[1].getY()+
AHEIGHT/2,
anchors[2].getX()+
AWIDTH/2,
anchors[2].getY()+
AHEIGHT/2,
anchors[3].getX()+
AWIDTH/2,
anchors[3].getY()+
AHEIGHT/2);
repaint ();
dragX = me.getX();
dragY = me.getY();
}
});
}
@Override
public void paint(Graphics g)
{
bg.setColor(Color.WHITE);
bg.fillRect(0, 0, getWidth(), getHeight());
Graphics2D g2 = (Graphics2D) bg;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
bg.setColor(Color.BLACK);
for (int i = 0; i < NANCHORS; i++)
g2.fill(anchors[i]);
bg.setColor(Color.RED);
g2.draw(curve);
g.drawImage(imBuffer, 0, 0, this);
}
@Override
public void update(Graphics g)
{
paint(g);
}
}
Listing 3: CubicCurveDemo.java
Listing 3 describes an applet that renders start, a pair of control, and end points (which are all stored as Rectangle2D objects in the anchors array); and also renders a cubic curve. The points are rendered as rectangular anchors (the actual point is in the middle of the anchor) to make it easier to drag them around.
Listing 4 presents the contents of this applet's CubicCurveDemo.html file.
<applet code="CubicCurveDemo.class" width=350 height=350> </applet>
Listing 4: CubicCurveDemo.html
After compiling this source code, execute appletviewer CubicCurveDemo.html to run this applet. Figure 2 shows the initially displayed cubic curve.
Figure 2: Drag the cubic curve's start, end, and two control anchors to manipulate the curve.
Double and Float subclasses?
You can download this post's code and answers here [1]. Code was developed and tested with JDK 7u4 on a Windows 7 platform.
* * *
I welcome your input to this blog, and will write about relevant topics that you suggest. While waiting for the next blog post, check out my TutorTutor website [2] to learn more about Java and other computer technologies (and that's just the beginning).
|
Learn more about the Java 7 language and many of its APIs by reading my book Beginning Java 7. You can obtain information about this book here [3] and here [4]. |
Links:
[1] http://tutortutor.ca/blogs/jt/16/code.zip
[2] http://tutortutor.ca
[3] http://www.amazon.com/Beginning-Java-7-Apress/dp/1430239093/ref=sr_1_2?s=books&ie=UTF8&qid=1327945301&sr=1-2
[4] http://tutortutor.ca/cgi-bin/makepage.cgi?/books/bj7