You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

370 lines
10 KiB

/*
DataMatrix.Net
DataMatrix.Net - .net library for decoding DataMatrix codes.
Copyright (C) 2009/2010 Michael Faschinger
This library 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.0 of the License, or (at your option) any later version.
You can also redistribute and/or modify it under the terms of the
GNU Lesser General Public License as published by the Free Software
Foundation; either version 3.0 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
General Public License or the GNU Lesser General Public License
for more details.
You should have received a copy of the GNU General Public
License and the GNU Lesser General Public License along with this
library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Contact: Michael Faschinger - michfasch@gmx.at
*/
using System;
namespace DataMatrix.net
{
internal struct DmtxScanGrid
{
#region Fields
int _minExtent;
int _maxExtent;
int _xOffset;
int _yOffset;
int _xMin;
int _xMax;
int _yMin;
int _yMax;
int _total;
int _extent;
int _jumpSize;
int _pixelTotal;
int _startPos;
int _pixelCount;
int _xCenter;
int _yCenter;
#endregion
#region Constructors
internal DmtxScanGrid(DmtxDecode dec)
{
int smallestFeature = dec.ScanGap;
this._xMin = dec.XMin;
this._xMax = dec.XMax;
this._yMin = dec.YMin;
this._yMax = dec.YMax;
/* Values that get set once */
int xExtent = this._xMax - this._xMin;
int yExtent = this._yMax - this._yMin;
int maxExtent = (xExtent > yExtent) ? xExtent : yExtent;
if (maxExtent < 1)
{
throw new ArgumentException("Invalid max extent for Scan Grid: Must be greater than 0");
}
int extent = 1;
this._minExtent = extent;
for (; extent < maxExtent; extent = ((extent + 1) * 2) - 1)
{
if (extent <= smallestFeature)
{
_minExtent = extent;
}
}
this._maxExtent = extent ;
this._xOffset = (this._xMin + this._xMax - this._maxExtent) / 2;
this._yOffset = (this._yMin + this._yMax - this._maxExtent) / 2;
/* Values that get reset for every level */
this._total = 1;
this._extent = this._maxExtent;
this._jumpSize = this._extent + 1;
this._pixelTotal = 2 * this._extent - 1;
this._startPos = this._extent / 2;
this._pixelCount = 0;
this._xCenter = this._yCenter = this._startPos;
SetDerivedFields();
}
#endregion
#region Methods
internal DmtxRange PopGridLocation(ref DmtxPixelLoc loc)
{
DmtxRange locStatus;
do
{
locStatus = GetGridCoordinates(ref loc);
/* Always leave grid pointing at next available location */
this._pixelCount++;
} while (locStatus == DmtxRange.DmtxRangeBad);
return locStatus;
}
private DmtxRange GetGridCoordinates(ref DmtxPixelLoc locRef)
{
/* 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 (this._pixelCount >= this._pixelTotal)
{
this._pixelCount = 0;
this._xCenter += this._jumpSize;
}
/* Jump to next cross pattern vertically if current row is done */
if (this._xCenter > this._maxExtent)
{
this._xCenter = this._startPos;
this._yCenter += this._jumpSize;
}
/* Increment level when vertical step goes too far */
if (this._yCenter > this._maxExtent)
{
this._total *= 4;
this._extent /= 2;
SetDerivedFields();
}
if (this._extent == 0 || this._extent < this._minExtent)
{
locRef.X = locRef.Y = -1;
return DmtxRange.DmtxRangeEnd;
}
int count = this._pixelCount;
if (count >= this._pixelTotal)
{
throw new Exception("Scangrid is beyong image limits!");
}
DmtxPixelLoc loc = new DmtxPixelLoc();
if (count == this._pixelTotal - 1)
{
/* center pixel */
loc.X = this._xCenter;
loc.Y = this._yCenter;
}
else
{
int half = this._pixelTotal / 2;
int quarter = half / 2;
/* horizontal portion */
if (count < half)
{
loc.X = this._xCenter + ((count < quarter) ? (count - quarter) : (half - count));
loc.Y = this._yCenter;
}
/* vertical portion */
else
{
count -= half;
loc.X = this._xCenter;
loc.Y = this._yCenter + ((count < quarter) ? (count - quarter) : (half - count));
}
}
loc.X += this._xOffset;
loc.Y += this._yOffset;
locRef.X = loc.X;
locRef.Y = loc.Y;
if (loc.X < this._xMin || loc.X > this._xMax ||
loc.Y < this._yMin || loc.Y > this._yMax)
{
return DmtxRange.DmtxRangeBad;
}
return DmtxRange.DmtxRangeGood;
}
/// <summary>
/// Update derived fields based on current state
/// </summary>
private void SetDerivedFields()
{
this._jumpSize = this._extent + 1;
this._pixelTotal = 2 * this._extent - 1;
this._startPos = this._extent / 2;
this._pixelCount = 0;
this._xCenter = this._yCenter = this._startPos;
}
#endregion
#region Properties
/// <summary>
/// Smallest cross size used in scan
/// </summary>
internal int MinExtent
{
get { return _minExtent; }
set { _minExtent = value; }
}
/// <summary>
/// Size of bounding grid region (2^N - 1)
/// </summary>
internal int MaxExtent
{
get { return _maxExtent; }
set { _maxExtent = value; }
}
/// <summary>
/// Offset to obtain image X coordinate
/// </summary>
internal int XOffset
{
get { return _xOffset; }
set { _xOffset = value; }
}
/// <summary>
/// Offset to obtain image Y coordinate
/// </summary>
internal int YOffset
{
get { return _yOffset; }
set { _yOffset = value; }
}
/// <summary>
/// Minimum X in image coordinate system
/// </summary>
internal int XMin
{
get { return _xMin; }
set { _xMin = value; }
}
/// <summary>
/// Maximum X in image coordinate system
/// </summary>
internal int XMax
{
get { return _xMax; }
set { _xMax = value; }
}
/// <summary>
/// Minimum Y in image coordinate system
/// </summary>
internal int YMin
{
get { return _yMin; }
set { _yMin = value; }
}
/// <summary>
/// Maximum Y in image coordinate system
/// </summary>
internal int YMax
{
get { return _yMax; }
set { _yMax = value; }
}
/// <summary>
/// Total number of crosses at this size
/// </summary>
internal int Total
{
get { return _total; }
set { _total = value; }
}
/// <summary>
/// Length/width of cross in pixels
/// </summary>
internal int Extent
{
get { return _extent; }
set { _extent = value; }
}
/// <summary>
/// Distance in pixels between cross centers
/// </summary>
internal int JumpSize
{
get { return _jumpSize; }
set { _jumpSize = value; }
}
/// <summary>
/// Total pixel count within an individual cross path
/// </summary>
internal int PixelTotal
{
get { return _pixelTotal; }
set { _pixelTotal = value; }
}
/// <summary>
/// X and Y coordinate of first cross center in pattern
/// </summary>
internal int StartPos
{
get { return _startPos; }
set { _startPos = value; }
}
/// <summary>
/// Progress (pixel count) within current cross pattern
/// </summary>
internal int PixelCount
{
get { return _pixelCount; }
set { _pixelCount = value; }
}
/// <summary>
/// X center of current cross pattern
/// </summary>
internal int XCenter
{
get { return _xCenter; }
set { _xCenter = value; }
}
/// <summary>
/// Y center of current cross pattern
/// </summary>
internal int YCenter
{
get { return _yCenter; }
set { _yCenter = value; }
}
#endregion
}
}