/// <summary>
/// Compute surface data.
/// </summary>
protected void Generate(FracValues act_val, int zyklen, double screensize, int formula, bool perspective)
{
Random rand = new Random();
_maxUpdateSteps = ParameterDict.Current.GetInt("View.UpdateSteps");
double[] col = null;
double xd, yd, zd;
double x, y, z;
double dephAdd = ParameterDict.Current.GetInt("View.DephAdd") * screensize;
act_val = act_val.Clone();
Formulas formulas = new Formulas(_pData);
_lastUsedFormulas = formulas;
if (ParameterDict.Current["Intern.Formula.Source"].Trim() == "")
{
formulas.InternFormula = new Fractrace.TomoGeometry.VecRotMandel2d();
}
else
{
Fractrace.TomoGeometry.TomoFormulaFactory fac = new Fractrace.TomoGeometry.TomoFormulaFactory();
formulas.InternFormula = fac.CreateFromString(ParameterDict.Current["Intern.Formula.Source"]);
}
if (formulas.InternFormula == null)
return;
formulas.InternFormula.Init();
double centerX = ParameterDict.Current.GetDouble("Scene.CenterX");
double centerY = ParameterDict.Current.GetDouble("Scene.CenterY");
double centerZ = ParameterDict.Current.GetDouble("Scene.CenterZ");
Rotation rotView = new Rotation();
rotView.Init(centerX, centerY, centerZ, ParameterDict.Current.GetDouble("Transformation.Camera.AngleX"), ParameterDict.Current.GetDouble("Transformation.Camera.AngleY"),
ParameterDict.Current.GetDouble("Transformation.Camera.AngleZ"));
formulas.Transforms.Add(rotView);
// TODO: only use in compatibility mode.
Rotation rot = new Rotation();
rot.Init();
formulas.Transforms.Add(rot);
if (_isRightView)
{
RightEyeView stereoTransform = new RightEyeView();
stereoTransform.Init();
formulas.Transforms.Add(stereoTransform);
}
col = formulas.col;
_maxxIter = _width;
_maxyIter = (int)(ParameterDict.Current.GetDouble("View.Deph") * screensize);
if(IsSmallPreview())
_maxyIter = _maxxIter;
_maxzIter = _height;
int MINX_ITER = 0;
int MINY_ITER = 0;
int MINZ_ITER = 0;
double fa1;
int xschl = 0, yschl = 0, zschl = 0, xx = 0, yy = 0;
double wix = 0, wiy = 0, wiz = 0;
double jx = 0, jy = 0, jz = 0, jzz = 0;
jx = ParameterDict.Current.GetDouble("Formula.Static.jx");
jy = ParameterDict.Current.GetDouble("Formula.Static.jy");
jz = ParameterDict.Current.GetDouble("Formula.Static.jz");
jzz = ParameterDict.Current.GetDouble("Formula.Static.jzz");
// Innenbereich
int minCycle = (int)ParameterDict.Current.GetDouble("Formula.Static.MinCycle");
if (minCycle == 0)
minCycle = zyklen;
// Offset für den Maximalzyklus für die klassische 2D-Darstellung
int cycleAdd = 128;
wix = act_val.arc.x;
wiy = act_val.arc.y;
wiz = act_val.arc.z;
xd = (act_val.end_tupel.x - act_val.start_tupel.x) / (_maxxIter - MINX_ITER);
yd = (act_val.end_tupel.y - act_val.start_tupel.y) / (_maxyIter - MINY_ITER);
zd = (act_val.end_tupel.z - act_val.start_tupel.z) / (_maxzIter - MINZ_ITER);
if (_oldData != null)
{
yd = yd / (_updateCount);
if (_updateCount < 5)
{
_maxyIter *= _updateCount;
}
}
if (_transformUpdate)
{
yd *= 3.0;
}
double xcenter = (act_val.start_tupel.x + act_val.end_tupel.x) / 2.0;
double ycenter = (act_val.start_tupel.y + act_val.end_tupel.y) / 2.0;
double zcenter = (act_val.start_tupel.z + act_val.end_tupel.z) / 2.0;
bool isYborder = true;
// Projektion initialisieren und der Berechnung zuordnen:
// TODO: Projektion über Einstellungen abwählbar machen
double cameraDeph = act_val.end_tupel.y - act_val.start_tupel.y;
cameraDeph *= ParameterDict.Current.GetDouble("Transformation.Perspective.Cameraposition");
Vec3 camera = new Vec3(xcenter, act_val.end_tupel.y + cameraDeph, zcenter);
Vec3 viewPoint = new Vec3(xcenter, act_val.end_tupel.y, zcenter);
Projection proj = new Projection(camera, viewPoint);
if (ParameterDict.Current.GetBool("View.Perspective"))
formulas.Projection = proj;
// Bei der Postererstellung werden die Parameter der räumlichen Projektion auf das mittlere Bild
// ausgerichtet und anschließend die Grenzen verschoben
double xPoster = ParameterDict.Current.GetInt("View.PosterX");
double zPoster = ParameterDict.Current.GetInt("View.PosterZ");
double xDiff = act_val.end_tupel.x - act_val.start_tupel.x;
double zDiff = act_val.end_tupel.z - act_val.start_tupel.z;
act_val.end_tupel.x += xDiff * xPoster;
act_val.start_tupel.x += xDiff * xPoster;
act_val.end_tupel.z += zDiff * zPoster;
act_val.start_tupel.z += zDiff * zPoster;
// Start der Iteration in der Reihenfolge: z,x,y (y entspricht der Tiefe)
z = act_val.end_tupel.z + zd;
for (zschl = (int)(_maxzIter); zschl >= (MINZ_ITER); zschl -= 1)
{
// Nur wenn der Scheduler die Erlaubnis gibt, zschl zu benutzen,
// die Berechnung ausführen (sonst nächste Iteration)
if (IsAvailable(_maxzIter - zschl))
{
System.Windows.Forms.Application.DoEvents();
z = act_val.end_tupel.z - (double)zd * (_maxzIter - zschl);
bool minYDetected = false;
for (xschl = (int)(MINX_ITER); xschl <= _maxxIter; xschl += 1)
{
if (_abort)
{
return;
}
x = act_val.start_tupel.x + (double)xd * xschl;
double miny = 0;
isYborder = true;
xx = xschl;
yy = _maxzIter - zschl;
if (double.IsNaN(x) )
return ;
// Used for better start values in update iteration
double yAdd = rand.NextDouble() * yd;
// In last computation a voxel ist found at (xx,zz)
bool centerIsSet = false;
// In last computation at least on voxel ist found near (xx,zz)
bool areaIsSet = false;
double yAddCenter = 0;
bool needComputing = true;
if (_oldPictureData != null)
{
needComputing = false;
PixelInfo pxInfoTest = _oldPictureData.Points[xx, yy];
if (pxInfoTest != null && pxInfoTest.Coord != null)
{
yAddCenter = pxInfoTest.Coord.Y;
yAdd = yAddCenter;
centerIsSet = true;
}
for (int xxi = -1; xxi <= 1; xxi++)
{
for (int yyi = -1; yyi <= 1; yyi++)
{
int xxposi = xx + xxi;
int yyposi = yy + yyi;
if (xxposi >= 0 && xxposi <= _maxxIter && yyposi >= 0 && yyposi <= _maxzIter)
{
PixelInfo pxInfo = _oldPictureData.Points[xxposi, yyposi];
if (pxInfo != null && pxInfo.Coord != null)
{
areaIsSet = true;
double yAddTemp = pxInfo.Coord.Y;
if (yAdd < yAddTemp || !centerIsSet)
yAdd = yAddTemp;
}
}
}
}
}
if (yAdd + yd < act_val.end_tupel.y)
{
if (centerIsSet)
{
if (yAddCenter + 4.0 * yd < yAdd)
{
needComputing = true;
yAdd = yAdd - act_val.end_tupel.y + 2.0 * ((double)_updateCount) * yd + rand.NextDouble() * yd;
_gData.Picture[xx, yy] = _oldData.Picture[xx, yy];
}
}
else
{
if (areaIsSet)
{
needComputing = true;
yAdd = rand.NextDouble() * yd;
}
}
}
if (needComputing)
{
// yadd cannot be easy handled (because of inside rendering).
for (yschl = (int)(_maxyIter); yschl >= MINY_ITER - dephAdd; yschl -= 1)
{
if (_abort)
return;
if (xx >= 0 && xx < _width && yy >= 0 && yy < _height)
{
if ((_gData.Picture)[xx, yy] == 0 || (_gData.Picture)[xx, yy] == 2)
{ // aha, noch zeichnen
// Test, ob Schnitt mit Begrenzung vorliegt
y = act_val.end_tupel.y - (double)yd * (_maxyIter - yschl);
y += yAdd;
if (double.IsNaN(x) || double.IsNaN(y) || double.IsNaN(z))
return;
fa1 = 0;
int usedCycles = 0;
bool inverse = false;
if (_gData == null)
{
System.Diagnostics.Debug.WriteLine("Error: GData == null");
return;
}
if ((_gData.Picture)[xx, yy] == 0)
usedCycles = formulas.Rechne(x, y, z, 0, zyklen,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, inverse);
if ((_gData.Picture)[xx, yy] == 2)
{// Inverse computing
inverse = true;
usedCycles = formulas.Rechne(x, y, z, 0, minCycle,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, inverse);
}
if (usedCycles == 0)
{
if (!minYDetected)
miny = yschl;
minYDetected = true;
// Iteration ist nicht abgebrochen, also weiterrechnen:
int oldPictureInfo = (_gData.Picture)[xx, yy]; // pictureInfo wird eventuell zurückgesetzt, wenn
// die Farbberechnung wiederholt wird.
_gData.Picture[xx, yy] = 1; // Punkt als gesetzt markieren
VoxelInfo vInfo = new VoxelInfo();
_gData.PointInfo[xx, yy] = vInfo;
vInfo.i = x;
vInfo.j = y;
vInfo.k = z;
cycleAdd = 1024;
if (minCycle >= 0)
{
cycleAdd = minCycle - zyklen;
}
if (isYborder)
{ // es liegt Schnitt mit Begrenzung vor
fa1 = formulas.Rechne(x, y, z, 0, zyklen + cycleAdd,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, false);
if (fa1 == 0)
{
fa1 = -1;
(_gData.Picture)[xx, yy] = 2; // Punkt nicht als gesetzt markieren
}
else
fa1 = 255 * fa1 / (zyklen + cycleAdd);
// debug only: alle Farbwerte auf 1 setzen
col[0] = col[1] = col[2] = col[3] = 255;
}
else
{// innerer Punkt
if (inverse)
{
if (IsSmallPreview())
{
fa1 = formulas.RayCastAt(minCycle, x, y, z, 0,
xd, yd, zd, 0,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, inverse, xx, yy, true);
}
else
{
fa1 = formulas.FixPoint(minCycle, x, y, z, 0,
xd, yd, zd, 0,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, inverse, xx, yy, true);
}
}
else
{
if (IsSmallPreview())
{
fa1 = formulas.RayCastAt(zyklen, x, y, z, 0,
xd, yd, zd, 0,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, inverse, xx, yy, true);
}
else
{
fa1 = formulas.FixPoint(zyklen, x, y, z, 0,
xd, yd, zd, 0,
wix, wiy, wiz,
jx, jy, jz, jzz, formula, inverse, xx, yy, true);
fa1 = (col[0] + col[1] + col[2] + col[3]) / 4.0;
}
}
}
}
}
}
isYborder = false;
}
if ((_gData.Picture)[xx, yy] == 0 || (_gData.Picture)[xx, yy] == 2)
{
if (_oldPictureData != null)
{
_pData.Points[xx, yy] = _oldPictureData.Points[xx, yy];
}
}
if (_oldData != null && _updateCount > 2)
{
if (_oldPictureData.Points[xx, yy] != null)
{
if (_pData.Points[xx, yy] == null)
{
_pData.Points[xx, yy] = _oldPictureData.Points[xx, yy];
}
else
{
if (_pData.Points[xx, yy].Coord.Y < _oldPictureData.Points[xx, yy].Coord.Y)
{
_pData.Points[xx, yy] = _oldPictureData.Points[xx, yy];
}
}
}
}
}
else
{
// Get the old values:
_pData.Points[xx, yy] = _oldPictureData.Points[xx, yy];
}
}
}
}
}