diff --git a/.gitignore b/.gitignore
index 4581ef2..baacc5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,7 @@
*.exe
*.out
*.app
+
+#python temporary files
+__pycache__
+*.pyc
diff --git a/README.md b/README.md
index 3861db9..57d5e88 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,49 @@
-# dollar
-[APACHE-2] $1 and $N recognition (ready for prod...)
+dollar
+======
+
+`dollar` is a $1 and $N gesture recognition
+
+
+Instructions
+============
+
+download Build system:
+----------------------
+
+ sudo pip install lutin
+ sudo pip install pillow
+
+download the software:
+----------------------
+
+ mkdir WORKING_DIRECTORY
+ cd WORKING_DIRECTORY
+ git clone https://github.com/atria-soft/etk.git
+ git clone https://github.com/atria-soft/ejson.git
+ git clone https://github.com/generic-library/gtest-lutin.git --recursive
+ git clone https://github.com/generic-library/z-lutin.git --recursive
+
+Compile software:
+-----------------
+
+ cd WORKING_DIRECTORY
+ lutin dollar-test?build?run
+
+
+License (APACHE v2.0)
+=====================
+Copyright dollar Edouard DUPIN
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
diff --git a/data/figure/arrow_1.json b/data/figure/arrow_1.json
new file mode 100644
index 0000000..07f4d28
--- /dev/null
+++ b/data/figure/arrow_1.json
@@ -0,0 +1,15 @@
+{
+ "type":"REFERENCE",
+ "value":"arrow",
+ "sub-id":1,
+ "data":[
+ [
+ [0.00,0.50],
+ [1.00,0.50]
+ ],[
+ [0.75,0.60],
+ [1.00,0.50],
+ [0.75,0.40]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/figure/circle_1.json b/data/figure/circle_1.json
new file mode 100644
index 0000000..a019c32
--- /dev/null
+++ b/data/figure/circle_1.json
@@ -0,0 +1,73 @@
+{
+ "type": "REFERENCE",
+ "value": "circle",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 1, 0.500000 ],
+ [ 0.997419, 0.551122 ],
+ [ 0.989842, 0.600767 ],
+ [ 0.977521, 0.648685 ],
+ [ 0.960707, 0.694623 ],
+ [ 0.939653, 0.738330 ],
+ [ 0.914608, 0.779555 ],
+ [ 0.885824, 0.818046 ],
+ [ 0.853553, 0.853553 ],
+ [ 0.818046, 0.885824 ],
+ [ 0.779555, 0.914608 ],
+ [ 0.738330, 0.939653 ],
+ [ 0.694623, 0.960707 ],
+ [ 0.648685, 0.977521 ],
+ [ 0.600767, 0.989842 ],
+ [ 0.551122, 0.997418 ],
+ [ 0.500000, 1.000000 ],
+ [ 0.448878, 0.997418 ],
+ [ 0.399233, 0.989842 ],
+ [ 0.351315, 0.977521 ],
+ [ 0.305377, 0.960707 ],
+ [ 0.261670, 0.939653 ],
+ [ 0.220445, 0.914608 ],
+ [ 0.181954, 0.885824 ],
+ [ 0.146447, 0.853553 ],
+ [ 0.114176, 0.818046 ],
+ [ 0.085392, 0.779555 ],
+ [ 0.060347, 0.738330 ],
+ [ 0.039292, 0.694623 ],
+ [ 0.022479, 0.648685 ],
+ [ 0.010158, 0.600767 ],
+ [ 0.002581, 0.551122 ],
+ [ 0, 0.500000 ],
+ [ 0.002581, 0.448878 ],
+ [ 0.010158, 0.399233 ],
+ [ 0.022479, 0.351315 ],
+ [ 0.039292, 0.305377 ],
+ [ 0.060347, 0.261670 ],
+ [ 0.085392, 0.220445 ],
+ [ 0.114176, 0.181954 ],
+ [ 0.146447, 0.146447 ],
+ [ 0.181954, 0.114176 ],
+ [ 0.220445, 0.085392 ],
+ [ 0.261670, 0.060347 ],
+ [ 0.305377, 0.039292 ],
+ [ 0.351315, 0.022479 ],
+ [ 0.399233, 0.010158 ],
+ [ 0.448878, 0.002581 ],
+ [ 0.500000, 0 ],
+ [ 0.551122, 0.002581 ],
+ [ 0.600767, 0.010158 ],
+ [ 0.648685, 0.022479 ],
+ [ 0.694623, 0.039292 ],
+ [ 0.738330, 0.060347 ],
+ [ 0.779555, 0.085392 ],
+ [ 0.818046, 0.114176 ],
+ [ 0.853553, 0.146447 ],
+ [ 0.885824, 0.181954 ],
+ [ 0.914608, 0.220445 ],
+ [ 0.939653, 0.261670 ],
+ [ 0.960707, 0.305377 ],
+ [ 0.977521, 0.351315 ],
+ [ 0.989842, 0.399233 ],
+ [ 0.997419, 0.448878 ]
+ ]
+ ]
+}
diff --git a/data/figure/circle_1.svg b/data/figure/circle_1.svg
new file mode 100644
index 0000000..75f7539
--- /dev/null
+++ b/data/figure/circle_1.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/data/figure/diamond_1.json b/data/figure/diamond_1.json
new file mode 100644
index 0000000..6b9181d
--- /dev/null
+++ b/data/figure/diamond_1.json
@@ -0,0 +1,16 @@
+{
+ "type":"REFERENCE",
+ "value":"diamond",
+ "sub-id":1,
+ "data":[
+ [
+ [0.5,0.0],[1.0,0.5]
+ ],[
+ [1.0,0.5],[0.5,1.0]
+ ],[
+ [0.5,1.0],[0.0,0.5]
+ ],[
+ [0.0,0.5],[0.5,0.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/figure/rectangle_1.json b/data/figure/rectangle_1.json
new file mode 100644
index 0000000..4226913
--- /dev/null
+++ b/data/figure/rectangle_1.json
@@ -0,0 +1,16 @@
+{
+ "type":"REFERENCE",
+ "value":"rectangle",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[1.0,0.0]
+ ],[
+ [1.0,0.0],[1.0,1.0]
+ ],[
+ [1.0,1.0],[0.0,1.0]
+ ],[
+ [0.0,1.0],[0.0,0.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/figure/tick_1.json b/data/figure/tick_1.json
new file mode 100644
index 0000000..442c344
--- /dev/null
+++ b/data/figure/tick_1.json
@@ -0,0 +1,12 @@
+{
+ "type":"REFERENCE",
+ "value":"tick",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.5],
+ [0.5,0.0],
+ [1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/figure/triangle_1.json b/data/figure/triangle_1.json
new file mode 100644
index 0000000..10f570e
--- /dev/null
+++ b/data/figure/triangle_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"triangle",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[1.0,0.0]
+ ],[
+ [1.0,0.0],[0.5,1.0]
+ ],[
+ [0.0,0.0],[0.5,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/test/Arrow.json b/data/test/Arrow.json
new file mode 100644
index 0000000..0b246da
--- /dev/null
+++ b/data/test/Arrow.json
@@ -0,0 +1,17 @@
+{
+ "data":[
+ [
+ [68,222],[70,220],[73,218],[75,217],[77,215],[80,213],
+ [82,212],[84,210],[87,209],[89,208],[92,206],[95,204],
+ [101,201],[106,198],[112,194],[118,191],[124,187],[127,186],
+ [132,183],[138,181],[141,180],[146,178],[154,173],[159,171],
+ [161,170],[166,167],[168,167],[171,166],[174,164],[177,162],
+ [180,160],[182,158],[183,156],[181,154],[178,153],[171,153],
+ [164,153],[160,153],[150,154],[147,155],[141,157],[137,158],
+ [135,158],[137,158],[140,157],[143,156],[151,154],[160,152],
+ [170,149],[179,147],[185,145],[192,144],[196,144],[198,144],
+ [200,144],[201,147],[199,149],[194,157],[191,160],[186,167],
+ [180,176],[177,179],[171,187],[169,189],[165,194],[164,196],
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/test/P.json b/data/test/P.json
new file mode 100644
index 0000000..e54de8a
--- /dev/null
+++ b/data/test/P.json
@@ -0,0 +1,12 @@
+{
+ "data":[
+ [
+ [507,8],[507,87]
+ ], [
+ [510,7],[528,7],[530,8],
+ [544,10],[550,12],[550,15],[558,20],[560,22],[561,27],
+ [562,33],[561,37],[559,42],[556,45],[550,48],[544,51],
+ [538,53],[532,54],[525,55],[519,55],[513,55],[510,55]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/A_1.json b/data/text/A_1.json
new file mode 100644
index 0000000..073b628
--- /dev/null
+++ b/data/text/A_1.json
@@ -0,0 +1,17 @@
+{
+ "type":"REFERENCE",
+ "value":"A",
+ "sub-id":1,
+ "data":[
+ [
+ [0.00,0.00],
+ [0.50,1.00]
+ ],[
+ [0.50,1.00],
+ [1.00,0.00]
+ ],[
+ [0.25,0.50],
+ [0.75,0.50]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/B_1.json b/data/text/B_1.json
new file mode 100644
index 0000000..f9d9314
--- /dev/null
+++ b/data/text/B_1.json
@@ -0,0 +1,63 @@
+{
+ "type": "REFERENCE",
+ "value": "B",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0, 0 ],
+ [ 0, 1 ]
+ ],
+ [
+ [ 0, 0.003491 ],
+ [ 0.232282, 0.009006 ],
+ [ 0.434124, 0.024593 ],
+ [ 0.605421, 0.048818 ],
+ [ 0.746066, 0.080245 ],
+ [ 0.855952, 0.117437 ],
+ [ 0.899328, 0.137747 ],
+ [ 0.934975, 0.158959 ],
+ [ 0.962878, 0.180896 ],
+ [ 0.983026, 0.203376 ],
+ [ 0.995404, 0.226222 ],
+ [ 1.000000, 0.249252 ],
+ [ 0.996800, 0.272289 ],
+ [ 0.985791, 0.295152 ],
+ [ 0.966959, 0.317662 ],
+ [ 0.940291, 0.339639 ],
+ [ 0.905775, 0.360904 ],
+ [ 0.863396, 0.381278 ],
+ [ 0.813142, 0.400581 ],
+ [ 0.754998, 0.418634 ],
+ [ 0.614992, 0.450271 ],
+ [ 0.443271, 0.474752 ],
+ [ 0.239728, 0.490644 ],
+ [ 0.004257, 0.496509 ]
+ ],
+ [
+ [ 0, 0.503491 ],
+ [ 0.232282, 0.509006 ],
+ [ 0.434124, 0.524593 ],
+ [ 0.605421, 0.548818 ],
+ [ 0.746066, 0.580245 ],
+ [ 0.855952, 0.617437 ],
+ [ 0.899328, 0.637747 ],
+ [ 0.934975, 0.658959 ],
+ [ 0.962878, 0.680896 ],
+ [ 0.983026, 0.703376 ],
+ [ 0.995404, 0.726222 ],
+ [ 1.000000, 0.749252 ],
+ [ 0.996800, 0.772289 ],
+ [ 0.985791, 0.795152 ],
+ [ 0.966959, 0.817662 ],
+ [ 0.940291, 0.839639 ],
+ [ 0.905775, 0.860904 ],
+ [ 0.863396, 0.881278 ],
+ [ 0.813142, 0.900581 ],
+ [ 0.754998, 0.918634 ],
+ [ 0.614992, 0.950271 ],
+ [ 0.443271, 0.974752 ],
+ [ 0.239728, 0.990644 ],
+ [ 0.004257, 0.996509 ]
+ ]
+ ]
+}
diff --git a/data/text/B_1.svg b/data/text/B_1.svg
new file mode 100644
index 0000000..32adc55
--- /dev/null
+++ b/data/text/B_1.svg
@@ -0,0 +1,67 @@
+
+
diff --git a/data/text/C_1.json b/data/text/C_1.json
new file mode 100644
index 0000000..71b953f
--- /dev/null
+++ b/data/text/C_1.json
@@ -0,0 +1,42 @@
+{
+ "type": "REFERENCE",
+ "value": "C",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 1, 0.147941 ],
+ [ 0.880008, 0.089209 ],
+ [ 0.767615, 0.046089 ],
+ [ 0.662835, 0.017541 ],
+ [ 0.565684, 0.002524 ],
+ [ 0.476174, 0 ],
+ [ 0.394320, 0.008928 ],
+ [ 0.320137, 0.028268 ],
+ [ 0.253638, 0.056979 ],
+ [ 0.194838, 0.094023 ],
+ [ 0.143752, 0.138359 ],
+ [ 0.100392, 0.188947 ],
+ [ 0.064774, 0.244747 ],
+ [ 0.036911, 0.304719 ],
+ [ 0.016819, 0.367824 ],
+ [ 0.004510, 0.433020 ],
+ [ 0, 0.499268 ],
+ [ 0.003302, 0.565529 ],
+ [ 0.014431, 0.630761 ],
+ [ 0.033401, 0.693926 ],
+ [ 0.060226, 0.753983 ],
+ [ 0.094920, 0.809892 ],
+ [ 0.137498, 0.860613 ],
+ [ 0.187974, 0.905106 ],
+ [ 0.246362, 0.942331 ],
+ [ 0.312676, 0.971249 ],
+ [ 0.386930, 0.990818 ],
+ [ 0.469139, 1 ],
+ [ 0.559317, 0.997754 ],
+ [ 0.657477, 0.983040 ],
+ [ 0.763635, 0.954818 ],
+ [ 0.877805, 0.912049 ],
+ [ 1, 0.853691 ]
+ ]
+ ]
+}
diff --git a/data/text/C_1.svg b/data/text/C_1.svg
new file mode 100644
index 0000000..32ca8eb
--- /dev/null
+++ b/data/text/C_1.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/data/text/D_1.json b/data/text/D_1.json
new file mode 100644
index 0000000..075ff29
--- /dev/null
+++ b/data/text/D_1.json
@@ -0,0 +1,46 @@
+{
+ "type": "REFERENCE",
+ "value": "D",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0, 0 ],
+ [ 0, 256 ]
+ ],
+ [
+ [ 0, -1.084746 ],
+ [ 30.558805, -0.344010 ],
+ [ 59.182121, 1.815285 ],
+ [ 85.866562, 5.298776 ],
+ [ 110.608734, 10.012094 ],
+ [ 133.405258, 15.860873 ],
+ [ 154.252762, 22.750751 ],
+ [ 173.147842, 30.587358 ],
+ [ 190.087112, 39.276329 ],
+ [ 205.067184, 48.723301 ],
+ [ 218.084686, 58.833897 ],
+ [ 229.136200, 69.513771 ],
+ [ 238.218399, 80.668533 ],
+ [ 245.327850, 92.203842 ],
+ [ 250.461166, 104.025307 ],
+ [ 253.614990, 116.038582 ],
+ [ 254.785934, 128.149292 ],
+ [ 253.970581, 140.263077 ],
+ [ 251.165573, 152.285568 ],
+ [ 246.367538, 164.122406 ],
+ [ 239.573044, 175.679199 ],
+ [ 230.778732, 186.861603 ],
+ [ 219.981201, 197.575256 ],
+ [ 207.177109, 207.725769 ],
+ [ 192.362991, 217.218811 ],
+ [ 175.535507, 225.959976 ],
+ [ 156.691330, 233.854935 ],
+ [ 135.826981, 240.809296 ],
+ [ 112.939117, 246.728699 ],
+ [ 88.024353, 251.518784 ],
+ [ 61.079292, 255.085190 ],
+ [ 32.100552, 257.333557 ],
+ [ 1.084746, 258.169495 ]
+ ]
+ ]
+}
diff --git a/data/text/D_1.svg b/data/text/D_1.svg
new file mode 100644
index 0000000..58d2c18
--- /dev/null
+++ b/data/text/D_1.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/data/text/E_1.json b/data/text/E_1.json
new file mode 100644
index 0000000..cef8f98
--- /dev/null
+++ b/data/text/E_1.json
@@ -0,0 +1,16 @@
+{
+ "type":"REFERENCE",
+ "value":"E",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,0.0],[1.0,0.0]
+ ],[
+ [0.0,0.5],[1.0,0.5]
+ ],[
+ [0.0,1.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/F_1.json b/data/text/F_1.json
new file mode 100644
index 0000000..e92767f
--- /dev/null
+++ b/data/text/F_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"F",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,0.5],[1.0,0.5]
+ ],[
+ [0.0,1.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/G_1.json b/data/text/G_1.json
new file mode 100644
index 0000000..2370cd1
--- /dev/null
+++ b/data/text/G_1.json
@@ -0,0 +1,50 @@
+{
+ "type": "REFERENCE",
+ "value": "G",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 1, 0.140482 ],
+ [ 0.852131, 0.079876 ],
+ [ 0.717526, 0.037124 ],
+ [ 0.595810, 0.010931 ],
+ [ 0.486605, 0 ],
+ [ 0.389537, 0.003035 ],
+ [ 0.304228, 0.018739 ],
+ [ 0.230304, 0.045815 ],
+ [ 0.167387, 0.082968 ],
+ [ 0.115103, 0.128901 ],
+ [ 0.073075, 0.182317 ],
+ [ 0.040926, 0.241921 ],
+ [ 0.018282, 0.306415 ],
+ [ 0.004765, 0.374503 ],
+ [ 0, 0.444889 ],
+ [ 0.003611, 0.516276 ],
+ [ 0.015222, 0.587368 ],
+ [ 0.034456, 0.656868 ],
+ [ 0.060939, 0.723480 ],
+ [ 0.094293, 0.785908 ],
+ [ 0.134143, 0.842855 ],
+ [ 0.180113, 0.893024 ],
+ [ 0.231826, 0.935120 ],
+ [ 0.288907, 0.967845 ],
+ [ 0.350979, 0.989904 ],
+ [ 0.417667, 1.000000 ],
+ [ 0.488595, 0.996836 ],
+ [ 0.563387, 0.979116 ],
+ [ 0.641665, 0.945544 ],
+ [ 0.723056, 0.894823 ],
+ [ 0.807182, 0.825656 ],
+ [ 0.893667, 0.736748 ],
+ [ 0.982136, 0.626801 ]
+ ],
+ [
+ [ 0.511234, 0.615937 ],
+ [ 0.993572, 0.615937 ]
+ ],
+ [
+ [ 0.993572, 0.979437 ],
+ [ 0.993572, 0.611660 ]
+ ]
+ ]
+}
diff --git a/data/text/G_1.svg b/data/text/G_1.svg
new file mode 100644
index 0000000..fdea3b8
--- /dev/null
+++ b/data/text/G_1.svg
@@ -0,0 +1,66 @@
+
+
diff --git a/data/text/H_1.json b/data/text/H_1.json
new file mode 100644
index 0000000..e7aa8c8
--- /dev/null
+++ b/data/text/H_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"H",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,0.5],[0.0,0.5]
+ ],[
+ [1.0,0.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/I_1.json b/data/text/I_1.json
new file mode 100644
index 0000000..4cce55a
--- /dev/null
+++ b/data/text/I_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"I",
+ "sub-id":1,
+ "data":[
+ [
+ [0.25,0.0],[0.75,0.0]
+ ],[
+ [0.5,0.0],[0.5,1.0]
+ ],[
+ [0.25,1.0],[0.75,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/J_1.json b/data/text/J_1.json
new file mode 100644
index 0000000..0a12ae9
--- /dev/null
+++ b/data/text/J_1.json
@@ -0,0 +1,35 @@
+{
+ "type": "REFERENCE",
+ "value": "J",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0.500000, 0 ],
+ [ 0.503189, 0.252934 ],
+ [ 0.494712, 0.462548 ],
+ [ 0.476102, 0.632184 ],
+ [ 0.448895, 0.765185 ],
+ [ 0.432547, 0.818994 ],
+ [ 0.414624, 0.864897 ],
+ [ 0.395320, 0.903314 ],
+ [ 0.374825, 0.934662 ],
+ [ 0.353332, 0.959359 ],
+ [ 0.331032, 0.977824 ],
+ [ 0.308117, 0.990473 ],
+ [ 0.284779, 0.997726 ],
+ [ 0.261209, 1.000000 ],
+ [ 0.237600, 0.997713 ],
+ [ 0.191031, 0.981127 ],
+ [ 0.146605, 0.951313 ],
+ [ 0.105857, 0.911614 ],
+ [ 0.070322, 0.865373 ],
+ [ 0.041534, 0.815934 ],
+ [ 0.021027, 0.766642 ],
+ [ 0.010336, 0.720839 ]
+ ],
+ [
+ [ 1, 0.005057 ],
+ [ 0, 0.005057 ]
+ ]
+ ]
+}
diff --git a/data/text/J_1.svg b/data/text/J_1.svg
new file mode 100644
index 0000000..b5c8bc9
--- /dev/null
+++ b/data/text/J_1.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/data/text/K_1.json b/data/text/K_1.json
new file mode 100644
index 0000000..af60081
--- /dev/null
+++ b/data/text/K_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"K",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,0.5],[1.0,0.0]
+ ],[
+ [0.0,0.5],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/L_1.json b/data/text/L_1.json
new file mode 100644
index 0000000..1390e35
--- /dev/null
+++ b/data/text/L_1.json
@@ -0,0 +1,12 @@
+{
+ "type":"REFERENCE",
+ "value":"L",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,0.0],[1.0,0.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/M_1.json b/data/text/M_1.json
new file mode 100644
index 0000000..f4d49aa
--- /dev/null
+++ b/data/text/M_1.json
@@ -0,0 +1,16 @@
+{
+ "type":"REFERENCE",
+ "value":"M",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,1.0],[0.5,0.5]
+ ],[
+ [0.5,0.5],[1.0,1.0]
+ ],[
+ [1.0,0.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/N_1.json b/data/text/N_1.json
new file mode 100644
index 0000000..24295f5
--- /dev/null
+++ b/data/text/N_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"N",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,1.0],[1.0,0.0]
+ ],[
+ [1.0,0.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/O_1.json b/data/text/O_1.json
new file mode 100644
index 0000000..d9fae09
--- /dev/null
+++ b/data/text/O_1.json
@@ -0,0 +1,73 @@
+{
+ "type": "REFERENCE",
+ "value": "O",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 1, 0.500000 ],
+ [ 0.997419, 0.551122 ],
+ [ 0.989842, 0.600767 ],
+ [ 0.977521, 0.648685 ],
+ [ 0.960707, 0.694623 ],
+ [ 0.939653, 0.738330 ],
+ [ 0.914608, 0.779555 ],
+ [ 0.885824, 0.818046 ],
+ [ 0.853553, 0.853553 ],
+ [ 0.818046, 0.885824 ],
+ [ 0.779555, 0.914608 ],
+ [ 0.738330, 0.939653 ],
+ [ 0.694623, 0.960707 ],
+ [ 0.648685, 0.977521 ],
+ [ 0.600767, 0.989842 ],
+ [ 0.551122, 0.997418 ],
+ [ 0.500000, 1.000000 ],
+ [ 0.448878, 0.997418 ],
+ [ 0.399233, 0.989842 ],
+ [ 0.351315, 0.977521 ],
+ [ 0.305377, 0.960707 ],
+ [ 0.261670, 0.939653 ],
+ [ 0.220445, 0.914608 ],
+ [ 0.181954, 0.885824 ],
+ [ 0.146447, 0.853553 ],
+ [ 0.114176, 0.818046 ],
+ [ 0.085392, 0.779555 ],
+ [ 0.060347, 0.738330 ],
+ [ 0.039292, 0.694623 ],
+ [ 0.022479, 0.648685 ],
+ [ 0.010158, 0.600767 ],
+ [ 0.002581, 0.551122 ],
+ [ 0, 0.500000 ],
+ [ 0.002581, 0.448878 ],
+ [ 0.010158, 0.399233 ],
+ [ 0.022479, 0.351315 ],
+ [ 0.039292, 0.305377 ],
+ [ 0.060347, 0.261670 ],
+ [ 0.085392, 0.220445 ],
+ [ 0.114176, 0.181954 ],
+ [ 0.146447, 0.146447 ],
+ [ 0.181954, 0.114176 ],
+ [ 0.220445, 0.085392 ],
+ [ 0.261670, 0.060347 ],
+ [ 0.305377, 0.039292 ],
+ [ 0.351315, 0.022479 ],
+ [ 0.399233, 0.010158 ],
+ [ 0.448878, 0.002581 ],
+ [ 0.500000, 0 ],
+ [ 0.551122, 0.002581 ],
+ [ 0.600767, 0.010158 ],
+ [ 0.648685, 0.022479 ],
+ [ 0.694623, 0.039292 ],
+ [ 0.738330, 0.060347 ],
+ [ 0.779555, 0.085392 ],
+ [ 0.818046, 0.114176 ],
+ [ 0.853553, 0.146447 ],
+ [ 0.885824, 0.181954 ],
+ [ 0.914608, 0.220445 ],
+ [ 0.939653, 0.261670 ],
+ [ 0.960707, 0.305377 ],
+ [ 0.977521, 0.351315 ],
+ [ 0.989842, 0.399233 ],
+ [ 0.997419, 0.448878 ]
+ ]
+ ]
+}
diff --git a/data/text/O_1.svg b/data/text/O_1.svg
new file mode 100644
index 0000000..75f7539
--- /dev/null
+++ b/data/text/O_1.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/data/text/P_1.json b/data/text/P_1.json
new file mode 100644
index 0000000..358baf0
--- /dev/null
+++ b/data/text/P_1.json
@@ -0,0 +1,37 @@
+{
+ "type": "REFERENCE",
+ "value": "P",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0, 0 ],
+ [ 0, 1 ]
+ ],
+ [
+ [ 0, 0.003491 ],
+ [ 0.232282, 0.009006 ],
+ [ 0.434124, 0.024593 ],
+ [ 0.605421, 0.048818 ],
+ [ 0.746066, 0.080245 ],
+ [ 0.855952, 0.117437 ],
+ [ 0.899328, 0.137747 ],
+ [ 0.934975, 0.158959 ],
+ [ 0.962878, 0.180896 ],
+ [ 0.983026, 0.203376 ],
+ [ 0.995404, 0.226222 ],
+ [ 1.000000, 0.249252 ],
+ [ 0.996800, 0.272289 ],
+ [ 0.985791, 0.295152 ],
+ [ 0.966959, 0.317662 ],
+ [ 0.940291, 0.339639 ],
+ [ 0.905775, 0.360904 ],
+ [ 0.863396, 0.381278 ],
+ [ 0.813142, 0.400581 ],
+ [ 0.754998, 0.418634 ],
+ [ 0.614992, 0.450271 ],
+ [ 0.443271, 0.474752 ],
+ [ 0.239728, 0.490644 ],
+ [ 0.004257, 0.496509 ]
+ ]
+ ]
+}
diff --git a/data/text/P_1.svg b/data/text/P_1.svg
new file mode 100644
index 0000000..1cdb6f1
--- /dev/null
+++ b/data/text/P_1.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/data/text/Q_1.json b/data/text/Q_1.json
new file mode 100644
index 0000000..59704e3
--- /dev/null
+++ b/data/text/Q_1.json
@@ -0,0 +1,77 @@
+{
+ "type": "REFERENCE",
+ "value": "Q",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0.990345, 0.495173 ],
+ [ 0.987789, 0.545801 ],
+ [ 0.980285, 0.594967 ],
+ [ 0.968083, 0.642422 ],
+ [ 0.951432, 0.687916 ],
+ [ 0.930580, 0.731201 ],
+ [ 0.905777, 0.772028 ],
+ [ 0.877272, 0.810148 ],
+ [ 0.845312, 0.845312 ],
+ [ 0.810148, 0.877272 ],
+ [ 0.772028, 0.905778 ],
+ [ 0.731201, 0.930581 ],
+ [ 0.687916, 0.951432 ],
+ [ 0.642422, 0.968083 ],
+ [ 0.594967, 0.980285 ],
+ [ 0.545801, 0.987789 ],
+ [ 0.495173, 0.990345 ],
+ [ 0.444544, 0.987789 ],
+ [ 0.395378, 0.980285 ],
+ [ 0.347923, 0.968083 ],
+ [ 0.302429, 0.951432 ],
+ [ 0.259144, 0.930581 ],
+ [ 0.218317, 0.905778 ],
+ [ 0.180197, 0.877272 ],
+ [ 0.145033, 0.845312 ],
+ [ 0.113073, 0.810148 ],
+ [ 0.084568, 0.772028 ],
+ [ 0.059765, 0.731201 ],
+ [ 0.038913, 0.687916 ],
+ [ 0.022262, 0.642422 ],
+ [ 0.010060, 0.594967 ],
+ [ 0.002557, 0.545801 ],
+ [ 0, 0.495173 ],
+ [ 0.002557, 0.444544 ],
+ [ 0.010060, 0.395378 ],
+ [ 0.022262, 0.347923 ],
+ [ 0.038913, 0.302429 ],
+ [ 0.059765, 0.259144 ],
+ [ 0.084568, 0.218317 ],
+ [ 0.113073, 0.180197 ],
+ [ 0.145033, 0.145033 ],
+ [ 0.180197, 0.113073 ],
+ [ 0.218317, 0.084568 ],
+ [ 0.259144, 0.059765 ],
+ [ 0.302429, 0.038913 ],
+ [ 0.347923, 0.022262 ],
+ [ 0.395378, 0.010060 ],
+ [ 0.444544, 0.002557 ],
+ [ 0.495173, 0 ],
+ [ 0.545801, 0.002557 ],
+ [ 0.594967, 0.010060 ],
+ [ 0.642422, 0.022262 ],
+ [ 0.687916, 0.038913 ],
+ [ 0.731201, 0.059765 ],
+ [ 0.772028, 0.084568 ],
+ [ 0.810148, 0.113073 ],
+ [ 0.845312, 0.145033 ],
+ [ 0.877272, 0.180197 ],
+ [ 0.905777, 0.218317 ],
+ [ 0.930580, 0.259144 ],
+ [ 0.951432, 0.302429 ],
+ [ 0.968083, 0.347923 ],
+ [ 0.980285, 0.395378 ],
+ [ 0.987789, 0.444544 ]
+ ],
+ [
+ [ 0.673347, 0.732738 ],
+ [ 1, 1 ]
+ ]
+ ]
+}
diff --git a/data/text/Q_1.svg b/data/text/Q_1.svg
new file mode 100644
index 0000000..045b3eb
--- /dev/null
+++ b/data/text/Q_1.svg
@@ -0,0 +1,62 @@
+
+
diff --git a/data/text/R_1.json b/data/text/R_1.json
new file mode 100644
index 0000000..f0f2d9c
--- /dev/null
+++ b/data/text/R_1.json
@@ -0,0 +1,41 @@
+{
+ "type": "REFERENCE",
+ "value": "R",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0, 0 ],
+ [ 0, 1 ]
+ ],
+ [
+ [ 0, 0.003491 ],
+ [ 0.231464, 0.009006 ],
+ [ 0.432595, 0.024593 ],
+ [ 0.603289, 0.048818 ],
+ [ 0.743438, 0.080245 ],
+ [ 0.852938, 0.117437 ],
+ [ 0.896161, 0.137747 ],
+ [ 0.931682, 0.158959 ],
+ [ 0.959487, 0.180896 ],
+ [ 0.979564, 0.203376 ],
+ [ 0.991898, 0.226222 ],
+ [ 0.996478, 0.249252 ],
+ [ 0.993289, 0.272289 ],
+ [ 0.982319, 0.295152 ],
+ [ 0.963553, 0.317662 ],
+ [ 0.936980, 0.339639 ],
+ [ 0.902585, 0.360904 ],
+ [ 0.860355, 0.381278 ],
+ [ 0.810278, 0.400581 ],
+ [ 0.752339, 0.418634 ],
+ [ 0.612826, 0.450271 ],
+ [ 0.441709, 0.474752 ],
+ [ 0.238884, 0.490644 ],
+ [ 0.004242, 0.496509 ]
+ ],
+ [
+ [ 0, 0.500000 ],
+ [ 1, 1 ]
+ ]
+ ]
+}
diff --git a/data/text/R_1.svg b/data/text/R_1.svg
new file mode 100644
index 0000000..0d83466
--- /dev/null
+++ b/data/text/R_1.svg
@@ -0,0 +1,67 @@
+
+
diff --git a/data/text/S_1.json b/data/text/S_1.json
new file mode 100644
index 0000000..656073b
--- /dev/null
+++ b/data/text/S_1.json
@@ -0,0 +1,56 @@
+{
+ "type": "REFERENCE",
+ "value": "S",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 1, 0 ],
+ [ 0.790439, 0.001118 ],
+ [ 0.606683, 0.013011 ],
+ [ 0.448298, 0.034223 ],
+ [ 0.314847, 0.063295 ],
+ [ 0.205897, 0.098774 ],
+ [ 0.121011, 0.139200 ],
+ [ 0.087457, 0.160814 ],
+ [ 0.059755, 0.183119 ],
+ [ 0.037852, 0.205933 ],
+ [ 0.021694, 0.229074 ],
+ [ 0.011225, 0.252359 ],
+ [ 0.006392, 0.275607 ],
+ [ 0.007140, 0.298636 ],
+ [ 0.013415, 0.321264 ],
+ [ 0.025162, 0.343308 ],
+ [ 0.042327, 0.364586 ],
+ [ 0.064856, 0.384917 ],
+ [ 0.092693, 0.404118 ],
+ [ 0.164079, 0.438404 ],
+ [ 0.256049, 0.465985 ],
+ [ 0.368167, 0.485408 ],
+ [ 0.500000, 0.495213 ],
+ [ 0.631746, 0.505541 ],
+ [ 0.743626, 0.526395 ],
+ [ 0.835242, 0.556114 ],
+ [ 0.873326, 0.573779 ],
+ [ 0.906193, 0.593038 ],
+ [ 0.933793, 0.613684 ],
+ [ 0.956077, 0.635508 ],
+ [ 0.972995, 0.658304 ],
+ [ 0.984497, 0.681863 ],
+ [ 0.990531, 0.705979 ],
+ [ 0.991049, 0.730444 ],
+ [ 0.986001, 0.755050 ],
+ [ 0.975336, 0.779590 ],
+ [ 0.959004, 0.803856 ],
+ [ 0.936955, 0.827642 ],
+ [ 0.909140, 0.850738 ],
+ [ 0.875508, 0.872938 ],
+ [ 0.836009, 0.894035 ],
+ [ 0.790593, 0.913820 ],
+ [ 0.681811, 0.948627 ],
+ [ 0.548761, 0.975700 ],
+ [ 0.391042, 0.993377 ],
+ [ 0.208256, 1 ],
+ [ 0, 0.993908 ]
+ ]
+ ]
+}
diff --git a/data/text/S_1.svg b/data/text/S_1.svg
new file mode 100644
index 0000000..a65b820
--- /dev/null
+++ b/data/text/S_1.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/data/text/T_1.json b/data/text/T_1.json
new file mode 100644
index 0000000..c859f3f
--- /dev/null
+++ b/data/text/T_1.json
@@ -0,0 +1,12 @@
+{
+ "type":"REFERENCE",
+ "value":"T",
+ "sub-id":1,
+ "data":[
+ [
+ [0.5,0.0],[0.5,1.0]
+ ],[
+ [0.25,1.0],[0.75,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/U_1.json b/data/text/U_1.json
new file mode 100644
index 0000000..c38d098
--- /dev/null
+++ b/data/text/U_1.json
@@ -0,0 +1,38 @@
+{
+ "type": "REFERENCE",
+ "value": "U",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0.991609, 0 ],
+ [ 0.992411, 0.755487 ],
+ [ 0.989280, 0.788232 ],
+ [ 0.980773, 0.818411 ],
+ [ 0.967246, 0.846070 ],
+ [ 0.949060, 0.871256 ],
+ [ 0.926571, 0.894016 ],
+ [ 0.900139, 0.914396 ],
+ [ 0.836874, 0.948202 ],
+ [ 0.762132, 0.973047 ],
+ [ 0.678776, 0.989304 ],
+ [ 0.589672, 0.997345 ],
+ [ 0.497686, 0.997543 ],
+ [ 0.405681, 0.990270 ],
+ [ 0.316525, 0.975899 ],
+ [ 0.233080, 0.954802 ],
+ [ 0.158214, 0.927352 ],
+ [ 0.094790, 0.893922 ],
+ [ 0.045675, 0.854883 ],
+ [ 0.027378, 0.833377 ],
+ [ 0.013733, 0.810609 ],
+ [ 0.005097, 0.786625 ],
+ [ 0.001829, 0.761472 ],
+ [ 0, 0.403139 ],
+ [ 0.001520, 0 ]
+ ],
+ [
+ [ 1.000000, 1 ],
+ [ 0.995805, 0 ]
+ ]
+ ]
+}
diff --git a/data/text/U_1.svg b/data/text/U_1.svg
new file mode 100644
index 0000000..60c6392
--- /dev/null
+++ b/data/text/U_1.svg
@@ -0,0 +1,61 @@
+
+
diff --git a/data/text/V_1.json b/data/text/V_1.json
new file mode 100644
index 0000000..10607e9
--- /dev/null
+++ b/data/text/V_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"V",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0, 1.0],
+ [0.5, 0.0]
+ ],[
+ [0.5, 0.0],
+ [1.0, 1.0]
+ ],
+ ]
+}
\ No newline at end of file
diff --git a/data/text/W_1.json b/data/text/W_1.json
new file mode 100644
index 0000000..79632fe
--- /dev/null
+++ b/data/text/W_1.json
@@ -0,0 +1,16 @@
+{
+ "type":"REFERENCE",
+ "value":"W",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,1.0],[0.25,0.0]
+ ],[
+ [0.25,0.0],[0.5,0.5]
+ ],[
+ [0.5,0.5],[0.75,0.0]
+ ],[
+ [0.75,0.0],[1.0,1.0]
+ ],
+ ]
+}
\ No newline at end of file
diff --git a/data/text/X_1.json b/data/text/X_1.json
new file mode 100644
index 0000000..01d10cb
--- /dev/null
+++ b/data/text/X_1.json
@@ -0,0 +1,12 @@
+{
+ "type":"REFERENCE",
+ "value":"X",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[1.0,1.0]
+ ],[
+ [0.0,1.0],[1.0,0.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/Y_1.json b/data/text/Y_1.json
new file mode 100644
index 0000000..2423495
--- /dev/null
+++ b/data/text/Y_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"Y",
+ "sub-id":1,
+ "data":[
+ [
+ [0.5,0.5],[1.0,1.0]
+ ],[
+ [0.5,0.5],[1.0,0.0]
+ ],[
+ [0.5,0.5],[0.5,0.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/Z_1.json b/data/text/Z_1.json
new file mode 100644
index 0000000..32f1486
--- /dev/null
+++ b/data/text/Z_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"Z",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,1.0],[1.0,1.0]
+ ],[
+ [1.0,1.0],[0.0,0.0]
+ ],[
+ [0.0,0.0],[1.0,0.0]
+ ],
+ ]
+}
\ No newline at end of file
diff --git a/data/text/brace-left_1.json b/data/text/brace-left_1.json
new file mode 100644
index 0000000..496b5cb
--- /dev/null
+++ b/data/text/brace-left_1.json
@@ -0,0 +1,57 @@
+{
+ "type": "REFERENCE",
+ "value": "{",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0.991543, 0 ],
+ [ 0.890026, 0.002108 ],
+ [ 0.802061, 0.008146 ],
+ [ 0.726682, 0.017683 ],
+ [ 0.662923, 0.030288 ],
+ [ 0.609817, 0.045532 ],
+ [ 0.566398, 0.062984 ],
+ [ 0.531700, 0.082213 ],
+ [ 0.504757, 0.102791 ],
+ [ 0.484602, 0.124285 ],
+ [ 0.470270, 0.146265 ],
+ [ 0.455206, 0.189965 ],
+ [ 0.452431, 0.264271 ],
+ [ 0.447350, 0.311527 ],
+ [ 0.432991, 0.352143 ],
+ [ 0.410679, 0.386614 ],
+ [ 0.381739, 0.415437 ],
+ [ 0.347497, 0.439105 ],
+ [ 0.309279, 0.458116 ],
+ [ 0.268410, 0.472965 ],
+ [ 0.226216, 0.484147 ],
+ [ 0.143152, 0.497491 ],
+ [ 0.070692, 0.502115 ],
+ [ 0, 0.501057 ],
+ [ 0.070992, 0.499438 ],
+ [ 0.143715, 0.502729 ],
+ [ 0.227016, 0.513478 ],
+ [ 0.310217, 0.535226 ],
+ [ 0.348443, 0.551333 ],
+ [ 0.382639, 0.571518 ],
+ [ 0.411471, 0.596225 ],
+ [ 0.433603, 0.625896 ],
+ [ 0.447702, 0.660974 ],
+ [ 0.452431, 0.701903 ],
+ [ 0.454730, 0.750956 ],
+ [ 0.465852, 0.801398 ],
+ [ 0.476296, 0.826397 ],
+ [ 0.490834, 0.850850 ],
+ [ 0.510098, 0.874461 ],
+ [ 0.534716, 0.896932 ],
+ [ 0.565318, 0.917967 ],
+ [ 0.602534, 0.937267 ],
+ [ 0.646995, 0.954536 ],
+ [ 0.699329, 0.969476 ],
+ [ 0.760167, 0.981790 ],
+ [ 0.830138, 0.991180 ],
+ [ 0.909873, 0.997349 ],
+ [ 1, 1 ]
+ ]
+ ]
+}
diff --git a/data/text/brace-left_1.svg b/data/text/brace-left_1.svg
new file mode 100644
index 0000000..51f4c44
--- /dev/null
+++ b/data/text/brace-left_1.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/data/text/brace-right_1.json b/data/text/brace-right_1.json
new file mode 100644
index 0000000..35d4aa2
--- /dev/null
+++ b/data/text/brace-right_1.json
@@ -0,0 +1,57 @@
+{
+ "type": "REFERENCE",
+ "value": "}",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0.008457, 0 ],
+ [ 0.109974, 0.002108 ],
+ [ 0.197939, 0.008146 ],
+ [ 0.273318, 0.017683 ],
+ [ 0.337077, 0.030288 ],
+ [ 0.390183, 0.045532 ],
+ [ 0.433602, 0.062984 ],
+ [ 0.468300, 0.082213 ],
+ [ 0.495243, 0.102791 ],
+ [ 0.515398, 0.124285 ],
+ [ 0.529730, 0.146265 ],
+ [ 0.544794, 0.189965 ],
+ [ 0.547569, 0.264271 ],
+ [ 0.552650, 0.311527 ],
+ [ 0.567009, 0.352143 ],
+ [ 0.589321, 0.386614 ],
+ [ 0.618261, 0.415437 ],
+ [ 0.652503, 0.439105 ],
+ [ 0.690721, 0.458116 ],
+ [ 0.731590, 0.472965 ],
+ [ 0.773784, 0.484147 ],
+ [ 0.856848, 0.497491 ],
+ [ 0.929308, 0.502115 ],
+ [ 1, 0.501057 ],
+ [ 0.929008, 0.499438 ],
+ [ 0.856285, 0.502729 ],
+ [ 0.772984, 0.513478 ],
+ [ 0.689783, 0.535226 ],
+ [ 0.651558, 0.551333 ],
+ [ 0.617361, 0.571518 ],
+ [ 0.588529, 0.596225 ],
+ [ 0.566397, 0.625896 ],
+ [ 0.552298, 0.660974 ],
+ [ 0.547569, 0.701903 ],
+ [ 0.545270, 0.750956 ],
+ [ 0.534148, 0.801398 ],
+ [ 0.523704, 0.826397 ],
+ [ 0.509166, 0.850850 ],
+ [ 0.489902, 0.874461 ],
+ [ 0.465284, 0.896932 ],
+ [ 0.434682, 0.917967 ],
+ [ 0.397466, 0.937267 ],
+ [ 0.353005, 0.954536 ],
+ [ 0.300671, 0.969476 ],
+ [ 0.239833, 0.981790 ],
+ [ 0.169862, 0.991180 ],
+ [ 0.090127, 0.997349 ],
+ [ 0, 1 ]
+ ]
+ ]
+}
diff --git a/data/text/brace-right_1.svg b/data/text/brace-right_1.svg
new file mode 100644
index 0000000..621ca88
--- /dev/null
+++ b/data/text/brace-right_1.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/data/text/bracket-left_1.json b/data/text/bracket-left_1.json
new file mode 100644
index 0000000..01ed814
--- /dev/null
+++ b/data/text/bracket-left_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"[",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[1.0,0.0]
+ ],[
+ [0.0,0.0],[0.0,1.0]
+ ],[
+ [0.0,1.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/bracket-right_1.json b/data/text/bracket-right_1.json
new file mode 100644
index 0000000..098efec
--- /dev/null
+++ b/data/text/bracket-right_1.json
@@ -0,0 +1,14 @@
+{
+ "type":"REFERENCE",
+ "value":"]",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],[1.0,0.0]
+ ],[
+ [1.0,0.0],[1.0,1.0]
+ ],[
+ [0.0,1.0],[1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/question-mark_1.json b/data/text/question-mark_1.json
new file mode 100644
index 0000000..4ca79ce
--- /dev/null
+++ b/data/text/question-mark_1.json
@@ -0,0 +1,38 @@
+{
+ "type": "REFERENCE",
+ "value": "?",
+ "sub-id": 1,
+ "data": [
+ [
+ [ 0, 0.307167 ],
+ [ 0.013307, 0.212637 ],
+ [ 0.050746, 0.139665 ],
+ [ 0.108336, 0.085491 ],
+ [ 0.182096, 0.047355 ],
+ [ 0.268044, 0.022498 ],
+ [ 0.362200, 0.008159 ],
+ [ 0.460582, 0.001580 ],
+ [ 0.559210, 0 ],
+ [ 0.652741, 0.005593 ],
+ [ 0.737685, 0.021704 ],
+ [ 0.812847, 0.047335 ],
+ [ 0.877029, 0.081485 ],
+ [ 0.929032, 0.123154 ],
+ [ 0.967660, 0.171342 ],
+ [ 0.991716, 0.225049 ],
+ [ 1, 0.283276 ],
+ [ 0.985056, 0.340744 ],
+ [ 0.944593, 0.393611 ],
+ [ 0.885164, 0.443039 ],
+ [ 0.813322, 0.490188 ],
+ [ 0.658614, 0.582285 ],
+ [ 0.588854, 0.629553 ],
+ [ 0.532895, 0.679181 ],
+ [ 0.492779, 0.727962 ],
+ [ 0.464844, 0.772504 ],
+ [ 0.437500, 0.852389 ],
+ [ 0.434827, 0.925875 ],
+ [ 0.440790, 1.000000 ]
+ ]
+ ]
+}
diff --git a/data/text/question-mark_1.svg b/data/text/question-mark_1.svg
new file mode 100644
index 0000000..5ddd505
--- /dev/null
+++ b/data/text/question-mark_1.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/data/text/slash-back_1.json b/data/text/slash-back_1.json
new file mode 100644
index 0000000..bb37293
--- /dev/null
+++ b/data/text/slash-back_1.json
@@ -0,0 +1,11 @@
+{
+ "type":"REFERENCE",
+ "value":"\\",
+ "sub-id":1,
+ "data":[
+ [
+ [1.0,0.0],
+ [0.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/slash_1.json b/data/text/slash_1.json
new file mode 100644
index 0000000..25501f9
--- /dev/null
+++ b/data/text/slash_1.json
@@ -0,0 +1,11 @@
+{
+ "type":"REFERENCE",
+ "value":"/",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.0],
+ [1.0,1.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/data/text/star_1.json b/data/text/star_1.json
new file mode 100644
index 0000000..accded1
--- /dev/null
+++ b/data/text/star_1.json
@@ -0,0 +1,16 @@
+{
+ "type":"REFERENCE",
+ "value":"*",
+ "sub-id":1,
+ "data":[
+ [
+ [0.0,0.5],[1.0,0.5]
+ ],[
+ [0.5,0.0],[0.5,1.0]
+ ],[
+ [0.0,0.0],[1.0,1.0]
+ ],[
+ [0.0,1.0],[1.0,0.0]
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/dollar/Engine.cpp b/dollar/Engine.cpp
new file mode 100644
index 0000000..8e5cd48
--- /dev/null
+++ b/dollar/Engine.cpp
@@ -0,0 +1,256 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#define MAX_FLOAT std::numeric_limits::max()
+// simple decree to radian convertion
+#define DEG_2_RAD(ddd) (ddd*M_PI/180.0)
+
+// Test is done on the square of 1.0f * 1.0f ==> the result depend on the diagonal size
+#define DIAGONAL (1.414213562)
+#define HALF_DIAGONAL (0.707106781)
+// an other magic number ratio of starting vetor pos... ==> must be reworked ==> nbElementInVector/RATIO_START_VECTOR
+#define RATIO_START_VECTOR (8)
+// angle precision of the detecting the way of rotation
+#define ANGLE_ROTATION (2.0f)
+// Angle to start processing of a start vector comparaison
+#define ANGLE_THRESHOLD_START_PROCESSING DEG_2_RAD(30.0)
+
+// A magic number: 0.5 * (-1.0 + sqrt(5.0))
+#define MAGIC_RATIO (0.618033989)
+
+
+
+static float angleBetweenUnitVectors(const vec2& _vect1, const vec2& _vect2) {
+ float n = _vect1.dot(_vect2);
+ // TODO : No needs
+ if (n < -1.0 || n > +1.0){
+ n = round(n*100000.0f)/100000.0f;
+ }
+ return std::acos(n); // arc cosine of the vector dot product
+}
+
+static float pathDistance(const std::vector& _path1, const std::vector& _path2) {
+ // assumes pts1.size == pts2.size
+ float distance = 0.0;
+ if (_path1.size() != _path2.size()) {
+ DOLLAR_ERROR("Path have not the same size: " << _path1.size() << " != " << _path2.size());
+ return MAX_FLOAT;
+ }
+ for (size_t iii=0; iii<_path1.size(); ++iii) {
+ distance += (_path2[iii]-_path1[iii]).length();
+ }
+ DOLLAR_VERBOSE("distance: " << distance << " size= " << _path1.size());
+ return (distance / _path1.size());
+}
+
+dollar::Engine::Engine() {
+ m_numPointsInGesture = 128;
+ DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ...");
+ setRotationInvariance(false);
+}
+
+
+void dollar::Engine::setNumberPointInGesture(size_t _value) {
+ if (_value == m_numPointsInGesture) {
+ return;
+ }
+ m_numPointsInGesture = _value;
+ DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ...");
+ for (auto &it: m_gestures) {
+ it.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation);
+ }
+}
+
+size_t dollar::Engine::getNumberPointInGesture() {
+ return m_numPointsInGesture;
+}
+
+float dollar::Engine::distanceAtBestAngle(const std::vector& _points, const std::vector& _reference) {
+ float startRange = -m_angleRange;
+ float endRange = m_angleRange;
+ float x1 = MAGIC_RATIO * startRange + (1.0 - MAGIC_RATIO) * endRange;
+ float f1 = pathDistance(dollar::rotateBy(_points, x1), _reference);
+ float x2 = (1.0 - MAGIC_RATIO) * startRange + MAGIC_RATIO * endRange;
+ float f2 = pathDistance(dollar::rotateBy(_points, x2), _reference);
+ DOLLAR_VERBOSE("init: startRange=" << startRange << " endRange=" << endRange << " MAGIC_RATIO=" << MAGIC_RATIO << " x1=" << x1 << " f1=" << f1 << " x2=" << x2 << " f2=" << f2);
+ while (fabs(endRange - startRange) > ANGLE_ROTATION) {
+ if (f1 < f2) {
+ endRange = x2;
+ x2 = x1;
+ f2 = f1;
+ x1 = MAGIC_RATIO * startRange + (1.0f - MAGIC_RATIO) * endRange;
+ f1 = pathDistance(dollar::rotateBy(_points, x1), _reference);
+ } else {
+ startRange = x1;
+ x1 = x2;
+ f1 = f2;
+ x2 = (1.0f - MAGIC_RATIO) * startRange + MAGIC_RATIO * endRange;
+ f2 = pathDistance(dollar::rotateBy(_points, x2), _reference);
+ }
+ }
+ return std::min(f1, f2);
+}
+
+float dollar::Engine::optimalCosineDistance(const std::vector& _vect1, const std::vector& _vect2) {
+ if (_vect1.size() != _vect2.size()) {
+ DOLLAR_ERROR("Vector have not the same size: " << _vect1.size() << " != " << _vect2.size());
+ return M_PI;
+ }
+ double somDot = 0;
+ double somCross = 0;
+ for (size_t iii=0; iii<_vect1.size(); ++iii) {
+ somDot += _vect1[iii].dot(_vect2[iii]);
+ somCross += _vect1[iii].cross(_vect2[iii]);
+ }
+ if (somDot == 0.0f) {
+ DOLLAR_ERROR("devide by 0");
+ return M_PI;
+ }
+ float angle = std::atan(somCross / somDot);
+ return std::acos(somDot * std::cos(angle) + somCross * std::sin(angle));
+}
+
+
+
+void dollar::Engine::setRotationInvariance(bool _ignoreRotation) {
+ m_paramterIgnoreRotation = _ignoreRotation;
+ if (m_paramterIgnoreRotation == true) {
+ m_angleRange = 45.0;
+ } else {
+ m_angleRange = 15.0;
+ }
+}
+
+bool dollar::Engine::loadPath(const std::string& _path) {
+ DOLLAR_INFO("Load Path: " << _path);
+ etk::FSNode path(_path);
+ std::vector files = path.folderGetSub(false, true, "*.json");
+ for (auto &it : files) {
+ loadGesture(it);
+ }
+ return true;
+}
+
+bool dollar::Engine::loadGesture(const std::string& _filename) {
+ dollar::Gesture ref;
+ DOLLAR_INFO("Load Gesture: " << _filename);
+ if (ref.load(_filename) == true) {
+ addGesture(std::move(ref));
+ return true;
+ }
+ return false;
+}
+
+void dollar::Engine::addGesture(Gesture _gesture) {
+ _gesture.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation);
+ m_gestures.push_back(std::move(_gesture));
+}
+
+dollar::Results dollar::Engine::recognize(const std::vector& _points, const std::string& _method) {
+ std::vector> tmp;
+ tmp.push_back(_points);
+ return recognize(tmp, _method);
+}
+#define MAX_RESULT_NUMBER (5)
+
+dollar::Results dollar::Engine::recognize(const std::vector>& _strokes, const std::string& _method) {
+ std::vector points = dollar::combineStrokes(_strokes);
+ // Make sure we have some templates to compare this to
+ // or else recognition will be impossible
+ if (m_gestures.empty()) {
+ DOLLAR_WARNING("No templates loaded so no symbols to match.");
+ return Results();
+ }
+ points = dollar::normalizePath(points, m_numPointsInGesture, m_paramterIgnoreRotation);
+ vec2 startv = dollar::getStartVector(points, m_numPointsInGesture/RATIO_START_VECTOR);
+ std::vector vector = normalyse(points);
+ // Keep maximum 5 results ...
+ float bestDistance[MAX_RESULT_NUMBER];
+ int32_t indexOfBestMatch[MAX_RESULT_NUMBER];
+ for (size_t iii=0; iii ANGLE_THRESHOLD_START_PROCESSING) {
+ continue;
+ }
+ float distance = MAX_FLOAT;
+ // for Protractor
+ if (_method=="protractor") {
+ distance = Engine::optimalCosineDistance(vector, gesture.getEngineVector(jjj));
+ } else {
+ // Golden Section Search (original $N)
+ distance = Engine::distanceAtBestAngle(points, gesture.getEnginePath(jjj));
+ }
+ for (size_t kkk=0; kkkint32_t(kkk); --rrr) {
+ bestDistance[rrr] = bestDistance[rrr-1];
+ indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1];
+ }
+ indexOfBestMatch[kkk] = iii;
+ }
+ bestDistance[kkk] = distance;
+ break;
+ } else {
+ if (kkk == 0) {
+ DOLLAR_VERBOSE("[" << iii << "," << jjj << "] d=" << distance << " < bd=" << bestDistance << " ");
+ }
+ }
+ }
+ }
+ }
+ // Make sure we actually found a good match
+ // Sometimes we don't, like when the user doesn't draw enough points
+ if (-1 == indexOfBestMatch[0]) {
+ DOLLAR_WARNING("Couldn't find a good match.");
+ return Results();
+ }
+ Results res;
+ // Turn the distance into a percentage by dividing it by half the maximum possible distance (across the diagonal of the square we scaled everything too)
+ // Distance = hwo different they are subtract that from 1 (100%) to get the similarity
+ if (_method == "protractor") {
+ for (size_t iii=0; iii
+#include
+#include
+#include
+#include
+#include
+
+namespace dollar {
+ class Engine {
+ protected:
+ float m_angleRange;
+ bool m_paramterIgnoreRotation; //!< Ignore the start rotation of the gesture
+ public:
+ void setRotationInvariance(bool _ignoreRotation);
+ protected:
+ size_t m_numPointsInGesture; //!< Number of point in a gesture to recognise patern ...
+ public:
+ void setNumberPointInGesture(size_t _value);
+ size_t getNumberPointInGesture();
+ protected:
+ std::vector m_gestures; //!< List of all loaded gesture in the engine
+ public:
+ Engine();
+ float distanceAtBestAngle(const std::vector& _points, const std::vector& _reference);
+ Results recognize(const std::vector>& _paths, const std::string& _method="normal");
+ Results recognize(const std::vector& _points, const std::string& _method="normal");
+ float optimalCosineDistance(const std::vector& _vect1, const std::vector& _vect2);
+ bool loadPath(const std::string& _path);
+ bool loadGesture(const std::string& _filename);
+ void addGesture(Gesture _gesture);
+ };
+}
+
+
diff --git a/dollar/Gesture.cpp b/dollar/Gesture.cpp
new file mode 100644
index 0000000..67c61c5
--- /dev/null
+++ b/dollar/Gesture.cpp
@@ -0,0 +1,169 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+static std::vector> loadPointsJson(const ejson::Document& _doc) {
+ // extract lines:
+ std::vector> out;
+ const ejson::Array listOfLines = _doc["data"].toArray();
+ if (listOfLines.exist() == false) {
+ DOLLAR_WARNING("Reference element has no element named 'data' " << _doc["data"]);
+ return out;
+ }
+ for (auto itLines : listOfLines) {
+ ejson::Array listOfpoint = itLines.toArray();
+ std::vector line;
+ for (auto itPoints : listOfpoint) {
+ ejson::Array pointsArray = itPoints.toArray();
+ line.push_back(vec2(pointsArray[0].toNumber().get(), pointsArray[1].toNumber().get()));
+ }
+ if (line.size() > 1) {
+ out.push_back(std::move(line));
+ }
+ }
+ return out;
+}
+
+std::vector> dollar::loadPoints(const std::string& _fileName) {
+ ejson::Document doc;
+ doc.load(_fileName);
+ return loadPointsJson(doc);
+}
+
+
+dollar::Gesture::Gesture():
+ m_name(""),
+ m_subId(0),
+ m_path(){
+
+}
+
+bool dollar::Gesture::load(const std::string& _fileName) {
+ std::string tmpName = etk::tolower(_fileName);
+ if (etk::end_with(tmpName, ".json") == true) {
+ return loadJSON(_fileName);
+ } else if (etk::end_with(tmpName, ".svg") == true) {
+ return loadSVG(_fileName);
+ }
+ DOLLAR_ERROR("Un-sopported LOAD extention : " << _fileName);
+ DOLLAR_ERROR(" supported: [svg,json]");
+ return false;
+}
+
+bool dollar::Gesture::loadJSON(const std::string& _fileName) {
+ ejson::Document doc;
+ doc.load(_fileName);
+ if (doc["type"].toString().get() != "REFERENCE") {
+ DOLLAR_WARNING("can not LOAD file that is not a reference");
+ }
+ m_name = doc["value"].toString().get();
+ m_subId = doc["sub-id"].toNumber().getU64(),
+ m_path = loadPointsJson(doc);
+ m_path = dollar::scaleToOne(m_path);
+ DOLLAR_DEBUG("Load gesture : " << m_name << " id=" << m_subId << " nb_elem=" << m_path.size());
+ return true;
+}
+
+bool dollar::Gesture::loadSVG(const std::string& _fileName) {
+ esvg::Document doc;
+ doc.load(_fileName);
+ std::vector plop = etk::split(_fileName, '.');
+ plop = etk::split(plop[plop.size() -2], '/');
+ plop = etk::split(plop[plop.size() -1], '_');
+ m_name = plop[0];
+ m_subId = etk::string_to_int32_t(plop[1]);
+ m_path = doc.getLines();
+ m_path = dollar::scaleToOne(m_path);
+ DOLLAR_DEBUG("Load gesture : " << m_name << " id=" << m_subId << " nb_elem=" << m_path.size());
+ return true;
+}
+
+
+bool dollar::Gesture::store(const std::string& _fileName) {
+ std::string tmpName = etk::tolower(_fileName);
+ if (etk::end_with(tmpName, ".json") == true) {
+ storeJSON(_fileName);
+ return true;
+ } else if (etk::end_with(tmpName, ".svg") == true) {
+ storeSVG(_fileName);
+ return true;
+ }
+ DOLLAR_ERROR("Un-sopported STORE extention : " << _fileName);
+ DOLLAR_ERROR(" supported: [svg,json]");
+ return false;
+}
+
+void dollar::Gesture::storeJSON(const std::string& _fileName) {
+ ejson::Document doc;
+ doc.add("type", ejson::String("REFERENCE"));
+ doc.add("value", ejson::String(m_name));
+ doc.add("sub-id", ejson::Number(m_subId));
+ ejson::Array data;
+ doc.add("data", data);
+ for (auto &it : m_path) {
+ ejson::Array path;
+ for (auto &pathIt : it) {
+ ejson::Array value;
+ value.add(ejson::Number(pathIt.x()));
+ value.add(ejson::Number(pathIt.y()));
+ path.add(value);
+ }
+ data.add(path);
+ }
+ doc.store(_fileName);
+}
+
+void dollar::Gesture::storeSVG(const std::string& _fileName) {
+ std::vector> strokes = dollar::scaleToOne(m_path);
+ std::string data("\n");
+ data += "\n";
+ etk::FSNodeWriteAllData(_fileName, data);
+}
+
+
+void dollar::Gesture::configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation) {
+ m_enginePath.clear();
+ m_engineVector.clear();
+ m_engineStartV.clear();
+ // Simplyfy paths
+ std::vector> uniPath = dollar::makeReferenceStrokes(m_path);
+ // normalize paths
+ for (auto &it : uniPath) {
+ std::vector val = dollar::normalizePath(it, _nbSample, _ignoreRotation);
+ m_enginePath.push_back(val);
+ // calculate start vector:
+ vec2 startv = dollar::getStartVector(val, _startAngleIndex);
+ m_engineStartV.push_back(startv);
+ m_engineVector.push_back(dollar::normalyse(val));
+ }
+}
\ No newline at end of file
diff --git a/dollar/Gesture.h b/dollar/Gesture.h
new file mode 100644
index 0000000..02f7b21
--- /dev/null
+++ b/dollar/Gesture.h
@@ -0,0 +1,57 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#pragma once
+#include
+#include
+
+namespace dollar {
+ class Gesture {
+ protected:
+ std::string m_name;
+ uint32_t m_subId;
+ std::vector> m_path;
+ public:
+ Gesture();
+ bool load(const std::string& _filename);
+ bool store(const std::string& _filename);
+ protected:
+ bool loadJSON(const std::string& _filename);
+ bool loadSVG(const std::string& _filename);
+ void storeJSON(const std::string& _filename);
+ void storeSVG(const std::string& _filename);
+ public:
+ const std::string& getName() {
+ return m_name;
+ }
+ const std::vector>& getPath() const {
+ return m_path;
+ }
+ std::vector>& getPath() {
+ return m_path;
+ }
+ protected:
+ std::vector> m_enginePath; // Singulized path with every conbinaison
+ std::vector> m_engineVector;
+ std::vector m_engineStartV;
+ public:
+ // Configure the reference gesture for recognition...
+ void configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation);
+ size_t getEngineSize() const {
+ return m_enginePath.size();
+ }
+ const std::vector& getEnginePath(size_t _id) const {
+ return m_enginePath[_id];
+ }
+ const std::vector& getEngineVector(size_t _id) const {
+ return m_engineVector[_id];
+ }
+ const vec2& getEngineStartVector(size_t _id) const {
+ return m_engineStartV[_id];
+ }
+ };
+ std::vector> loadPoints(const std::string& _fileName);
+}
diff --git a/dollar/Rectangle.cpp b/dollar/Rectangle.cpp
new file mode 100644
index 0000000..113f652
--- /dev/null
+++ b/dollar/Rectangle.cpp
@@ -0,0 +1,47 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+#include
+#include
+
+#define MAX_FLOAT std::numeric_limits::max()
+
+dollar::Rectangle::Rectangle(const vec2& _pos, const vec2& _size):
+ m_pos(_pos),
+ m_size(_size) {
+
+}
+dollar::Rectangle::Rectangle(const std::vector& _points) {
+ vec2 minPos(MAX_FLOAT,MAX_FLOAT);
+ vec2 maxPos(-MAX_FLOAT,-MAX_FLOAT);
+ for (auto &it : _points) {
+ minPos.setMin(it);
+ maxPos.setMax(it);
+ }
+ m_pos = minPos;
+ m_size = maxPos-minPos;
+}
+dollar::Rectangle::Rectangle(const std::vector>& _points) {
+ vec2 minPos(MAX_FLOAT,MAX_FLOAT);
+ vec2 maxPos(-MAX_FLOAT,-MAX_FLOAT);
+ for (auto &it : _points) {
+ for (auto &itPoint : it) {
+ minPos.setMin(itPoint);
+ maxPos.setMax(itPoint);
+ }
+ }
+ m_pos = minPos;
+ m_size = maxPos-minPos;
+}
+
+const vec2& dollar::Rectangle::getPos() const {
+ return m_pos;
+}
+
+const vec2& dollar::Rectangle::getSize() const {
+ return m_size;
+}
+
+
diff --git a/dollar/Rectangle.h b/dollar/Rectangle.h
new file mode 100644
index 0000000..1539d21
--- /dev/null
+++ b/dollar/Rectangle.h
@@ -0,0 +1,53 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+namespace dollar {
+ /**
+ * @brief Simple rectangle area (AABB mode)
+ */
+ class Rectangle {
+ protected:
+ vec2 m_pos; //!< Position of the start of the rectangle (min position)
+ vec2 m_size; //!< Size of the rectangle
+ public:
+ /**
+ * @brief Create a rectangle as a bounding box
+ * @param[in] _points List of point that is contained in this area
+ */
+ Rectangle(const std::vector& _points);
+ /**
+ * @brief Create a rectangle as a bounding box
+ * @param[in] _points List of point that is contained in this area
+ */
+ Rectangle(const std::vector>& _points);
+ /**
+ * @brief Create a rectangle with values
+ * @param[in] _pos Start position
+ * @param[in] _size Size of the rectangle
+ */
+ Rectangle(const vec2& _pos, const vec2& _size);
+ public:
+ /**
+ * @brief Get start position of the rectangle
+ * @return Start position.
+ */
+ const vec2& getPos() const;
+ /**
+ * @brief Get the size of the rectangle
+ * @return Size of the rectangle
+ */
+ const vec2& getSize() const;
+ };
+}
+
+
diff --git a/dollar/Results.cpp b/dollar/Results.cpp
new file mode 100644
index 0000000..7de7662
--- /dev/null
+++ b/dollar/Results.cpp
@@ -0,0 +1,47 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+#include
+
+
+dollar::Results::Results() {
+ // nothing to do ...
+}
+
+bool dollar::Results::haveMath() const {
+ return m_values.size() != 0;
+}
+
+size_t dollar::Results::getSize() const {
+ return m_values.size();
+}
+
+std::string dollar::Results::getName(size_t _id) const {
+ if (_id >= m_values.size()) {
+ DOLLAR_ERROR("request acces error result out of range (name)");
+ return "";
+ }
+ return m_values[_id].first;
+}
+
+float dollar::Results::getConfidence(size_t _id) const {
+ if (_id >= m_values.size()) {
+ DOLLAR_ERROR("request acces error result out of range (value)");
+ return 0;
+ }
+ return m_values[_id].second;
+}
+
+void dollar::Results::addValue(const std::string& _name, float _confidence) {
+ m_values.push_back(std::make_pair(_name, _confidence));
+}
+
+
+void dollar::Results::clear() {
+ m_values.clear();
+}
+
diff --git a/dollar/Results.h b/dollar/Results.h
new file mode 100644
index 0000000..ec45003
--- /dev/null
+++ b/dollar/Results.h
@@ -0,0 +1,28 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace dollar {
+ class Results {
+ protected:
+ std::vector> m_values;
+ public:
+ Results();
+ bool haveMath() const;
+ size_t getSize() const;
+ std::string getName(size_t _id=0) const;
+ float getConfidence(size_t _id=0) const;
+ void addValue(const std::string& _name, float _confidence);
+ void clear();
+ };
+}
+
+
diff --git a/dollar/debug.cpp b/dollar/debug.cpp
new file mode 100644
index 0000000..e242d8c
--- /dev/null
+++ b/dollar/debug.cpp
@@ -0,0 +1,13 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+
+int32_t dollar::getLogId() {
+ static int32_t g_val = elog::registerInstance("dollar");
+ return g_val;
+}
+
diff --git a/dollar/debug.h b/dollar/debug.h
new file mode 100644
index 0000000..a64f380
--- /dev/null
+++ b/dollar/debug.h
@@ -0,0 +1,45 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+
+#pragma once
+
+#include
+
+namespace dollar {
+ int32_t getLogId();
+};
+
+#define DOLLAR_BASE(info,data) ELOG_BASE(dollar::getLogId(),info,data)
+
+#define DOLLAR_PRINT(data) DOLLAR_BASE(-1, data)
+#define DOLLAR_CRITICAL(data) DOLLAR_BASE(1, data)
+#define DOLLAR_ERROR(data) DOLLAR_BASE(2, data)
+#define DOLLAR_WARNING(data) DOLLAR_BASE(3, data)
+#ifdef DEBUG
+ #define DOLLAR_INFO(data) DOLLAR_BASE(4, data)
+ #define DOLLAR_DEBUG(data) DOLLAR_BASE(5, data)
+ #define DOLLAR_VERBOSE(data) DOLLAR_BASE(6, data)
+ #define DOLLAR_TODO(data) DOLLAR_BASE(4, "TODO : " << data)
+#else
+ #define DOLLAR_INFO(data) do { } while(false)
+ #define DOLLAR_DEBUG(data) do { } while(false)
+ #define DOLLAR_VERBOSE(data) do { } while(false)
+ #define DOLLAR_TODO(data) do { } while(false)
+#endif
+
+#define DOLLAR_HIDDEN(data) do { } while(false)
+
+#define DOLLAR_ASSERT(cond,data) \
+ do { \
+ if (!(cond)) { \
+ DOLLAR_CRITICAL(data); \
+ assert(!#cond); \
+ } \
+ } while (0)
+
+
diff --git a/dollar/tools.cpp b/dollar/tools.cpp
new file mode 100644
index 0000000..f88fccb
--- /dev/null
+++ b/dollar/tools.cpp
@@ -0,0 +1,209 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+
+float dollar::pathLength(std::vector _points) {
+ float distance = 0;
+ for (size_t iii = 1; iii < _points.size(); ++iii) {
+ distance += (_points[iii] - _points[iii-1]).length();
+ }
+ return distance;
+}
+
+vec2 dollar::getBaryCenter(const std::vector& _points) {
+ vec2 center(0,0);
+ for (auto &it : _points) {
+ center += it;
+ }
+ center /= float(_points.size());
+ return center;
+}
+
+// TODO: Change this with the use of a generic matrix 2D...
+std::vector dollar::rotateBy(const std::vector& _points, float _rotation) {
+ std::vector out;
+ vec2 center = getBaryCenter(_points);
+ float cosine = std::cos(_rotation);
+ float sine = std::sin(_rotation);
+ for (auto &it : _points) {
+ float qx = (it.x() - center.x()) * cosine - (it.y() - center.y()) * sine + center.x();
+ float qy = (it.x() - center.x()) * sine + (it.y() - center.y()) * cosine + center.y();
+ out.push_back(vec2(qx, qy));
+ }
+ return out;
+}
+
+std::vector dollar::rotateToZero(const std::vector& _points) {
+ vec2 center = getBaryCenter(_points);
+ float rotation = std::atan2(center.y() - _points[0].y(), center.x() - _points[0].x());
+ return rotateBy(_points, -rotation);
+}
+
+// TODO : Rework this to have a correct scale with keeping aspect ration ... or not ...
+std::vector dollar::scaleToOne(const std::vector& _points, bool _keepAspectRation) {
+ dollar::Rectangle box(_points);
+ std::vector out;
+ vec2 scale(1.0f/box.getSize().x(), 1.0f/box.getSize().y());
+ if (_keepAspectRation == true) {
+ float val = 1;
+ if (box.getSize().x() > 0) {
+ val = 1.0f/box.getSize().x();
+ } else {
+ val = 1.0f/box.getSize().y();
+ }
+ scale = vec2(val,val);
+ }
+ for (auto &it : _points) {
+ vec2 tmp = it - box.getPos();
+ tmp *= scale;
+ out.push_back(tmp);
+ }
+ return out;
+}
+
+std::vector> dollar::scaleToOne(const std::vector>& _points, bool _keepAspectRation) {
+ dollar::Rectangle box(_points);
+ std::vector> out;
+ vec2 scale(1.0f/box.getSize().x(), 1.0f/box.getSize().y());
+ if (_keepAspectRation == true) {
+ float val = 1;
+ if (box.getSize().x() > 0) {
+ val = 1.0f/box.getSize().x();
+ } else {
+ val = 1.0f/box.getSize().y();
+ }
+ scale = vec2(val,val);
+ }
+ for (auto &it : _points) {
+ std::vector stroke;
+ for (auto &itPoint : it) {
+ vec2 tmp = itPoint - box.getPos();
+ tmp *= scale;
+ stroke.push_back(tmp);
+ }
+ out.push_back(stroke);
+ }
+ return out;
+}
+
+std::vector dollar::translateBariCenterToZero(std::vector _points) {
+ std::vector out;
+ vec2 center = getBaryCenter(_points);
+ for (auto &it :_points) {
+ out.push_back(it - center);
+ }
+ return out;
+}
+
+
+std::vector dollar::resample(std::vector _points, int32_t _nbPoints) {
+ std::vector out;
+ // calculate the interval between every points ...
+ float interval = pathLength(_points) / (_nbPoints - 1);
+ float distance = 0.0;
+ // same first point ==> no change
+ out.push_back(_points.front());
+ // For all other point we have to resample elements
+ for (size_t iii=1; iii<_points.size(); ++iii) {
+ vec2 currentPoint = _points[iii];
+ vec2 previousPoint = _points[iii-1];
+ float tmpDist = (currentPoint-previousPoint).length();
+ if ((distance + tmpDist) >= interval) {
+ vec2 point = previousPoint + (currentPoint - previousPoint) * ((interval - distance) / tmpDist);
+ out.push_back(point);
+ _points.insert(_points.begin() + iii, point);
+ distance = 0.0;
+ } else {
+ distance += tmpDist;
+ }
+ }
+ // somtimes we fall a rounding-error short of adding the last point, so add it if so
+ if (int64_t(out.size()) == (_nbPoints - 1)) {
+ out.push_back(_points.back());
+ }
+ return out;
+}
+
+std::vector> dollar::makeReferenceStrokes(const std::vector>& _strokes) {
+ std::vector> out;
+ // create the ordr of all possibilities of writing the strokes ... (ABC, ACB, BAC, BCA ...)
+ std::vector order;
+ for(size_t iii=0; iii<_strokes.size(); ++iii) {
+ order.push_back(iii);
+ }
+ // For all orders (every permutation of the path):
+ do {
+ // now we have an other problem: the user can write in multiple way the path
+ size_t nbPermutation = std::pow(2, order.size());
+ // we use the bit like a flag to know the order of the draw
+ for (size_t permut=0; permut stroke;
+ for (size_t iii=0; iii pts = _strokes[order[iii]];
+ // check to permut the value order
+ if (((permut>>iii) & 0x01) == 1) {
+ reverse(pts.begin(),pts.end());
+ }
+ // Add point in next of the path...
+ for (auto &it : pts) {
+ stroke.push_back(it);
+ }
+ }
+ // Add new generated stroke
+ out.push_back(stroke);
+ }
+ } while (next_permutation(order.begin(), order.end()));
+ return out;
+}
+
+std::vector dollar::combineStrokes(const std::vector>& _strokes) {
+ std::vector out;
+ for (auto &it : _strokes) {
+ for (auto &pointIt : it) {
+ out.push_back(pointIt);
+ }
+ }
+ return out;
+}
+
+vec2 dollar::getStartVector(const std::vector& _points, float _index) {
+ DOLLAR_ASSERT(_index > 0, "index must be != of 0");
+ vec2 vect = _points[_index] - _points[0];
+ float len = vect.length();
+ return vect / len;
+}
+
+std::vector dollar::normalyse(const std::vector& _points) {
+ float sum = 0.0;
+ std::vector out = _points;
+ for (auto &it : _points) {
+ sum += it.length2();
+ }
+ float magnitude = sqrt(sum);
+ if (magnitude == 0.0f) {
+ DOLLAR_ERROR("Magnetude is == 0");
+ return out;
+ }
+ for (auto &it : out) {
+ it /= magnitude;
+ }
+ return out;
+}
+
+
+std::vector dollar::normalizePath(std::vector _points, size_t _nbSample, bool _ignoreRotation) {
+ _points = dollar::resample(_points, _nbSample);
+ if (_ignoreRotation == true) {
+ _points = rotateToZero(_points);
+ }
+ _points = scaleToOne(_points);
+ return translateBariCenterToZero(_points);;
+}
diff --git a/dollar/tools.h b/dollar/tools.h
new file mode 100644
index 0000000..8cc8ccb
--- /dev/null
+++ b/dollar/tools.h
@@ -0,0 +1,106 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+#pragma once
+#include
+#include
+#include
+
+namespace dollar {
+ /**
+ * @brief Get the size of a path (not the number of element but the distance of the path
+ * @param[in] _points List of point of the path
+ * @return the size of the path
+ */
+ float pathLength(std::vector _points);
+ /**
+ * @brief Get the center position of the Path (baricenter)...
+ * @param[in] _points List of points.
+ * @return The center position of all the points.
+ */
+ vec2 getBaryCenter(const std::vector& _points);
+ /**
+ * @brief Rotate a list of point from the center to the precise angle.
+ * @param[in] _points List of point in the path.
+ * @param[in] _rotation Angle to apply.
+ * @return new path with the rotated points.
+ */
+ // TODO: Change this with the use of a generic matrix 2D...
+ std::vector rotateBy(const std::vector& _points, float _rotation);
+ /**
+ * @brief Rotate a path to a specific angle (0rad)
+ * @param[in] _points Path to rotate
+ * @return the Path aligned with 0;
+ */
+ std::vector rotateToZero(const std::vector& _points);
+ /**
+ * @brief Get the Bounding box associated at a path
+ * @param[in] _points List of point at the path
+ * @return the rectangle with the bounding box associated
+ */
+ dollar::Rectangle boundingBox(const std::vector& _points);
+ /**
+ * @brief Scale the list of point in a 1.0*1.0 box started at 0.0*0.0
+ * @param[in] _points input path
+ * @param[in] _keepAspectRation Keep the aspect ratio of the scaling
+ * @return modify points
+ */
+ std::vector scaleToOne(const std::vector& _points, bool _keepAspectRation=false);
+ /**
+ * @brief Scale the list of point in a 1.0*1.0 box started at 0.0*0.0
+ * @param[in] _points input path
+ * @param[in] _keepAspectRation Keep the aspect ratio of the scaling
+ * @return modify points
+ */
+ std::vector> scaleToOne(const std::vector>& _points, bool _keepAspectRation=false);
+ /**
+ * @brief Get center of the path and move the path to be center at (0,0)
+ * @param[in] _points List of point in the path
+ * @return centered path.
+ */
+ std::vector translateBariCenterToZero(std::vector _points);
+ /**
+ * @brief Resample a path With a specific number of elements
+ * @param[in] _points Path to change number of elements
+ * @param[in] _nbPoints Number of point desired in the output path
+ * @return Resample path.
+ */
+ std::vector resample(std::vector _points, int32_t _nbPoints);
+ /**
+ * @brief Make a list of all single stroke possible for a specific stroke (take in case the user can write the second stroke befor the first and he can do the stroke in the oposite way
+ * @param[in] _strokes List of all strokes
+ * @return List of a list of single stroke of multiple stroke
+ */
+ std::vector> makeReferenceStrokes(const std::vector>& _strokes);
+ /**
+ * @brief combine some stroke in a single one.
+ * @param[in] _strokes value to merge
+ * @return Merged vector
+ */
+ std::vector combineStrokes(const std::vector>& _strokes);
+ /**
+ * @brief Normalise the Path with the full magnetude of the data
+ * @param[in] _points Input path
+ * @return Normalized path
+ */
+ std::vector normalyse(const std::vector& _points);
+ /**
+ * @brief Calculate a starting vector of the path
+ * @param[in] _points List of point of the path
+ * @param[in] _index position index to get the vector (ratio to 0)
+ * @return the start vector.
+ */
+ vec2 getStartVector(const std::vector& _points, float _index = 1);
+ /**
+ * @brief Transform the path to be comparable, resample the path with a specific number of sample, and limit size at 1.0 square center around 0
+ * @param[in] _points List of points in the path
+ * @param[in] _nbSample Number of element to resample
+ * @param[in] _ignoreRotation Ignore start rotation of the algorithm
+ * @return new list of points
+ */
+ std::vector normalizePath(std::vector _points, size_t _nbSample, bool _ignoreRotation);
+}
+
+
diff --git a/lutin_dollar-converter.py b/lutin_dollar-converter.py
new file mode 100644
index 0000000..7c77d1e
--- /dev/null
+++ b/lutin_dollar-converter.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+import lutin.module as module
+import lutin.tools as tools
+
+
+def get_type():
+ return "BINARY"
+
+def get_sub_type():
+ return "TOOL"
+
+def get_desc():
+ return "Dollar converter svg to json and json to SVG"
+
+def get_licence():
+ return "APACHE-2"
+
+def get_compagny_type():
+ return "com"
+
+def get_compagny_name():
+ return "atria-soft"
+
+def get_maintainer():
+ return ["Mr DUPIN Edouard "]
+
+def create(target, module_name):
+ my_module = module.Module(__file__, module_name, get_type())
+ my_module.add_src_file([
+ 'tool/converter/main.cpp'
+ ])
+ my_module.add_module_depend([
+ 'dollar',
+ 'test-debug',
+ ])
+ return my_module
+
diff --git a/lutin_dollar-data.py b/lutin_dollar-data.py
new file mode 100644
index 0000000..16b78ef
--- /dev/null
+++ b/lutin_dollar-data.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+import lutin.module as module
+import lutin.tools as tools
+
+
+def get_type():
+ return "DATA"
+
+def get_desc():
+ return "dallar test-unit"
+
+def get_licence():
+ return "APACHE-2"
+
+def get_compagny_type():
+ return "com"
+
+def get_compagny_name():
+ return "atria-soft"
+
+def get_maintainer():
+ return ["Mr DUPIN Edouard "]
+
+def create(target, module_name):
+ my_module = module.Module(__file__, module_name, get_type())
+ my_module.copy_path('data/text/*.json', 'text')
+ my_module.copy_path('data/figure/*.json', 'figure')
+ my_module.copy_path('data/test/*.json', 'test')
+ return my_module
+
diff --git a/lutin_dollar-test.py b/lutin_dollar-test.py
new file mode 100644
index 0000000..d9d4c66
--- /dev/null
+++ b/lutin_dollar-test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+import lutin.module as module
+import lutin.tools as tools
+
+
+def get_type():
+ return "BINARY"
+
+def get_sub_type():
+ return "TEST"
+
+def get_desc():
+ return "dollar test-unit"
+
+def get_licence():
+ return "APACHE-2"
+
+def get_compagny_type():
+ return "com"
+
+def get_compagny_name():
+ return "atria-soft"
+
+def get_maintainer():
+ return ["Mr DUPIN Edouard "]
+
+def create(target, module_name):
+ my_module = module.Module(__file__, module_name, get_type())
+ my_module.add_src_file([
+ 'test/main.cpp'
+ ])
+ my_module.add_module_depend([
+ 'dollar',
+ 'dollar-data',
+ 'test-debug',
+ 'gtest',
+ ])
+ return my_module
+
diff --git a/lutin_dollar.py b/lutin_dollar.py
new file mode 100644
index 0000000..9a0a321
--- /dev/null
+++ b/lutin_dollar.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+import lutin.module as module
+import lutin.tools as tools
+
+
+def get_type():
+ return "LIBRARY"
+
+def get_desc():
+ return "$N gesture recognition"
+
+def get_licence():
+ return "BSD-3"
+
+def get_compagny_type():
+ return "com"
+
+def get_compagny_name():
+ return "atria-soft"
+
+def get_maintainer():
+ return ["Mr DUPIN Edouard "]
+
+def get_version():
+ return [0,1,"dev"]
+
+def create(target, module_name):
+ my_module = module.Module(__file__, module_name, get_type())
+ my_module.add_extra_compile_flags()
+ # add the file to compile:
+ my_module.add_src_file([
+ 'dollar/debug.cpp',
+ 'dollar/Engine.cpp',
+ 'dollar/Gesture.cpp',
+ 'dollar/Results.cpp',
+ 'dollar/tools.cpp',
+ 'dollar/Rectangle.cpp'
+ ])
+
+ my_module.add_header_file([
+ 'dollar/*.h',
+ ],
+ destination_path="dollar")
+
+ # build in C++ mode
+ my_module.compile_version("c++", 2011)
+ # add dependency of the generic C++ library:
+ my_module.add_module_depend([
+ 'cxx',
+ 'elog',
+ 'etk',
+ 'ejson',
+ 'esvg',
+ ])
+ return my_module
+
+
diff --git a/test/main.cpp b/test/main.cpp
new file mode 100644
index 0000000..19eb54a
--- /dev/null
+++ b/test/main.cpp
@@ -0,0 +1,92 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2016, Edouard DUPIN, all right reserved
+ * @license APACHE v2.0 (see license file)
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+
+int main(int _argc, const char *_argv[]) {
+ // init Google test :
+ ::testing::InitGoogleTest(&_argc, const_cast(_argv));
+ // init etk log system and file interface:
+ etk::init(_argc, _argv);
+ // Run all test with gtest
+ return RUN_ALL_TESTS();
+}
+
+/*
+ * single-stroke gesture recognition
+ */
+TEST(TestAll, singleStroke_normal) {
+ dollar::Engine reco;
+ reco.loadPath("DATA:figure");
+ dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/Arrow.json"), "normal");
+ EXPECT_EQ(res.haveMath(), true);
+ if (res.haveMath() == false) {
+ TEST_INFO(" Recognise noting ...");
+ return;
+ }
+ EXPECT_EQ(res.getName(), "arrow");
+ TEST_INFO("Results");
+ for (size_t iii=0; iii