1

私は、ビジュアル エディター (Java で記述) を実行しているプロジェクトに参加しています。今、JPanel を拡張するクラスでペイントしている 2 つの異なるオブジェクトを結合する曲線を作成しようとしています (このクラスは、メソッド paintComponent をオーバーライドして、JFrame 内でペイントするために使用しているものです)。クラス QuadCurve2D を使用してこれを作成しているので困っていますが、クリック可能にすることはできません (contains メソッドを使用していますが、毎回機能しません)、編集可能にする (たとえば、曲率を変更するための中間点の正方形. コンストラクタが呼び出されたときに QuadCurve2D の中央で使用される点は曲線の外側にあります) またはどの点が中にあるかを教えてくれる何か (メソッド、変数、イテレータなど) QuadCurve2D。

しばらく探しても答えがないので、ここに投稿して解決策を見つけようとしています。とにかくQuadCurve2Dクラスでそれを作ることはありますか、それとも外部ライブラリで試す必要がありますか?

4

1 に答える 1

4

まず第一に、長い返事をお詫び申し上げます。私は今あなたの質問に対する完全な答えを投稿しています。QuadCurve2D.Doubleクラスをサブクラス化しており、少し計算して、コントロールポイントではなく、開始点、終了点、および中間点を使用して曲線を定義します。また、ポイントがカーブ上にあるかどうかをチェックする新しいメソッドを作成しました。交差メソッドは、形状の凸包が提供された形状と交差するかどうかをチェックするため、凹曲線の場合、これは機能しますが正確ではありません。ポイントが曲線上にあるかどうかをチェックするメソッドの実装は、指定された解像度で曲線の長さに沿ってチェックしているため、計算コストが高く、100%正確ではないことに注意してください(0は曲線の始まり、1は終わりです)。 。したがって、提供された例では、解像度0でチェックしています。01は、曲線に沿って100回のチェックが行われることを意味します)。その点については、解像度の提供されたステップが0.5(中間点)の分周器であることを確認して、それを選択できるようにします。それが意味をなさない場合は、注意を払わないでください。それは実際には問題ではありません。私の例をそのまま使用できます。また、マウスがカーブ上にあるかどうかを確認するために、intersectsメソッドと自分のメソッドを切り替えるためのチェックボックスも提供していることに注意してください。また、新しい方法を使用する場合は、さまざまな値の効果を確認できるように、解像度を指定するためのスライダーも用意しています。これがクラスです。箱から出して私の例を使用できます。また、マウスがカーブ上にあるかどうかを確認するために、intersectsメソッドと自分のメソッドを切り替えるためのチェックボックスも提供していることに注意してください。また、新しい方法を使用する場合は、さまざまな値の効果を確認できるように、解像度を指定するためのスライダーも用意しています。これがクラスです。箱から出して私の例を使用できます。また、マウスがカーブ上にあるかどうかを確認するために、intersectsメソッドと自分のメソッドを切り替えるためのチェックボックスも提供していることに注意してください。また、新しい方法を使用する場合は、さまざまな値の効果を確認できるように、解像度を指定するためのスライダーも用意しています。これがクラスです。

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);
            }
    }
}

そしてまた:

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;
    }

}

私がどのようにクラスを作成したかを知りたい場合は、基本的な線形代数を検索し、ウィキペディアでベジェ曲線を検索してください。

于 2009-07-01T14:40:44.410 に答える