package net.developpez.oscillo; import java.awt.Canvas; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferStrategy; import java.util.concurrent.atomic.AtomicLong; import javax.swing.JFrame; import javax.swing.SwingUtilities; public class OscilloscopeExemple extends Canvas { private static final int BUFFER_SIZE = 300; private static final Color MAIN_GRID_COLOR = Color.WHITE; private static final Color SECONDARY_GRID_COLOR = Color.GRAY; private static final int HORIZONTAL_GRID_DIVISION_NUMBER = 10; private static final int VERTICAL_GRID_DIVISION_NUMBER = 10; private static final Color SIGNAL_COLOR = Color.RED; private FunctionThread thread; private final BackgroundGrid grid; private double[] buffer; private int next; private volatile boolean bufferFilled; private final AtomicLong lastInput; private int lastWidth; private int lastHeight; private BufferStrategy buffereStrategy; private float scalex; private float scaley; private double adaptedScalex; private final IFuntion function; private int midy; private int midx; private double leftx; private boolean scaleXDependsOnBufferSize; private int componentWidth; public OscilloscopeExemple(int bufferSize, float scalex, float scaley, IFuntion function) { this(bufferSize, scalex, scaley, function, true); } /** * * @param bufferSize nombre de mesures conservées * @param scalex facteur d'échelle x * @param scaley facteur d'échelle y * @param function function de signal * @param scaleXDependsOnBufferSize true si le buffer doit être affichée entièrement dans la largeur (donc que l'échelle s'adapte), false sinon (par défaut) */ public OscilloscopeExemple(int bufferSize, float scalex, float scaley, IFuntion function, boolean scaleXDependsOnBufferSize) { this.function = function; buffer = new double[bufferSize]; next = 0; bufferFilled = false; lastInput = new AtomicLong(); grid = new BackgroundGrid(MAIN_GRID_COLOR, SECONDARY_GRID_COLOR, HORIZONTAL_GRID_DIVISION_NUMBER, VERTICAL_GRID_DIVISION_NUMBER); lastWidth = lastHeight = -1; this.scaleXDependsOnBufferSize = scaleXDependsOnBufferSize; this.scalex=scalex; this.scaley=scaley; setIgnoreRepaint(true); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { initOrReset(); } }); } private synchronized void initOrReset() { componentWidth = getWidth(); final int height = getHeight(); if (lastWidth != componentWidth || lastHeight != height) { grid.setSize(componentWidth, height); midy = height >> 1; midx = componentWidth >> 1; if ( scaleXDependsOnBufferSize ) { adaptedScalex = (scalex * componentWidth)/buffer.length; } else { adaptedScalex = scalex; } // leftx = midx-buffer.length/2*adaptedScalex; leftx = midx * ( 1 - scalex ); } } public void setScaleX(float scalex) { this.scalex=scalex; if ( scaleXDependsOnBufferSize ) { adaptedScalex = (scalex * componentWidth)/buffer.length; } else { adaptedScalex = scalex; } leftx = midx * ( 1 - scalex ); } public void setScaleY(float scaley) { this.scaley=scaley; } public synchronized void start() { if (thread == null) { initOrReset(); createBufferStrategy(2); buffereStrategy = getBufferStrategy(); thread = new FunctionThread(); thread.start(); } } public synchronized void stop() { if (thread != null) { thread.stopThread(); thread = null; buffereStrategy.dispose(); buffereStrategy=null; } } private void drawDirect() { if ( buffereStrategy==null ) return; Graphics2D grBuffer = (Graphics2D) buffereStrategy.getDrawGraphics(); grBuffer.drawImage(grid.getImage(), 0, 0, null); grBuffer.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); grBuffer.setColor(SIGNAL_COLOR); grBuffer.translate(0, midy); double prevx=leftx; int prevy=0; if ( bufferFilled ) { int max = scaleXDependsOnBufferSize?buffer.length:(componentWidth>buffer.length?buffer.length:Math.min(next+componentWidth,buffer.length)); /*if ( nextnext?next:componentWidth); if ( 0 run()); } public static void run() { //System.setProperty("sun.java2d.transaccel", "True"); //System.setProperty("sun.java2d.ddforcevram", "True"); JFrame frame = new JFrame("Démo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); OscilloscopeExemple panel = new OscilloscopeExemple(300, 1/*BUFFER_SIZE/300f*/, 1, (t)-> Math.sin(t/30d) * 100d ); //OscilloscopeExemple panel = new OscilloscopeExemple(BUFFER_SIZE, 1/*BUFFER_SIZE/300f*/, 1, (t)-> Math.sin(t/30d) * 100d, false ); frame.getContentPane().add(panel); frame.setSize(300, 300); frame.setLocationRelativeTo(null); frame.addWindowListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { panel.start(); } @Override public void windowClosed(WindowEvent e) { panel.stop(); } }); frame.setVisible(true); } // ************************************************************************************ }