跳转到内容

分形/MandelMachine

来自 Wikibooks,开放世界中的开放书籍

Mandel Machine Mandel Machine 是由 Botond Kósa 开发的高效 Mandelbrot 集浏览器。[1]


  • c++ 部分 (mm64.cpp) 仅用于声明在汇编语言中实现的函数,其余部分使用 java 编写。
  • FractalCanvas.java 是最重要的文件


FractalCanvas.java 第 1996 行及以后

 if(itTransferFunction==1) ;
		else if(itTransferFunction==2) it = Math.sqrt(it+1);
	    else if(itTransferFunction==3) it = Math.cbrt(it+1);
	    else if(itTransferFunction==4) it = Math.sqrt(Math.sqrt(it+1));
	    else if(itTransferFunction==5) it = Math.log(it+1);
	    else if(itTransferFunction==6) it = Math.log(Math.log(it+1)+1);
	    else if(itTransferFunction==7) it = Math.atan(it);
		else it = -1;

凹凸贴图

[编辑 | 编辑源代码]

"凹凸贴图。它允许对以前隐藏在调色板中缓慢渐变的细微细节进行假 3D 可视化。

凹凸贴图由 3 个参数控制

  • 照明方向(以度为单位):指定模拟照明角度。面向光线的表面会被突出显示,而被光线遮挡的表面会被变暗。
  • 深度:控制结构从缓慢渐变的背景中突出的程度。较小的深度会导致浮雕/压花外观。较大的深度值会导致结构之间出现更深的谷底(参见下面的示例)。
  • 强度:控制高光和阴影引起的色彩变化量。

这些参数可以连续调整,以提供即时反馈。" [2]

数据格式

[编辑 | 编辑源代码]

"Mandel Machine MMIT 压缩迭代数据文件格式

  • 每个数据类型都需要以大端序写入。
  • 以下内容通过 Deflater(原始 zlib 格式)流式传输" Dinkydau[3]
<int 4 bytes> Program Version
<int 4 bytes> Canvas Width
<int 4 bytes> Canvas Height
<byte> Supersampling
<double> Magnification
<double> Rotation
<int 4 bytes> Number of coordinate digits represented by long ints
<long long array> array 2 times as long as the above int
<int 4 bytes> Iteration limit
<byte> Bytes per sample
<double> minimum iteration count
<double> granularity (equal to iterRange / (2^(bytes_per_sample*8) - 6), where iterRange is maxIt - minIt)
<int array> row by row encoded samples (one int value per pixel)

KFB 到 MMIT 转换器

[编辑 | 编辑源代码]

源代码(使用 C 编写),依赖于来自 kf-extras 的 kfb.h 和 kfb.c

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "kfb.h"

void asserts(){
    assert(sizeof(char)==1);
    assert(sizeof(short)==2);
    assert(sizeof(int)==4);
    assert(sizeof(float)==4);
    assert(sizeof(double)==8);
    assert(sizeof(long)==4);
    assert(sizeof(long long)==8);
    return;
}

//data_size counts how large the mmit data is before zlib formatting
int data_size = 0;
const char one = 1;

union DoubleBytes {//to interpret double as char array and inverse byte order
   double d;
   char b[8];
};

union IntBytes {//to interpret int as char array
   int i;
   char b[4];
};

//functions to write data in big endian notation

int le_to_be_int(int input){
    int num = input;
    int b0,b1,b2,b3;
    int res;
    b0 = (num & 0x000000ff) << 24u;
    b1 = (num & 0x0000ff00) << 8u;
    b2 = (num & 0x00ff0000) >> 8u;
    b3 = (num & 0xff000000) >> 24u;
    res = b0 | b1 | b2 | b3;
    return res;
}

void write_be_int(int input, FILE *outfile){
    int res = le_to_be_int(input);
    fwrite(&res, 4, 1, outfile);
    data_size += 4;
}

void write_be_char(char input, FILE *outfile){
	fwrite(&input, 1, 1, outfile);
	data_size += 1;
}

void write_be_double(double input, FILE *outfile){
	union DoubleBytes doublebytes;
	doublebytes.d = input;
	for(int i=0; i<4; i++){//reverse byte order in the double with char array interpretation
		char temp = doublebytes.b[i];
		doublebytes.b[i] = doublebytes.b[7-i];
		doublebytes.b[7-i] = temp;
	}
	fwrite(&doublebytes.d, 8, 1, outfile);
	data_size += 8;
}

int main(int argc, char **argv) {
    //Check and load KFB file-----------------------------------------------------------------------------------
    asserts();
    if (argc < 2)
    {
  	    printf("This program converts a given KFB file to MMIT. Program version: 1.0
");
  	    printf("Usage: "); printf(argv[0]); printf(" path_to_KFB [path_to_MMIT]
");
  	    printf("Default for path_to_MMIT: MMIT-convert.mmit
");
        return 1;
    }
    printf("Loading KFB file...
");
    kfb *in = kfb_load(argv[1]);
    if (! in) { printf("Loading KFB file failed.
"); return 1; }
    int width = kfb_width(in);
    int height = kfb_height(in);
  
    //Writing all relevant mmit data to tempoutfile without zlib format--------------------------------------------

    FILE *tempoutfile;
    tempoutfile=fopen("tempoutfile", "wb");
    
    //Get min and max iteration values present in KFB
	double max_iters = 0;
	double min_iters = 800100100;
	for(int i=0; i<height; i++){
    	for(int j=0; j<width; j++){
    		double ij = kfb_get(in, j, i);
    		if(ij<min_iters) min_iters = ij;
    		if(ij>max_iters) max_iters = ij;
    	}
    }
    printf("Lowest iteration count: %lf
", min_iters);
    printf("Highest iteration count: %lf
", max_iters);
    
    //Parameters and settings
    write_be_int(one, tempoutfile); //Program version
    write_be_int(width, tempoutfile); //Canvas width
    write_be_int(height, tempoutfile); //Canvas height
    char supersampling = 0; write_be_char(supersampling, tempoutfile); //Supersampling (Always 0 for no supersampling)
    double magnification = 512; write_be_double(magnification, tempoutfile); //Fake magnification default to arbitrary value;
    double rotation = 256; write_be_double(rotation, tempoutfile); //Fake rotation default to arbitrary value;
    int coord_digits = 11; write_be_int(coord_digits, tempoutfile); //Fake number of coordinate digits
    int coords[44] = {-1, -1, -1, -1, -1768346623, 1239184185, -1450836726, -1610156628, -1160793342, 1122682978, 1750969101, 1468815386, -86691575, -319241320, -141699069, 731720154, -1302511102, 2092147506, 1358717447, -121412270, -362838523, 1906712988, 218032387, 147395776, 1528659973, -1874890155, 1817790991, 431114295, 1763611407, -389200653, 1363516937, 1455562147, 707986444, -847133922, 1130970381, 1568324293, 1567881485, -580086891, 1843248142, 1016614712, 1950251523, -75377623, -1674907892, 1914116203};
    for(int i=0; i<44; i++){ //Fake array of coordinate digits
	    fwrite(&coords[i], 4, 1, tempoutfile);
		data_size += 4;
	}
    
	int iteration_limit = 799999999; write_be_int(iteration_limit, tempoutfile); //default one below MM's 800M limit, seems safe
	char bytesPerSample = 4; write_be_char(bytesPerSample, tempoutfile); //always 4 (the max) for simplicity
	write_be_double(min_iters, tempoutfile); //minimum number of iterations in the data
	double granularity = (799999999 - min_iters)/4294967290; write_be_double(granularity, tempoutfile); //(equal to iterRange / 4294967290, where iterRange is maxIt - minIt)	
	
	printf("Writing iteration data...
");
	//Iteration data
    double granRec = 0; if(granularity != 0) granRec = 1/granularity;
    long long prevEncoded = 0;
    char buffer[width*4];
    union IntBytes intbytes;
    for(int row=0; row<height; row++){
    	for(int col=0; col<width; col++){
    		double it = kfb_get(in, col, row);
    		long long encoded;
    		if (it == max_iters) encoded = 3; //Point inside minibrot
    		else encoded = round((it-min_iters)*granRec) + 5; //encodeSample
    		int diff = encoded - prevEncoded;
    		//writeSample:
    		intbytes.i = diff;
    		buffer[col+3*width] = intbytes.b[3];
			buffer[col+2*width] = intbytes.b[2];
			buffer[col+width] = intbytes.b[1];
			buffer[col] = intbytes.b[0];
			//
    		prevEncoded = encoded;
    	}
    	fwrite(&buffer, width*4, 1, tempoutfile);
    	data_size += width*4;
    }
  
    fclose(tempoutfile);
    kfb_free(in);
    
    printf ("Total data size: %d
", data_size);

    //read uncompressed MMIT data into array a---------------------------------------------------------------------
    char* a = malloc(data_size);
    if(a==NULL){ printf ("Allocation of memory failed.
"); return 1;}
    FILE *readbackfile;
    readbackfile=fopen("tempoutfile", "rb");
    fread(a, data_size, 1, readbackfile);
  
    printf("Writing zlib format...
");
    //Convert to zlib format and write to file---------------------------------------------------------------------
    FILE *outfile;
    if(argc > 2) outfile=fopen(argv[2], "wb");
    else outfile=fopen("MMIT-convert.mmit", "wb");
  
    int bytes_written = 0;
	char header_more[] = {0, 86, 129, 169, 126}; // hardcoded zlib header for a block size of 33110;
    while(bytes_written<data_size)
    {
    	if(data_size - bytes_written > 33110)
  	    { //not the last block header
  		    fwrite(&header_more, 5, 1, outfile);
  		    for(int j=0; j<33110; j++)
  		    {
  			    fwrite(&a[bytes_written+j], 1, 1, outfile);
  		    }
  		    bytes_written += 33110;
	    }
	    else
	    { //the last block header
		    short to_go = data_size - bytes_written;
  		    short complement = 65535 - to_go;
  		    fwrite(&one, 1, 1, outfile);
  		    fwrite(&to_go, 2, 1, outfile);
  		    fwrite(&complement, 2, 1, outfile);
  		    for(int j=0; j<to_go; j++)
  		    {
  			    fwrite(&a[bytes_written+j], 1, 1, outfile);
  		    }
  		    bytes_written += to_go;
	    }
    }
  
    //-----------------------------------------------------------------------------------
  
    fclose(readbackfile);
    if(remove("tempoutfile") != 0) printf("Deleting the temporary file failed.");

    printf ("Done");

    return 0;
}

参考文献

[编辑 | 编辑源代码]
  1. Botond Kósa 的 Mandel Machine。
  2. fractalforums : mandel-machine -bump-mapping-and-improved-histogram-coloring-v1-3-10-is-available/
  3. fractalforums kfb-to-mmit-converter
华夏公益教科书