Vor allem Entschuldigung für die lange Antwort. Ich poste jetzt eine vollständige Antwort auf Ihre Frage. Ich klassifiziere die QuadCurve2D.Double-Klasse und mit ein wenig Mathe definieren Sie nun die Kurve mit einem Anfang, Ende und einem Mittelpunkt anstelle eines Kontrollpunkts. Außerdem habe ich eine neue Methode erstellt, die überprüft, ob ein Punkt auf der Kurve ist. Die Schnittpunktmethode prüft, ob sich die konvexe Hülle der Form mit der bereitgestellten Form schneidet, so dass dies im Fall der konkaven Kurve funktional, aber nicht genau ist. Beachten Sie, dass meine Implementierung der Methode, um zu überprüfen, ob ein Punkt auf der Kurve ist, eher rechenintensiv und nicht 100% genau ist, da ich die Kurvenlänge mit einer bestimmten Auflösung überprüfe (0 ist der Anfang der Kurve, 1 ist das Ende) Englisch: www.doc-o-matic.com/webhelp/Tdlg.html Im Beispiel wird also mit einer Auflösung von 0,01 geprüft, dass 100 Checks entlang der Kurve gemacht werden. Stellen Sie daher sicher, dass der angegebene Schritt in der Auflösung ein Teiler von 0,5 (der Mittelpunkt) ist, damit Sie ihn auswählen können. Wenn das keinen Sinn macht passe nicht auf, ist es nicht wirklich wichtig, du kannst mein Beispiel out of the box benutzen. Beachten Sie, dass ich auch ein Kontrollkästchen zur Verfügung stelle, um zwischen der Schnittpunktmethode und meiner eigenen zu wechseln, um zu überprüfen, ob sich die Maus auf der Kurve befindet. Und wenn ich meine neue Methode verwende, stelle ich auch einen Schieberegler zur Verfügung, um die Auflösung anzugeben, so dass Sie die Auswirkungen verschiedener Werte sehen können. Hier sind die Klassen.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
@SuppressWarnings("serial")
public class CurvePanel extends JPanel implements MouseListener,MouseMotionListener{
Point2D startPoint = new Point2D.Double(50, 50);
Point2D middlePoint = new Point2D.Double(100,80);
Point2D endPoint = new Point2D.Double(200, 200);
Point2D[] points = new Point2D[] {startPoint,middlePoint,endPoint};
QuadCurveWithMiddlePoint curve;
private Point2D movingPoint;
private boolean dragIt = false;
private boolean showControls = false;
JCheckBox useNewMethod;
JSlider resolution;
public CurvePanel() {
setPreferredSize(new Dimension(300,300));
addMouseListener(this);
addMouseMotionListener(this);
curve = new QuadCurveWithMiddlePoint();
useNewMethod = new JCheckBox("Use new \"contains\" method");
resolution = new JSlider(JSlider.HORIZONTAL,1,10,1);
useNewMethod.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
resolution.setEnabled(useNewMethod.isSelected());
}
});
useNewMethod.setSelected(false);
resolution.setEnabled(false);
setCurve();
}
private void setCurve() {
curve.setCurveWithMiddlePoint(startPoint, middlePoint, endPoint);
}
public static void main(String[] args) {
JFrame f = new JFrame("Test");
CurvePanel panel = new CurvePanel();
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(panel.useNewMethod,BorderLayout.NORTH);
f.getContentPane().add(panel,BorderLayout.CENTER);
f.getContentPane().add(panel.resolution,BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
@Override
public void mouseClicked(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
for (Point2D point : points) {
if (e.getPoint().distance(point) <= 2) {
movingPoint = point;
dragIt = true;
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
dragIt = false;
}
@Override
public void mouseDragged(MouseEvent e) {
if (dragIt) {
movingPoint.setLocation(e.getPoint());
setCurve();
repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {
if (useNewMethod.isSelected())
showControls = curve.pointOnCurve(e.getPoint(), 2, resolution.getValue()/100.0);
else
showControls = curve.intersects(e.getX()-2, e.getY()-2, 4, 4);
repaint();
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(Color.white);
g2.fillRect(0, 0, getWidth(), getHeight());
g2.setPaint(Color.black);
g2.draw(curve);
if (showControls)
for (Point2D point : points) {
g2.setPaint(Color.black);
g2.drawOval((int)point.getX()-2, (int)point.getY()-2, 4, 4);
g2.setPaint(Color.red);
g2.fillOval((int)point.getX()-2, (int)point.getY()-2, 4, 4);
}
}
}
Und auch:
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D.Double;
@SuppressWarnings("serial")
public class QuadCurveWithMiddlePoint extends Double {
private Point2D middlePoint = new Point2D.Double();
private final double L = 0.5;
public QuadCurveWithMiddlePoint(double x1,double y1, double xm, double ym, double x2, double y2) {
super(x1,y1,xm,ym,x2,y2);
setMiddlePoint(xm, ym);
}
public QuadCurveWithMiddlePoint() {
this(0,0,0,0,0,0);
}
public Point2D getMiddlePoint() {
calculateMiddlePoint();
return middlePoint;
}
public void setMiddlePoint(double middleX, double middleY) {
setCurve(getP1(), getControlPointByMiddle(middleX, middleY), getP2());
calculateMiddlePoint();
}
public void setMiddlePoint(Point2D middle) {
setMiddlePoint(middle.getX(),middle.getY());
}
private Point2D getControlPointByMiddle(double middleX,double middleY) {
double cpx = (middleX-(L*L-2*L+1)*x1-(L*L)*x2)/(-2*L*L+2*L);
double cpy = (middleY-(L*L-2*L+1)*y1-(L*L)*y2)/(-2*L*L+2*L);
return new Point2D.Double(cpx,cpy);
}
private Point2D calculatePoint(double position) {
if (position<0 || position>1)
return null;
double middlex = (position*position-2*position+1)*x1+(-2*position*position+2*position)*ctrlx+(position*position)*x2;
double middley = (position*position-2*position+1)*y1+(-2*position*position+2*position)*ctrly+(position*position)*y2;
return new Point2D.Double(middlex,middley);
}
public void calculateMiddlePoint() {
middlePoint.setLocation(calculatePoint(L));
}
public void setCurveWithMiddlePoint(double xx1,double yy1, double xxm, double yym, double xx2, double yy2) {
setCurve(xx1, yy1, xxm, yym, xx2, yy2);
setMiddlePoint(xxm,yym);
}
public void setCurveWithMiddlePoint(Point2D start, Point2D middle, Point2D end) {
setCurveWithMiddlePoint(start.getX(),start.getY(),middle.getX(),middle.getY(),end.getX(),end.getY());
}
public boolean pointOnCurve(Point2D point, double accuracy, double step) {
if (accuracy<=0)
return false;
if (step<=0 || step >1)
return false;
boolean oncurve = false;
double current = 0;
while (!oncurve && current <= 1) {
if (calculatePoint(current).distance(point)<accuracy)
oncurve = true;
current += step;
}
return oncurve;
}
}
Wenn Sie wissen möchten, wie ich die Klasse gemacht, eine Suche nach grundlegenden linearen Algebra und auch Wikipedia für Bézier curves suchen.
Vielen Dank für Ihre Antwort. Genau das habe ich getan, aber das, was ich brauche, ist dasselbe, aber ich setze das Ellipse2D nur auf den mittleren Punkt innerhalb der Kurve. Wie kann ich diesen Punkt bekommen? –
Bitte lesen Sie die vollständige Antwort, die ich gepostet habe. Sie erhalten eine Arbeiterklasse mit einem Kontrollpunkt in der Mitte der Kurve. –