vtkParametricRandomHills.cxx 9.06 KB
Newer Older
1 2 3 4 5
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkParametricRandomHills.cxx

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 8 9
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

10 11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 13 14 15 16 17 18
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkParametricRandomHills.h"
#include "vtkObjectFactory.h"
#include "vtkMath.h"
#include "vtkDoubleArray.h"
19
#include "vtkMinimalStandardRandomSequence.h"
20

21
#include <ctime>
22 23 24

vtkStandardNewMacro(vtkParametricRandomHills);

25
//----------------------------------------------------------------------------
26 27 28 29 30 31 32 33 34
vtkParametricRandomHills::vtkParametricRandomHills() :
  NumberOfHills(30)
  , HillXVariance(2.5)
  , HillYVariance(2.5)
  , HillAmplitude(2)
  , RandomSeed(1)
  , XVarianceScaleFactor(1.0/3.0)
  , YVarianceScaleFactor(1.0/3.0)
  , AmplitudeScaleFactor(1.0/3.0)
35
  , AllowRandomGeneration(1)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
{
  // Preset triangulation parameters
  this->MinimumU = -10;
  this->MinimumV = -10;
  this->MaximumU = 10;
  this->MaximumV = 10;

  this->JoinU = 0;
  this->JoinV = 0;
  this->TwistU = 0;
  this->TwistV = 0;
  this->ClockwiseOrdering = 1;
  this->DerivativesAvailable = 0;

  this->hillData = vtkDoubleArray::New();

52 53 54 55 56 57 58 59 60
  this->previousNumberOfHills = 0;
  this->previousHillXVariance = 0;
  this->previousHillYVariance = 0;
  this->previousHillAmplitude = 0;
  this->previousRandomSeed = 0;
  this->previousXVarianceScaleFactor = 0;
  this->previousYVarianceScaleFactor = 0;
  this->previousAmplitudeScaleFactor = 0;
  this->previousAllowRandomGeneration = 0;
61 62 63 64

  this->randomSequenceGenerator = vtkMinimalStandardRandomSequence::New();
  // Initialise the sequence.
  this->randomSequenceGenerator->SetSeed(this->RandomSeed);
65 66
}

67
//----------------------------------------------------------------------------
68 69 70
vtkParametricRandomHills::~vtkParametricRandomHills()
{
  this->hillData->Delete();
71
  this->randomSequenceGenerator->Delete();
72 73
}

74
//----------------------------------------------------------------------------
75
void vtkParametricRandomHills::InitRNG ( int randomSeed )
76
{
77 78 79
  (randomSeed < 0) ?
    this->randomSequenceGenerator->SetSeed(static_cast<int>(time(NULL))):
    this->randomSequenceGenerator->SetSeed(randomSeed);
80 81
}

82
//----------------------------------------------------------------------------
83 84
double vtkParametricRandomHills::Rand ( void )
{
85 86 87
  double x = this->randomSequenceGenerator->GetValue();
  this->randomSequenceGenerator->Next();
  return x;
88 89
}

90
//----------------------------------------------------------------------------
91 92
void vtkParametricRandomHills::Evaluate(double uvw[3], double Pt[3], double Duvw[9])
{
93 94 95 96 97 98
  // If parameters have changed then regenerate the hills.
  if (this->ParametersChanged())
    {
    this->MakeTheHillData();
    }

99 100 101 102 103 104
  double u = uvw[0];
  double v = uvw[1];
  double *Du = Duvw;
  double *Dv = Duvw + 3;

  // Zero out the point and derivatives.
105
  for ( int i = 0; i < 3; ++i )
106 107 108 109 110 111 112
    Pt[i] = Du[i] = Dv[i] = 0;

  // The point
  // The height of the surface is made up from
  // the contributions from all the Hills.
  Pt[0] = u;
  Pt[1] = this->MaximumV - v; // Texturing is oriented OK if we do this.
113
  for ( int j = 0; j < NumberOfHills; ++j )
114
    {
115
    double hillTuple[5]; // 0: mX, 1: mY, 2: VarX, 3: VarY, 4: Amplitude
116
    this->hillData->GetTuple(j,hillTuple);
117 118
    double x = (u - hillTuple[0])/hillTuple[2];
    double y = (v - hillTuple[1])/hillTuple[3];
119
    Pt[2] += hillTuple[4] * exp( -(x*x+y*y) / 2.0 );
120
    }
121 122
}

123
//----------------------------------------------------------------------------
124 125
double vtkParametricRandomHills::EvaluateScalar(double* vtkNotUsed(uv[3]),
                                                double* vtkNotUsed(Pt[3]),
126 127 128 129 130
                                                double* vtkNotUsed(Duv[9]))
{
  return 0;
}

131
void vtkParametricRandomHills::MakeTheHillData( void )
132 133 134 135 136
{
  this->hillData->Initialize();
  this->hillData->SetNumberOfComponents(5);
  this->hillData->SetNumberOfTuples(NumberOfHills);

137 138
  double dU = MaximumU - MinimumU;
  double dV = MaximumV - MinimumV;
139 140
  double hillTuple[5]; // 0: mX, 1: mY, 2: VarX, 3: VarY, 4: Amplitude
  // Generate the centers of the Hills, standard deviations and amplitudes.
141
  if ( AllowRandomGeneration != 0 )
142
    {
143 144 145 146 147 148 149 150 151 152 153 154 155
    InitRNG(this->RandomSeed);
    for (int i = 0; i < this->NumberOfHills; ++i)
      {
      hillTuple[0] = MinimumU + Rand() * dU;
      hillTuple[1] = MinimumV + Rand() * dV;
      hillTuple[2] = this->HillXVariance *
                    (Rand() + this->XVarianceScaleFactor);
      hillTuple[3] = this->HillYVariance *
                    (Rand() + this->YVarianceScaleFactor);
      hillTuple[4] = this->HillAmplitude *
                    (Rand() + this->AmplitudeScaleFactor);
      this->hillData->SetTuple(i, hillTuple);
      }
156
    }
157
  else
158
    {
159 160
    // Here the generation is nonrandom.
    // We put hills in a regular grid over the whole surface.
161
    double gridMax = sqrt(static_cast<double>(this->NumberOfHills));
162 163
    int counter = 0;

164
    double midU = dU/2.0;
165
    double shiftU = midU / gridMax;
166
    double midV = dV/2.0;
167 168
    double shiftV = midV / gridMax;

169 170 171 172
    hillTuple[2] = this->HillXVariance * this->XVarianceScaleFactor;
    hillTuple[3] = this->HillYVariance * this->YVarianceScaleFactor;
    hillTuple[4] = this->HillAmplitude * this->AmplitudeScaleFactor;
    for (int i = 0; i < static_cast<int>(gridMax); ++i)
173
      {
174
      hillTuple[0] = MinimumU + shiftU + (i / gridMax) * dU;
175
      for ( int j = 0; j < static_cast<int>(gridMax); ++j )
176
        {
177
        hillTuple[1] = MinimumV + shiftV + (j / gridMax) * dV;
178 179
        this->hillData->SetTuple(counter,hillTuple);
        ++counter;
180
        }
181
      }
182 183 184
    // Zero out the variance and amplitude for the remaining hills.
    hillTuple[2] = 0;
    hillTuple[3] = 0;
185
    hillTuple[4] = 0;
186
    for (int k = counter; k < this->NumberOfHills; ++k)
187 188 189 190 191
      {
      hillTuple[0] = MinimumU + midU;
      hillTuple[1] = MinimumV + midV;
      this->hillData->SetTuple(k,hillTuple);
      }
192
    }
193 194 195 196 197 198 199 200 201 202 203
}

//----------------------------------------------------------------------------
bool vtkParametricRandomHills::ParametersChanged()
{
  if (this->previousNumberOfHills != this->NumberOfHills)
    {
    this->CopyParameters();
    return true;
    }
  if (this->previousHillXVariance != this->HillXVariance)
204
    {
205 206
    this->CopyParameters();
    return true;
207
    }
208
  if (this->previousHillYVariance != this->HillYVariance)
209
    {
210 211
    this->CopyParameters();
    return true;
212
    }
213
  if (this->previousHillAmplitude != this->HillAmplitude)
214
    {
215 216
    this->CopyParameters();
    return true;
217
    }
218
  if (this->previousRandomSeed != this->RandomSeed)
219
    {
220 221
    this->CopyParameters();
    return true;
222
    }
223
  if (this->previousXVarianceScaleFactor != this->XVarianceScaleFactor)
224
    {
225 226
    this->CopyParameters();
    return true;
227
    }
228
  if (this->previousYVarianceScaleFactor != this->YVarianceScaleFactor)
229
    {
230 231
    this->CopyParameters();
    return true;
232
    }
233
  if (this->previousAmplitudeScaleFactor != this->AmplitudeScaleFactor)
234
    {
235 236
    this->CopyParameters();
    return true;
237
    }
238
  if (this->previousAllowRandomGeneration != this->AllowRandomGeneration)
239
    {
240 241
    this->CopyParameters();
    return true;
242
    }
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
  return false;
}

//----------------------------------------------------------------------------
void vtkParametricRandomHills::CopyParameters()
{
  this->previousNumberOfHills = this->NumberOfHills;
  this->previousHillXVariance = this->HillXVariance;
  this->previousHillYVariance = this->HillYVariance;
  this->previousHillAmplitude = this->HillAmplitude;
  this->previousRandomSeed = this->RandomSeed;
  this->previousXVarianceScaleFactor = this->XVarianceScaleFactor;
  this->previousYVarianceScaleFactor = this->YVarianceScaleFactor;
  this->previousAmplitudeScaleFactor = this->AmplitudeScaleFactor;
  this->previousAllowRandomGeneration = this->AllowRandomGeneration;
}
259

260
//----------------------------------------------------------------------------
261 262 263 264 265 266
void vtkParametricRandomHills::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

   os << indent << "Hills: " << this->NumberOfHills << "\n";
   os << indent << "Hill variance x-direction: " << this->HillXVariance << "\n";
267 268
   os << indent << "Hill variance x-direction scaling factor: " <<
                    this->XVarianceScaleFactor << "\n";
269
   os << indent << "Hill variance y-direction: " << this->HillYVariance << "\n";
270 271
   os << indent << "Hill variance y-direction scaling factor: " <<
                    this->YVarianceScaleFactor << "\n";
272
   os << indent << "Hill amplitude (height): " << this->HillAmplitude << "\n";
273 274 275 276 277 278
   os << indent << "Amplitude scaling factor: " <<
                    this->AmplitudeScaleFactor << "\n";
   os << indent << "Random number generator seed: " <<
                    this->RandomSeed << "\n";
   os << indent << "Allow random generation: " <<
                    this->AllowRandomGeneration << "\n";
279
}