# 1
Adjust the flatness parameter to control accuracy.
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
public class Searching extends JPanel {
QuadCurve2D.Double quad;
CubicCurve2D.Double cubic;
QuadCurve2D.Double liveQuad;
Point2D.Double[]points;
Point2D.Double[]p;
public void setPoint(int index, double x, double y) {
points[index].setLocation(x, y);
liveQuad.setCurve(points, 0);
setIntersects();
repaint();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if(quad == null)
initGeoms();
g2.setPaint(Color.blue);
g2.draw(quad);
g2.draw(cubic);
g2.draw(liveQuad);
for(int j = 0; j < points.length; j++) {
Color color = (j%2 == 0) ? Color.red : Color.green.darker();
g2.setPaint(color);
g2.fill(new Ellipse2D.Double(points[j].x-2, points[j].y-2, 4, 4));
}
// Mark intersection points.
g2.setPaint(Color.magenta);
for(int j = 0; j < p.length; j++) {
g2.draw(new Line2D.Double(p[j].x, p[j].y-20, p[j].x, p[j].y+20));
g2.draw(new Line2D.Double(p[j].x-20, p[j].y, p[j].x+20, p[j].y));
}
}
private void setIntersects() {
p[0] = getIntersectionPoint(quad, liveQuad);
p[1] = getIntersectionPoint(cubic, liveQuad);
}
private Point2D.Double getIntersectionPoint(Shape s1, Shape s2) {
Point2D.Double closest = new Point2D.Double();
double min = Double.MAX_VALUE;
double flatness = 0.005;
PathIterator pit = s1.getPathIterator(null, flatness);
double[] coords = new double[6];
while(!pit.isDone()) {
int type = pit.currentSegment(coords);
Point2D.Double p = getClosestPoint(s2, coords[0], coords[1]);
double distance = p.distance(coords[0], coords[1]);
if(distance < min) {
min = distance;
closest.setLocation(coords[0], coords[1]);
}
pit.next();
}
return closest;
}
private Point2D.Double getClosestPoint(Shape s, double x, double y) {
Point2D.Double closest = new Point2D.Double();
double min = Double.MAX_VALUE;
double flatness = 0.005;
PathIterator pit = s.getPathIterator(null, flatness);
double[] coords = new double[6];
while(!pit.isDone()) {
int type = pit.currentSegment(coords);
double distance = Point2D.distance(x, y, coords[0], coords[1]);
if(distance < min) {
min = distance;
closest.setLocation(coords[0], coords[1]);
}
pit.next();
}
return closest;
}
private void initGeoms() {
int w = getWidth();
int h = getHeight();
double x1 = w/8;
double y1 = h/16;
double ctrlx1 = w*15/16;
double ctrly1 = h/3;
double x2 = w*3/4;
double y2 = h*7/8;
quad = new QuadCurve2D.Double(x1, y1, ctrlx1, ctrly1, x2, y2);
x1 = w/16;
y1 = h/8;
ctrlx1 = 0;
ctrly1 = h*2/3;
double ctrlx2 = w*2/3;
double ctrly2 = h*3/4;
x2 = w/2;
y2 = h*15/16;
cubic = new CubicCurve2D.Double(x1, y1, ctrlx1, ctrly1,
ctrlx2, ctrly2, x2, y2);
points = new Point2D.Double[3];
points[0] = new Point2D.Double(w/16, h*11/12);
points[1] = new Point2D.Double(w/2, h/4);
points[2] = new Point2D.Double(w*11/12, h/3);
liveQuad = new QuadCurve2D.Double();
liveQuad.setCurve(points, 0);
p = new Point2D.Double[] { new Point2D.Double(), new Point2D.Double() };
setIntersects();
}
public Dimension getPreferredSize() {
return new Dimension(400,400);
}
public static void main(String[] args) {
Searching test = new Searching();
ArcTester arcTester = new ArcTester(test);
test.addMouseListener(arcTester);
test.addMouseMotionListener(arcTester);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(test);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ArcTester extends MouseInputAdapter {
Searching component;
Cursor hitCursor;
Point2D.Double offset = new Point2D.Double();
int selectedIndex = -1;
boolean dragging = false;
final int PROXIMITY = 5;
public ArcTester(Searching s) {
component = s;
createCursor();
}
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
if(selectedIndex != -1) {
Point2D.Double[] points = component.points;
offset.x = p.x - points[selectedIndex].x;
offset.y = p.y - points[selectedIndex].y;
dragging = true;
}
}
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;
component.setPoint(selectedIndex, x, y);
}
}
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
Point2D.Double[] points = component.points;
if(points == null) return;
boolean hovering = false;
for(int j = 0; j < points.length; j++) {
if(p.distance(points[j]) <= PROXIMITY) {
if(selectedIndex != j) {
selectedIndex = j;
component.setCursor(hitCursor);
}
hovering = true;
break;
}
}
if(!hovering && selectedIndex != -1) {
selectedIndex = -1;
component.setCursor(Cursor.getDefaultCursor());
}
}
private void createCursor() {
BufferedImage image = getImage();
Point hotSpot = new Point(image.getWidth()/2+3, image.getHeight()/2+3);
hitCursor = Toolkit.getDefaultToolkit()
.createCustomCursor(image, hotSpot, "hitCursor");
}
private BufferedImage getImage() {
int w = 27;
int h = 27;
int type = BufferedImage.TYPE_INT_ARGB_PRE;
BufferedImage image = new BufferedImage(w, h, type);
Graphics2D g2 = image.createGraphics();
g2.setPaint(Color.black);
g2.draw(new Line2D.Double(w/2, 0, w/2, 10));
g2.draw(new Line2D.Double(w-10, h/2, w, h/2));
g2.draw(new Line2D.Double(w/2, h-10, w/2, h));
g2.draw(new Line2D.Double(0, h/2, 10, h/2));
g2.dispose();
return image;
}
}