All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jadice.barcode.twod.dmtx.ScanGrid Maven / Gradle / Ivy

There is a newer version: 1.1.31
Show newest version
/*
 * This file is part of a java-port of the libdmtx library.
 * 
 * Copyright (C) 2014 levigo solutions gmbh Contact: [email protected]
 * 
 * 
 * The original library's copyright statement follows:
 * 
 * libdmtx - Data Matrix Encoding/Decoding Library
 * 
 * Copyright (C) 2011 Mike Laughton
 * 
 * This library 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
 * 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 this library;
 * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Contact: [email protected]
 */
package com.jadice.barcode.twod.dmtx;

import java.awt.Point;

import com.jadice.barcode.DiagnosticSettings;
import com.jadice.barcode.Options;
import com.jadice.barcode.Marker.Feature;
import com.jadice.barcode.grid.Grid;

public class ScanGrid implements ScanStrategy {
  public enum Range {
    Good, Bad, End
  }

  /* set once */
  private int minExtent; /* Smallest cross size used in scan */
  private final int maxExtent; /* Size of bounding grid region (2^N - 1) */
  private final int xOffset; /* Offset to obtain image X coordinate */
  private final int yOffset; /* Offset to obtain image Y coordinate */
  private final int xMin; /* Minimum X in image coordinate system */
  private final int xMax; /* Maximum X in image coordinate system */
  private final int yMin; /* Minimum Y in image coordinate system */
  private final int yMax; /* Maximum Y in image coordinate system */

  /* reset for each level */
  @SuppressWarnings("unused")
  private int total; /* Total number of crosses at this size */
  private int extent; /* Length/width of cross in pixels */
  private int jumpSize; /* Distance in pixels between cross centers */
  private int pixelTotal; /* Total pixel count within an individual cross path */
  private int startPos; /* X and Y coordinate of first cross center in pattern */

  /* reset for each cross */
  private int pixelCount; /* Progress (pixel count) within current cross pattern */
  private int xCenter; /* X center of current cross pattern */
  private int yCenter; /* Y center of current cross pattern */

  private final boolean createMarkup;
  private final DiagnosticSettings diagnostics;

  /**
   * \brief Initialize scan grid pattern \param dec \return Initialized grid
   * 
   * @param options
   */
  ScanGrid(Grid grid, Options options) {
    createMarkup = options.getSettings(DiagnosticSettings.class).isMarkupEnabled();
    diagnostics = options.getSettings(DiagnosticSettings.class);

    int scale = 1;
    int smallestFeature = 1 / scale;

    xMin = 0;
    xMax = grid.getWidth() - 1;
    yMin = 0;
    yMax = grid.getHeight() - 1;

    /* Values that get set once */
    int xExtent = xMax - xMin;
    int yExtent = yMax - yMin;
    int maxExtent = Math.max(xExtent, yExtent);
    assert maxExtent > 1;

    int minExtent = 1;
    int extent;
    for (extent = 1; extent < maxExtent; extent = (extent + 1) * 2 - 1)
      if (extent <= smallestFeature)
        minExtent = extent;
    this.minExtent = minExtent;
    this.maxExtent = extent;

    xOffset = (xMin + xMax - this.maxExtent) / 2;
    yOffset = (yMin + yMax - this.maxExtent) / 2;

    /* Values that get reset for every level */
    total = 1;
    this.extent = this.maxExtent;

    setDerivedFields();
  }

  /**
   * \brief Extract current grid position in pixel coordinates and return whether location is good,
   * bad, or end \param grid \return Pixel location
   */
  private Range getGridCoordinates(PixelLocation p) {
    /*
     * Initially pixelCount may fall beyond acceptable limits. Update grid state before testing
     * coordinates
     */

    /* Jump to next cross pattern horizontally if current column is done */
    if (pixelCount >= pixelTotal) {
      pixelCount = 0;
      xCenter += jumpSize;
    }

    /* Jump to next cross pattern vertically if current row is done */
    if (xCenter > maxExtent) {
      xCenter = startPos;
      yCenter += jumpSize;
    }

    /* Increment level when vertical step goes too far */
    if (yCenter > maxExtent) {
      total *= 4;
      this.extent = extent / 2;
      setDerivedFields();
    }

    if (extent == 0 || extent < minExtent) {
      p.x = p.y = -1;
      return Range.End;
    }

    int count = pixelCount;

    assert count < pixelTotal;

    final PixelLocation loc = new PixelLocation();
    if (count == pixelTotal - 1) {
      /* center pixel */
      loc.x = xCenter;
      loc.y = yCenter;
    } else {
      int half = pixelTotal / 2;
      int quarter = half / 2;

      /* horizontal portion */
      if (count < half) {
        loc.x = xCenter + (count < quarter ? count - quarter : half - count);
        loc.y = yCenter;
      }
      /* vertical portion */
      else {
        count -= half;
        loc.x = xCenter;
        loc.y = yCenter + (count < quarter ? count - quarter : half - count);
      }
    }

    loc.x += xOffset;
    loc.y += yOffset;

    p.x = loc.x;
    p.y = loc.y;

    if (loc.x < xMin || loc.x > xMax || loc.y < yMin || loc.y > yMax)
      return Range.Bad;

    return Range.Good;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.levigo.barcode.twod.dmtx.ScanStrategy#popGridLocation(com.levigo.barcode.twod.dmtx.
   * PixelLocation)
   */
  @Override
  public boolean getNextScanLocation(PixelLocation p) {
    Range locStatus;
    do {
      locStatus = getGridCoordinates(p);

      /* Always leave grid pointing at next available location */
      pixelCount++;
    } while (locStatus == Range.Bad);

    if (createMarkup)
      diagnostics.add(Feature.INITIAL_SCAN, new Point(p.x, p.y));

    return locStatus != Range.End;
  }

  /**
   * \brief Update derived fields based on current state \param grid \return void
   */
  private void setDerivedFields() {
    jumpSize = extent + 1;
    pixelTotal = 2 * extent - 1;
    startPos = extent / 2;
    pixelCount = 0;
    xCenter = yCenter = startPos;
  }

  public int getMinExtent() {
    return minExtent;
  }

  public void setMinExtent(int minExtent) {
    this.minExtent = minExtent;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy