/***************************************************************************************
 *
 *  WRITEPAD(r): Handwriting Recognition Engine (HWRE) and components.
 *  Copyright (c) 2001-2016 PhatWare (r) Corp. All rights reserved.
 *
 *  Licensing and other inquires: <developer@phatware.com>
 *  Developer: Stan Miasnikov, et al. (c) PhatWare Corp. <http://www.phatware.com>
 *
 *  WRITEPAD HWRE is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
 *  AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 *  INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 *  FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL PHATWARE CORP.
 *  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL,
 *  INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER,
 *  INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS
 *  OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT PHATWARE CORP.
 *  HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
 *  POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
 *  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with WritePad.  If not, see <http://www.gnu.org/licenses/>.
 *
 **************************************************************************************/

#include  "bastypes.h"
#include  "param.h"


#if FIXED_ARITHMETIC == USE_C_32

typedef struct
{
	_ULONG  L0;
	_ULONG  L1;
	_ULONG  L2;
	_ULONG  L3;
	_ULONG  L4;
	_ULONG  L5;
} _FIX24;

typedef _FIX24& _FIX24_PARAM;
#define  FIX24_VAL(L) ((L).L0)

_VOID  DivFix24(_ULONG R2, _ULONG R1, _FIX24& Res)
{
	_ULONG l = 0;
	_ULONG N = 12;

	while (R2 >= R1)
	{
		R2 -= R1;
		l++;
	}

	do
	{
		R2 <<= 1;
		l <<= 1;
		if (R2 > R1)
		{
			R2 -= R1;
			l++;
		}
		R2 <<= 1;
		l <<= 1;
		if (R2 > R1)
		{
			R2 -= R1;
			l++;
		}
	}
	while (--N > 0);

	Res.L0 = l;
	Res.L1 = (l >> 24);
	Res.L2 = (l >> 16) & 0x00FF;
	Res.L3 = (l >> 8) & 0x00FF;
	Res.L5 = (l >> 8) & 0xFFFF;
	Res.L4 = (l) & 0x00FF;
}

_LONG  IMulByFix24(_LONG R, _FIX24_PARAM Fix)
{
	_LONG   R2;

	if (R > 65536L)
	{
		R2 = ((_LONG) (R * Fix.L2)) >> 8;
		R2 += ((_LONG) (R * Fix.L3)) >> 16;
		R2 += ((_LONG) (R * Fix.L4)) >> 24;
	}
	else
	{
		R2 = ((_LONG) (R * Fix.L5)) >> 16;
	}

	if ( Fix.L1 == 0 )
	{
		return R2;
	}
	else
		if ( Fix.L1 == 1 )
		{
			return R2 + R;
		}
		else
		{
			return R2 + (_LONG)(R * Fix.L1);
		}
}


#elif FIXED_ARITHMETIC == USE_ASM_86  // USE Inline Assembler for I386

typedef  _ULONG  _FIX24;
typedef  _FIX24  _FIX24_PARAM;
#define   FIX24_VAL(L) (L)

_VOID  DivFix24 ( _ULONG R2, _ULONG R1, _FIX24& Lam )
{
	_asm     mov  edx, R2
	_asm     shr  edx, 8
	_asm     mov  eax, eax
	_asm     shl  eax, 24
	_asm     mov  ebx, dword ptr Lam
	_asm     div  dword ptr R1
	_asm     mov  dword ptr [ebx], eax
}

_ULONG  IMulByFix24(_ULONG R, _FIX24_PARAM Lam)
{
	_asm     mov  eax, dword ptr R
	_asm     imul dword ptr Lam
	_asm     shl  edx, 8
	_asm     shr  eax, 24
	_asm     add  eax, edx
	_asm     ret
	return  R;
}

#else
#endif

_VOID  ResetParam(_INT sm, p_ARDATA  pARdata, _LONG LenApp)
{
	_INT     i;

	LenApp /= sm - 1;
	for (i = 0; i < sm; i++)
	{
		if (i == 0)
		{
			pARdata[0].s = 0;
			pARdata[0].r = 0;
		}
		else
		{
			pARdata[i].s = LenApp;
			pARdata[i].r = pARdata[i - 1].r + LenApp;
		}
	}
}

_VOID  ResetParam3D(_INT sm, p_ARDATA3D  pARdata, _LONG LenApp)
{
	_INT     i;

	LenApp /= sm - 1;
	for (i = 0; i < sm; i++)
	{
		if (i == 0)
		{
			pARdata[0].s = 0;
			pARdata[0].r = 0;
		}
		else
		{
			pARdata[i].s = LenApp;
			pARdata[i].r = pARdata[i - 1].r + LenApp;
		}
	}
}

/**********************************************************************/


_LONG  Repar(_INT Sam, p_ODATA   pOdata,
             _INT ReSam, p_ARDATA  pARdata)
{
	_LONG    R1;
	_LONG    R2;
	_FIX24   lam;
	_FIX24   alf;

	pARdata->Rx = pOdata[0].x;
	pARdata->Ry = pOdata[0].y;
	pARdata[ReSam - 1].Rx = pOdata[Sam - 1].x;
	pARdata[ReSam - 1].Ry = pOdata[Sam - 1].y;

	DivFix24(pOdata[Sam - 1].r, pARdata[ReSam - 1].r, lam);

	pARdata = pARdata + 1;
	pOdata = pOdata + 1;

	do
	{
		R2 = IMulByFix24(pARdata->r, lam);
		while (R2 >= pOdata->r)
		{
			pOdata++;
		}

		R2 = pOdata->r - R2;
		R1 = pOdata->s;
		R2 = R1 - R2;

		DivFix24(R2, R1, alf);

		pARdata->Rx = (pOdata - 1)->x + IMulByFix24(pOdata->dx, alf);
		pARdata->Ry = (pOdata - 1)->y + IMulByFix24(pOdata->dy, alf);

		pARdata++;

	}
	while (--ReSam > 2);

	return  FIX24_VAL(lam);
}

// 3D - version
_LONG  Repar3D(_INT Sam, p_ODATA3D   pOdata,
               _INT ReSam, p_ARDATA3D  pARdata)
{
	_LONG    R1;
	_LONG    R2;
	_LONG    R3;
	_FIX24   lam;
	_FIX24   alf;

	pARdata->Rx = pOdata[0].x;
	pARdata->Ry = pOdata[0].y;
	pARdata->Rz = pOdata[0].z;
	pARdata[ReSam - 1].Rx = pOdata[Sam - 1].x;
	pARdata[ReSam - 1].Ry = pOdata[Sam - 1].y;
	pARdata[ReSam - 1].Rz = pOdata[Sam - 1].z;

	R3 = pOdata[Sam - 1].r;

	DivFix24(pOdata[Sam - 1].r, pARdata[ReSam - 1].r, lam);

	pARdata = pARdata + 1;
	pOdata = pOdata + 1;

	do
	{
		R2 = IMulByFix24(pARdata->r, lam);
		while (R2 >= pOdata->r && R2 < R3)
		{
			pOdata++;
		}

		R2 = pOdata->r - R2;
		R1 = pOdata->s;
		R2 = R1 - R2;

		DivFix24(R2, R1, alf);

		pARdata->Rx = (pOdata - 1)->x + IMulByFix24(pOdata->dx, alf);
		pARdata->Ry = (pOdata - 1)->y + IMulByFix24(pOdata->dy, alf);
		pARdata->Rz = (pOdata - 1)->z + IMulByFix24(pOdata->dz, alf);

		pARdata++;

	}
	while (--ReSam > 2);

	return  FIX24_VAL(lam);
}

/**********************************************************************/
/*                                                                    */
/*     FUNCTION  Tracing (_INT sm, p_ARDATA pData);                   */
/*                                                                    */
/*     FILL  the  s and r fields in Adata data array                  */
/**********************************************************************/

_VOID  Tracing(_INT sm, p_ARDATA pData)
{
	_LONG       dx;
	_LONG       dy;
	_ULONG      dl;
	_ULONG       R;

	dl = pData->s = pData->r = 0L;
	pData++;
	sm--;
	do
	{
		dx = pData->Ax - (pData - 1)->Ax;
		dy = pData->Ay - (pData - 1)->Ay;
		if (dx < 0)
		{
			dx = -dx;
		}
		if (dy < 0)
		{
			dy = -dy;
		}
		R = (_ULONG) dx * (_ULONG) dx;
		R += (_ULONG) dy * (_ULONG) dy;
		R = SQRT32(R);
		pData->s = R;
		pData->r = dl += R;
		pData++;
	}
	while (--sm);
}

_VOID  Tracing3D(_INT sm, p_ARDATA3D pData)
{
	_LONG       dv;
	_ULONG      dl;
	_ULONG       R;

	dl = pData->s = pData->r = 0L;
	pData++;
	sm--;
	do
	{
		dv = pData->Ax - (pData - 1)->Ax;
		if (dv < 0)
		{
			dv = -dv;
		}
		R = (_ULONG) dv * (_ULONG) dv;

		dv = pData->Ay - (pData - 1)->Ay;
		if (dv < 0)
		{
			dv = -dv;
		}
		R += (_ULONG) dv * (_ULONG) dv;

		dv = pData->Az - (pData - 1)->Az;
		if (dv < 0)
		{
			dv = -dv;
		}
		R += (_ULONG) dv * (_ULONG) dv;

		R = SQRT32(R);
		pData->s = R;
		pData->r = dl += R;
		pData++;
	}
	while (--sm);
}

/**********************************************************************/

_LONG  ApprError(_INT Sam, p_ARDATA  pARdata)
{
	_INT  i;
	_LONG T;
	_LONG E = 0;

	for (i = 0; i < Sam; i++, pARdata++)
	{
		T = pARdata->Ax - pARdata->Rx;
		if (T < 0)
		{
			T = -T;
		}
		E += T;
		T = pARdata->Ay - pARdata->Ry;
		if (T < 0)
		{
			T = -T;
		}
		E += T;
	}
	return  E / Sam;
}


_LONG  ApprError3D(_INT Sam, p_ARDATA3D  pARdata)
{
	_INT  i;
	_LONG T;
	_LONG E = 0;

	for (i = 0; i < Sam; i++, pARdata++)
	{
		T = pARdata->Ax - pARdata->Rx;
		if (T < 0)
		{
			T = -T;
		}
		E += T;

		T = pARdata->Ay - pARdata->Ry;
		if (T < 0)
		{
			T = -T;
		}
		E += T;

		T = pARdata->Az - pARdata->Rz;
		if (T < 0)
		{
			T = -T;
		}
		E += T;
	}
	return  E / Sam;
}


/***********************************************************************/


_ULONG  SQRT32(_ULONG R0)
{
	_ULONG  R1 = 1L;
	_ULONG  R2 = 0L;
	_ULONG  R3 = 1L;


	if (R0 >= (R1 << 30))
	{
		R0 = R0 - (R1 << 30);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 28))
	{
		R0 = R0 - (R1 << 28);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 26))
	{
		R0 = R0 - (R1 << 26);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 24))
	{
		R0 = R0 - (R1 << 24);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 22))
	{
		R0 = R0 - (R1 << 22);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 20))
	{
		R0 = R0 - (R1 << 20);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 18))
	{
		R0 = R0 - (R1 << 18);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 16))
	{
		R0 = R0 - (R1 << 16);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 14))
	{
		R0 = R0 - (R1 << 14);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 12))
	{
		R0 = R0 - (R1 << 12);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 10))
	{
		R0 = R0 - (R1 << 10);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 8))
	{
		R0 = R0 - (R1 << 8);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 6))
	{
		R0 = R0 - (R1 << 6);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 4))
	{
		R0 = R0 - (R1 << 4);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= (R1 << 2))
	{
		R0 = R0 - (R1 << 2);
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	R1 = R3 + (R2 << 2);

	if (R0 >= R1)
	{
		R2 += R2 + 1;
	}
	else
	{
		R2 += R2;
	}
	return  R2;
}
