mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
519 lines
12 KiB
C++
519 lines
12 KiB
C++
//---------------------------------------------------------------------------
|
|
|
|
#include "system.hpp"
|
|
#include "classes.hpp"
|
|
#pragma hdrstop
|
|
|
|
#include "Geometry.h"
|
|
#include "Spline.h"
|
|
#include "usefull.h"
|
|
#include "maptextfile.hpp"
|
|
|
|
//#define asSplinesPatch AnsiString("Scenery\\")
|
|
|
|
|
|
bool __fastcall Connect(TKnot *k1, TKnot *k2)
|
|
{
|
|
if (k1 && k2)
|
|
{
|
|
k1->Next= k2;
|
|
k2->Prev= k1;
|
|
k1->InitLength();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
#define Precision 10000
|
|
float __fastcall CurveLength(vector3 p1, vector3 cp1, vector3 cp2, vector3 p2)
|
|
{
|
|
float t,l=0;
|
|
vector3 tmp,last= p1;
|
|
for (int i=1; i<=Precision; i++)
|
|
{
|
|
t= float(i)/float(Precision);
|
|
tmp= Interpolate(t,p1,cp1,cp2,p2);
|
|
t= vector3(tmp-last).Length();
|
|
l+= t;
|
|
last= tmp;
|
|
}
|
|
return (l);
|
|
|
|
}
|
|
|
|
__fastcall TKnot::TKnot()
|
|
{
|
|
Next=Prev= NULL;
|
|
Length= -1;
|
|
IsCurve= false;
|
|
fLengthIn=fLengthOut= 0;
|
|
fRoll= 0;
|
|
bSwitchDirectionForward= false;
|
|
bSwitchDirectionBackward= false;
|
|
}
|
|
|
|
__fastcall TKnot::TKnot(int n)
|
|
{
|
|
bSwitchDirectionForward= false;
|
|
bSwitchDirectionBackward= false;
|
|
Next=Prev= NULL;
|
|
Length= -1;
|
|
IsCurve= false;
|
|
fLengthIn=fLengthOut= 0;
|
|
if (n>0)
|
|
{
|
|
Next= new TKnot(n-1);
|
|
Next->Prev= this;
|
|
}
|
|
}
|
|
|
|
__fastcall TKnot::~TKnot()
|
|
{
|
|
}
|
|
|
|
vector3 __fastcall TKnot::GetDirection(float t)
|
|
{
|
|
if (IsCurve)
|
|
{
|
|
vector3 v1= CPointOut-Point;
|
|
vector3 v2= Next->Point-Next->CPointIn; //BUGBUG
|
|
return v1*(1-t)+v2*(t);
|
|
}
|
|
else
|
|
return (Next->Point-Point);//Spline->Knots[KnotIndex].Point-Spline->Knots[KnotIndex].Point);
|
|
}
|
|
|
|
float __fastcall TKnot::GetTFromS(float s)
|
|
{
|
|
// initial guess for Newton's method
|
|
int it=0;
|
|
float fTolerance= 0.001;
|
|
float fRatio = s/RombergIntegral(0,1);
|
|
float fOmRatio = 1.0 - fRatio;
|
|
float fTime = fOmRatio*0 + fRatio*1;
|
|
|
|
// for (int i = 0; i < iIterations; i++)
|
|
while (true)
|
|
{
|
|
it++;
|
|
if (it>10)
|
|
MessageBox(0,"Too many iterations","TSpline->GetTFromS",MB_OK);
|
|
|
|
float fDifference = RombergIntegral(0,fTime) - s;
|
|
if ( ( fDifference>0 ? fDifference : -fDifference) < fTolerance )
|
|
return fTime;
|
|
|
|
fTime -= fDifference/GetFirstDerivative(fTime).Length();
|
|
}
|
|
|
|
// Newton's method failed. If this happens, increase iterations or
|
|
// tolerance or integration accuracy.
|
|
return -1;
|
|
|
|
}
|
|
|
|
bool __fastcall TKnot::Init(TKnot *NNext, TKnot *NPrev)
|
|
{
|
|
if (NNext!=NULL)
|
|
{
|
|
Next= NNext;
|
|
Next->Prev= this;
|
|
}
|
|
if (NPrev!=NULL)
|
|
{
|
|
Prev= NPrev;
|
|
Prev->Next= this;
|
|
}
|
|
}
|
|
|
|
bool __fastcall TKnot::InitCPoints()
|
|
{
|
|
if (Prev!=NULL)
|
|
if (Prev->IsCurve)
|
|
if (Next!=NULL)
|
|
{
|
|
if (!IsCurve)
|
|
{
|
|
CPointIn= Point-fLengthIn*Normalize(Next->Point-Point);
|
|
}
|
|
else
|
|
CPointIn= Point-fLengthIn*(Normalize(Normalize(Next->Point-Point)+Normalize(Point-Prev->Point)));
|
|
}
|
|
else
|
|
CPointIn= Point-fLengthIn*Normalize(Point-Prev->Point);
|
|
else
|
|
CPointIn= Prev->Point;
|
|
|
|
if (Next!=NULL)
|
|
if (IsCurve)
|
|
if (Prev!=NULL)
|
|
{
|
|
if (!Prev->IsCurve)
|
|
{
|
|
CPointOut= Point-fLengthOut*Normalize(Prev->Point-Point);
|
|
}
|
|
else
|
|
CPointOut= Point-fLengthOut*(Normalize(Normalize(Prev->Point-Point)+Normalize(Point-Next->Point)));
|
|
}
|
|
else;
|
|
// CPointOut= -fLengthOut*Normalize(Next->Point-Point);
|
|
else
|
|
CPointOut= Next->Point;
|
|
else
|
|
CPointOut= Point-fLengthOut*Normalize(Prev->Point-Point);
|
|
}
|
|
|
|
bool __fastcall TKnot::InitLength()
|
|
{
|
|
|
|
if (IsCurve)
|
|
if (Next)
|
|
Length= RombergIntegral(0,1);
|
|
else;
|
|
else
|
|
if (Next)
|
|
Length= (Point-Next->Point).Length();
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
vector3 TKnot::GetFirstDerivative(float fTime)
|
|
{
|
|
|
|
float fOmTime = 1.0 - fTime;
|
|
float fPowTime = fTime;
|
|
vector3 kResult = fOmTime*(CPointOut-Point);
|
|
|
|
int iDegreeM1 = 3 - 1;
|
|
|
|
float fCoeff = 2*fPowTime;
|
|
kResult = (kResult+fCoeff*(Next->CPointIn-CPointOut))*fOmTime;
|
|
fPowTime *= fTime;
|
|
|
|
kResult += fPowTime*(Next->Point-Next->CPointIn);
|
|
kResult *= 3;
|
|
|
|
return kResult;
|
|
}
|
|
|
|
float TKnot::RombergIntegral(float fA, float fB)
|
|
{
|
|
float fH = fB - fA;
|
|
|
|
const int ms_iOrder= 5;
|
|
|
|
float ms_apfRom[2][ms_iOrder];
|
|
|
|
ms_apfRom[0][0] = 0.5*fH*((GetFirstDerivative(fA).Length())+(GetFirstDerivative(fB).Length()));
|
|
for (int i0 = 2, iP0 = 1; i0 <= ms_iOrder; i0++, iP0 *= 2, fH *= 0.5)
|
|
{
|
|
// approximations via the trapezoid rule
|
|
float fSum = 0.0;
|
|
int i1;
|
|
for (i1 = 1; i1 <= iP0; i1++)
|
|
fSum += (GetFirstDerivative(fA + fH*(i1-0.5)).Length());
|
|
|
|
// Richardson extrapolation
|
|
ms_apfRom[1][0] = 0.5*(ms_apfRom[0][0] + fH*fSum);
|
|
for (int i2 = 1, iP2 = 4; i2 < i0; i2++, iP2 *= 4)
|
|
{
|
|
ms_apfRom[1][i2] =
|
|
(iP2*ms_apfRom[1][i2-1] - ms_apfRom[0][i2-1])/(iP2-1);
|
|
}
|
|
|
|
for (i1 = 0; i1 < i0; i1++)
|
|
ms_apfRom[0][i1] = ms_apfRom[1][i1];
|
|
}
|
|
|
|
return ms_apfRom[0][ms_iOrder-1];
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------//
|
|
|
|
|
|
__fastcall TSpline::TSpline()
|
|
{
|
|
// Closed= true;
|
|
// asName= "foo";
|
|
// Knots= NULL;
|
|
RootKnot= NULL;
|
|
iNumKnots= 0;
|
|
KnotsAllocated= false;
|
|
// Next=Prev= this;
|
|
}
|
|
|
|
__fastcall TSpline::TSpline(AnsiString asNName)
|
|
{
|
|
// Closed= true;
|
|
// asName= asNName;
|
|
// Knots= NULL;
|
|
RootKnot= NULL;
|
|
iNumKnots= 0;
|
|
KnotsAllocated= false;
|
|
// Next=Prev= this;
|
|
}
|
|
|
|
__fastcall TSpline::~TSpline()
|
|
{
|
|
// if (KnotsAllocated)
|
|
// SafeDeleteArray(Knots);
|
|
|
|
// SafeDelete(RootKnot);
|
|
|
|
TKnot *ck,*tk;
|
|
ck= RootKnot;
|
|
|
|
for (int i=0; i<iNumKnots; i++)
|
|
{
|
|
tk= ck;
|
|
ck= ck->Next;
|
|
SafeDelete(tk);
|
|
}
|
|
|
|
}
|
|
|
|
bool __fastcall TSpline::Create( int n, AnsiString asNName )
|
|
{
|
|
/*
|
|
// asName= asNName;
|
|
iNumKnots= n;
|
|
Knots= new TKnot[iNumKnots];
|
|
KnotsAllocated= true;
|
|
Knots[0].Prev= NULL;
|
|
Knots[iNumKnots-1].Next= NULL;
|
|
for (int i=1; i<iNumKnots; i++)
|
|
Knots[i].Init(NULL,Knots+i-1);
|
|
*/
|
|
}
|
|
|
|
bool __fastcall TSpline::AssignKnots( TKnot *FirstKnot, int n )
|
|
{
|
|
// iNumKnots= n;
|
|
// Knots= FirstKnot;
|
|
// KnotsAllocated= false;
|
|
|
|
}
|
|
|
|
int __fastcall TSpline::LoadFromFile( AnsiString FileName, TKnot *FirstKnot )
|
|
{
|
|
return false;
|
|
/*
|
|
int i;
|
|
|
|
iNumKnots= -1;
|
|
|
|
|
|
AnsiString buf;
|
|
buf.SetLength(255);
|
|
|
|
TMapTextfile *tf= new TMapTextfile();
|
|
tf->Open(asSceneryPatch+FileName,mmRead);
|
|
|
|
tf->ReadLn(buf);
|
|
|
|
if (buf==AnsiString("\"SPLINE\""))
|
|
{
|
|
tf->ReadLn(buf);
|
|
if (FirstKnot==NULL)
|
|
Create(buf.ToInt());
|
|
else
|
|
AssignKnots(FirstKnot,buf.ToInt());
|
|
TKnot *CurrentKnot= Knots;
|
|
// iNumKnots= buf.ToInt();
|
|
// Knots= new TKnot[iNumKnots];// malloc(*sizeof(TKnot));
|
|
|
|
DecimalSeparator= '.';
|
|
for (i=0; i<iNumKnots; i++)
|
|
{
|
|
|
|
tf->ReadLn(buf); CurrentKnot->Point.x= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->Point.z= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->Point.y= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->CPointIn.x= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->CPointIn.z= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->CPointIn.y= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->CPointOut.x= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->CPointOut.z= buf.ToDouble();
|
|
tf->ReadLn(buf); CurrentKnot->CPointOut.y= buf.ToDouble();
|
|
|
|
tf->ReadLn(buf);
|
|
// buf.Trim();
|
|
Knots[i].IsCurve= (buf!="#line ");
|
|
CurrentKnot= CurrentKnot->Next;
|
|
|
|
|
|
}
|
|
DecimalSeparator= ',';
|
|
|
|
CurrentKnot= Knots;
|
|
|
|
for (i=0; i<iNumKnots-1; i++)
|
|
{
|
|
// Knots[i].InitLength();
|
|
if (CurrentKnot->IsCurve)
|
|
{
|
|
|
|
CurrentKnot->Length= CurveLength(CurrentKnot->Point,CurrentKnot->CPointOut,CurrentKnot->Next->CPointIn,CurrentKnot->Next->Point);
|
|
}
|
|
else
|
|
{
|
|
CurrentKnot->CPointOut= 2*CurrentKnot->Point-CurrentKnot->CPointIn;
|
|
CurrentKnot->Next->CPointIn= CurrentKnot->Point;
|
|
CurrentKnot->Length= (CurrentKnot->Point-CurrentKnot->Next->Point).Length();
|
|
}
|
|
CurrentKnot= CurrentKnot->Next;
|
|
}
|
|
CurrentKnot->Length= -1;
|
|
}
|
|
|
|
|
|
|
|
tf->Close();
|
|
|
|
delete tf;
|
|
|
|
return (iNumKnots);
|
|
*/
|
|
}
|
|
|
|
int __fastcall TSpline::Load( TQueryParserComp *Parser, AnsiString asEndString )
|
|
{
|
|
TKnot *LastKnot= NULL;;
|
|
if (RootKnot!=NULL)
|
|
for (LastKnot= RootKnot; LastKnot->Next!=NULL; LastKnot= LastKnot->Next);
|
|
|
|
TKnot *tmp;
|
|
|
|
tmp= new TKnot(0);
|
|
tmp->Prev= LastKnot;
|
|
if (LastKnot!=NULL)
|
|
LastKnot->Next= tmp;
|
|
else
|
|
RootKnot= tmp;
|
|
|
|
LastKnot= tmp;
|
|
|
|
float tf,r,pr;
|
|
vector3 dir;
|
|
|
|
// asName= Parser->GetNextSymbol();
|
|
|
|
iNumKnots= 0;
|
|
|
|
do
|
|
{
|
|
LastKnot->fLengthIn= Parser->GetNextSymbol().ToDouble();
|
|
tf= Parser->GetNextSymbol().ToDouble();
|
|
LastKnot->Point.x= tf;
|
|
tf= Parser->GetNextSymbol().ToDouble();
|
|
LastKnot->Point.y= tf;
|
|
tf= Parser->GetNextSymbol().ToDouble();
|
|
LastKnot->Point.z= tf;
|
|
tf= Parser->GetNextSymbol().ToDouble();
|
|
LastKnot->fRoll= tf/180*M_PI;
|
|
|
|
LastKnot->fLengthOut= Parser->GetNextSymbol().ToDouble();
|
|
|
|
LastKnot->IsCurve= (LastKnot->fLengthOut!=0);
|
|
|
|
LastKnot->Next= new TKnot(0);
|
|
LastKnot->Next->Prev= LastKnot;
|
|
LastKnot= LastKnot->Next;
|
|
|
|
iNumKnots++;
|
|
|
|
|
|
} while (Parser->GetNextSymbol().LowerCase()!=asEndString && !Parser->EOF);
|
|
|
|
LastKnot->Prev->Next= NULL;
|
|
delete LastKnot;
|
|
if (RootKnot!=NULL)
|
|
for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next)
|
|
LastKnot->InitCPoints();
|
|
if (RootKnot!=NULL)
|
|
for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next)
|
|
LastKnot->InitLength();
|
|
}
|
|
|
|
float __fastcall TSpline::GetLength()
|
|
{
|
|
TKnot *tmp= RootKnot;
|
|
float l= 0;
|
|
for (int i=0; i<iNumKnots; i++)
|
|
{
|
|
l+= tmp->Length;
|
|
tmp= tmp->Next;
|
|
}
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
vector3 __fastcall TSpline::GetCenter()
|
|
{
|
|
TKnot *ck,*tk;
|
|
ck= RootKnot;
|
|
vector3 pt= vector3(0,0,0);
|
|
|
|
for (int i=0; i<iNumKnots; i++)
|
|
{
|
|
pt+= ck->Point;
|
|
ck= ck->Next;
|
|
}
|
|
if (iNumKnots>0)
|
|
pt/= iNumKnots;
|
|
|
|
}
|
|
|
|
TKnot* __fastcall TSpline::GetLastKnot()
|
|
{
|
|
TKnot *ck;
|
|
ck= RootKnot;
|
|
|
|
for (int i=0; i<iNumKnots-1; i++)
|
|
{
|
|
ck= ck->Next;
|
|
}
|
|
return ck;
|
|
}
|
|
|
|
|
|
bool __fastcall TSpline::Render()
|
|
{
|
|
TKnot *LastKnot= NULL;;
|
|
|
|
// if (RootKnot==NULL)
|
|
// RootKnot= Knots;
|
|
|
|
if (RootKnot!=NULL)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glBegin(GL_LINE_STRIP);
|
|
int i=0;
|
|
for (LastKnot= RootKnot; LastKnot!=NULL && i<iNumKnots; LastKnot= LastKnot->Next, i++)
|
|
// for (LastKnot= RootKnot; LastKnot!=NULL; LastKnot= LastKnot->Next)
|
|
glVertex3f(LastKnot->Point.x,LastKnot->Point.y,LastKnot->Point.z);
|
|
glEnd();
|
|
/*
|
|
if (RootKnot->Prev!=NULL)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glBegin(GL_LINE_STRIP);
|
|
glVertex3f(RootKnot->Point.x,RootKnot->Point.y,RootKnot->Point.z);
|
|
glVertex3f(RootKnot->Prev->Point.x,RootKnot->Prev->Point.y,RootKnot->Prev->Point.z);
|
|
glEnd();
|
|
}*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
#pragma package(smart_init)
|