/*
This program 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 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
In addition, as a special exception, <Borland Software Corporation >
gives permission to link the code of this program with
the Kylix library, and distribute linked combinations including
the two. You must obey the GNU General Public License in all
respects for all of the code used other than Kylix. If you modify
this file, you may extend this exception to your version of the
file, but you are not obligated to do so. If you do not wish to
do so, delete this exception statement from your version.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <vcl.h>
#pragma hdrstop
#include "dneedle.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
__fastcall
TfrmMain::TfrmMain (TComponent * Owner):
TForm (Owner)
{
isPositionCenterMode = false;
isPositionNeedleMode = false;
haltPlayback = false;
}
void __fastcall
TfrmMain::btnCenterClick (TObject * Sender)
{
isPositionCenterMode = true;
img->Cursor = crCross;
status->SimpleText = "Point at record's center";
}
void __fastcall
TfrmMain::btnNeedleClick (TObject * Sender)
{
isPositionNeedleMode = true;
img->Cursor = crCross;
status->SimpleText = "Point at needle position";
}
void __fastcall
TfrmMain::btnLoadClick (TObject * Sender)
{
dlgOpen->InitialDir = (AnsiString) BMP_PATH;
if (dlgOpen->Execute ())
img->Picture->LoadFromFile (dlgOpen->FileName);
}
void __fastcall
TfrmMain::imgMouseUp (TObject * Sender, TMouseButton Button,
TShiftState Shift, int X, int Y)
{
if (isPositionCenterMode)
{
centerX = X;
centerY = Y;
}
if (isPositionNeedleMode)
{
needleX = X;
needleY = Y;
}
isPositionNeedleMode = isPositionCenterMode = false;
img->Cursor = crDefault;
status->SimpleText = "";
}
void __fastcall
TfrmMain::btnHaltPlaybackClick (TObject * Sender)
{
haltPlayback = true;
}
void __fastcall
TfrmMain::btnPlayClick (TObject * Sender)
{
long double newNeedleX, newNeedleY;
long double curLum;
long double ndx, ndy;
long double dx = needleX - centerX;
long double dy = needleY - centerY;
long double stickyFact = txtSticky->Text.ToDouble ();
long double omega = txtOmega->Text.ToDouble ();
areaWidth = txtArea->Text.ToInt ();
long i, time, numSamples = txtSamples->Text.ToInt ();
long double mass = txtMass->Text.ToDouble ();
long double damping = txtDamping->Text.ToDouble ();
long double avgRadius, radius, dr;
long double avgRadiusSpeed, avgRadiusAccel;
long double alpha, alpha0;
// Allocate the sample buffers
long double *dBuf =
(long double *) malloc (sizeof (long double) * numSamples);
word *wBuf = (word *) malloc (sizeof (word) * numSamples);
radius = sqrtl (powl (dx, 2) + powl (dy, 2));
alpha0 = acos (dx / radius);
avgRadius = radius;
avgRadiusSpeed = 0;
for (time = 0; time < numSamples && !haltPlayback; time++)
{
// Idle background operations
if (time % NUM_ITERATIONS_TO_IDLE == 0)
{
img->Canvas->Refresh ();
Application->ProcessMessages ();
}
alpha = alpha0 + (omega * time);
needleX = ((radius * cos (alpha)) + centerX);
needleY = ((radius * sin (alpha)) + centerY);
curLum = getDirection (&ndx, &ndy);
newNeedleX = needleX + (ndx * stickyFact);
newNeedleY = needleY + (ndy * stickyFact);
radius = sqrtl (powl (newNeedleX - centerX, 2) +
powl (newNeedleY - centerY, 2));
dr = avgRadius - radius;
curLum = (curLum - 45) / 18;
// dBuf[time] = dr;
// dBuf[time] = curLum;
dBuf[time] = ((40 * dr) + (60 * curLum)) / 100;
avgRadiusAccel = -(dr / mass);
avgRadiusSpeed = (avgRadiusSpeed * damping) + avgRadiusAccel;
avgRadius += avgRadiusSpeed;
radius = ((100 * radius) + (35 * avgRadius)) / 135;
}
// Reset halt flag
if (haltPlayback)
haltPlayback = false;
// Filter dBuf into wBuf
for (i = 2; i < (time - 2); i++)
dBuf =
(dBuf[i - 2] + dBuf[i - 1] + dBuf + dBuf[i + 1] + dBuf[i + 2]) / 5;
for (i = 2; i < (time - 2); i++)
wBuf = (word) ((long) ((dBuf * 47 * 256) + 0.5));
// Write wBuf
FILE *fp = fopen (RAW_PATH, "wb");
fwrite (wBuf, 1, sizeof (word) * time, fp);
// Done
fclose (fp);
free (dBuf);
free (wBuf);
status->SimpleText = "Done.";
}
float _fastcall
TfrmMain::getDirection (long double *dx, long double *dy)
{
TColor curTCol;
float avgCol;
long sumCount = 0;
long sumCol = 0;
long cntCol;
long curCol;
long cntx = 0;
long cnty = 0;
long cntrx = (long) (needleX + 0.5);
long cntry = (long) (needleY + 0.5);
long x, y;
long double r;
curTCol = img->Canvas->Pixels[cntrx][cntry];
cntCol = (curTCol & 0x000000FF);
(*dx) = 0;
(*dy) = 0;
for (y = -areaWidth; y < areaWidth; y++)
{
for (x = -areaWidth; x < areaWidth; x++)
{
curTCol = img->Canvas->Pixels[cntrx + x][cntry + y];
curCol = (curTCol & 0x000000FF);
sumCol += curCol;
sumCount++;
if (x != 0)
{
(*dx) += ((curCol - cntCol) / x);
cntx++;
}
if (y != 0)
{
(*dy) += ((curCol - cntCol) / y);
cnty++;
}
}
}
(*dx) /= (cntx * 255);
(*dy) /= (cnty * 255);
r = sqrtl (powl ((*dx), 2) + powl ((*dy), 2));
if (r > 0)
{
(*dx) /= r;
(*dy) /= r;
}
else
{
(*dx) = 0;
(*dy) = 0;
}
img->Canvas->Pixels[needleX][needleY] = (TColor) (0x00FF0000 &
img->Canvas->
Pixels[needleX][needleY]);
avgCol = (float) sumCol / sumCount;
return avgCol;
}