using System;
using System.Collections.Generic;
using UnityEngine;
using Debug = System.Diagnostics.Debug;
namespace LibNoise.Operator
{
///
/// Provides a noise module that maps the output value from a source module onto a
/// terrace-forming curve. [OPERATOR]
///
public class Terrace : ModuleBase
{
#region Fields
private readonly List _data = new List();
private bool _inverted;
#endregion
#region Constructors
///
/// Initializes a new instance of Terrace.
///
public Terrace()
: base(1)
{
}
///
/// Initializes a new instance of Terrace.
///
/// The input module.
public Terrace(ModuleBase input)
: base(1)
{
Modules[0] = input;
}
///
/// Initializes a new instance of Terrace.
///
/// Indicates whether the terrace curve is inverted.
/// The input module.
public Terrace(bool inverted, ModuleBase input)
: base(1)
{
Modules[0] = input;
IsInverted = inverted;
}
#endregion
#region Properties
///
/// Gets the number of control points.
///
public int ControlPointCount
{
get { return _data.Count; }
}
///
/// Gets the list of control points.
///
public List ControlPoints
{
get { return _data; }
}
///
/// Gets or sets a value whether the terrace curve is inverted.
///
public bool IsInverted
{
get { return _inverted; }
set { _inverted = value; }
}
#endregion
#region Methods
///
/// Adds a control point to the curve.
///
/// The curves input value.
public void Add(double input)
{
if (!_data.Contains(input))
{
_data.Add(input);
}
_data.Sort(delegate(double lhs, double rhs) { return lhs.CompareTo(rhs); });
}
///
/// Clears the control points.
///
public void Clear()
{
_data.Clear();
}
///
/// Auto-generates a terrace curve.
///
/// The number of steps.
public void Generate(int steps)
{
if (steps < 2)
{
throw new ArgumentException("Need at least two steps");
}
Clear();
var ts = 2.0 / (steps - 1.0);
var cv = -1.0;
for (var i = 0; i < steps; i++)
{
Add(cv);
cv += ts;
}
}
#endregion
#region ModuleBase Members
///
/// Returns the output value for the given input coordinates.
///
/// The input coordinate on the x-axis.
/// The input coordinate on the y-axis.
/// The input coordinate on the z-axis.
/// The resulting output value.
public override double GetValue(double x, double y, double z)
{
Debug.Assert(Modules[0] != null);
Debug.Assert(ControlPointCount >= 2);
var smv = Modules[0].GetValue(x, y, z);
int ip;
for (ip = 0; ip < _data.Count; ip++)
{
if (smv < _data[ip])
{
break;
}
}
var i0 = Mathf.Clamp(ip - 1, 0, _data.Count - 1);
var i1 = Mathf.Clamp(ip, 0, _data.Count - 1);
if (i0 == i1)
{
return _data[i1];
}
var v0 = _data[i0];
var v1 = _data[i1];
var a = (smv - v0) / (v1 - v0);
if (_inverted)
{
a = 1.0 - a;
var t = v0;
v0 = v1;
v1 = t;
}
a *= a;
return Utils.InterpolateLinear(v0, v1, a);
}
#endregion
}
}