Skip to content

Commit

Permalink
new feature for auto limit - SetBoundingBoxAsLimits
Browse files Browse the repository at this point in the history
SetBoundingBoxAsLimits - Calculates the bounding box of the fractal and
sets these as the limit values. This can be helpful to automatically set
the limits for the voxel export.

The bounding box is calculated in the following way:
foreach limit dimension a virtual plane is placed far away of the
fractal orthogonal to the limit direction.
The distance of the plane to the fractal is calculated and this distance
is then used to determine the limit value (plus some little border).

To calculate a distance of a plane to the fractal the new method
CalculateDistanceMinPlane is used.
CalculateDistanceMinPlane takes the plane and iteratively moves the
plane point closer to the fractal surface by moving along the plane
orthogonal and slightly moving orthogonal to the plane orthogonal in any
direction which has a minimum of fractal distance in each marching step.

This is not an universal solution but works quite okay for some test
cases (try menger sponge, quaternion).

TODO: user defined bounding box max value
  • Loading branch information
zebastian committed Nov 9, 2016
1 parent 5e6a81c commit 0440f41
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 0 deletions.
6 changes: 6 additions & 0 deletions mandelbulber2/qt/dock_rendering_engine.cpp
Expand Up @@ -74,6 +74,8 @@ void cDockRenderingEngine::ConnectSignals()
connect(ui->logedit_detail_level, SIGNAL(returnPressed()), this, SLOT(slotDetailLevelChanged()));
connect(ui->comboBox_delta_DE_method, SIGNAL(currentIndexChanged(int)), this,
SLOT(slotChangedComboDistanceEstimationMethod(int)));
connect(ui->bu_bounding_box_to_limit, SIGNAL(clicked()), this,
SLOT(slotPressedButtonSetBoundingBoxAsLimits()));

// NetRender
connect(ui->bu_netrender_connect, SIGNAL(clicked()), this, SLOT(slotNetRenderClientConnect()));
Expand Down Expand Up @@ -305,3 +307,7 @@ void cDockRenderingEngine::slotPressedButtonOptimizeForHQ()
{
gMainInterface->OptimizeStepFactor(0.01);
}
void cDockRenderingEngine::slotPressedButtonSetBoundingBoxAsLimits()
{
gMainInterface->SetBoundingBoxAsLimits();
}
1 change: 1 addition & 0 deletions mandelbulber2/qt/dock_rendering_engine.h
Expand Up @@ -68,6 +68,7 @@ private slots:
void slotPressedButtonOptimizeForHQ();
void slotDetailLevelChanged();
void slotChangedComboDistanceEstimationMethod(int index);
void slotPressedButtonSetBoundingBoxAsLimits();

// NetRender
void slotNetRenderClientConnect();
Expand Down
16 changes: 16 additions & 0 deletions mandelbulber2/qt/dock_rendering_engine.ui
Expand Up @@ -751,6 +751,22 @@ of fractal iterations
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QPushButton" name="bu_bounding_box_to_limit">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Calculates the bounding box of the fractal and sets these as the limit values. This can be helpful to automatically set the limits for the voxel export&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Bounding Box to limit</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_21">
<property name="spacing">
Expand Down
49 changes: 49 additions & 0 deletions mandelbulber2/src/calculate_distance.cpp
Expand Up @@ -345,3 +345,52 @@ double CalculateDistanceSimple(const cParamRender &params, const cNineFractals &

return distance;
}

double CalculateDistanceMinPlane(const cParamRender &params, const cNineFractals &fractals,
const CVector3 planePoint, const CVector3 direction, const CVector3 orthDdirection)
{
// the plane is defined by the 'planePoint' and the orthogogonal 'direction'
// the method will return the minimum distance from the plane to the fractal
double distStep = 0.0;
CVector3 point = planePoint;
const double detail = 0.5;
const int transVectorAngles = 5;

CVector3 rotationAxis = planePoint;
rotationAxis.Normalize();

while (distStep == 0 || distStep > 0.00001)
{
CVector3 pointNextBest(0, 0, 0);
double newDistStepMin = 0;
for(int i = 0; i <= transVectorAngles; i++)
{
double angle = (1.0 * i / transVectorAngles) * 2.0 * M_PI;
CVector3 transversalVect = orthDdirection;
transversalVect = transversalVect.RotateAroundVectorByAngle(rotationAxis, angle);
transversalVect.Normalize();
CVector3 pointNext = point + direction * distStep;
if(i > 0) pointNext += transversalVect * distStep / 2.0;
sDistanceIn in(pointNext, 0, false);
sDistanceOut out;
double dist = CalculateDistance(params, fractals, in, &out);
double newDistStep = dist * detail * 0.5;
if(newDistStep < newDistStepMin || newDistStepMin == 0)
{
pointNextBest = pointNext;
newDistStepMin = newDistStep;
}
}
if(newDistStepMin > 1000) newDistStepMin = 1000;
if(distStep != 0 && newDistStepMin > distStep) break;
distStep = newDistStepMin;
point = pointNextBest;
// qDebug() << "pointNextBest" << pointNextBest.Debug();
if(point.Length() > 1000000)
{
qDebug() << "surface not found!";
return 0;
}
}
return CVector3(point - planePoint).Dot(direction);
}
2 changes: 2 additions & 0 deletions mandelbulber2/src/calculate_distance.hpp
Expand Up @@ -71,5 +71,7 @@ double CalculateDistance(const cParamRender &params, const cNineFractals &fracta
const sDistanceIn &in, sDistanceOut *out, sRenderData *data = NULL);
double CalculateDistanceSimple(const cParamRender &params, const cNineFractals &fractals,
const sDistanceIn &in, sDistanceOut *out, int forcedFormulaIndex);
double CalculateDistanceMinPlane(const cParamRender &params, const cNineFractals &fractals,
const CVector3 point, const CVector3 direction, const CVector3 orthDdirection);

#endif /* MANDELBULBER2_SRC_CALCULATE_DISTANCE_HPP_ */
81 changes: 81 additions & 0 deletions mandelbulber2/src/interface.cpp
Expand Up @@ -1278,6 +1278,87 @@ void cInterface::ResetView()
StartRender();
}

void cInterface::SetBoundingBoxAsLimits()
{
SynchronizeInterface(gPar, gParFractal, qInterface::read);

cParameterContainer parTemp = *gPar;
parTemp.Set("limits_enabled", false);
parTemp.Set("interior_mode", false);

cParamRender *params = new cParamRender(&parTemp);
cNineFractals *fractals = new cNineFractals(gParFractal, &parTemp);

CVector3 direction;
CVector3 orthDirection;
CVector3 point;
double dist;

// negative x limit
cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Negative X Limit"), 0.0 / 6.0);
direction = CVector3(1, 0, 0);
orthDirection = CVector3(0, 1, 0);
point = CVector3(-100000, 0, 0);
dist = CalculateDistanceMinPlane(*params, *fractals, point, direction, orthDirection);
double minX = point.x + dist;

// negative y limit
cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Negative Y Limit"), 1.0 / 6.0);
direction = CVector3(0, 1, 0);
orthDirection = CVector3(0, 0, 1);
point = CVector3(0, -100000, 0);
dist = CalculateDistanceMinPlane(*params, *fractals, point, direction, orthDirection);
double minY = point.y + dist;

// negative z limit
cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Negative Z Limit"), 2.0 / 6.0);
direction = CVector3(0, 0, 1);
orthDirection = CVector3(1, 0, 0);
point = CVector3(0, 0, -100000);
dist = CalculateDistanceMinPlane(*params, *fractals, point, direction, orthDirection);
double minZ = point.z + dist;

// positive x limit
cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Positive X Limit"), 3.0 / 6.0);
direction = CVector3(-1, 0, 0);
orthDirection = CVector3(0, -1, 0);
point = CVector3(100000, 0, 0);
dist = CalculateDistanceMinPlane(*params, *fractals, point, direction, orthDirection);
double maxX = point.x - dist;

// positive y limit
cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Positive Y Limit"), 4.0 / 6.0);
direction = CVector3(0, -1, 0);
orthDirection = CVector3(0, 0, -1);
point = CVector3(0, 100000, 0);
dist = CalculateDistanceMinPlane(*params, *fractals, point, direction, orthDirection);
double maxY = point.y - dist;

// positive z limit
cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Positive Z Limit"), 5.0 / 6.0);
direction = CVector3(0, 0, -1);
orthDirection = CVector3(-1, 0, 0);
point = CVector3(0, 0, 100000);
dist = CalculateDistanceMinPlane(*params, *fractals, point, direction, orthDirection);
double maxZ = point.z - dist;

double medX = (maxX + minX) / 2.0;
double medY = (maxY + minY) / 2.0;
double medZ = (maxZ + minZ) / 2.0;
double rangeX = maxX - minX;
double rangeY = maxY - minY;
double rangeZ = maxZ - minZ;

gPar->Set("limit_min", CVector3(medX - rangeX * 0.6, medY - rangeY * 0.6, medZ - rangeZ * 0.6));
gPar->Set("limit_max", CVector3(medX + rangeX * 0.6, medY + rangeY * 0.6, medZ + rangeZ * 0.6));

cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Done"), 1.0);
delete params;
delete fractals;
SynchronizeInterface(gPar, gParFractal, qInterface::write);
}


void cInterface::NewPrimitive(const QString &primitiveType, int index)
{
QString primitiveName = QString("primitive_") + primitiveType;
Expand Down
1 change: 1 addition & 0 deletions mandelbulber2/src/interface.hpp
Expand Up @@ -101,6 +101,7 @@ class cInterface
void Undo();
void Redo();
void ResetView();
void SetBoundingBoxAsLimits();
void NewPrimitive(const QString &primitiveType, int index = 0);
void DeletePrimitive(const QString &primitiveName);
void RebuildPrimitives(cParameterContainer *par);
Expand Down

0 comments on commit 0440f41

Please sign in to comment.