QuadCurve2D

Given a Point p and a QuadCurve2D c, what is the easiest way, programatically, to find the point on the QuadCurve2D c that is closest to Point p?
[159 byte] By [hendog] at [2007-9-26 8:46:21]
# 1
Hi!I think this is a hard question that involves some math knowledge. I'm also interested to hear an answer.Tom
Tom7 at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 2
A very simple but time-consuming method would be to get the curve's PathIterator and, moving through the iterator, look at each point individually.I will try to write a sample program ...Tom
Tom7 at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 3

Ok, here's an applet demonstrating my solution. Say point p is given. What I'm doing basically is create a flattened PathIterator, iterate through it and take the distance between each point on the PathIterator and p. I arbitrarily chose the flatness of the PathIterator ... so maybe you have to adjust it.

The solution is not very elegant, but maybe it's helpful to you.

If someone knows a direct calculation of the closest point, let me know .....

Cheers, Tom

import java.awt.*;

import java.awt.geom.*;

import java.applet.*;

public class QuadCurveTest extends Applet {

Point2D.Double p0 = new Point2D.Double(100,100);

Point2D.Double p1 = new Point2D.Double(140,45);

Point2D.Double p2 = new Point2D.Double(285,90);

QuadCurve2D quad = new QuadCurve2D.Double(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);

Point2D.Double p = new Point2D.Double(200, 220);

public void init() {}

public void paint(Graphics g){

Graphics2D g2 = (Graphics2D)g;

drawPoint(p0, "start", g2);

drawPoint(p1, "control point", g2);

drawPoint(p2, "end", g2);

drawPoint(p, "p", g2);

g2.draw(quad);

Point2D closeP = closestPoint(quad, p, g2);

g2.setColor(Color.red);

drawPoint(closeP, "", g2);

g2.setColor(Color.green);

Line2D line = new Line2D.Double(p, closeP);

g2.draw(line);

}

public Point2D closestPoint (QuadCurve2D quad, Point2D.Double p, Graphics2D g2) {

PathIterator path = quad.getPathIterator(null, 0.005);

// 0.005 = the flatness; reduce if result is not accurate enough!

double[] coords = new double[2];

int counter = 0;

double x = 0.0, y = 0.0;

double px = p.x, py = p.y;

double closestX = 0.0;

double closestY = 0.0;

double closestDistanceSquare = 1000000.0;

while( !path.isDone() ) {

path.currentSegment(coords);

x = coords[0]; y = coords[1];

double distanceSquare = Point2D.distanceSq(x,y,px,py);

if (distanceSquare < closestDistanceSquare) {

closestDistanceSquare = distanceSquare;

closestX = x;

closestY = y;

}

path.next();

}

return new Point2D.Double(closestX, closestY);

}

private void drawPoint(Point2D p, String text, Graphics g) {

int x = (int)p.getX(),

y = (int)p.getY();

g.fillOval(x-2, y-2, 4, 4);

g.drawString(text, x-4, y+10);

}

static void p(String s) {

System.out.println(s);

}

}

Tom7 at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 4
.... of course, you can remove the third argument 'Graphics2D g2' in the method 'closestPoint' ! I just used it for debugging purposes.Tom
Tom7 at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 5

An analytic approach leads to a 3rd degree polynomial, by the way.

All QuadCurve2D's can be transformed to segments of the unit parabola y = x^2 with an affine tranformation so it suffices to find p1(x1,y1) on the curve such that the distance from p1 to p2(x2,y2), a given point, is minimal.

The distance squared is d(x1,y1) = (x1-x2)^2+ (y1-y2)^2 = (x1-x2)^2+ (x1^2-y2)^2.

Taking the derivative gives d'(x1) = 2(x1-x2) + 2 (2 x1)(x1^2-y2) = 2x1 - 2x2 + 4x1^3 - 4x1y2

Solving for zeroes leads to 2x1^3 + (1 - 2 y2) x1 - x2 = 0 for the x coordinate of the point on the curve.

jsalonen at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 6
That is what I am looking for. However, as my Math skills are a little rusty, how do I solve for x1 in the final formula. It looks like a third degree polynomial but its been 6 years since I had to do something like that.
hendog at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 7
You don't need to know math if you know the API :-)Use java.awt.geom.CubicCurve2D method:static int solveCubic(double[])
PaulFMendler at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 8

Hi,

I would like to do something with CubicCurves but I am not sure about the approach. In a CAD/CAM app I am writing I have curves with control points and when manipulating the control points the mouse has to travel much farther than the shape moves obviously, sometimes having to go offscreen to move the control point to the proper position. What I wanted to do was put the control points on the curve itself and any manipulations corresponding to the actual control point. If someone has any pointers (none in Java!) I would appreciate it. Not sure how fast solveCubic returns but if I have to call it every time the mouse is moved its going to slow things down. Thanks!

a__riot at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...
# 9
> I would like to do something with CubicCurves but I am not sure about the approachYou might want to look at: http://www.sourceforge.net/projects/curves/
rkippen at 2007-7-1 19:37:48 > top of Java-index,Security,Cryptography...