[1] ГОСТ Р 52633.0-2006. Защита информации. Техника защиты информации. Требования к средствам высоконадежной биометрической аутентификации – Введ. 2007–31–03. –М.: Изд-во стандартов, 2007. – 25 с.
[2] Современные биометрические методы идентификации [Электронный ресурс]. – Режим доступа: http://habrahabr.ru/post/126144 Дата доступа: 15.03.2016.
[3] Connell, S. D. On-line signature verification / S.D. Connell // Pattern Recognition Letters. 2002. - Volume 35, Issue 12. - P: 2963-2972
[4] Itoh, Y. Multi-Matcher On-Line Signature: Verification System in DWT Domain // IEEE transactions fundamentals. 2006. - Vol. E89-A, №1. -P. 178-185.
[5] Schimke, S. Biometrics: Different Approaches for Using Gaussian Mixture Models in Handwriting / S. Schimke // CMS, LNCS. 2005. - №3677. - 2005. -P. 261-263.
[6] Zhang, J. Online Signature Verification Using Segment-to-Segment Matching / J.Zhang, S.Kamata // International Conference on Frontiers in Handwriting Recognition ICFHR. Montreal, Quebec. - 2008. - P. 51-57.
[7] Moallem, P. Dynamic online signatures recognition system using a novel signature-based normalized features string and MLP neuralnetwork / P. Moallem, S. A. Monadjemi // Iranian Journal of Engineering Sciences. 2007. - Vol. 1, №1. -P. 24-36
[8] McCabe, Y. Neural Network-based Handwritten Signature Verification / Y. McCabe // Journal of Computers. 2008. - Vol. 3, №8. - P. 9-22.
[9] Wintab Backgrounder [Электронный ресурс]. – Режим доступа: http://www.wacomeng.com/windows/docs/WintabBackground.htm Дата доступа: 15.03.2016.
|
|
[10] Носенко А.А. Технико-экономическое обоснование дипломных проектов: Методическое пособие для студентов всех специальностей БГУ-ИР дневной и заочной̆ форм обучения. В 4-х ч. Ч. 2: Расчет экономической эффективности инвестиционных проектов / А.А. Носенко, А.В. Грицай. – Мн.: БГУИР, 2002. – 6 с.
ПРИЛОЖЕНИЕ А
(обязательное)
Исходный текст приложения
Файл GMath.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace diplom.core
{
class GMath
{
public static double angle(double p1x, double p1y, double p2x, double p2y)
{
//traslation of axes
p2x -= p1x;
p2y -= p1y;
//compute the angle
double angle = Math.Atan2(p2y, p2x);
//"convert" negative value to a value between pi and 2 pi
if (angle < 0) angle = Math.PI * 2 + angle; // 6.283185307179586 = Math.PI*2
return angle;
}
public static double angleDegrees(double p1x, double p1y, double p2x, double p2y)
{
return angle(p1x, p1y, p2x, p2y) * 57.29577951308232; // 57.29577951308232 = 180/Math.PI;
}
public static double angle(double p1x, double p1y, double cX, double cY, double p3x, double p3y)
{
double pC2 = distance(cX, cY, p3x, p3y);
double pC3 = distance(cX, cY, p1x, p1y);
double p23 = distance(p3x, p3y, p1x, p1y);
double t = (pC2 * pC2) + (pC3 * pC3) - (p23 * p23);
t = div(t, 2 * pC2 * pC3);
//def of acos: -1 =< t =< 1
if (t < -1) t = -1;
else if (t > 1) t = 1;
return Math.Acos(t);
}
public static double angleDegrees(double p1x, double p1y, double cX, double cY, double p3x, double p3y)
{
return angle(p1x, p1y, cX, cY, p3x, p3y) * 57.29577951308232; // 180/Math.PI = 57.29577951308232
}
public static double div(double a, double b)
{
if (b == 0)
return 0;
return a / b;
}
public static double distance(double p1x, double p1y, double p2x, double p2y)
{
double dX = p2x - p1x;
double dY = p2y - p1y;
return Math.Sqrt(Math.Pow(dX, 2) + Math.Pow(dY, 2));
}
public static double polyLen(double[] x, double[] y)
{
double len = 0;
if (x.Length!= y.Length)
return 0;
for (int i = 1; i < x.Length; i++)
{
len += distance(x[i - 1], y[i - 1], x[i], y[i]);
}
return len;
}
public static double polyLen(List<Double> x, List<Double> y)
{
double len = 0;
|
|
if (x.Count!= y.Count)
return 0;
for (int i = 1; i < x.Count; i++)
{
len += distance(x[i - 1], y[i - 1], x[i], y[i]);
}
return len;
}
public static double polyLen(List<Double> x, List<Double> y, int firstPoint, int segmPoints)
{
double len = 0;
if (x.Count!= y.Count || segmPoints > x.Count)
return 0;
for (int i = firstPoint + 1; i < segmPoints; i++)
{
len += distance(x[i - 1], y[i - 1], x[i], y[i]);
}
return len;
}
}
}
Файл Normalizer.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace diplom.core
{
class Normalizer
{
private double minX, maxX, meanX;
private double minY, maxY, meanY;
private List<Sign> words;
public List<Sign> coords()
{
List<Sign> normWords = merger(words);
foreach (var s in normWords)
{
coords(s);
}
return normWords;
}
/**
* Normalize the signature coordinates and apply rotation
*/
private void coords(Sign signatureWord)
{
List<Double> yList = signatureWord.Y;
List<Double> xList = signatureWord.X;
importMMM(signatureWord);
// applyRotation(yList, xList);
double newX, newY, newMinX = 0, newMinY = 0, newMaxX = 0, newMaxY = 0, sumX = 0, sumY = 0;
double deltaX = Math.Abs(maxX - minX);
double deltaY = Math.Abs(maxY - minY);
for (int i = 0; i < yList.Count; i++)
{
newX = ((xList[i] - minX) / deltaX);
xList[i] = newX;
newY = ((yList[i] - minY) / deltaY);
yList[i] = newY;
//to compute values to set into words
sumX += newX;
sumY += newY;
if (i == 0)
{
newMaxX = newMinX = newX;
newMaxY = newMinY = newY;
}
else
{
if (newX < newMinX) newMinX = newX;
if (newX > newMaxX) newMaxX = newX;
if (newY < newMinY) newMinY = newY;
if (newY > newMaxY) newMaxY = newY;
}
}
minX = newMinX;
maxX = newMaxX;
minY = newMinY;
maxY = newMaxY;
meanX = sumX / yList.Count;
meanY = sumY / yList.Count;
//set new Min, Max and Mean values in the SignWord
setWordMMM(signatureWord);
return;
}
private bool canJoin(Sign a, Sign b)
{
int minDist = 10;
if (b.X.Min() <= a.X.Max() + minDist)
return true;
return false;
}
public static double mean(List<Double> data)
{
double mean = 0;
foreach (var d in data)
{
mean += d;
}
return mean / data.Count;
}
private List<Sign> merger(List<Sign> words)
{
List<Sign> mergedWords = new List<Sign>();
List<int> unionPoints = new List<int>();
//loop on input words
int uP = 0;
Sign merged = null; //no words merged
int i = 0;
while (i < words.Count)
{
if ((i + 1 < words.Count) && (canJoin(words[i], words[i + 1])))
{
uP += words[i].X.Count;
unionPoints.Add(uP);
if (merged == null)
{
merged = new Sign(words[i], null);
merged.X.AddRange(words[i+1].X);
merged.Y.AddRange(words[i+1].Y);
merged.T.AddRange(words[i+1].T);
merged.P.AddRange(words[i+1].P);
}
}
else
{
uP += words[i].X.Count;
unionPoints.Add(uP);
if (merged == null)
{
mergedWords.Add(new Sign(words[i], unionPoints));
}
else
{
mergedWords.Add(merged);
merged.PartsSize = unionPoints;
}
merged = null; //start an other word merging
unionPoints = new List<int>();
uP = 0;
}
i++;
}
words.Clear();
return mergedWords;
}
public List<Sign> size()
{
List<Sign> normWords = merger(words);
foreach (var s in normWords)
{
size(s);
}
return normWords;
}
public static void size(Sign s)
{
double minX;
double maxX, minY, maxY, meanX, meanY;
minX = s.X.Min();
minY = s.Y.Min();
maxX = s.X.Max();
maxY = s.Y.Max();
meanX = s.GetMeanX();
meanY = s.GetMeanY();
List<Double> yList = s.Y;
List<Double> xList = s.X;
double newX, newY, sumX = 0, sumY = 0;
double deltaX = Math.Abs(maxX - minX);
double deltaY = Math.Abs(maxY - minY);
for (int i = 0; i < xList.Count; i++)
{
//apply size normalization
newX = (xList[i] - minX) / deltaX;
s.X[i] = newX;
newY = (yList[i] - minY) / deltaY;
s.Y[i] = newY;
}
if (s.X.Min() < 0)
{
int min = (int)s.X.Min();
for (int i = 0; i < xList.Count; i++)
{
s.X[i] += Math.Abs(min);
}
}
if (s.Y.Min() < 0)
{
int min = (int)Math.Abs(s.Y.Min());
for (int i = 0; i < xList.Count; i++)
{
s.Y[i] += min;
}
}
return;
}
public static void applyRotation(Sign s)
{
double ang = Math.Atan2(s.GetMeanX(), s.GetMeanY());// (meanX, meanY) is word barycenter
double cosA = Math.Cos(ang);
double sinA = Math.Sin(ang);
double sumX = 0, sumY = 0, size = s.X.Count;
double newX, newY, x, y;
for (int i = 0; i < size; i++)
{
x = s.X[i];
y = s.Y[i];
//apply rotation matrix
newX = x * cosA - y * sinA;
newY = x * cosA + y * sinA;
s.X[i] = newX;
s.Y[i] = newY;
sumX += newX;
sumY += newY;
}
if (s.X.Min() < 0)
{
int min = (int)s.X.Min();
for (int i = 0; i < size; i++)
{
s.X[i] += Math.Abs(min);
}
}
if (s.Y.Min() < 0)
{
int min =(int) Math.Abs(s.Y.Min());
for (int i = 0; i < size; i++)
{
s.Y[i] += min;
}
}
return;
}
}
}
Файл ReferenceSet.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using diplom.core;
namespace diplom.core
{
class ReferenceSet
{
List<Sign> signes;
public int indexOfTemplate = -1;
public double averageMin, averageMax, averageTemp;
public ReferenceSet()
{
signes = new List<Sign>();
}
public ReferenceSet(List<Sign> s)
{
signes = s;
}
public void Add(Sign s)
{
signes.Add(s);
}
public void Calculate()
{
for (int i = 0; i < signes.Count; i++)
{
Extract.calculateVelocities(signes[i]);
Extract.angles(signes[i]);
}
CalculateDtwPairwise();
SetTemplateSign();
GetAverageByMinDtw();
|
|
GetAverageByMaxDtw();
GetAverageByTempDtw();
}
private void CalculateDtwPairwise()
{
for (int i = 0; i < signes.Count; i++)
{
List<Sign> thisSignXAnother = new List<Sign>();
List<Sign> anothersignes = new List<Sign>();
for (int k = 0; k < signes.Count; k++)
{
//if (k + 1!= signes.Count)
thisSignXAnother.Add(signes[i]);
//if (k!= i)
anothersignes.Add(signes[k]);
}
signes[i].coordsDtw = Verification.coordsDTW(thisSignXAnother, anothersignes);
signes[i].pressureDtw = Verification.pressionDTW(thisSignXAnother, anothersignes);
signes[i].internalAnglesDtw = Verification.internalAnglesDTW(thisSignXAnother, anothersignes);
signes[i].externalAnglesDtw = Verification.externalAnglesDTW(thisSignXAnother, anothersignes);
signes[i].criticalDtw = Verification.criticalPointsDTW(thisSignXAnother, anothersignes);
signes[i].velocityDtw = Verification.velDTW(thisSignXAnother, anothersignes);
signes[i].CalculateSumDtw();
}
}
private void SetTemplateSign()
{
indexOfTemplate = 0;
var minSumByAllDtw = signes[0].sumDtw.Sum();
for (int i = 1; i < signes.Count; i++)
{
var s = signes[i].sumDtw.Sum();
if (s < minSumByAllDtw)
{
minSumByAllDtw = s;
indexOfTemplate = i;
}
}
}
private void GetAverageByMinDtw()
{
averageMin = 0;
//sumDtw min
for (int i = 0; i < signes.Count; i++)
{
double min = 1;
foreach(var sum in signes[i].sumDtw)
{
if (sum == 0)
continue;
if (min == 1)
min = sum;
if (min > sum)
min = sum;
}
averageMin += min;
}
averageMin /= signes.Count;
}
public void GetAverageByMaxDtw()
{
averageMax = 0;
for (int i = 0; i < signes.Count; i++)
{
averageMax += signes[i].sumDtw.Max();
}
averageMax /= signes.Count;
}
private void GetAverageByTempDtw()
{
averageTemp = 0;
for (int i = 0; i < signes.Count; i++)
{
if (i == indexOfTemplate)
continue;
averageTemp += signes[i].sumDtw[indexOfTemplate];
}
averageTemp /= (signes.Count-1);
}
private void CalculateDtwWithSign(Sign s)
{
List<Sign> thisSignes = new List<Sign>();
for (int i = 0; i < signes.Count; i++)
thisSignes.Add(s);
s.coordsDtw = Verification.coordsDTW(thisSignes, signes);
s.pressureDtw = Verification.pressionDTW(thisSignes, signes);
s.internalAnglesDtw = Verification.internalAnglesDTW(thisSignes, signes);
s.externalAnglesDtw = Verification.externalAnglesDTW(thisSignes, signes);
s.criticalDtw = Verification.criticalPointsDTW(thisSignes, signes);
s.velocityDtw = Verification.velDTW(thisSignes, signes);
s.CalculateSumDtw();
}
public double[] GetFeatureVector(Sign s)
{
Extract.calculateVelocities(s);
Extract.angles(s);
CalculateDtwWithSign(s);
double dmin = s.sumDtw.Min() / averageMin;
double dmax = s.sumDtw.Max() / averageMax;
double dtemp = s.sumDtw[indexOfTemplate] / averageTemp;
return new double[] { dmin, dmax, dtemp };
}
}
}
Файл Sign.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace diplom.core
{
public class CriticalPoints
{
public List<double> values1 {get; set;}
public List<double> values2 { get; set; }
public CriticalPoints()
{
values1 = new List<double>();
values2 = new List<double>();
}
|
|
public CriticalPoints(List<double> v1, List<double> v2)
{
values1 = v1;
values2 = v2;
}
}
public class Sign
{
public List<Double> X {set; get;}
public List<Double> Y {set; get;}
public List<Double> P {set; get;}
public List<long> T {set; get;}
public List<int> PartsSize {set; get;} //pos where words are merged
public List<Double> Vx { set; get; }
public List<Double> Vy { set; get; }
public CriticalPoints CriticalPoints { set; get; }
public List<Double> internalAngles { set; get; }
public List<Double> externalAngles { set; get; }
public List<Double> coordsDtw { set; get; }
public List<Double> pressureDtw { set; get; }
public List<Double> internalAnglesDtw { set; get; }
public List<Double> externalAnglesDtw { set; get; }
public List<Double> criticalDtw { set; get; }
public List<Double> velocityDtw { set; get; }
public List<Double> sumDtw { set; get; }
public Sign()
{
X = new List<double>();
Y = new List<double>();
P = new List<double>();
T = new List<long>();
Vx = new List<double>();
Vy = new List<double>();
coordsDtw = new List<double>();
pressureDtw = new List<double>();
internalAnglesDtw= new List<double>();
externalAnglesDtw= new List<double>();
criticalDtw = new List<double>();
velocityDtw = new List<double>();
sumDtw = new List<double>();
internalAngles = new List<double>();
externalAngles = new List<double>();
}
public Sign(Sign s, List<int> partsSize)
{
X = s.X;
Y = s.Y;
P = s.P;
T = s.T;
PartsSize = partsSize;
}
public double Mean (List<Double> data)
{
double mean = 0;
foreach (var d in data)
{
mean += d;
}
return mean / data.Count;
}
public double MinX { get; set; }
public double MinY { get; set; }
public double MaxX { get; set; }
public double MaxY { get; set; }
public double MeanX { get; set; }
public double MeanY { get; set; }
public void AddPoint(double x, double y, double p, long t)
{
if ((x!=0)&& (y!=0) && (p!=0))
{
X.Add(x);
Y.Add(y);
P.Add(p);
T.Add(t);
}
}
public double GetMeanX()
{
return X.Sum() / X.Count;
}
public double GetMeanY()
{
return Y.Sum() / Y.Count;
}
public void CalculateSumDtw()
{
int count = velocityDtw.Count;
for (int i = 0; i < count; i++)
{
sumDtw.Add(coordsDtw[i] + pressureDtw[i] + internalAnglesDtw[i] +
externalAnglesDtw[i] + criticalDtw[i] + velocityDtw[i]);
}
}
}
}
Файл DynamicTimeWarping.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace diplom.core
{
class DynamicTimeWarping
{
private double[,] DTWMatrix;
//private int[,] wrapPath;
private int numRows, numCols;
private int T, costSCB; // Sakoe-Chiba band attribs.
private int numOptimalDistance;
public DynamicTimeWarping()
{
numOptimalDistance = int.MaxValue;
}
public double perform2D(CriticalPoints signatureOriginal, CriticalPoints signatureTest)
{
double[,] distanceMatrix;
// original signature
List<Double> xOriginalSign = signatureOriginal.values1;
List<Double> yOriginalSign = signatureOriginal.values2;
numRows = xOriginalSign.Count;
// signature to test
List<Double> xTestSign = signatureTest.values1;
List<Double> yTestSign = signatureTest.values2;
numCols = xTestSign.Count;
// for warping paths having a local slope within the bounds 1/2 and 2
if ((numCols >= 2 * numRows)
|| (numRows >= 2 * numCols)) {
return Double.PositiveInfinity;
}
// compute the distance matrix
distanceMatrix = new double[numRows, numCols];
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
// compute the euclidean distance
double deltaX = xOriginalSign[i] - xTestSign[j];
double deltaY = yOriginalSign[i] - yTestSign[j];
distanceMatrix[i,j] = Math.Sqrt((deltaX * deltaX)
+ (deltaY * deltaY));
}
}
return computeDTWMatrix(distanceMatrix);
}
public double perform1D(List<Double> original, List<Double> test)
{
double[,] distanceMatrix;
// original signature
numRows = original.Count;
// signature to test
numCols = test.Count;
// for warping paths having a local slope within the bounds 1/2 and 2
if ((numCols >= 2 * numRows) || (numRows >= 2 * numCols)) {
return Double.PositiveInfinity;
}
// compute the distance matrix
distanceMatrix = new double[numRows,numCols];
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numCols; j++) {
// compute the euclidean distance
distanceMatrix[i,j] = Math.Abs(original[i] - test[j]);
}
}
return computeDTWMatrix(distanceMatrix);
}
private double computeDTWMatrix(double[,] distanceMatrix)
{
DTWMatrix = new double[numRows,numCols];
DTWMatrix[0,0] = distanceMatrix[0,0];
// fill the first row
for (int i = 1; i < numRows; i++)
DTWMatrix[i,0] = distanceMatrix[i,0]
+ DTWMatrix[i - 1,0];
// initialize the first column
for (int i = 1; i < numCols; i++)
DTWMatrix[0,i] = distanceMatrix[0,i]
+ DTWMatrix[0,i - 1];
// fill the others
for (int i = 1; i < numRows; i++)
for (int j = 1; j < numCols; j++)
DTWMatrix[i,j] = distanceMatrix[i,j]
+ Math.Min(DTWMatrix[i - 1,j], //insetion
Math.Min(
DTWMatrix[i - 1,j - 1], // match
DTWMatrix[i,j - 1]) //deletion
);
return computePath();
/*
* Inaccurate
* return DTWMatrix[numRows-1,numCols-1];
*/
}
public double computePath()
{
// wrapPath = new int[4000,2]; //save the warp path
// for Sakoe-Chiba band
T = (int)numRows / 5;
costSCB = (numCols - T) / (numRows - T);
numOptimalDistance = 0;
int i = numRows - 1;
int j = numCols - 1;
double pathCost = DTWMatrix[i,j];
double minimumValue;
while ((i > 0) || (j > 0))
{
if (i == 0)
{
j--;
}
else if (j == 0)
{
i--;
}
else
{
// here you can change the step size
minimumValue = min(i, j);
if (minimumValue == DTWMatrix[i - 1,j])
i--;
else if (minimumValue == DTWMatrix[i,j - 1])
j--;
else
{
i--;
j--;
}
} // end else
pathCost += DTWMatrix[i,j];
/*
* wrapPath[numOptimalDistance,0] = i;
* wrapPath[numOptimalDistance,1] = j;
*/
numOptimalDistance++;
}
return pathCost;
}
private double min(int i, int j)
{
bool first = true, third = true; // second=true; -> [i-i,j-1] can't
// be check
int minBand, maxBand;
// check Sakoe-Chiba band on [i-1,j]
minBand = costSCB * (i - 1 - T);
if (minBand < 0)
minBand = 0; // can be < 0
maxBand = costSCB * (i - 1 + T);
if (maxBand > numCols - 1)
maxBand = numCols - 1;
if (j < minBand || j > maxBand)
first = false;
// check on [i,j-1]
minBand = costSCB * (i - T);
if (minBand < 0)
minBand = 0; // can be < 0
maxBand = costSCB * (i + T);
if (maxBand > numCols - 1)
maxBand = numCols - 1;
if ((j - 1) < minBand || (j - 1) > maxBand)
third = false;
// now take the min value
if (first && third)
{
return Math.Min(DTWMatrix[i - 1,j], Math.Min(DTWMatrix[i - 1,j - 1], DTWMatrix[i,j - 1]));
}
if (first == false)
{
return Math.Min(DTWMatrix[i - 1,j - 1], DTWMatrix[i,j - 1]);
}
return Math.Min(DTWMatrix[i - 1,j - 1], DTWMatrix[i - 1,j]);
}
/**
* Get the warp path length
*
* @return Integer.MAX_VALUE if DTW hasn't success
*/
public double getPathLength()
{
return numOptimalDistance;
}
}
}
Файл СWintabData:
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WintabDN
{
public enum EWintabPacketBit
{
PK_CONTEXT = 0x0001, /* reporting context */
PK_STATUS = 0x0002, /* status bits */
PK_TIME = 0x0004, /* time stamp */
PK_CHANGED = 0x0008, /* change bit vector */
PK_SERIAL_NUMBER = 0x0010, /* packet serial number */
PK_CURSOR = 0x0020, /* reporting cursor */
PK_BUTTONS = 0x0040, /* button information */
PK_X = 0x0080, /* x axis */
PK_Y = 0x0100, /* y axis */
PK_Z = 0x0200, /* z axis */
PK_NORMAL_PRESSURE = 0x0400, /* normal or tip pressure */
PK_TANGENT_PRESSURE = 0x0800, /* tangential or barrel pressure */
PK_ORIENTATION = 0x1000, /* orientation info: tilts */
PK_PKTBITS_ALL = 0x1FFF // The Full Monty - all the bits execept Rotation - not supported
}
public enum EWintabEventMessage
{
WT_PACKET = 0x7FF0,
WT_CTXOPEN = 0x7FF1,
WT_CTXCLOSE = 0x7FF2,
WT_CTXUPDATE = 0x7FF3,
WT_CTXOVERLAP = 0x7FF4,
WT_PROXIMITY = 0x7FF5,
WT_INFOCHANGE = 0x7FF6,
WT_CSRCHANGE = 0x7FF7,
WT_PACKETEXT = 0x7FF8
}
public enum EWintabPacketStatusValue
{
TPS_PROXIMITY = 0x0001,
TPS_QUEUE_ERR = 0x0002,
TPS_MARGIN = 0x0004,
TPS_GRAB = 0x0008,
TPS_INVERT = 0x0010
}
public enum EWintabPacketButtonCode
{
TBN_NONE = 0,
TBN_UP = 1,
TBN_DOWN = 2
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTOrientation
{
public Int32 orAzimuth;
public Int32 orAltitude;
public Int32 orTwist;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTRotation
{
public Int32 rotPitch;
public Int32 rotRoll;
public Int32 rotYaw;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WintabPacket
{
public HCTX pkContext;
public UInt32 pkStatus;
public UInt32 pkTime;
public WTPKT pkChanged;
public UInt32 pkSerialNumber;
public UInt32 pkCursor;
public UInt32 pkButtons;
public Int32 pkX;
public Int32 pkY;
public Int32 pkZ;
public UInt32 pkNormalPressure; // PK_NORMAL_PRESSURE
public UInt32 pkTangentPressure; // PK_TANGENT_PRESSURE
public WTOrientation pkOrientation; // ORIENTATION
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTExtensionBase
public HCTX nContext;
public UInt32 nStatus;
public WTPKT nTime;
public UInt32 nSerialNumber;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTExpKeyData
{
public byte nTablet;
public byte nControl;
public byte nLocation;
public byte nReserved;
public WTPKT nState;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WTSliderData
{
public byte nTablet;
public byte nControl;
public byte nMode;
public byte nReserved;
public WTPKT nPosition;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct WintabPacketExt
{
public WTExtensionBase pkBase;
public WTExpKeyData pkExpKey;
public WTSliderData pkTouchStrip;
public WTSliderData pkTouchRing;
}
public class CWintabData
{
private CWintabContext m_context;
public CWintabData(CWintabContext context_I)
{
Init(context_I);
}
private void Init(CWintabContext context_I)
{
try
{
if (context_I == null)
{
throw new Exception("Trying to init CWintabData with null context.");
}
m_context = context_I;
// Watch for the Wintab WT_PACKET event.
MessageEvents.WatchMessage((int)EWintabEventMessage.WT_PACKET);
// Watch for the Wintab WT_PACKETEXT event.
MessageEvents.WatchMessage((int)EWintabEventMessage.WT_PACKETEXT);
}
catch (Exception ex)
{
MessageBox.Show("FAILED CWintabData.Init: " + ex.ToString());
}
}
public void SetWTPacketEventHandler(EventHandler<MessageReceivedEventArgs> handler_I)
{
MessageEvents.MessageReceived += handler_I;
}
public bool SetPacketQueueSize(UInt32 numPkts_I)
{
bool status = false;
try
{
CheckForValidHCTX("SetPacketQueueSize");
status = CWintabFuncs.WTQueueSizeSet(m_context.HCtx, numPkts_I);
}
catch (Exception ex)
{
MessageBox.Show("FAILED SetPacketQueueSize: " + ex.ToString());
}
return status;
}
public UInt32 GetPacketQueueSize()
{
UInt32 numPkts = 0;
try
{
CheckForValidHCTX("GetPacketQueueSize");
numPkts = CWintabFuncs.WTQueueSizeGet(m_context.HCtx);
}
catch (Exception ex)
{
MessageBox.Show("FAILED GetPacketQueueSize: " + ex.ToString());
}
return numPkts;
}
public WintabPacketExt GetDataPacketExt(UInt32 hCtx_I, UInt32 pktID_I)
{
int size = (int)(Marshal.SizeOf(new WintabPacketExt()));
IntPtr buf = CMemUtils.AllocUnmanagedBuf(size);
WintabPacketExt[] packets = null;
try
{
bool status = false;
if (pktID_I == 0)
{
throw new Exception("GetDataPacket - invalid pktID");
}
CheckForValidHCTX("GetDataPacket");
status = CWintabFuncs.WTPacket(hCtx_I, pktID_I, buf);
if (status)
{
packets = CMemUtils.MarshalDataExtPackets(1, buf);
}
else
{
// If fails, make sure context is zero.
packets[0].pkBase.nContext = 0;
}
}
catch (Exception ex)
{
MessageBox.Show("FAILED GetDataPacketExt: " + ex.ToString());
}
CMemUtils.FreeUnmanagedBuf(buf);
return packets[0];
}
public WintabPacket GetDataPacket(UInt32 pktID_I)
{
return GetDataPacket(m_context.HCtx, pktID_I);
}
public WintabPacket GetDataPacket(UInt32 hCtx_I, UInt32 pktID_I)
{
IntPtr buf = CMemUtils.AllocUnmanagedBuf(Marshal.SizeOf(typeof(WintabPacket)));
WintabPacket packet = new WintabPacket();
if (pktID_I == 0)
{
throw new Exception("GetDataPacket - invalid pktID");
}
CheckForValidHCTX("GetDataPacket");
if (CWintabFuncs.WTPacket(hCtx_I, pktID_I, buf))
{
packet = (WintabPacket)Marshal.PtrToStructure(buf, typeof(WintabPacket));
}
else
{
packet.pkContext = 0;
}
CMemUtils.FreeUnmanagedBuf(buf);
return packet;
}
public void FlushDataPackets(uint numPacketsToFlush_I)
{
try
{
CheckForValidHCTX("FlushDataPackets");
CWintabFuncs.WTPacketsGet(m_context.HCtx, numPacketsToFlush_I, IntPtr.Zero);
}
catch (Exception ex)
{
MessageBox.Show("FAILED GetPacketDataRange: " + ex.ToString());
}
}
public WintabPacket[] GetDataPackets(UInt32 maxPkts_I, bool remove_I, ref UInt32 numPkts_O)
{
WintabPacket[] packets = null;
try
{
CheckForValidHCTX("GetDataPackets");
if (maxPkts_I == 0)
{
throw new Exception("GetDataPackets - maxPkts_I is zero.");
}
int size = (int)(maxPkts_I * Marshal.SizeOf(new WintabPacket()));
IntPtr buf = CMemUtils.AllocUnmanagedBuf(size);
if (remove_I)
{
numPkts_O = CWintabFuncs.WTPacketsGet(m_context.HCtx, maxPkts_I, buf);
if (numPkts_O > 0)
{
packets = CMemUtils.MarshalDataPackets(numPkts_O, buf);
}
}
else
{
UInt32 pktIDOldest = 0;
UInt32 pktIDNewest = 0;
if (CWintabFuncs.WTQueuePacketsEx(m_context.HCtx, ref pktIDOldest, ref pktIDNewest))
{
UInt32 pktIDStart = pktIDOldest;
UInt32 pktIDEnd = pktIDNewest;
if (pktIDStart == 0)
{ throw new Exception("WTQueuePacketsEx reports zero start packet identifier"); }
if (pktIDEnd == 0)
{ throw new Exception("WTQueuePacketsEx reports zero end packet identifier"); }
// Peek up to the max number of packets specified.
UInt32 numFoundPkts = CWintabFuncs.WTDataPeek(m_context.HCtx, pktIDStart, pktIDEnd, maxPkts_I, buf, ref numPkts_O);
System.Diagnostics.Debug.WriteLine("GetDataPackets: WTDataPeek - numFoundPkts: " + numFoundPkts + ", numPkts_O: " + numPkts_O);
if (numFoundPkts > 0 && numFoundPkts < numPkts_O)
{
throw new Exception("WTDataPeek reports more packets returned than actually exist in queue.");
}
packets = CMemUtils.MarshalDataPackets(numPkts_O, buf);
}
}
}
catch (Exception ex)
{
MessageBox.Show("FAILED GetPacketDataRange: " + ex.ToString());
}
return packets;
}
private void CheckForValidHCTX(string msg)
{
if (m_context.HCtx == 0)
{
throw new Exception(msg + " - Bad Context");
}
}
}
}