Skip to content
Snippets Groups Projects
VectorOptimizer.java 4.71 KiB
Newer Older
  • Learn to ignore specific revisions
  • /**
     * This file is part of LibLaserCut.
     * Copyright (C) 2011 - 2013 Thomas Oster <thomas.oster@rwth-aachen.de>
     * RWTH Aachen University - 52062 Aachen, Germany
     *
     * LibLaserCut is free software: you can redistribute it and/or modify
     * it under the terms of the GNU Lesser General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     *
     * LibLaserCut 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 Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public License
     * along with LibLaserCut. If not, see <http://www.gnu.org/licenses/>.
     *
     */
    package com.t_oster.liblasercut.vectoroptimizers;
    
    import com.t_oster.liblasercut.LaserProperty;
    import com.t_oster.liblasercut.VectorCommand;
    import com.t_oster.liblasercut.VectorPart;
    import com.t_oster.liblasercut.platform.Point;
    import com.t_oster.liblasercut.platform.Rectangle;
    import java.util.LinkedList;
    import java.util.List;
    
    /**
     *
     * @author Thomas Oster <thomas.oster@rwth-aachen.de>
     */
    public abstract class VectorOptimizer
    {
    
      public enum OrderStrategy
      {
        FILE,
        NEAREST,
        INNER_FIRST,
        SMALLEST_FIRST
      }
    
      protected class Element
      {
    
        LaserProperty prop;
        Point start;
        List<Point> moves = new LinkedList<Point>();
    
        void invert()
        {
          if (!moves.isEmpty())
          {
            moves.add(0, start);
            start = moves.remove(moves.size() - 1);
            List<Point> inv = new LinkedList<Point>();
            while (!moves.isEmpty())
            {
              inv.add(moves.remove(moves.size() - 1));
            }
            moves = inv;
          }
        }
    
        Point getEnd()
        {
          return moves.isEmpty() ? start : moves.get(moves.size() - 1);
        }
    
        /**
         * compute bounding box of moves, including start point
         *
         * @return Rectangle
         */
        Rectangle boundingBox()
        {
          if (start == null)
          { // TODO may this happen?
            return null;
          }
          Rectangle bb = new Rectangle(start.x, start.y, start.x, start.y);
          for (Point p : moves)
          {
            bb.add(p);
          }
          return bb;
        }
    
        /**
         * test if this Element represents a closed path (polygon)
         *
         * @return true if start equals end, false otherwise
         */
        boolean isClosedPath()
        {
          if ((start == null) || moves.isEmpty())
          {
            return false;
          }
          return getEnd().equals(start);
        }
      }
    
      public static VectorOptimizer create(OrderStrategy s)
      {
        switch (s)
        {
          case FILE:
            return new FileVectorOptimizer();
          case NEAREST:
            return new NearestVectorOptimizer();
          case INNER_FIRST:
            return new InnerFirstVectorOptimizer();
          case SMALLEST_FIRST:
            return new SmallestFirstVectorOptimizer();
        }
        throw new IllegalArgumentException("Unknown Order Strategy: " + s);
      }
    
      protected List<Element> divide(VectorPart vp)
      {
        List<Element> result = new LinkedList<Element>();
        Element cur = null;
        Point lastMove = null;
        LaserProperty lastProp = null;
        boolean stop = false;
        for (VectorCommand cmd : vp.getCommandList())
        {
          switch (cmd.getType())
          {
            case MOVETO:
            {
              lastMove = new Point(cmd.getX(), cmd.getY());
              stop = true;
              break;
            }
            case LINETO:
            {
              if (stop)
              {
                stop = false;
                if (cur != null)
                {
                  result.add(cur);
                }
                cur = new Element();
                cur.start = lastMove;
                cur.prop = lastProp;
              }
              cur.moves.add(new Point(cmd.getX(), cmd.getY()));
              break;
            }
            case SETPROPERTY:
            {
              lastProp = cmd.getProperty();
              stop = true;
              break;
            }
          }
        }
        if (cur != null)
        {
          result.add(cur);
        }
        return result;
      }
    
      protected double dist(Point a, Point b)
      {
        return Math.sqrt((a.y - b.y) * (a.y - b.y) + (a.x - b.x) * (a.x - b.x));
      }
    
      protected abstract List<Element> sort(List<Element> e);
    
      public VectorPart optimize(VectorPart vp)
      {
        List<Element> opt = this.sort(this.divide(vp));
        LaserProperty cp = opt.isEmpty() ? vp.getCurrentCuttingProperty() : opt.get(0).prop;
        VectorPart result = new VectorPart(cp, vp.getDPI());
        for (Element e : opt)
        {
          if (!e.prop.equals(cp))
          {
            result.setProperty(e.prop);
            cp = e.prop;
          }
          result.moveto(e.start.x, e.start.y);
          for (Point p : e.moves)
          {
            result.lineto(p.x, p.y);
          }
        }
        return result;
      }
    }