Листинг 9.9. Фрактализация отрезка прямой
void fract(Point2 A. Point 2 В. double stdDev) // generate a fractal curve from A to B. // генерируем фрактальную кривую от А до В
double xDiff - А.х - В.х, yDiff - А.у - В.у:
Point2 С:
if(xDiff * XDiff + YDiff * yDiff < minLenSq) cvs.lintTo(B.x. B.y);
else {
stdDev *= factor: // scale stdDev by factor // масштабируем stdDev с множителем factor
double t - 0:
// make a gaussian variate t lying between 0 and 12.0 // создаем Гауссову случайную величину t. // лежащую между 0 и 12.0
forCint i - 0: i . 12:
t += rand()/3276B.0:
t - (t - 6) * stdDev: // shift the mean to 0 and scale // смещаем среднее в 0 и масштабируем С.х - 0.5 * (А.х + В.х) - t * (B.y - А.у): Су 0.5 * (А.у + B.y) + t * (В.х - А.х):
fractCA. С. stdDev):
fractCC. В. stdDev):
}
Подпрограмма tract О, представленная в листинге 9.9, генерирует кривые, приближающиеся к настоящим фракталам. Эта подпрограмма рекурсивно заменяет каждый отрезок прямой на случайном колене на еще меньшее случайное колено. Использован простой критерий выхода из цикла: когда длина отрезка становится достаточно малой (а точнее, когда квадрат его длины становится меньше, чем некоторая глобальная переменная minLenSq, задаваемая пользователем); отрезок рисуется подпрограммой cvs.lineToO, где cvs - объект класса Canvas (см. главу 3). Случайная величина г имеет закон распределения, близкий к Гауссовому; это достигается сложением 12 равномерно распределенных случайных величин, лежащих между 0 и 1 [Knuth, 124]. Результат имеет математическое ожидание 6 и дисперсию 1. Затем среднее значение смещается в 0 и случайная величина должным образом масштабируется.
Отметим, что поскольку смещение, выраженное уравнением (9.21), пропорционально длине порождающего отрезка, фрактальные кривые будут действительно самоподобными (статистически). На каждом последовательном уровне рекурсии среднеквадратическое отклонение stdDev масштабируется с помощью глобального множителя factor, который будет рассмотрен ниже.