/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code 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. OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // spline.h: Spline paths. // #pragma once #include "g_local.h" #include template class cSpline : public Class { public: int m_iPoints; float m_vPoints[cPoints][cGrids]; int m_iPointFlags[cPoints]; cSpline(); void Reset(void); int Add(float *fAdd, int flags); void Modify(int, float *, int); void UniformAdd(float *pos); void Remove(class cSpline *, int); void RemoveRange(int, int); int Right(float x); float *Get(float x, int *flags); float *GetByNode(float x, int *flags); int Append(cSpline *pNew); void Archive(Archiver& arc); }; template cSpline::cSpline() { m_iPoints = 0; } template void cSpline::Archive(Archiver& arc) { arc.ArchiveInteger(&m_iPoints); for (int i = 0; i < cPoints; i++) { for (int j = 0; j < cGrids; j++) { arc.ArchiveFloat(&m_vPoints[i][j]); } arc.ArchiveInteger(&m_iPointFlags[i]); } } template void cSpline::Reset(void) { m_iPoints = 0; } template int cSpline::Add(float *fAdd, int flags) { int i; int ii; int insertIndex; if (m_iPoints + 1 > cPoints) { return -1; } insertIndex = Right(*fAdd); for (i = m_iPoints; i > insertIndex; i--) { for (ii = 0; ii < cGrids; ii++) { m_vPoints[i][ii] = m_vPoints[i - 1][ii]; } m_iPointFlags[i] = m_iPointFlags[i - 1]; } for (i = 0; i < cGrids; i++) { m_vPoints[insertIndex][i] = fAdd[i]; } m_iPointFlags[insertIndex] = flags; m_iPoints++; return insertIndex; } template void cSpline::UniformAdd(float *pos) { int i; int ii; for (i = 0; i < m_iPoints; i++) { for (ii = 0; ii < cGrids; ii++) { m_vPoints[i][ii] += pos[ii]; } } } template int cSpline::Right(float x) { int i; for (i = 0; i < m_iPoints; i++) { if (m_vPoints[i][0] > x) { break; } } return i; } template float *cSpline::Get(float x, int *flags) { if (!m_iPoints) { return NULL; } int rp; int i; static float r[cGrids]; double delta[cGrids]; rp = Right(x); if (rp) { if (rp == m_iPoints) { if (flags) { *flags = m_iPointFlags[rp - 1]; } for (i = 0; i < cGrids; i++) { r[i] = m_vPoints[rp - 1][i]; } } else { if (flags) { *flags = m_iPointFlags[rp - 1]; } for (i = 0; i < cGrids; i++) { delta[i] = m_vPoints[rp][i] - m_vPoints[rp - 1][i]; } for (i = 0; i < cGrids; i++) { r[i] = (x - m_vPoints[rp - 1][0]) / delta[0] * delta[i] + m_vPoints[rp - 1][i]; } } } else { if (flags) { *flags = m_iPointFlags[0]; } for (i = 0; i < cGrids; i++) { r[i] = m_vPoints[0][i]; } } return r; } template float *cSpline::GetByNode(float x, int *flags) { if (!m_iPoints) { return NULL; } int rp; int i; static float r[cGrids]; double delta[cGrids]; rp = (int)(floor(x) + 1.0); if (rp <= 0) { if (flags) { *flags = m_iPointFlags[0]; } for (i = 0; i < cGrids; i++) { r[i] = m_vPoints[0][i]; } } else if (rp < m_iPoints) { if (flags) { *flags = m_iPointFlags[rp - 1]; } for (i = 0; i < cGrids; i++) { delta[i] = m_vPoints[rp][i] - m_vPoints[rp - 1][i]; } for (i = 0; i < cGrids; i++) { r[i] = (x - (rp - 1)) * delta[i] + m_vPoints[rp - 1][i]; } } else { if (flags) { *flags = m_iPointFlags[m_iPoints - 1]; } for (i = 0; i < cGrids; i++) { r[i] = m_vPoints[m_iPoints - 1][i]; } } return r; } template int cSpline::Append(cSpline *pNew) { float *i_fTmp; float o_fTmp[4]; float fIndexAdd; int i; int ii; int iFlags = 0; if (!pNew || pNew->m_iPoints == 0) { return -1; } if (m_iPoints) { int points; points = m_iPoints; fIndexAdd = *GetByNode(m_iPoints, NULL); for (i = 0; i < pNew->m_iPoints; i++) { i_fTmp = pNew->GetByNode(i, &iFlags); for (ii = 0; ii < cGrids; ii++) { o_fTmp[ii] = i_fTmp[ii]; } o_fTmp[0] += fIndexAdd; Add(o_fTmp, iFlags); } return points; } else { for (i = 0; i < pNew->m_iPoints; i++) { i_fTmp = pNew->GetByNode(i, &iFlags); for (ii = 0; ii < cGrids; ii++) { o_fTmp[ii] = i_fTmp[ii]; } Add(o_fTmp, iFlags); } return 0; } }