CopyNormalizedStrokes:
PROC [ns: NormalizedStrokes]
RETURNS [copy: NormalizedStrokes] = {
copy ¬ NEW[NormalizedStrokesRec[ns.strokeCnt]];
copy.key ¬ ns.key;
copy.strokes ¬ ns.strokes; --pointer copy because is readonly
copy.dx ¬ ns.dx;
copy.dy ¬ ns.dy;
copy.f ¬ ns.f;
copy.included ¬ FALSE;
FOR i:
NAT
IN [0..ns.strokeCnt)
DO
copy.data[i] ¬ ns.data[i];
ENDLOOP;
};
NormalizeStrokes:
PROC [strokes: Strokes]
RETURNS [ns: NormalizedStrokes] = {
factor: INT;
totalLeng: INT ¬ 0;
strokeCnt, strokeIdx: INT ¬ 0;
min: Xl.Point ¬ [INT.LAST, INT.LAST];
max: Xl.Point ¬ [INT.FIRST, INT.FIRST];
av: Xl.Point ¬ [0, 0];
--Count strokes and allocate memory
strokeCnt ¬ CountStrokes[strokes];
IF strokeCnt=0 THEN ERROR;
ns ¬ NEW[NormalizedStrokesRec[strokeCnt]];
--Find total bounding box and length
strokeIdx ¬ 0;
FOR sl: Strokes ¬ strokes, sl.rest
WHILE sl#
NIL
DO
strokeLeng: INT ¬ 0;
lastP: Xl.Point ¬ sl.first.first;
FOR seg: Stroke ¬ sl.first, seg.rest
WHILE seg#
NIL
DO
nextP: Xl.Point ~ seg.first;
min.x ¬ MIN[min.x, nextP.x]; min.y ¬ MIN[min.y, nextP.y];
max.x ¬ MAX[max.x, nextP.x]; max.y ¬ MAX[max.y, nextP.y];
strokeLeng ¬ strokeLeng + ABS[lastP.x-nextP.x] + ABS[lastP.y-nextP.y];
lastP ¬ nextP;
ENDLOOP;
ns.data[strokeIdx][idxForLeng].x ¬ strokeLeng;
totalLeng ¬ totalLeng+strokeLeng;
strokeIdx ¬ strokeIdx+1;
ENDLOOP;
--Copy with normalized size and position of original segments
ns.dx ¬ -(max.x+min.x)/2;
ns.dy ¬-(max.y+min.y)/2;
IF (max.x-min.x)<=3
AND (max.y-min.y)<=3
THEN {
--Special case for a dot
ns.f ¬ 1;
ns.strokes ¬ MCopyStrokes[strokes: strokes, dx: ns.dx, dy: ns.dy, f: 1];
FOR si:
NAT
IN [1..strokeCnt)
DO
ns.data[si] ¬ ALL[[0, 0]];
ENDLOOP;
RETURN;
};
factor ¬ ns.f ¬ MAX[(normalizedLengthConst / MAX[totalLeng, 1]), 1];
strokes ¬ ns.strokes ¬ MCopyStrokes[strokes: strokes, dx: ns.dx, dy: ns.dy, f: factor];
--Interpolate points
strokeIdx ¬ 0;
FOR ss: Strokes ¬ strokes, ss.rest
WHILE ss#
NIL
DO
seg: Stroke ¬ ss.first;
next: Stroke;
actualStrokeLeng: INT ¬ ns.data[strokeIdx][idxForLeng].x*factor;
desiredPieceLeng: INT ¬ actualStrokeLeng/(normalPoints-1);
sofarLeng: INT ¬ 0;
goalLeng: INT ¬ 0;
lastP: Xl.Point ¬ seg.first;
ns.data[strokeIdx][0].x ¬ lastP.x;
ns.data[strokeIdx][0].y ¬ lastP.y;
--Find each interpolated point
FOR i:
NAT
IN [1..normalPoints)
DO
dx, dy, dl: INT ¬ 0;
goalLeng ¬ sofarLeng+desiredPieceLeng;
DO
--eventually skip some segments
next ¬ seg.rest;
IF next=
NIL
THEN {
dl ¬ 0;
EXIT;
};
dx ¬ next.first.x-lastP.x;
dy ¬ next.first.y-lastP.y;
dl ¬ ABS[dx] + ABS[dy];
IF sofarLeng+dl>=goalLeng
THEN EXIT --found the right segment
ELSE {
sofarLeng ¬ sofarLeng+dl;
seg ¬ next;
lastP ¬ next.first;
};
ENDLOOP;
IF sofarLeng+dl<=goalLeng
OR dl<=0
THEN {
IF next#NIL THEN lastP ¬ next.first;
}
ELSE {
desiredSegLeng: INT ¬ (goalLeng-sofarLeng);
lastP.x ¬ lastP.x+(desiredSegLeng*dx)/dl;
lastP.y ¬ lastP.y+(desiredSegLeng*dy)/dl;
};
sofarLeng ¬ goalLeng;
ns.data[strokeIdx][i].x ¬ lastP.x;
ns.data[strokeIdx][i].y ¬ lastP.y;
ENDLOOP;
strokeIdx ¬ strokeIdx+1;
ENDLOOP;
--reset offsets to move the origin to the mass center
IF strokeCnt>0
THEN {
tx, ty: INT ¬ 0;
FOR si:
INT
IN [0..strokeCnt)
DO
FOR pi:
INT
IN [0..normalPoints)
DO
tx ¬ tx + ns.data[si][pi].x; ty ¬ ty + ns.data[si][pi].y;
ENDLOOP;
ENDLOOP;
tx ¬ tx/(normalPoints*strokeCnt);
ty ¬ ty/(normalPoints*strokeCnt);
FOR si:
INT
IN [0..strokeCnt)
DO
FOR pi:
INT
IN [0..normalPoints)
DO
ns.data[si][pi].x ¬ ns.data[si][pi].x - tx;
ns.data[si][pi].y ¬ ns.data[si][pi].y - ty;
ENDLOOP;
ENDLOOP;
};
};
ToStrokes:
PROC [ns: NormalizedStrokes, sizemax:
INT ¬ 40]
RETURNS [strokes: Strokes ¬
NIL] = {
normalize: INT;
min: Xl.Point ¬ [INT.LAST, INT.LAST];
max: Xl.Point ¬ [INT.FIRST, INT.FIRST];
FOR si:
INT
DECREASING
IN [0..ns.strokeCnt)
DO
FOR pi:
INT
DECREASING
IN [0..normalPoints)
DO
p: Xl.Point ¬ [ ns.data[si][pi].x, ns.data[si][pi].y ];
min.x ¬ MIN[min.x, p.x];
min.y ¬ MIN[min.y, p.y];
max.x ¬ MAX[max.x, p.x];
max.y ¬ MAX[max.y, p.y];
ENDLOOP;
ENDLOOP;
normalize ¬ MAX[ABS[max.x], ABS[max.y], ABS[min.x], ABS[min.y], 1];
FOR si:
INT
DECREASING
IN [0..ns.strokeCnt)
DO
s: Stroke ¬ NIL;
FOR pi:
INT
DECREASING
IN [0..normalPoints)
DO
p: Xl.Point ¬ [ ns.data[si][pi].x, ns.data[si][pi].y ];
p.x ¬ (p.x*sizemax)/normalize;
p.y ¬ (p.y*sizemax)/normalize;
s ¬ CONS[p, s];
ENDLOOP;
strokes ¬ CONS[s, strokes];
ENDLOOP;
};