n3ss3s
2011-12-27 17:30:28
The concept - Identifier is used to find an unique set of points in the point array of each character, that won't be found in any of the arrays of the other characters of the same font. If someone wants to use it for RuneScape, you'd make a program that parses all the font masks to TPAs and then run it through this, and then store the unique arrays paired with characters.
Finder will split a provided point array of the assumed text into sections (vertical splits, you're assumed to input a single line), and then match a letter of the instance's font with the point array of each section. Spaces work (sort of?) by counting empty lines between characters, if the count is greater than the provided min spacing, the gap is a space.
This is useful for only scenarios like RuneScape or other computer generated text that is constant.
Credits for the Combination class which is basically responsible for creating each possible combination of an array's elements go to some dude on daniweb.
Identifier -
Points.cs
Combination.cs
Finder -
CR.cs
Program.cs - A small example
Finder will split a provided point array of the assumed text into sections (vertical splits, you're assumed to input a single line), and then match a letter of the instance's font with the point array of each section. Spaces work (sort of?) by counting empty lines between characters, if the count is greater than the provided min spacing, the gap is a space.
This is useful for only scenarios like RuneScape or other computer generated text that is constant.
Credits for the Combination class which is basically responsible for creating each possible combination of an array's elements go to some dude on daniweb.
Identifier -
Points.cs
/*
* Created by SharpDevelop.
* User: Owner
* Date: 12/21/2011
* Time: 1:41 AM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Drawing;
using System.Collections.Generic;
namespace Identifier
{
/// <summary>
/// Description of Points.
/// </summary>
public static class Points
{
private static bool ContainsPoint(Point p, Point[] pts)
{
foreach (Point pp in pts)
{
if (pp.Equals(p))
return true;
}
return false;
}
public static Point[] FindUniqueSet(Point[] arr, Point[][] total, int max)
{
for (int i = 2; i < max; i++)
{
Combination<Point> c = new Combination<Point>(arr, i);
foreach (Point[] pts in c)
{
foreach (Point[] t in total)
{
Boolean success = true;
foreach (Point p in pts)
{
if (ContainsPoint(p, t))
{
success = false;
break;
}
}
if (success)
return pts;
}
}
}
return new Point[] {};
}
private static Point[] Crop(Point[] p)
{
int minX = p[0].X;
int minY = p[0].Y;
foreach (Point point in p)
{
if (point.X < minX)
minX = point.X;
if (point.Y < minY)
minY = point.Y;
}
List<Point> n = new List<Point>();
foreach (Point point in p)
{
n.Add(new Point(point.X - minX, point.Y - minY));
}
return n.ToArray();
}
}
}Combination.cs
/*
* Created by SharpDevelop.
* User: Owner
* Date: 12/21/2011
* Time: 12:45 AM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections;
namespace Identifier {
/// <summary>
/// Class to generate all the combinations of an array of objects. This code
/// is released under the GPL v3 license with the aditional restriction that
/// any use in a public product requires notification of the author.
/// </summary>
/// <typeparam name="T">The type of objects</typeparam>
public class Combination<T> : IEnumerable, IEnumerator {
private T[] items;
private int atATime;
private int current = -1;
private long count;
/// <summary>
/// Constructor for the Combination class
/// </summary>
/// <param name="list">Array of objects used to build combinations</param>
/// <param name="n">Number of items in each combination</param>
public Combination(T[] list, int n) {
this.items = list;
this.atATime = n;
this.count = Choose(this.items.Length, this.atATime);
}
/// <summary>
/// Gets the specific lexical combination. Note that combinations are numbered from 0 to NumberOfCombinations - 1
/// </summary>
/// <param name="n">Lexical combination to return</param>
/// <returns>Array containing the nth lexical combination</returns>
public T[] GetCombination(long n) {
if (n >= count) {
throw new ArgumentOutOfRangeException(String.Format("Requested combination ({0}) exceeds number of combinations ({1})", n, count));
}
T[] result = new T[this.atATime];
int[] ans = new int[this.atATime];
int a = this.items.Length;
int b = this.atATime;
long x = (Choose(a, b) - 1) - n;
for (int i = 0; i < this.atATime; i++) {
ans[i] = LargestV(a, b, x);
x -= Choose(ans[i], b);
a = ans[i];
b--;
}
for (int i = 0; i < this.atATime; i++) {
result[i] = items[items.Length - 1 - ans[i]];
}
return result;
}
/// <summary>
/// Number of combinations for this specific set of objects and grouping size
/// </summary>
public long NumberOfCombinations {
get {
return count;
}
}
/// <summary>
/// Method to allow indexing into combinations.
/// </summary>
/// <param name="n">Lexical combination to return</param>
/// <returns>Array containing the nth lexical combination</returns>
public T[] this[int n] {
get {
return GetCombination(n);
}
}
// The next two methods are used to calculate the combinadic. See
// Wikipedia article at [url]http://en.wikipedia.org/wiki/Combinatorial_number_system[/url]
// and the 2006 MSDN Article "Test Run" by Dr. James McCaffrey
private int LargestV(int a, int b, long x) {
int v = a - 1;
while (Choose(v, b) > x) {
v--;
}
return v;
}
private long Choose(int n, int k) {
long result = 0;
int delta;
int max;
if (n < 0 || k < 0) {
throw new ArgumentOutOfRangeException("Invalid negative parameter in Choose()");
}
if (n < k) {
result = 0;
} else if (n == k) {
result = 1;
} else {
if (k < n - k) {
delta = n - k;
max = k;
} else {
delta = k;
max = n - k;
}
result = delta + 1;
for (int i = 2; i <= max; i++) {
checked {
result = (result * (delta + i)) / i;
}
}
}
return result;
}
#region IEnumerator & IEnumerable methods
IEnumerator IEnumerable.GetEnumerator() {
return this;
}
object IEnumerator.Current {
get {
return GetCombination(current);
}
}
bool IEnumerator.MoveNext() {
current++;
return (current < count);
}
void IEnumerator.Reset() {
current = -1;
}
#endregion
}
}
Finder -
CR.cs
/*
* Created by SharpDevelop.
* User: Owner
* Date: 12/21/2011
* Time: 9:05 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Diagnostics;
using System.Drawing;
using System.Collections.Generic;
namespace Finder
{
public class CR
{
private List<List<Point>> pts;
private string[] chars;
private int spacing;
public CR(Point[][] idPts, string[] characters, int spacing)
{
this.pts = new List<List<Point>>();
foreach (Point[] x in idPts)
this.pts.Add(new List<Point>(x));
this.chars = characters;
this.spacing = spacing;
}
public string PointsToText(Point[] textPoints)
{
if (textPoints.Length < 1 || chars.Length < 1)
return "";
string n = "";
List<List<Point>> split = Split(textPoints, spacing);
foreach (List<Point> pp in split)
{
List<Point> lp = new List<Point>(Crop(pp.ToArray()));
if (lp.Count == 0)
{
n += "[]";
} else
{
for (int i = 0; i < pts.Count; i++)
{
bool d = false;
foreach (Point rP in lp)
{
bool b = true;
foreach (Point nP in pts[i])
{
if (!ContainsPoint(new Point(nP.X + rP.X, nP.Y + rP.Y), lp.ToArray()))
{
b = false;
break;
}
}
if (b)
{
n += chars[i];
d = true;
break;
}
}
if (d)
break;
}
}
}
return n;
}
private Point[] Crop(Point[] p)
{
if (p.Length < 1)
return new Point[] {};
int minX = p[0].X;
int minY = p[0].Y;
foreach (Point point in p)
{
if (point.X < minX)
minX = point.X;
if (point.Y < minY)
minY = point.Y;
}
List<Point> n = new List<Point>();
foreach (Point point in p)
{
n.Add(new Point(point.X - minX, point.Y - minY));
}
return n.ToArray();
}
private int GetWidth(Point[] pts)
{
Point[] n = Crop(pts);
int max = 0;
foreach (Point p in n)
{
if (p.X > max)
max = p.X;
}
return max;
}
private int GetHeight(Point[] pts)
{
Point[] n = Crop(pts);
int max = 0;
foreach (Point p in n)
{
if (p.Y > max)
max = p.Y;
}
return max;
}
private bool ContainsPoint(Point p, Point[] pts)
{
foreach (Point pp in pts)
{
if (pp.Equals(p))
return true;
}
return false;
}
public List<List<Point>> Split(Point[] pts, int minSpaceWidth)
{
List<List<Point>> chars = new List<List<Point>>();
int width = GetWidth(pts) + 1;
int height = GetHeight(pts) + 1;
Point[] n = Crop(pts);
List<Point> p = new List<Point>();
int empties = 0;;
for (int x = 0; x < width; x++)
{
int count = 0;
for (int y = 0; y < height; y++)
{
if (ContainsPoint(new Point(x, y), n))
{
p.Add(new Point(x, y));
count++;
}
}
if (count != 0)
empties = 0;
if (count == 0)
{
empties++;
}
if (empties == 1 || empties == minSpaceWidth)
{
chars.Add(p);
p = new List<Point>();
if (empties == minSpaceWidth)
empties = 0;
}
if (x + 1 == width)
{
chars.Add(p);
}
}
return chars;
}
}
}
Program.cs - A small example
/*
* Created by SharpDevelop.
* User: Owner
* Date: 12/21/2011
* Time: 8:51 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Drawing;
namespace Finder
{
class Program
{
public static void Main(string[] args)
{
// In this example a square is shown as [], because counting spaces is superhuman.
Point[] pts = new Point[] {new Point(5, 4), new Point(6, 4), new Point(7, 4), new Point(8, 4), new Point(17, 4), new Point(18, 4), new Point(7, 5), new Point(9, 5), new Point(17, 5), new Point(18, 5)};
Point[] v = new Point[] {new Point(0, 0), new Point(2, 0), new Point(1, 1)}; //a crude letter "v".
Point[] s = new Point[] {new Point(0, 0), new Point(1, 0), new Point(0, 1), new Point(1, 1)}; // s for square
CR cr = new CR(new Point[][] {v, s}, new string[] {"v", "s"}, 4);
string str = cr.PointsToText(pts);
Console.WriteLine(str);
Console.ReadKey(true);
}
}