gpt4 book ai didi

java - 如何使连接两个对象的曲线可编辑?

转载 作者:行者123 更新时间:2023-11-29 04:04:21 25 4
gpt4 key购买 nike

我参与了一个项目,我们正在做一个可视化编辑器(用 Java 编写)。现在,我正在尝试创建连接两个不同对象的曲线,这两个对象是我在一个扩展 JPanel 的类中绘制的(这个类是我用来绘制的,在 JFrame 中,覆盖了 paintComponent 方法)。我遇到了麻烦,因为我正在使用 QuadCurve2D 类来制作它,但我无法使其可点击(我正在使用包含的方法,但它并非每次都有效),使其可编辑(例如,设置方形在它的中间点修改它的曲率。调用构造函数时在 QuadCurve2D 中间使用的点在曲线之外)或可以告诉我哪些点在曲线之外的东西(方法,变量,迭代器等) QuadCurve2D。

找了一段时间后,我没有找到答案,所以我试着把它贴在这里寻找解决方案。无论如何都可以使用 QuadCurve2D 类来实现,还是我必须尝试使用​​一些外部库?

最佳答案

首先很抱歉这么长的回复。我现在发布了您问题的完整答案。我正在对 QuadCurve2D.Double 类进行子类化,现在用一点数学就可以用起点、终点和中点而不是控制点来定义曲线。我还创建了一种新方法来检查一个点是否在曲线上。 intersects 方法检查形状的凸包是否与提供的形状相交,因此在凹曲线的情况下,这是功能性的但不准确。请注意,我实现的检查一个点是否在曲线上的方法在计算上相当昂贵并且不是 100% 准确,因为我正在以指定的分辨率沿着曲线长度检查(0 是曲线的开始,1 是结束. 所以在我提供的示例中,我使用 0.01 的分辨率进行检查,这意味着沿着曲线进行了 100 次检查)。为此,请确保分辨率中提供的步骤是 0.5(中间点)的分频器,以便您可以选择它。如果那没有意义,请不要注意它并不重要,您可以开箱即用地使用我的示例。请注意,我还提供了一个复选框,用于在相交方法和我自己的方法之间切换,以检查鼠标是否在曲线上。在使用我的新方法时,我还提供了一个 slider 来指定分辨率,以便您可以看到各种值的效果。这是类。

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

}

如果您想知道我是如何上这门课的,请搜索基本线性代数并在维基百科上搜索 Bézier curves .

关于java - 如何使连接两个对象的曲线可编辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1069396/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com