From 4d84c8343e7601b624350d2e235916a7e312221b Mon Sep 17 00:00:00 2001 From: Piotr Machura Date: Thu, 9 Feb 2023 22:26:08 +0100 Subject: [PATCH] PoC graphical solver - with interrupts --- src/main/java/gui/FunctionFrame.java | 78 ++++-- src/main/java/visual/AnimatedSpace.java | 91 ++++++ src/main/java/visual/GraphicSolver.java | 353 ------------------------ src/main/java/visual/InputSpace.java | 128 +++++---- src/main/java/visual/OutputSpace.java | 114 +------- 5 files changed, 219 insertions(+), 545 deletions(-) create mode 100644 src/main/java/visual/AnimatedSpace.java delete mode 100644 src/main/java/visual/GraphicSolver.java diff --git a/src/main/java/gui/FunctionFrame.java b/src/main/java/gui/FunctionFrame.java index 5d8dbf6..a34950a 100644 --- a/src/main/java/gui/FunctionFrame.java +++ b/src/main/java/gui/FunctionFrame.java @@ -9,6 +9,8 @@ import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; @@ -44,7 +46,7 @@ import visual.OutputSpace; import solver.ComplexUtils; import solver.Solver; import solver.SolverAccuracy; -import visual.GraphicSolver; +import visual.AnimatedSpace; import com.expression.parser.function.Complex; /** @@ -82,8 +84,12 @@ class FunctionFrame extends JFrame implements ActionListener { SolverAccuracy acc; /** Animation components */ - JFrame graphicSolverFrame; - GraphicSolver graphicSolver; + JFrame animationFrame; + AnimatedSpace animatedSpace; + + /** Output space */ + JFrame outFrame; + OutputSpace outputSpace; /** Abort calculations after a time threshold has passed */ private static final int TIMEOUT_THRESHOLD = 3000; @@ -157,7 +163,7 @@ class FunctionFrame extends JFrame implements ActionListener { } }); - outSpace = new OutputSpace(this.f_z); + outSpace = new OutputSpace(); this.acc = acc; /** Panels */ @@ -206,32 +212,46 @@ class FunctionFrame extends JFrame implements ActionListener { /* Solve and showcase roots */ this.calculate(); + this.outputSpace = new OutputSpace(); + outFrame = new JFrame("Output space"); + outFrame.setSize(300, 350); + outFrame.setResizable(false); + outFrame.setLocationRelativeTo(null); + outFrame.add(this.outputSpace); + outFrame.setIconImage(Toolkit.getDefaultToolkit().getImage(url)); + /** GraphicSolver definition */ - graphicSolver = new GraphicSolver(f_z, range); - graphicSolverFrame = new JFrame("Animating input space for f(z) = " + f_z); - graphicSolverFrame.addWindowListener(new WindowAdapter() { + animatedSpace = new AnimatedSpace(f_z, range); + animationFrame = new JFrame("Animating input space for f(z) = " + f_z); + animationFrame.add(animatedSpace); + animationFrame.setDefaultCloseOperation(HIDE_ON_CLOSE); + animationFrame.addComponentListener(new ComponentAdapter() { + @Override + public void componentHidden(ComponentEvent e) { + animatedSpace.stop(); + } @Override - public void windowClosed(WindowEvent e) { - graphicSolver.graphicExec.shutdownNow(); + public void componentShown(ComponentEvent e) { + animatedSpace.start(); } }); /** Set GraphicSolver frame */ - graphicSolverFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); - graphicSolverFrame.setSize(500, 500); - graphicSolverFrame.setResizable(false); - graphicSolverFrame.setLocationRelativeTo(null); + animationFrame.setSize(500, 500); + animationFrame.setResizable(false); + animationFrame.setLocationRelativeTo(null); url = Thread.currentThread().getContextClassLoader().getResource("icons/reset.png"); - graphicSolverFrame.setIconImage(Toolkit.getDefaultToolkit().getImage(url)); + animationFrame.setIconImage(Toolkit.getDefaultToolkit().getImage(url)); + + this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - graphicSolverFrame.dispatchEvent(new WindowEvent(FunctionFrame.this, WindowEvent.WINDOW_CLOSING)); - graphicSolver.outFrame.dispatchEvent(new WindowEvent(FunctionFrame.this, WindowEvent.WINDOW_CLOSING)); + animationFrame.dispatchEvent(new WindowEvent(FunctionFrame.this, WindowEvent.WINDOW_CLOSING)); + outFrame.dispatchEvent(new WindowEvent(FunctionFrame.this, WindowEvent.WINDOW_CLOSING)); super.windowClosing(e); } }); - graphicSolverFrame.add(graphicSolver); } @@ -298,23 +318,23 @@ class FunctionFrame extends JFrame implements ActionListener { final String buttonID = e.getActionCommand(); switch (buttonID) { case "output": - if (!graphicSolver.outFrame.isVisible()) { - graphicSolver.outFrame.setVisible(true); + if (!outFrame.isVisible()) { + outFrame.setVisible(true); } else { - graphicSolver.outFrame.setState(JFrame.NORMAL); - graphicSolver.outFrame.toFront(); - graphicSolver.outFrame.requestFocus(); + outFrame.setState(JFrame.NORMAL); + outFrame.toFront(); + outFrame.requestFocus(); } break; case "animation": - if (!graphicSolverFrame.isVisible()) { - graphicSolver.replay(); - graphicSolverFrame.setVisible(true); + if (!animationFrame.isVisible()) { + // graphicSolver.replay(); + animationFrame.setVisible(true); } else { - graphicSolver.replay(); - graphicSolverFrame.setState(JFrame.NORMAL); - graphicSolverFrame.toFront(); - graphicSolverFrame.requestFocus(); + // graphicSolver.replay(); + animationFrame.setState(JFrame.NORMAL); + animationFrame.toFront(); + animationFrame.requestFocus(); } break; case "saveSolutions": diff --git a/src/main/java/visual/AnimatedSpace.java b/src/main/java/visual/AnimatedSpace.java new file mode 100644 index 0000000..581e5b2 --- /dev/null +++ b/src/main/java/visual/AnimatedSpace.java @@ -0,0 +1,91 @@ +package visual; + +import java.awt.Color; +import java.awt.Graphics; + +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +import javax.swing.SwingUtilities; + +public class AnimatedSpace extends InputSpace { + public Thread animationThread; + ArrayList pixels; + ReentrantLock pixelLock; + int range; + + public AnimatedSpace(final String f_z, final int range) { + super(f_z); + this.range = range; + pixelLock = new ReentrantLock(); + removeMouseMotionListener(mouseAdapter); + } + + public void start() { + stop(); + pixelLock.lock(); + pixels = new ArrayList<>(); + pixelLock.unlock(); + animationThread = new Thread(() -> { + int i = 0; + SwingUtilities.invokeLater( + new Runnable() { + @Override + public void run() { + repaint(); + } + }); + + while (true) { + try { + i++; + Pixel p = new Pixel(i, i, 1, 1); + pixelLock.lock(); + pixels.add(p); + pixelLock.unlock(); + SwingUtilities.invokeLater( + new Runnable() { + @Override + public void run() { + repaint(); + } + }); + TimeUnit.MILLISECONDS.sleep(500); + } catch (InterruptedException ex) { + return; + } + } + }); + animationThread.start(); + } + + public void stop() { + if (animationThread != null) { + animationThread.interrupt(); + try { + animationThread.join(); + } catch (InterruptedException ex) { + /** Go ahead */ + } + } + } + + @Override + protected void paintComponent(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + int w = getWidth(); + int h = getHeight(); + g2.translate(w / 2, h / 2); + + pixelLock.lock(); + for (Pixel p : pixels) { + g2.setColor(Color.getHSBColor((float) p.phi, 1, (float) p.r)); + g2.fillRect(p.i + centerX, p.j - centerY, 10, 10); + } + pixelLock.unlock(); + paintAxis(g2); + } + +} diff --git a/src/main/java/visual/GraphicSolver.java b/src/main/java/visual/GraphicSolver.java deleted file mode 100644 index 0976f7c..0000000 --- a/src/main/java/visual/GraphicSolver.java +++ /dev/null @@ -1,353 +0,0 @@ -package visual; - -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Toolkit; -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.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.util.ArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import javax.swing.Timer; -import javax.swing.JFrame; -import javax.swing.JPanel; -import java.net.URL; - -import com.expression.parser.function.Complex; -import com.expression.parser.Parser; -import com.expression.parser.util.Point; - -import solver.ComplexUtils; -import solver.Solver; -import solver.SolverAccuracy; - -/** - * @Author Kacper Ledwosiński - */ -public class GraphicSolver extends JPanel - implements MouseMotionListener, MouseListener, MouseWheelListener, ActionListener, Runnable { - private static final long serialVersionUID = 1L; - - enum Direction { - RIGHT, DOWN, LEFT, UP, STOP - } - - int originX = -1, originY = -1; - int offX, offY; - int scrollSpeed = 2; - int centerX = 10, centerY = 10; - float zoomX = 200, zoomY = 200; - float scaleX, scaleY; - String f; - ArrayList sq_points = new ArrayList(); - boolean panning = false; - - double tickX, tickY; - - /** Animation components */ - Direction dir = Direction.RIGHT; // 0-right, 1-down, 2-left, 3-up - Complex A, B, C, D; - ArrayList childPosition = new ArrayList(); - int range; - double res; // rect resolution - difference between points - int divideDeep = 6; - int deepCounter = 0; - Timer graphicTime; - Boolean newSquare = true; - - int speed = 0; // ms timer delay - - public ExecutorService graphicExec = Executors.newSingleThreadExecutor(); - - public JFrame outFrame; - OutputSpace outputSpace; - - public GraphicSolver(final String f, final int range) { - this.f = f; - this.range = range; - scaleX = range; - scaleY = range; - - tickX = scaleX / zoomX; - tickY = scaleY / zoomY; - - res = tickX; - - addMouseMotionListener(this); - addMouseListener(this); - addMouseWheelListener(this); - - A = new Complex(-range, -range); - B = new Complex(range, -range); - C = new Complex(range, range); - D = new Complex(-range, range); - - childPosition = getChildPositions(divideDeep, new Complex[] { A, B, C, D }); - graphicExec.execute(this); - - this.outputSpace = new OutputSpace(this.f); - - /** Output space frame */ - outFrame = new JFrame("Output space"); - outFrame.setSize(200, 250); - outFrame.setResizable(false); - outFrame.setLocationRelativeTo(null); - outFrame.add(this.outputSpace); - URL url = Thread.currentThread().getContextClassLoader().getResource("icons/main.png"); - outFrame.setIconImage(Toolkit.getDefaultToolkit().getImage(url)); - } - - public void replay() { - sq_points = new ArrayList(); - A = new Complex(-range, -range); - B = new Complex(range, -range); - C = new Complex(range, range); - D = new Complex(-range, range); - deepCounter = 0; - dir = Direction.RIGHT; - newSquare = true; - this.repaint(); - } - - public void addPoint(final Complex p) { - sq_points.add(p); - } - - ArrayList getChildPositions(int deep, Complex[] parents) { - ArrayList tmpChilds = new ArrayList(); - tmpChilds.add(parents); - if (deep == 0) { - return tmpChilds; - } - - // remove first square - if (deep == this.divideDeep) { - tmpChilds = new ArrayList(); - } - - Complex AB_mid = new Complex((parents[1].getR() + parents[0].getR()) / 2, parents[0].getI()); - Complex BC_mid = new Complex(parents[1].getR(), (parents[2].getI() + parents[1].getI()) / 2); - Complex CD_mid = new Complex((parents[2].getR() + parents[3].getR()) / 2, parents[2].getI()); - Complex AD_mid = new Complex(parents[3].getR(), (parents[3].getI() + parents[0].getI()) / 2); - Complex MIDDLE = new Complex((AB_mid.getR() + CD_mid.getR()) / 2, (AD_mid.getI() + BC_mid.getI()) / 2); - - Boolean rect1zero = new Solver(parents[0], AB_mid, MIDDLE, AD_mid, SolverAccuracy.LOW) - .checkWindingNumber(this.f); - ArrayList rect1 = new ArrayList(); - if (rect1zero) - rect1 = getChildPositions(deep - 1, new Complex[] { parents[0], AB_mid, MIDDLE, AD_mid }); - - Boolean rect2zero = new Solver(AB_mid, parents[1], BC_mid, MIDDLE, SolverAccuracy.LOW) - .checkWindingNumber(this.f); - ArrayList rect2 = new ArrayList(); - if (rect2zero) - rect2 = getChildPositions(deep - 1, new Complex[] { AB_mid, parents[1], BC_mid, MIDDLE }); - - Boolean rect3zero = new Solver(MIDDLE, BC_mid, parents[2], CD_mid, SolverAccuracy.LOW) - .checkWindingNumber(this.f); - ArrayList rect3 = new ArrayList(); - if (rect3zero) - rect3 = getChildPositions(deep - 1, new Complex[] { MIDDLE, BC_mid, parents[2], CD_mid }); - - Boolean rect4zero = new Solver(AD_mid, MIDDLE, CD_mid, parents[3], SolverAccuracy.LOW) - .checkWindingNumber(this.f); - ArrayList rect4 = new ArrayList(); - if (rect4zero) - rect4 = getChildPositions(deep - 1, new Complex[] { AD_mid, MIDDLE, CD_mid, parents[3] }); - - tmpChilds.addAll(rect1); - tmpChilds.addAll(rect2); - tmpChilds.addAll(rect3); - tmpChilds.addAll(rect4); - - return tmpChilds; - } - - @Override - protected void paintComponent(final Graphics g) { - super.paintComponent(g); - final Graphics2D g2 = (Graphics2D) g; - g2.translate(getWidth() / 2, getHeight() / 2); - - if (!graphicTime.isRunning()) - graphicTime.start(); - - if (panning) { - graphicTime.stop(); - g2.setColor(Color.black); - g2.drawLine(-getWidth() / 2 + originX, -getHeight() / 2 + originY, -getWidth() / 2 + originX - offX, - -getHeight() / 2 + originY - offY); - g2.drawLine(-getWidth() / 2, -centerY - offY, getWidth() / 2, -centerY - offY); - g2.drawLine(centerX - offX, -getHeight() / 2, centerX - offX, getHeight() / 2); - return; - } - - // draw rectangle points - for (Complex p : sq_points) { - Point z0 = new Point("z", p); - Complex z = Parser.eval(f, z0).getComplexValue(); - - double fi; - try { - fi = ComplexUtils.phase(z) / 2 / Math.PI; - } catch (Exception e) { - fi = 0; - } - - double r = Complex.abs(z); - if (r > 1) - r = 1; - - g2.setColor(Color.getHSBColor((float) fi, 1, (float) r)); - g2.fillRect((int) (p.getR() * zoomX / scaleX) - 2 + centerX, - (int) (p.getI() * zoomY / scaleY) - 2 - centerY, 4, 4); - } - - // draw axes - g2.setColor(Color.gray); - g2.drawLine(-getWidth() / 2, -centerY, getWidth() / 2, -centerY); - g2.drawLine(centerX, -getHeight() / 2, centerX, getHeight() / 2); - - // draw ticks - g2.setColor(Color.gray); - for (int i = -(int) ((getWidth() + 2 * centerX) / (2 * zoomX / scaleX)) - - 1; i < (int) ((getWidth() - 2 * centerX) / (2 * zoomX / scaleX)) + 1; i++) { - g2.fillRect((int) (i * zoomX / scaleX) - 1 + centerX, -5 - centerY, 2, 10); - } - for (int i = -(int) ((getHeight() - 2 * centerY) / (2 * zoomY / scaleY)) - - 1; i < (int) ((getHeight() + 2 * centerY) / (2 * zoomY / scaleY)) + 1; i++) { - g2.fillRect(-5 + centerX, (int) (i * zoomY / scaleY) - 1 - centerY, 10, 2); - } - - repaint(); - } - - @Override - public void run() { - graphicTime = new Timer(speed, this); - } - - public void update() { - - // add square points - int sq_pts_len = sq_points.size(); - if (newSquare) { - sq_points.add(A); - newSquare = false; - } else if (dir != Direction.STOP) { - Complex last = sq_points.get(sq_pts_len - 1); - double l_re = last.getR(); - double l_im = last.getI(); - - if (dir == Direction.RIGHT) { - Complex new_pt = new Complex(l_re + res, l_im); - sq_points.add(new_pt); - outputSpace.setCurrent(new_pt); - if (new_pt.getR() > B.getR()) { - sq_points.add(B); - dir = Direction.DOWN; - } - } else if (dir == Direction.DOWN) { - Complex new_pt = new Complex(l_re, l_im + res); - sq_points.add(new_pt); - outputSpace.setCurrent(new_pt); - if (new_pt.getI() > C.getI()) { - sq_points.add(C); - dir = Direction.LEFT; - } - } else if (dir == Direction.LEFT) { - Complex new_pt = new Complex(l_re - res, l_im); - sq_points.add(new_pt); - outputSpace.setCurrent(new_pt); - if (new_pt.getR() < D.getR()) { - sq_points.add(D); - dir = Direction.UP; - } - } else if (dir == Direction.UP) { - Complex new_pt = new Complex(l_re, l_im - res); - sq_points.add(new_pt); - outputSpace.setCurrent(new_pt); - if (new_pt.getI() < A.getI()) { - sq_points.add(A); - dir = Direction.STOP; - } - } - } else { - if (deepCounter < childPosition.size()) { - Complex[] nexSquare = childPosition.get(deepCounter); - A = nexSquare[0]; - B = nexSquare[1]; - C = nexSquare[2]; - D = nexSquare[3]; - dir = Direction.RIGHT; - deepCounter++; - newSquare = true; - } else { - dir = Direction.STOP; - graphicExec.shutdownNow(); - } - } - } - - @Override - public void mousePressed(final MouseEvent e) { - originX = e.getX(); - originY = e.getY(); - panning = true; - } - - @Override - public void mouseDragged(final MouseEvent e) { - if (originX != -1 && originY != -1) { - offX = originX - e.getX(); - offY = originY - e.getY(); - this.repaint(); - } - this.repaint(); - } - - @Override - public void mouseReleased(final MouseEvent e) { - centerX -= offX; - centerY += offY; - panning = false; - this.repaint(); - originX = -1; - originY = -1; - } - - @Override - public void mouseWheelMoved(final MouseWheelEvent e) { - zoomX -= e.getPreciseWheelRotation() * scrollSpeed; - zoomY -= e.getPreciseWheelRotation() * scrollSpeed; - this.repaint(); - } - - @Override - public void mouseMoved(final MouseEvent e) { - } - - @Override - public void mouseClicked(final MouseEvent e) { - } - - @Override - public void mouseEntered(final MouseEvent e) { - } - - @Override - public void mouseExited(final MouseEvent e) { - } - - @Override - public void actionPerformed(ActionEvent e) { - this.update(); - } - -} diff --git a/src/main/java/visual/InputSpace.java b/src/main/java/visual/InputSpace.java index 08bf2dc..b816b3a 100644 --- a/src/main/java/visual/InputSpace.java +++ b/src/main/java/visual/InputSpace.java @@ -35,7 +35,7 @@ public class InputSpace extends JPanel { * * @Author Kacper Ledwosiński, Piotr Machura */ - private class Pixel { + protected class Pixel { /** Location */ public int i; public int j; @@ -66,63 +66,89 @@ public class InputSpace extends JPanel { int scrollSpeed = 10; /** Function to plot */ - String function; + String f_z; /** If the user is panning, do not repaint the whole graph */ boolean panning = false; - /** - * InputSpace instance constructor. - */ - public InputSpace(String function) { - this.function = function; - - /** Mouse events used to pan/zoom the graph */ - MouseAdapter mouseAdapter = new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - originX = e.getX(); - originY = e.getY(); - panning = true; - } + /** Mouse adapter used to zoom/pan */ + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + originX = e.getX(); + originY = e.getY(); + panning = true; + } - @Override - public void mouseDragged(MouseEvent e) { - if (originX != -1 && originY != -1) { - offX = originX - e.getX(); - offY = originY - e.getY(); - repaint(); - } - repaint(); + @Override + public void mouseDragged(MouseEvent e) { + if (originX != -1 && originY != -1) { + offX = originX - e.getX(); + offY = originY - e.getY(); } + repaint(); + } - @Override - public void mouseReleased(MouseEvent e) { - centerX -= offX; - centerY += offY; - panning = false; - repaint(); - originX = -1; - originY = -1; - } + @Override + public void mouseReleased(MouseEvent e) { + centerX -= offX; + centerY += offY; + panning = false; + repaint(); + originX = -1; + originY = -1; + } - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - zoomX -= e.getPreciseWheelRotation() * scrollSpeed; - zoomY -= e.getPreciseWheelRotation() * scrollSpeed; - repaint(); - } - - }; + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + zoomX -= e.getPreciseWheelRotation() * scrollSpeed; + zoomY -= e.getPreciseWheelRotation() * scrollSpeed; + repaint(); + } + + }; + /** + * InputSpace instance constructor. + */ + public InputSpace(String function) { + this.f_z = function; addMouseMotionListener(mouseAdapter); addMouseListener(mouseAdapter); addMouseWheelListener(mouseAdapter); } + /** + * paintAxis. + * + * Paints axis on given graphics object. It is assumed that the graphics object + * is already translated by half of widht/height. + * + * @param g2 the graphics object to paint axis on. + */ + protected void paintAxis(Graphics2D g2) { + int w = getWidth(); + int h = getHeight(); + + // Draw axes + g2.setColor(Color.gray); + g2.drawLine(-w / 2, -centerY, w / 2, -centerY); + g2.drawLine(centerX, -h / 2, centerX, h / 2); + + // Draw ticks + g2.setColor(Color.gray); + for (int i = -(int) ((w + 2 * centerX) / (2 * zoomX / scaleX)) + - 1; i < (int) ((w - 2 * centerX) / (2 * zoomX / scaleX)) + 1; i++) { + g2.fillRect((int) (i * zoomX / scaleX) - 1 + centerX, -5 - centerY, 2, 10); + } + for (int i = -(int) ((h - 2 * centerY) / (2 * zoomY / scaleY)) + - 1; i < (int) ((h + 2 * centerY) / (2 * zoomY / scaleY)) + 1; i++) { + g2.fillRect(-5 + centerX, (int) (i * zoomY / scaleY) - 1 - centerY, 10, 2); + } + } + @Override protected void paintComponent(Graphics g) { - super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; int w = getWidth(); int h = getHeight(); @@ -169,7 +195,7 @@ public class InputSpace extends JPanel { double x = ii * tickX; double y = (originY - jj) * tickY; Point z0 = new Point("z", new Complex(x, y)); - Complex z = Parser.eval(function, z0).getComplexValue(); + Complex z = Parser.eval(f_z, z0).getComplexValue(); double phi; try { phi = ComplexUtils.phase(z) / 2 / Math.PI; @@ -198,20 +224,6 @@ public class InputSpace extends JPanel { } } - // Draw axes - g2.setColor(Color.gray); - g2.drawLine(-w / 2, -centerY, w / 2, -centerY); - g2.drawLine(centerX, -h / 2, centerX, h / 2); - - // Draw ticks - g2.setColor(Color.gray); - for (int i = -(int) ((w + 2 * centerX) / (2 * zoomX / scaleX)) - - 1; i < (int) ((w - 2 * centerX) / (2 * zoomX / scaleX)) + 1; i++) { - g2.fillRect((int) (i * zoomX / scaleX) - 1 + centerX, -5 - centerY, 2, 10); - } - for (int i = -(int) ((h - 2 * centerY) / (2 * zoomY / scaleY)) - - 1; i < (int) ((h + 2 * centerY) / (2 * zoomY / scaleY)) + 1; i++) { - g2.fillRect(-5 + centerX, (int) (i * zoomY / scaleY) - 1 - centerY, 10, 2); - } + paintAxis(g2); } } diff --git a/src/main/java/visual/OutputSpace.java b/src/main/java/visual/OutputSpace.java index d04f174..36aa51d 100644 --- a/src/main/java/visual/OutputSpace.java +++ b/src/main/java/visual/OutputSpace.java @@ -1,112 +1,16 @@ package visual; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.util.ArrayList; - -import javax.swing.JPanel; - -import com.expression.parser.exception.CalculatorException; -import com.expression.parser.function.Complex; -import solver.ComplexUtils; - /** - * @Author Kacper Ledwosiński + * The class OutputSpace. + * + * An InputSpace with f(z) = z. + * + * @Author Piotr Machura */ -public class OutputSpace extends JPanel { - private static final long serialVersionUID = 1L; - - float zoomX = 200, zoomY = 200; - float scaleX = 4, scaleY = 4; - String f; - ArrayList sq_points = new ArrayList(); - - Complex currentPoint = new Complex(0, 0); - - public OutputSpace(String f) { - this.f = f; - } - - public void addPoint(Complex p) { - sq_points.add(p); - this.repaint(); - } - - public void setCurrent(Complex c) { - this.currentPoint = c; - repaint(); - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - Graphics2D g2 = (Graphics2D) g; - g2.translate(getWidth() / 2, getHeight() / 2); - - double tickX = scaleX / zoomX; - double tickY = scaleY / zoomY; - - /** - * Paints output space with 1x1 pixel rectangles, color chosen as follows: hue = - * phase, saturation = 1, brightness = radius - */ - for (int j = -getHeight() / 2; j < getHeight() / 2; j++) { - for (int i = -getWidth() / 2; i < getWidth() / 2; i++) { - - double x = i * tickX; - double y = j * tickY; - double fi; - try { - fi = ComplexUtils.phase(new Complex(x, y)) / (2 * Math.PI); - } catch (Exception e) { - fi = 0; - } - double r = Complex.abs(new Complex(x, y)); - if (r > 1) { - r = 1; - } - g2.setColor(Color.getHSBColor((float) fi, 1, (float) r)); - g2.fillRect(i, j, 1, 1); - - } - } - - // draw current point - - g2.setColor(Color.white); - int x; - int y; - try { - double R = Complex.abs(currentPoint) * 10; - x = (int) (R * Math.cos(ComplexUtils.phase(currentPoint))); - y = (int) (R * Math.sin(ComplexUtils.phase(currentPoint))); - } catch (CalculatorException e) { - x = 0; - y = 0; - } - g2.fillArc(x - 5, y - 5, 10, 10, 0, 360); - - g2.setColor(Color.gray); - g2.drawLine(-getWidth() / 2, 0, getWidth() / 2, 0); - g2.drawLine(0, -getHeight() / 2, 0, getHeight() / 2); - - g2.setColor(Color.gray); - for (int i = -(int) (getWidth() / (2 * zoomX / scaleX)) - 1; i < (int) (getWidth() / (2 * zoomX / scaleX)) - + 1; i++) { - g2.fillRect((int) (i * zoomX / scaleX) - 1, -5, 2, 10); - } - for (int i = -(int) (getHeight() / (2 * zoomY / scaleY)) - 1; i < (int) (getHeight() / (2 * zoomY / scaleY)) - + 1; i++) { - g2.fillRect(-5, (int) (i * zoomY / scaleY) - 1, 10, 2); - } - - g2.setColor(Color.black); - for (int i = 0; i < sq_points.size(); i++) { - Complex p = sq_points.get(i); - g2.fillRect((int) (p.getR() * zoomY / scaleY) - 2, (int) (p.getI() * zoomY / scaleY) - 2, 4, 4); - } +public class OutputSpace extends InputSpace { + public OutputSpace() { + super("z"); + removeMouseWheelListener(mouseAdapter); } - } -- 2.45.2