Package Makelangelo

Source Code of Makelangelo.DrawPanel$DrawPanelNode

package Makelangelo;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.prefs.Preferences;

import javax.swing.JPanel;
import javax.swing.event.MouseInputListener;

import DrawingTools.DrawingTool;


  // Custom drawing panel written as an inner class to access the instance variables.
public class DrawPanel extends JPanel implements MouseListener, MouseInputListener  {
  static final long serialVersionUID=2;

  private Preferences prefs = Preferences.userRoot().node("DrawBot").node("Graphics");
 
  // arc smoothness - increase to make more smooth and run slower.
  public static final double STEPS_PER_DEGREE=1;
  public static final double RAD2DEG = 180.0/Math.PI;
  public static final double DEG2RAD = Math.PI/180.0;

  // progress
  long linesProcessed=0;
  boolean connected=false;
  boolean running=false;

  // config
  boolean show_pen_up=false;
 
  // motion control
  boolean mouseIn=false;
  int buttonPressed=MouseEvent.NOBUTTON;
  int oldx, oldy;

  // scale + position
  double cameraOffsetX=0,cameraOffsetY=0;
  double cameraZoom=20;
  float drawScale=0.1f;
  final float extraScale=100;

  ArrayList<String> instructions;

  public enum NodeType { COLOR, POS, TOOL };
 
  // optimization attempt
  class DrawPanelNode {
    double x1,y1,x2,y2;
    Color c;
    int tool_id;
    int line_number;
    NodeType type;
  }
  ArrayList<DrawPanelNode> fast_nodes = new ArrayList<DrawPanelNode>();
  BasicStroke fast_stroke;
 
 
  public DrawPanel() {
    super();
        addMouseMotionListener(this);
        addMouseListener(this);
  }
 
 
  public void setGCode(ArrayList<String> gcode) {
    instructions = gcode;
    emptyNodeBuffer();
    // process the image into a buffer once rather than re-reading the gcode over and over again?
      repaint();
  }
 
  public void emptyNodeBuffer() {
    fast_nodes.clear();
    OptimizeNodes();
  }
 
 
  public void updateMachineConfig() {
    repaint();
  }
 
 
  public void setShowPenUp(boolean state) {
    show_pen_up=state;
    emptyNodeBuffer();
    repaint();
  }
 
  public boolean getShowPenUp() {
    return show_pen_up;
  }
 
 
  public void setLinesProcessed(long c) {
    linesProcessed=c;
    if((linesProcessed%10)==0) repaint();
  }
 
  public void setConnected(boolean state) {
    connected=state;
    repaint();
  }
 
  public void setRunning(boolean state) {
    running=state;
    if(running==false) {
      linesProcessed=0;
    }
  }
 
  // returns angle of dy/dx as a value from 0...2PI
  private double atan3(double dy,double dx) {
    double a=Math.atan2(dy,dx);
    if(a<0) a=(Math.PI*2.0)+a;
    return a;
  }


  private void MoveCamera(int x,int y) {
      cameraOffsetX+=oldx-x;
      cameraOffsetY+=oldy-y;
  }
 
  private void ZoomCamera(int x,int y) {
    double amnt = (double)(y-oldy)*0.01;
    cameraZoom += amnt;
    if(cameraZoom<0.1) cameraZoom=0.1f;
  }
 
  public void ZoomIn() {
    cameraZoom*=4.0/3.0;
    cameraOffsetX*=4.0/3.0;
    cameraOffsetY*=4.0/3.0;
      repaint();
  }
  public void ZoomOut() {
    cameraZoom*=3.0/4.0;
    cameraOffsetX*=3.0/4.0;
    cameraOffsetY*=3.0/4.0;
      repaint();
  }
 
  public void ZoomToFitPaper() {
    MachineConfiguration mc=MachineConfiguration.getSingleton();
   
    float w=(float)this.getWidth();
    float h=(float)this.getHeight();
    // which one do we have to zoom more to fit the picture in the component?
    float wzoom=w/(float)(mc.paper_right-mc.paper_left);
    float hzoom=h/(float)(mc.paper_top-mc.paper_bottom);
    cameraZoom = (wzoom < hzoom ? wzoom : hzoom) / extraScale;
    cameraOffsetX=0;
    cameraOffsetY=0;
    repaint();
  }
 
  public void mousePressed(MouseEvent e) {
    buttonPressed=e.getButton();
      oldx=e.getX();
      oldy=e.getY();
  }
    public void mouseReleased(MouseEvent e) {
      buttonPressed=MouseEvent.NOBUTTON;
    }
    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseDragged(MouseEvent e) {
      int x=e.getX();
      int y=e.getY();
      if(buttonPressed==MouseEvent.BUTTON1) {
        MoveCamera(x,y);
      } else if(buttonPressed==MouseEvent.BUTTON3) {
        ZoomCamera(x,y);
      }
      oldx=x;
      oldy=y;
      repaint();
    }
    public void mouseMoved(MouseEvent e) {}

   
    private double TX(double a) {
      return (+a)*extraScale;
    }
    private double TY(double a) {
      return (-a)*extraScale;
    }
    private double ITX(double a) {
      return TX(a); // TX(a*imageScale-imageOffsetX);
    }
    private double ITY(double a) {
      return TY(a); // TY(a*imageScale-imageOffsetY);
    }
   
    private void paintCamera(Graphics2D g2d) {
    float w=(float)this.getWidth();
    float h=(float)this.getHeight();
    if(prefs.getBoolean("antialias", true)) g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    if(prefs.getBoolean("speed over quality", true)) g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);
    g2d.translate(-cameraOffsetX+w/2, -cameraOffsetY+h/2);
    g2d.scale(cameraZoom, cameraZoom);
    }
   
    private void paintBackground() {
    setBackground(Color.GRAY);
    }
   
    private void paintLimits(Graphics2D g2d,MachineConfiguration mc) {
    if(!connected) {
      g2d.setColor(new Color(194.0f/255.0f,133.0f/255.0f,71.0f/255.0f));
      g2d.drawRect((int)TX(mc.limit_left),(int)TY(mc.limit_top),
          (int)((mc.limit_right-mc.limit_left)*extraScale),
          (int)((mc.limit_top-mc.limit_bottom)*extraScale));
      g2d.setColor(Color.WHITE);
      g2d.fillRect((int)TX(mc.paper_left),(int)TY(mc.paper_top),
          (int)((mc.paper_right-mc.paper_left)*extraScale),
          (int)((mc.paper_top-mc.paper_bottom)*extraScale));
    } else {
      g2d.setColor(new Color(194.0f/255.0f,133.0f/255.0f,71.0f/255.0f));
      g2d.fillRect((int)TX(mc.limit_left),(int)TY(mc.limit_top),
          (int)((mc.limit_right-mc.limit_left)*extraScale),
          (int)((mc.limit_top-mc.limit_bottom)*extraScale));
      g2d.setColor(Color.WHITE);
      g2d.fillRect((int)TX(mc.paper_left),(int)TY(mc.paper_top),
          (int)((mc.paper_right-mc.paper_left)*extraScale),
          (int)((mc.paper_top-mc.paper_bottom)*extraScale));
    }
    }
   
    private void paintCenter(Graphics2D g2d) {
    // draw calibration point
    g2d.setColor(Color.RED);
    g2d.drawLine((int)TX(-0.25),(int)TY( 0.00), (int)TX(0.25),(int)TY(0.00));
    g2d.drawLine((int)TX( 0.00),(int)TY(-0.25), (int)TX(0.00),(int)TY(0.25));
    }
   
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);    // paint background
    Graphics2D g2d = (Graphics2D)g;

    MachineConfiguration mc = MachineConfiguration.getSingleton();
    DrawingTool tool = mc.GetTool(0);
   
    paintBackground();
    paintCamera(g2d);
    paintLimits(g2d,mc);
    paintCenter(g2d);
    // TODO draw left motor
    // TODO draw right motor
    // TODO draw control box
   
    final int look_ahead=500;

    g2d.setColor(Color.BLACK);
   
    // draw image   
    if(fast_nodes.size()>0) {
      // draw the nodes
      for(int i=0;i<fast_nodes.size();++i) {
        DrawPanelNode n=fast_nodes.get(i);

        if(running) {
          if(n.line_number<=linesProcessed) {
            g2d.setColor(Color.RED);
          } else if(n.line_number<=linesProcessed+look_ahead) {
            g2d.setColor(Color.GREEN);
          } else if(prefs.getBoolean("Draw all while running", true) == false) {
            break;
          }
        }
       
        switch(n.type) {
        case TOOL:
          tool = MachineConfiguration.getSingleton().GetTool(n.tool_id);
          g2d.setStroke(tool.getStroke());
          break;
        case COLOR:
          if(!running || n.line_number>linesProcessed+look_ahead) {
            g2d.setColor(n.c);
          }
          break;
        default:
          tool.DrawLine(g2d, n.x1, n.y1, n.x2, n.y2);
          break;
        }
      }
    }
    g2d.dispose();
  }
 
  private void addNodePos(int i,double x1,double y1,double x2,double y2) {
    DrawPanelNode n = new DrawPanelNode();
    n.line_number=i;
    n.x1=x1;
    n.x2=x2;
    n.y1=y1;
    n.y2=y2;
    n.type=NodeType.POS;
    fast_nodes.add(n);
  }
 
  private void addNodeColor(int i,Color c) {
    DrawPanelNode n = new DrawPanelNode();
    n.line_number=i;
    n.c=c;
    n.type=NodeType.COLOR;
    fast_nodes.add(n);
  }
 
  private void addNodeTool(int i,int tool_id) {
    DrawPanelNode n = new DrawPanelNode();
    n.line_number=i;
    n.tool_id=tool_id;
    n.type=NodeType.TOOL;
    fast_nodes.add(n);
   
  }

  private void OptimizeNodes() {
    if(instructions == null) return;
   
    MachineConfiguration mc = MachineConfiguration.getSingleton();
    DrawingTool tool = mc.GetTool(0);
   
    drawScale=0.1f;
   
    float px=0,py=0,pz=90;
    float x,y,z,ai,aj;
    int i,j;
    boolean absMode=true;
    String tool_change="M06 T";
    Color tool_color=Color.BLACK;
   
    pz=0.5f;
   
    for(i=0;i<instructions.size();++i) {
      String line=instructions.get(i);
      String[] pieces=line.split(";");
      if(pieces.length==0) continue;

      if(line.startsWith(tool_change)) {
        String numberOnly= line.substring(tool_change.length()).replaceAll("[^0-9]", "");
        int id = (int)Integer.valueOf(numberOnly, 10);
        addNodeTool(i,id);
        switch(id) {
        case 1: tool_color = Color.RED; break;
        case 2: tool_color = Color.GREEN; break;
        case 3: tool_color = Color.BLUE; break;
        default: tool_color = Color.BLACK; break;
        }
        continue;
      }
     
      String[] tokens = pieces[0].split("\\s");
      if(tokens.length==0) continue;
     
      // have we changed scale?
      // what are our coordinates?
      x=px;
      y=py;
      z=pz;
      ai=px;
      aj=py;
      for(j=0;j<tokens.length;++j) {
        if(tokens[j].equals("G20")) drawScale=2.54f; // in->cm
        else if(tokens[j].equals("G21")) drawScale=0.10f; // mm->cm
        else if(tokens[j].equals("G90")) {
          absMode=true;
          break;
        } else if(tokens[j].equals("G91")) {
          absMode=false;
          break;
        }
        else if(tokens[j].equals("G54")) break;
        else if(tokens[j].startsWith("X")) {
          float tx = Float.valueOf(tokens[j].substring(1)) * drawScale;
          x = absMode ? tx : x + tx;
        }
        else if(tokens[j].startsWith("Y")) {
          float ty = Float.valueOf(tokens[j].substring(1)) * drawScale;
          y = absMode ? ty : y + ty;
        }
        else if(tokens[j].startsWith("Z")) {
          float tz = z = Float.valueOf(tokens[j].substring(1));// * drawScale;
          z =  absMode ? tz : z + tz;
        }
        if(tokens[j].startsWith("I")) ai = Float.valueOf(tokens[j].substring(1)) * drawScale;
        if(tokens[j].startsWith("J")) aj = Float.valueOf(tokens[j].substring(1)) * drawScale;
      }
      if(j<tokens.length) continue;
      //*
      // is pen up or down?
      tool.DrawZ(z);
      if(tool.DrawIsOff()) {
        if(show_pen_up==false) {
          px=x;
          py=y;
          pz=z;
          continue;
        }
        addNodeColor(i, Color.BLUE );
      } else if(tool.DrawIsOn()) {
        addNodeColor(i, tool_color )// TODO use actual pen color
      } else {
        addNodeColor(i, Color.ORANGE );
      }
     
      // what kind of motion are we going to make?
      if(tokens[0].equals("G00") || tokens[0].equals("G0") ||
         tokens[0].equals("G01") || tokens[0].equals("G1")) {
        //if(z==pz)
        {
          addNodePos(i,ITX(px),ITY(py),ITX(x),ITY(y))
        }
      } else if(tokens[0].equals("G02") || tokens[0].equals("G2") ||
            tokens[0].equals("G03") || tokens[0].equals("G3")) {
        // draw an arc
       
        // clockwise or counter-clockwise?
        int dir = (tokens[0].equals("G02") || tokens[0].equals("G2")) ? -1 : 1;

        double dx=px - ai;
        double dy=py - aj;
        double radius=Math.sqrt(dx*dx+dy*dy);

        // find angle of arc (sweep)
        double angle1=atan3(dy,dx);
        double angle2=atan3(y-aj,x-ai);
        double theta=angle2-angle1;

        if(dir>0 && theta<0) angle2+=Math.PI*2.0;
        else if(dir<0 && theta>0) angle1+=Math.PI*2.0;

        theta=Math.abs(angle2-angle1)*RAD2DEG*STEPS_PER_DEGREE;

        // Draw the arc from a lot of little line segments.
        for(int k=0;k<=theta;++k) {
          double angle3 = (angle2-angle1) * ((double)k/theta) + angle1;
          float nx = (float)(ai + Math.cos(angle3) * radius);
            float ny = (float)(aj + Math.sin(angle3) * radius);

            addNodePos(i,ITX(px),ITY(py),ITX(nx),ITY(ny));
          px=nx;
          py=ny;
        }
        addNodePos(i,ITX(px),ITY(py),ITX(x),ITY(y))
      }
     
      px=x;
      py=y;
      pz=z;
    // for ( each instruction )
  }
}



/**
* This file is part of DrawbotGUI.
*
* DrawbotGUI is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DrawbotGUI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
*/
TOP

Related Classes of Makelangelo.DrawPanel$DrawPanelNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.