Я пытаюсь создать простую Java-программу, которая принимает математическую функцию в качестве входных данных и отображает 2D (x и y) график в JPanel.У меня график отображается правильно изначально.Я попытался добавить прокрутку к холсту (я назвал подкласс JPanel, я сделал GraphCanvas), и я имею в виду, что когда мышь перетаскивается по ней, прокручивается и 2D-плоскость, и график обновляется для вновь выявленных областей.Чтобы отобразить эту фактическую функцию, я использую объект Path2D, который состоит из сегментов, соединяющих достаточно точек, чтобы график находился в максимальном разрешении, и я использовал AffineTransforms для перевода пути.Стоит отметить, что я до сих пор тестировал программу только с функциями в форме f (x), а не с параметрическими, хотя я создал класс и поддерживающий код в классе GraphedInstance для параметрических функций.Я не хотел включать весь код для проекта, но я поместил его в репозиторий GitHub здесь (я очень мало знаю о том, как работает GitHub, но это должно быть правильно).
Моя проблема в том, что в данный момент, когда я пытаюсь прокрутить график, функция просто делает свое дело и неправильно соединяется с инициализированной частью.Он не отображает вновь сгенерированные части правильно.
Я проделал некоторую работу над этим и значительно улучшил проблему, ожидая преобразования пути, описывающего функцию, до тех пор, пока я не добавлю новые части к ней., но он все еще не соединяется правильно.
Это метод, который должен создавать и объединять новые части пути функции, и именно в этом, я думаю, проблема, возможно, кроется.Этот и остальной проект также можно найти в репозитории GitHub.Кроме того, извините за любой грязный код и / или отсутствие комментариев, я только новичок в колледже и на самом деле не имел никакого официального обучения Java, я просто как-то поднял его на ходу.Я был бы рад принять любые предложения или рекомендации о лучших способах сделать что-нибудь также!
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
public class Minimal {
private static int[] lastPointer = new int[2];
private static double xMin, xMax, yMin, yMax;
private static double xScale, yScale;
private static double minXGraphed, maxXGraphed;
public static Path2D.Double function;
//The frame enclosing the graphing canvas
private static JFrame frame;
//The graphing canvas
private static JPanel canvas = new JPanel() {
private static final int DEFAULT_CANVAS_SIZE = 600;
//Ensures the frame initialized to the right size
@Override
public Dimension getPreferredSize() {
return new Dimension(DEFAULT_CANVAS_SIZE, DEFAULT_CANVAS_SIZE);
}
//Paints the graph whenever it needs updating
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
super.paintComponent(g2);
xScale = getWidth() / (xMax - xMin);
yScale = getHeight() / (yMax - yMin);
g2.setColor(Color.BLUE);
try {
g2.draw(function);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
};
/**
* I'm using the function y = exp(x) as an example. Feel free to replace it.
* @param x the x-value
* @return exp(x), the y-value
*/
private static double getYVal(double x) {
return Math.exp(x);
}
//Initializes the function path
public static void initPath() {
final double STEP_X = (xMax - xMin) / canvas.getWidth();
function = new Path2D.Double();
double x = xMin;
double y = getYVal(x);
function.moveTo(getGraphX(x), getGraphY(y));
for(x = xMin + STEP_X; x <= xMax; x += STEP_X) {
y = getYVal(x);
function.lineTo(getGraphX(x), getGraphY(y));
}
}
/**
* Gets the pixel x-coordinate on the canvas
* that corresponds to a given x-value of the function
* @param x the x-value of the function
* @return the adjusted x-coordinate
*/
private static int getGraphX(double x) {
return (int) (canvas.getWidth() * (x - xMin) / (xMax - xMin));
}
//Same thing as getGraphX except for y-coords
private static int getGraphY(double y) {
return (int) (canvas.getHeight() * (yMax - y) / (yMax - yMin));
}
/*
* This is probably where the problem is, this extends the path so that it
* covers the entire visible range
*/
public static void updateFunctionBounds(double dx) {
double newXMin = xMin - dx / xScale;
double newXMax = xMax - dx / xScale;
final int WIDTH = canvas.getWidth();
final double STEP_X = (xMax - xMin) / WIDTH;
double drawTo;
if((drawTo = newXMin) < xMin && drawTo < minXGraphed) {
minXGraphed = drawTo;
double x = drawTo;
function.moveTo(getGraphX(x), getGraphY(getYVal(x)));
for(x = drawTo + STEP_X; x < xMin; x += STEP_X) {
function.lineTo(getGraphX(x), getGraphY(getYVal(x)));
}
x = xMin;
function.lineTo(getGraphX(x), getGraphY(getYVal(x)));
} else if((drawTo = newXMax) > xMax && drawTo > maxXGraphed) {
maxXGraphed = drawTo;
double x = xMax;
function.moveTo(getGraphX(x), getGraphY(getYVal(x)));
for(x = xMax + STEP_X; x < drawTo; x += STEP_X) {
function.lineTo(getGraphX(x), getGraphY(getYVal(x)));
}
x = drawTo;
function.lineTo(getGraphX(x), getGraphY(getYVal(x)));
}
}
public static void main(String[] args) {
initBounds();
initFrame();
}
//Initializes the graph boundaries. Feel free to change this
private static void initBounds() {
xMin = yMin = minXGraphed = -10;
xMax = yMax = maxXGraphed = 10;
}
//Initializes the frame and a MouseAdapter that controls the scrolling
private static void initFrame() {
MouseAdapter adapter = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
lastPointer[0] = e.getX();
lastPointer[1] = e.getY();
}
@Override
public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
AffineTransform t = new AffineTransform();
double dx = e.getX() - lastPointer[0];
double dy = e.getY() - lastPointer[1];
t.translate(dx, dy);
updateFunctionBounds(dx);
function.transform(t);
xMin -= dx / xScale;
xMax -= dx / xScale;
yMin -= dy / yScale;
yMax -= dy / yScale;
canvas.repaint();
lastPointer[0] = e.getX();
lastPointer[1] = e.getY();
}
};
canvas.addMouseListener(adapter);
canvas.addMouseMotionListener(adapter);
frame = new JFrame("Minimal Reproducible Approach");
frame.setContentPane(canvas);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
initPath();
canvas.repaint();
}
}
Если бы это работало правильно, сшивание было бы бесшовным, и функция плавно прокручивалась, как указатель мыши былперетаскивали по холсту, как в Desmos.На самом деле он не сохраняет правильную высоту (значение y) и фактически не соединяется с предыдущими сегментами во всех случаях.
Спасибо за любую помощь!
Редактировать: я обновил код до минимального воспроизводимого примера.