- define variables and functions as static when not declared by headers. - remove some unused defines. - other minor changes to quiet warnings.
1256 lines
25 KiB
C++
1256 lines
25 KiB
C++
/*******************************************************************************
|
|
* fpmetric.cpp
|
|
*
|
|
* This module implements the parametric shapetype.
|
|
*
|
|
* This module was written by D.Skarda&T.Bily and modified by R.Suzuki.
|
|
* Ported to POV-Ray 3.5 by Thorsten Froehlich.
|
|
*
|
|
* ---------------------------------------------------------------------------
|
|
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
|
|
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
|
|
*
|
|
* POV-Ray is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* POV-Ray is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------------
|
|
* POV-Ray is based on the popular DKB raytracer version 2.12.
|
|
* DKBTrace was originally written by David K. Buck.
|
|
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
|
|
* ---------------------------------------------------------------------------
|
|
* $File: //depot/public/povray/3.x/source/backend/shape/fpmetric.cpp $
|
|
* $Revision: #1 $
|
|
* $Change: 6069 $
|
|
* $DateTime: 2013/11/06 11:59:40 $
|
|
* $Author: chrisc $
|
|
*******************************************************************************/
|
|
|
|
#include <limits.h>
|
|
#include <algorithm>
|
|
|
|
// frame.h must always be the first POV file included (pulls in platform config)
|
|
#include "backend/frame.h"
|
|
#include "backend/scene/objects.h"
|
|
#include "backend/scene/threaddata.h"
|
|
#include "backend/shape/fpmetric.h"
|
|
#include "backend/shape/spheres.h" // TODO - Move sphere intersection function to math code! [trf]
|
|
#include "backend/shape/boxes.h" // TODO - Move box intersection function to math code! [trf]
|
|
#include "backend/vm/fnpovfpu.h"
|
|
|
|
// this must be the last file included
|
|
#include "base/povdebug.h"
|
|
|
|
namespace pov
|
|
{
|
|
|
|
/*****************************************************************************
|
|
* Local preprocessor defines
|
|
******************************************************************************/
|
|
|
|
const int Max_intNumber = 10000000;
|
|
#define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
|
|
|
|
const int INDEX_U = 0;
|
|
const int INDEX_V = 1;
|
|
|
|
/* Side hit. */
|
|
const int SIDE_X_0 = 1;
|
|
const int SIDE_X_1 = 2;
|
|
const int SIDE_Y_0 = 3;
|
|
const int SIDE_Y_1 = 4;
|
|
const int SIDE_Z_0 = 5;
|
|
const int SIDE_Z_1 = 6;
|
|
|
|
const int OK_X = 1;
|
|
const int OK_Y = 2;
|
|
const int OK_Z = 4;
|
|
const int OK_R = 8;
|
|
const int OK_S = 16;
|
|
const int OK_T = 32;
|
|
const int OK_U = 64;
|
|
const int OK_V = 128;
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* All_Parametric_Intersections
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
bool Parametric::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
|
|
{
|
|
VECTOR P, D, IPoint;
|
|
UV_VECT low_vect, hi_vect, uv;
|
|
Ray New_Ray;
|
|
DBL XRayMin, XRayMax, YRayMin, YRayMax, ZRayMin, ZRayMax, TPotRes, TLen;
|
|
DBL Depth1, Depth2, temp, Len, TResult = HUGE_VAL;
|
|
DBL low, hi, len;
|
|
int MaxPrecompX, MaxPrecompY, MaxPrecompZ;
|
|
int split, i = 0, Side1, Side2;
|
|
int parX, parY;
|
|
int i_flg;
|
|
DBL Intervals_Low[2][32];
|
|
DBL Intervals_Hi[2][32];
|
|
int SectorNum[32];
|
|
|
|
Thread->Stats()[Ray_Par_Bound_Tests]++;
|
|
|
|
if(container_shape)
|
|
{
|
|
if(Trans != NULL)
|
|
{
|
|
MInvTransPoint(New_Ray.Origin, ray.Origin, Trans);
|
|
MInvTransDirection(New_Ray.Direction, ray.Direction, Trans);
|
|
VLength(len, New_Ray.Direction);
|
|
VInverseScaleEq(New_Ray.Direction, len);
|
|
i_flg = Sphere::Intersect(New_Ray, container.sphere.center,
|
|
(container.sphere.radius) * (container.sphere.radius),
|
|
&Depth1, &Depth2);
|
|
Depth1 = Depth1 / len;
|
|
Depth2 = Depth2 / len;
|
|
}
|
|
else
|
|
{
|
|
i_flg = Sphere::Intersect(ray, container.sphere.center,
|
|
(container.sphere.radius) * (container.sphere.radius), &Depth1, &Depth2);
|
|
}
|
|
Thread->Stats()[Ray_Sphere_Tests]--;
|
|
if(i_flg)
|
|
Thread->Stats()[Ray_Sphere_Tests_Succeeded]--;
|
|
}
|
|
else
|
|
{
|
|
i_flg = Box::Intersect(ray, Trans, container.box.corner1, container.box.corner2,
|
|
&Depth1, &Depth2, &Side1, &Side2);
|
|
}
|
|
|
|
if(!i_flg)
|
|
return false;
|
|
|
|
Thread->Stats()[Ray_Par_Bound_Tests_Succeeded]++;
|
|
Thread->Stats()[Ray_Parametric_Tests]++;
|
|
|
|
if (Trans != NULL)
|
|
{
|
|
MInvTransPoint(P, ray.Origin, Trans);
|
|
MInvTransDirection(D, ray.Direction, Trans);
|
|
}
|
|
else
|
|
{
|
|
P[X] = ray.Origin[X];
|
|
P[Y] = ray.Origin[Y];
|
|
P[Z] = ray.Origin[Z];
|
|
D[X] = ray.Direction[X];
|
|
D[Y] = ray.Direction[Y];
|
|
D[Z] = ray.Direction[Z];
|
|
}
|
|
|
|
if (Depth1 == Depth2)
|
|
Depth1 = 0;
|
|
|
|
if ((Depth1 += 4 * accuracy) > Depth2)
|
|
return false;
|
|
|
|
Intervals_Low[INDEX_U][0] = umin;
|
|
Intervals_Hi[INDEX_U][0] = umax;
|
|
|
|
Intervals_Low[INDEX_V][0] = vmin;
|
|
Intervals_Hi[INDEX_V][0] = vmax;
|
|
/* Fri 09-27-1996 0. */
|
|
SectorNum[0] = 1;
|
|
|
|
MaxPrecompX = MaxPrecompY = MaxPrecompZ = 0;
|
|
if (PData != NULL)
|
|
{
|
|
if (((PData->flags) & OK_X) != 0)
|
|
MaxPrecompX = 1 << (PData->depth);
|
|
if (((PData->flags) & OK_Y) != 0)
|
|
MaxPrecompY = 1 << (PData->depth);
|
|
if (((PData->flags) & OK_Z) != 0)
|
|
MaxPrecompZ = 1 << (PData->depth);
|
|
}
|
|
/* 0 */
|
|
while (i >= 0)
|
|
{
|
|
low_vect[U] = Intervals_Low[INDEX_U][i];
|
|
hi_vect[U] = Intervals_Hi[INDEX_U][i];
|
|
Len = hi_vect[U] - low_vect[U];
|
|
split = INDEX_U;
|
|
|
|
low_vect[V] = Intervals_Low[INDEX_V][i];
|
|
hi_vect[V] = Intervals_Hi[INDEX_V][i];
|
|
temp = hi_vect[V] - low_vect[V];
|
|
if (temp > Len)
|
|
{
|
|
Len = temp;
|
|
split = INDEX_V;
|
|
}
|
|
parX = parY = 0;
|
|
TLen = 0;
|
|
|
|
/* X */
|
|
if (SectorNum[i] < MaxPrecompX)
|
|
{
|
|
low = PData->Low[0][SectorNum[i]];
|
|
hi = PData->Hi[0][SectorNum[i]];
|
|
}
|
|
else
|
|
Evaluate_Function_Interval_UV(Thread->functionContext, *(Function[0]), accuracy, low_vect, hi_vect, max_gradient, low, hi);
|
|
/* fabs(D[X] *(T2-T1)) is not OK with new method */
|
|
|
|
if (close(D[0], 0))
|
|
{
|
|
parX = 1;
|
|
if ((hi < P[0]) || (low > P[0]))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
XRayMin = (hi - P[0]) / D[0];
|
|
XRayMax = (low - P[0]) / D[0];
|
|
if (XRayMin > XRayMax)
|
|
{
|
|
temp = XRayMin;
|
|
XRayMin = XRayMax;
|
|
XRayMax = temp;
|
|
}
|
|
|
|
if ((XRayMin > Depth2) || (XRayMax < Depth1))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
if ((TPotRes = XRayMin) > TResult)
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
|
|
TLen = XRayMax - XRayMin;
|
|
}
|
|
|
|
/* Y */
|
|
if (SectorNum[i] < MaxPrecompY)
|
|
{
|
|
low = PData->Low[1][SectorNum[i]];
|
|
hi = PData->Hi[1][SectorNum[i]];
|
|
}
|
|
else
|
|
Evaluate_Function_Interval_UV(Thread->functionContext, *(Function[1]), accuracy, low_vect, hi_vect, max_gradient, low, hi);
|
|
|
|
if (close(D[1], 0))
|
|
{
|
|
parY = 1;
|
|
if ((hi < P[1]) || (low > P[1]))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
YRayMin = (hi - P[1]) / D[1];
|
|
YRayMax = (low - P[1]) / D[1];
|
|
if (YRayMin > YRayMax)
|
|
{
|
|
temp = YRayMin;
|
|
YRayMin = YRayMax;
|
|
YRayMax = temp;
|
|
}
|
|
if ((YRayMin > Depth2) || (YRayMax < Depth1))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
if ((TPotRes = YRayMin) > TResult)
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
if (parX == 0)
|
|
{
|
|
if ((YRayMin > XRayMax) || (YRayMax < XRayMin))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
if ((temp = YRayMax - YRayMin) > TLen)
|
|
TLen = temp;
|
|
}
|
|
|
|
/* Z */
|
|
if ((SectorNum[i] < MaxPrecompZ) && (0 < SectorNum[i]))
|
|
{
|
|
low = PData->Low[2][SectorNum[i]];
|
|
hi = PData->Hi[2][SectorNum[i]];
|
|
}
|
|
else
|
|
Evaluate_Function_Interval_UV(Thread->functionContext, *(Function[2]), accuracy, low_vect, hi_vect, max_gradient, low, hi);
|
|
|
|
if (close(D[2], 0))
|
|
{
|
|
if ((hi < P[2]) || (low > P[2]))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ZRayMin = (hi - P[2]) / D[2];
|
|
ZRayMax = (low - P[2]) / D[2];
|
|
if (ZRayMin > ZRayMax)
|
|
{
|
|
temp = ZRayMin;
|
|
ZRayMin = ZRayMax;
|
|
ZRayMax = temp;
|
|
}
|
|
if ((ZRayMin > Depth2) || (ZRayMax < Depth1))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
if ((TPotRes = ZRayMin) > TResult)
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
if (parX == 0)
|
|
{
|
|
if ((ZRayMin > XRayMax) || (ZRayMax < XRayMin))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
if (parY == 0)
|
|
{
|
|
if ((ZRayMin > YRayMax) || (ZRayMax < YRayMin))
|
|
{
|
|
i--;
|
|
continue;
|
|
}
|
|
}
|
|
if ((temp = ZRayMax - ZRayMin) > TLen)
|
|
TLen = temp;
|
|
}
|
|
|
|
if (Len > TLen)
|
|
Len = TLen;
|
|
if (Len < accuracy)
|
|
{
|
|
if ((TResult > TPotRes) && (TPotRes > Depth1))
|
|
{
|
|
TResult = TPotRes;
|
|
Assign_UV_Vect(uv, low_vect);
|
|
}
|
|
i--;
|
|
}
|
|
else
|
|
{
|
|
/* 1 copy */
|
|
if ((SectorNum[i] *= 2) >= Max_intNumber)
|
|
SectorNum[i] = Max_intNumber;
|
|
SectorNum[i + 1] = SectorNum[i];
|
|
SectorNum[i]++;
|
|
i++;
|
|
Intervals_Low[INDEX_U][i] = low_vect[U];
|
|
Intervals_Hi[INDEX_U][i] = hi_vect[U];
|
|
|
|
Intervals_Low[INDEX_V][i] = low_vect[V];
|
|
Intervals_Hi[INDEX_V][i] = hi_vect[V];
|
|
|
|
/* 2 split */
|
|
temp = (Intervals_Hi[split][i] + Intervals_Low[split][i]) / 2.0;
|
|
Intervals_Hi[split][i] = temp;
|
|
Intervals_Low[split][i - 1] = temp;
|
|
}
|
|
}
|
|
|
|
if (TResult < Depth2)
|
|
{
|
|
Thread->Stats()[Ray_Parametric_Tests_Succeeded]++;
|
|
VScale(IPoint, ray.Direction, TResult);
|
|
VAddEq(IPoint, ray.Origin);
|
|
|
|
if (Clip.empty() || Point_In_Clip(IPoint, Clip, Thread))
|
|
{
|
|
/*
|
|
compute_param_normal( Par, UResult, VResult , &N);
|
|
push_normal_entry( TResult ,IPoint, N, (ObjectPtr ) Object, Depth_Stack);
|
|
*/
|
|
Depth_Stack->push(Intersection(TResult, IPoint, uv, this));
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
/* 0 */
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Inside_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
bool Parametric::Inside(const VECTOR, TraceThreadData *Thread) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parametric_Normal
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Normal(VECTOR Result, Intersection *Inter, TraceThreadData *Thread) const
|
|
{
|
|
VECTOR RU, RV;
|
|
UV_VECT uv_vect;
|
|
|
|
uv_vect[U] = Inter->Iuv[U];
|
|
uv_vect[V] = Inter->Iuv[V];
|
|
RU[X] = RV[X] = -Evaluate_Function_UV(Thread->functionContext, *(Function[X]), uv_vect);
|
|
RU[Y] = RV[Y] = -Evaluate_Function_UV(Thread->functionContext, *(Function[Y]), uv_vect);
|
|
RU[Z] = RV[Z] = -Evaluate_Function_UV(Thread->functionContext, *(Function[Z]), uv_vect);
|
|
|
|
uv_vect[U] += accuracy;
|
|
RU[X] += Evaluate_Function_UV(Thread->functionContext, *(Function[X]), uv_vect);
|
|
RU[Y] += Evaluate_Function_UV(Thread->functionContext, *(Function[Y]), uv_vect);
|
|
RU[Z] += Evaluate_Function_UV(Thread->functionContext, *(Function[Z]), uv_vect);
|
|
|
|
uv_vect[U] = Inter->Iuv[U];
|
|
uv_vect[V] += accuracy;
|
|
RV[X] += Evaluate_Function_UV(Thread->functionContext, *(Function[X]), uv_vect);
|
|
RV[Y] += Evaluate_Function_UV(Thread->functionContext, *(Function[Y]), uv_vect);
|
|
RV[Z] += Evaluate_Function_UV(Thread->functionContext, *(Function[Z]), uv_vect);
|
|
|
|
VCross(Result, RU, RV);
|
|
if (Trans != NULL)
|
|
MTransNormal(Result, Result, Trans);
|
|
VNormalize(Result, Result);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Compute_Parametric_BBox
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Compute_BBox()
|
|
{
|
|
if(container_shape != 0)
|
|
{
|
|
Make_BBox(BBox,
|
|
container.sphere.center[X] - container.sphere.radius,
|
|
container.sphere.center[Y] - container.sphere.radius,
|
|
container.sphere.center[Z] - container.sphere.radius,
|
|
container.sphere.radius * 2,
|
|
container.sphere.radius * 2,
|
|
container.sphere.radius * 2);
|
|
}
|
|
else
|
|
{
|
|
// [ABX 20.01.2004] Low_Left introduced to hide BCC 5.5 bug
|
|
BBOX_VECT& Low_Left = BBox.Lower_Left;
|
|
|
|
Assign_BBox_Vect(Low_Left, container.box.corner1);
|
|
VSub(BBox.Lengths, container.box.corner2, container.box.corner1);
|
|
}
|
|
|
|
if(Trans != NULL)
|
|
{
|
|
Recompute_BBox(&BBox, Trans);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Translate_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Translate(const VECTOR, const TRANSFORM* tr)
|
|
{
|
|
Transform(tr);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Rotate_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Rotate(const VECTOR, const TRANSFORM* tr)
|
|
{
|
|
Transform(tr);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Scale_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Scale(const VECTOR, const TRANSFORM* tr)
|
|
{
|
|
Transform(tr);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Transform_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Transform(const TRANSFORM* tr)
|
|
{
|
|
if(Trans == NULL)
|
|
Trans = Create_Transform();
|
|
Compose_Transforms(Trans, tr);
|
|
Compute_BBox();
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Invert_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Invert()
|
|
{
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Copy_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
ObjectPtr Parametric::Copy()
|
|
{
|
|
Parametric *New = new Parametric();
|
|
Destroy_Transform(New->Trans);
|
|
*New = *this;
|
|
|
|
New->Function[0] = Parser::Copy_Function(vm, Function[0]);
|
|
New->Function[1] = Parser::Copy_Function(vm, Function[1]);
|
|
New->Function[2] = Parser::Copy_Function(vm, Function[2]);
|
|
New->Trans = Copy_Transform(Trans);
|
|
New->PData = Copy_PrecompParVal();
|
|
|
|
return (New);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Destroy_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
Parametric::~Parametric()
|
|
{
|
|
Destroy_Transform(Trans);
|
|
Parser::Destroy_Function(vm, Function[0]);
|
|
Parser::Destroy_Function(vm, Function[1]);
|
|
Parser::Destroy_Function(vm, Function[2]);
|
|
Destroy_PrecompParVal();
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Create_Parametric
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
Parametric::Parametric() : ObjectBase(PARAMETRIC_OBJECT)
|
|
{
|
|
Make_Vector(container.box.corner1, -1.0, -1.0, -1.0);
|
|
Make_Vector(container.box.corner2, 1.0, 1.0, 1.0);
|
|
|
|
Make_BBox(BBox, -1.0, -1.0, -1.0, 2.0, 2.0, 2.0);
|
|
|
|
Trans = Create_Transform();
|
|
|
|
Function[0] = NULL;
|
|
Function[1] = NULL;
|
|
Function[2] = NULL;
|
|
accuracy = 0.001;
|
|
max_gradient = 1;
|
|
Inverted = false;
|
|
PData = NULL;
|
|
container_shape = 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Parametric_UVCoord
|
|
*
|
|
* INPUT
|
|
*
|
|
* As for all UVCoord methods object and interstcion structure
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* As for all UVCoord methods 2D vector with UV coordinates
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Wlodzimierz ABX Skiba
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::UVCoord(UV_VECT Result, const Intersection *inter, TraceThreadData *Thread) const
|
|
{
|
|
Assign_UV_Vect(Result, inter->Iuv);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Precomp_Par_Int
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Precomp_Par_Int(int depth, DBL umin, DBL vmin, DBL umax, DBL vmax, FPUContext *ctx)
|
|
{
|
|
int j;
|
|
|
|
if(depth >= PrecompLastDepth)
|
|
{
|
|
for(j = 0; j < 3; j++)
|
|
{
|
|
if(PData->flags & (1 << j))
|
|
{
|
|
UV_VECT low,hi;
|
|
|
|
low[U] = umin;
|
|
hi[U] = umax;
|
|
low[V] = vmin;
|
|
hi[V] = vmax;
|
|
|
|
Evaluate_Function_Interval_UV(ctx,
|
|
*Function[j],
|
|
accuracy,
|
|
low,
|
|
hi,
|
|
max_gradient,
|
|
PData->Low[j][depth],
|
|
PData->Hi[j][depth]);
|
|
}
|
|
}
|
|
}
|
|
else /* split */
|
|
{
|
|
if(umax - umin < vmax - vmin)
|
|
{
|
|
Precomp_Par_Int(2 * depth, umin, vmin, umax, (vmin + vmax) / 2.0, ctx);
|
|
Precomp_Par_Int(2 * depth + 1, umin, (vmin + vmax) / 2.0, umax, vmax, ctx);
|
|
}
|
|
else
|
|
{
|
|
Precomp_Par_Int(2 * depth, umin, vmin, (umin + umax) / 2.0, vmax, ctx);
|
|
Precomp_Par_Int(2 * depth + 1, (umin + umax) / 2.0, vmin, umax, vmax, ctx);
|
|
}
|
|
for(j = 0; j < 3; j++)
|
|
{
|
|
if(PData->flags & (1 << j))
|
|
{
|
|
if(PData->Hi[j][2 * depth] > PData->Hi[j][2 * depth + 1])
|
|
PData->Hi[j][depth] = PData->Hi[j][2 * depth];
|
|
else
|
|
PData->Hi[j][depth] = PData->Hi[j][2 * depth + 1];
|
|
if(PData->Low[j][2 * depth] < PData->Low[j][2 * depth + 1])
|
|
PData->Low[j][depth] = PData->Low[j][2 * depth];
|
|
else
|
|
PData->Low[j][depth] = PData->Low[j][2 * depth + 1];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Precompute_Parametric_Values
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Precompute_Parametric_Values(char flags, int depth, FPUContext *ctx)
|
|
{
|
|
DBL * Last;
|
|
const char* es = "precompute";
|
|
int nmb;
|
|
|
|
if ((depth < 1) || (depth > 20))
|
|
throw POV_EXCEPTION_STRING("Precompute: invalid depth");
|
|
nmb = 1 << depth;
|
|
|
|
PData = (PRECOMP_PAR_DATA *)POV_MALLOC(sizeof(PRECOMP_PAR_DATA), es);
|
|
if (PData == NULL)
|
|
throw POV_EXCEPTION_STRING("Cannot allocate memory for parametric precomputation data.");
|
|
PData->flags = flags;
|
|
PData->depth = depth;
|
|
PData->use = 1;
|
|
|
|
if (flags & OK_X)
|
|
{
|
|
PData->Low[0] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
|
|
Last = PData->Hi[0] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
|
|
}
|
|
if (flags & OK_Y)
|
|
{
|
|
PData->Low[1] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
|
|
Last = PData->Hi[1] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
|
|
}
|
|
if (flags & OK_Z)
|
|
{
|
|
PData->Low[2] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
|
|
Last = PData->Hi[2] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
|
|
}
|
|
if (Last == NULL)
|
|
throw POV_EXCEPTION_STRING("Cannot allocate memory for parametric precomputation data.");
|
|
|
|
PrecompLastDepth = 1 << (depth - 1);
|
|
Precomp_Par_Int(1, umin, vmin, umax, vmax, ctx);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Copy_PrecompParVal
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
PRECOMP_PAR_DATA* Parametric::Copy_PrecompParVal()
|
|
{
|
|
if (PData == NULL)
|
|
return NULL;
|
|
|
|
(PData->use)++;
|
|
|
|
return (PData);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Destroy_PrecompParVal
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Destroy_PrecompParVal()
|
|
{
|
|
if (PData == NULL)
|
|
return;
|
|
|
|
PData->use--;
|
|
if (PData->use == 0)
|
|
{
|
|
if (PData->flags & OK_X)
|
|
{
|
|
POV_FREE(PData->Low[0]);
|
|
POV_FREE(PData->Hi[0]);
|
|
}
|
|
if (PData->flags & OK_Y)
|
|
{
|
|
POV_FREE(PData->Low[1]);
|
|
POV_FREE(PData->Hi[1]);
|
|
}
|
|
if (PData->flags & OK_Z)
|
|
{
|
|
POV_FREE(PData->Low[2]);
|
|
POV_FREE(PData->Hi[2]);
|
|
}
|
|
POV_FREE(PData);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Evaluate_Function
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
DBL Parametric::Evaluate_Function_UV(FPUContext *ctx, FUNCTION funct, const UV_VECT fnvec)
|
|
{
|
|
ctx->SetLocal(U, fnvec[U]);
|
|
ctx->SetLocal(V, fnvec[V]);
|
|
|
|
return POVFPU_Run(ctx, funct);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Interval
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* Ron Parker
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* Assume that the function attains its maximum gradient over the whole
|
|
* range and determine its minimum and maximum (really lower and upper
|
|
* bounds, not strict maxima and minima) accordingly.
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Interval(DBL dx, DBL a, DBL b, DBL max_gradient, DBL *Min, DBL *Max)
|
|
{
|
|
DBL dy = fabs(a-b);
|
|
DBL ofs = max_gradient*(dx-dy/max_gradient)/2;
|
|
if ( ofs < 0 ) {
|
|
ofs=0;
|
|
}
|
|
*Max = max(a,b)+ofs;
|
|
*Min = min(a,b)-ofs;
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* Evaluate_Function_Interval
|
|
*
|
|
* INPUT
|
|
*
|
|
* OUTPUT
|
|
*
|
|
* RETURNS
|
|
*
|
|
* AUTHOR
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
* -
|
|
*
|
|
* CHANGES
|
|
*
|
|
* -
|
|
*
|
|
******************************************************************************/
|
|
|
|
void Parametric::Evaluate_Function_Interval_UV(FPUContext *ctx, FUNCTION funct, DBL threshold, const UV_VECT fnvec_low, const UV_VECT fnvec_hi, DBL max_gradient, DBL& low, DBL& hi)
|
|
{
|
|
DBL f_0_0, f_0_1, f_1_0, f_1_1;
|
|
DBL f_0_min, f_0_max;
|
|
DBL f_1_min, f_1_max;
|
|
DBL junk;
|
|
|
|
/* Calculate the values at each corner */
|
|
ctx->SetLocal(U, fnvec_low[U]);
|
|
ctx->SetLocal(V, fnvec_low[V]);
|
|
|
|
f_0_0 = POVFPU_Run(ctx, funct) - threshold;
|
|
|
|
ctx->SetLocal(U, fnvec_low[U]);
|
|
ctx->SetLocal(V, fnvec_hi[V]);
|
|
|
|
f_0_1 = POVFPU_Run(ctx, funct) - threshold;
|
|
|
|
ctx->SetLocal(U, fnvec_hi[U]);
|
|
ctx->SetLocal(V, fnvec_low[V]);
|
|
|
|
f_1_0 = POVFPU_Run(ctx, funct) - threshold;
|
|
|
|
ctx->SetLocal(U, fnvec_hi[U]);
|
|
ctx->SetLocal(V, fnvec_hi[V]);
|
|
|
|
f_1_1 = POVFPU_Run(ctx, funct) - threshold;
|
|
|
|
/* Determine a min and a max along the left edge of the patch */
|
|
Interval( fnvec_hi[V]-fnvec_low[V], f_0_0, f_0_1, max_gradient, &f_0_min, &f_0_max);
|
|
|
|
/* Determine a min and a max along the right edge of the patch */
|
|
Interval( fnvec_hi[V]-fnvec_low[V], f_1_0, f_1_1, max_gradient, &f_1_min, &f_1_max);
|
|
|
|
/* Assume that the upper bounds of both edges are attained at the same
|
|
u coordinate and determine what an upper bound along that line would
|
|
be if it existed. That's the worst-case maximum value we can reach. */
|
|
Interval( fnvec_hi[U]-fnvec_low[U], f_0_max, f_1_max, max_gradient, &junk, &hi);
|
|
|
|
/* same as above to get a lower bound from the two edge lower bounds */
|
|
Interval( fnvec_hi[U]-fnvec_low[U], f_0_min, f_1_min, max_gradient, &low, &junk);
|
|
|
|
/*
|
|
char str[200];
|
|
int its=0;
|
|
its++;
|
|
if (its>20) Error("Boom!");
|
|
sprintf( str, "%lf %lf %lf %lf %lf %lf %lf\n%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
|
|
max_gradient,
|
|
fnvec_low[U], fnvec_low[V],
|
|
fnvec_hi[U], fnvec_hi[V],
|
|
fnvec_hi[U]-fnvec_low[U],
|
|
fnvec_hi[V]-fnvec_low[V],
|
|
|
|
f_0_0,f_0_1,f_1_0,f_1_1,
|
|
f_0_min,f_0_max,
|
|
f_1_min,f_1_max,
|
|
low,hi);
|
|
Warning( 0, str );
|
|
*/
|
|
/* f_min and f_max now contain the maximum interval. */
|
|
}
|
|
|
|
}
|