Noise-1.0.0: libnoise/noise/src/module/curve.cpp
// curve.cpp
//
// Copyright (C) 2003, 2004 Jason Bevins
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library 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 Lesser General Public
// License (COPYING.txt) for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// The developer's email is jlbezigvins@gmzigail.com (for great email, take
// off every 'zig'.)
//
#include "../interp.h"
#include "../misc.h"
#include "curve.h"
using namespace noise::module;
Curve::Curve ():
Module (GetSourceModuleCount ()),
m_pControlPoints (NULL)
{
m_controlPointCount = 0;
}
Curve::~Curve ()
{
delete[] m_pControlPoints;
}
void Curve::AddControlPoint (double inputValue, double outputValue)
{
// Find the insertion point for the new control point and insert the new
// point at that position. The control point array will remain sorted by
// input value.
int insertionPos = FindInsertionPos (inputValue);
InsertAtPos (insertionPos, inputValue, outputValue);
}
void Curve::ClearAllControlPoints ()
{
delete[] m_pControlPoints;
m_pControlPoints = NULL;
m_controlPointCount = 0;
}
int Curve::FindInsertionPos (double inputValue)
{
int insertionPos;
for (insertionPos = 0; insertionPos < m_controlPointCount; insertionPos++) {
if (inputValue < m_pControlPoints[insertionPos].inputValue) {
// We found the array index in which to insert the new control point.
// Exit now.
break;
} else if (inputValue == m_pControlPoints[insertionPos].inputValue) {
// Each control point is required to contain a unique input value, so
// throw an exception.
throw noise::ExceptionInvalidParam ();
}
}
return insertionPos;
}
double Curve::GetValue (double x, double y, double z) const
{
assert (m_pSourceModule[0] != NULL);
assert (m_controlPointCount >= 4);
// Get the output value from the source module.
double sourceModuleValue = m_pSourceModule[0]->GetValue (x, y, z);
// Find the first element in the control point array that has an input value
// larger than the output value from the source module.
int indexPos;
for (indexPos = 0; indexPos < m_controlPointCount; indexPos++) {
if (sourceModuleValue < m_pControlPoints[indexPos].inputValue) {
break;
}
}
// Find the four nearest control points so that we can perform cubic
// interpolation.
int index0 = ClampValue (indexPos - 2, 0, m_controlPointCount - 1);
int index1 = ClampValue (indexPos - 1, 0, m_controlPointCount - 1);
int index2 = ClampValue (indexPos , 0, m_controlPointCount - 1);
int index3 = ClampValue (indexPos + 1, 0, m_controlPointCount - 1);
// If some control points are missing (which occurs if the value from the
// source module is greater than the largest input value or less than the
// smallest input value of the control point array), get the corresponding
// output value of the nearest control point and exit now.
if (index1 == index2) {
return m_pControlPoints[index1].outputValue;
}
// Compute the alpha value used for cubic interpolation.
double input0 = m_pControlPoints[index1].inputValue;
double input1 = m_pControlPoints[index2].inputValue;
double alpha = (sourceModuleValue - input0) / (input1 - input0);
// Now perform the cubic interpolation given the alpha value.
return CubicInterp (
m_pControlPoints[index0].outputValue,
m_pControlPoints[index1].outputValue,
m_pControlPoints[index2].outputValue,
m_pControlPoints[index3].outputValue,
alpha);
}
void Curve::InsertAtPos (int insertionPos, double inputValue,
double outputValue)
{
// Make room for the new control point at the specified position within the
// control point array. The position is determined by the input value of
// the control point; the control points must be sorted by input value
// within that array.
ControlPoint* newControlPoints = new ControlPoint[m_controlPointCount + 1];
for (int i = 0; i < m_controlPointCount; i++) {
if (i < insertionPos) {
newControlPoints[i] = m_pControlPoints[i];
} else {
newControlPoints[i + 1] = m_pControlPoints[i];
}
}
delete[] m_pControlPoints;
m_pControlPoints = newControlPoints;
++m_controlPointCount;
// Now that we've made room for the new control point within the array, add
// the new control point.
m_pControlPoints[insertionPos].inputValue = inputValue ;
m_pControlPoints[insertionPos].outputValue = outputValue;
}