povray/source/backend/pattern/pattern.cpp
Campbell Barton b3846f5723 quiet compiler warnings building with gcc and clang.
- define variables and functions as static when not declared by headers.
- remove some unused defines.
- other minor changes to quiet warnings.
2013-11-17 07:34:00 +11:00

8897 lines
193 KiB
C++

/*******************************************************************************
* pattern.cpp
*
* This module implements texturing functions that return a value to be
* used in a pigment or normal.
*
* ---------------------------------------------------------------------------
* 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/pattern/pattern.cpp $
* $Revision: #1 $
* $Change: 6069 $
* $DateTime: 2013/11/06 11:59:40 $
* $Author: chrisc $
*******************************************************************************/
/*
* Some texture ideas garnered from SIGGRAPH '85 Volume 19 Number 3,
* "An Image Synthesizer" By Ken Perlin.
* Further Ideas Garnered from "The RenderMan Companion" (Addison Wesley).
*/
// frame.h must always be the first POV file included (pulls in platform config)
#include "backend/frame.h"
#include "backend/pattern/pattern.h"
#include "backend/texture/texture.h"
#include "backend/texture/pigment.h"
#include "backend/scene/objects.h"
#include "backend/scene/scene.h"
#include "backend/support/imageutil.h"
#include "backend/colour/colour.h"
#include "backend/parser/parse.h"
#include "backend/math/vector.h"
#include "backend/math/matrices.h"
#include "backend/vm/fnpovfpu.h"
#include "backend/support/fileutil.h"
#include "base/fileinputoutput.h"
#include <algorithm>
#include <climits>
// this must be the last file included
#include "base/povdebug.h"
namespace pov
{
using namespace pov_base;
/*****************************************************************************
* Local preprocessor defines
******************************************************************************/
#define CLIP_DENSITY(r) { if((r) < 0.0) { (r) = 1.0; } else if((r) > 1.0) { (r) = 0.0; } else { (r) = 1.0 - (r); } }
const int FRACTAL_MAX_EXPONENT = 33;
/*****************************************************************************
* Local variables
******************************************************************************/
static RandomDoubleSequence PatternRands(0.0, 1.0, 32768);
static int BinomialCoefficients[((FRACTAL_MAX_EXPONENT+1)*(FRACTAL_MAX_EXPONENT+2))/2]; // GLOBAL VARIABLE
boost::hash<Crackle_Cell_Coord> Crackle_Cell_Hasher;
static int CrackleCubeTable[81*3];
/*****************************************************************************
* Static functions
******************************************************************************/
static DBL agate_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator);
static DBL boxed_pattern (const VECTOR EPoint);
static DBL brick_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL cells_pattern (const VECTOR EPoint);
static DBL checker_pattern (const VECTOR EPoint);
static DBL crackle_pattern (const VECTOR EPoint, const TPATTERN *TPat, TraceThreadData *Thread);
static DBL cylindrical_pattern (const VECTOR EPoint);
static DBL dents_pattern (const VECTOR EPoint, int noise_generator);
static DBL density_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL function_pattern (const VECTOR EPoint, const TPATTERN *TPat, TraceThreadData *Thread);
static DBL gradient_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL granite_pattern (const VECTOR EPoint, int noise_generator);
static DBL hexagon_pattern (const VECTOR EPoint);
static DBL square_pattern (const VECTOR EPoint);
static DBL triangular_pattern (const VECTOR EPoint);
static DBL cubic_pattern (const VECTOR EPoint);
static DBL julia_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL julia3_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL julia4_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL juliax_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL leopard_pattern (const VECTOR EPoint);
static DBL magnet1m_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL magnet1j_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL magnet2m_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL magnet2j_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL mandel_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL mandel3_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL mandel4_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL mandelx_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL marble_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator);
static DBL object_pattern (const VECTOR EPoint, const TPATTERN *TPat, TraceThreadData *Thread);
static DBL onion_pattern (const VECTOR EPoint);
static DBL pavement_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL pigment_pattern (const VECTOR EPoint, const TPATTERN *TPat, const Intersection *isect, const Ray *ray, TraceThreadData *Thread);
static DBL planar_pattern (const VECTOR EPoint);
static DBL quilted_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL radial_pattern (const VECTOR EPoint);
static DBL ripples_pattern (const VECTOR EPoint, const TPATTERN *TPat, const TraceThreadData *Thread);
static DBL slope_pattern (const VECTOR EPoint, const TPATTERN *TPat, const Intersection *Intersection);
static DBL aoi_pattern (const Intersection *Intersection, const Ray *ray);
static DBL spiral1_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator);
static DBL spiral2_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator);
static DBL spherical_pattern (const VECTOR EPoint);
static DBL tiling_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL waves_pattern (const VECTOR EPoint, const TPATTERN *TPat, const TraceThreadData *Thread);
static DBL wood_pattern (const VECTOR EPoint, const TPATTERN *TPat);
static DBL wrinkles_pattern (const VECTOR EPoint, int noise_generator);
static DBL fractal_exterior_color(const TPATTERN *TPat, int iters, DBL a, DBL b);
static DBL fractal_interior_color(const TPATTERN *TPat, int iters, DBL a, DBL b, DBL mindist2);
static const TURB *Search_For_Turb(const WARP *Warps);
static unsigned short readushort(IStream *infile);
static unsigned int readuint(IStream *infile);
#define SQRT3_2 0.86602540378443864676372317075294 ///< sqrt(3)/2
#define SQRT3 1.7320508075688772935274463415059 ///< sqrt(3)
#define SQRT2 1.4142135623730950488016887242097 ///< sqrt(2)
#define SQRT2_2 0.70710678118654752440084436210485 ///< sqrt(2)/2
#define SIN18 0.30901699437494742410229341718282 ///< sin(18 deg)
#define SIN36 0.58778525229247312916870595463907 ///< sin(36 deg)
#define SIN54 0.80901699437494742410229341718282 ///< sin(54 deg)
#define SIN72 0.95105651629515357211643933337938 ///< sin(72 deg)
#define SIN108 SIN72 ///< sin(108 deg)
#define SIN144 SIN36 ///< sin(144 deg)
#define SIN162 SIN18 ///< sin(162 deg)
#define COS18 SIN72 ///< cos(18 deg)
#define COS36 SIN54 ///< cos(36 deg)
#define COS54 SIN36 ///< cos(54 deg)
#define COS72 SIN18 ///< cos(72 deg)
#define COS108 (-COS72) ///< cos(108 deg)
#define COS126 (-COS54) ///< cos(126 deg)
#define COS144 (-COS36) ///< cos(144 deg)
#define COS162 (-COS18) ///< cos(162 deg)
#define TAN18 0.32491969623290632615587141221513 ///< tan(18 deg)
#define TAN36 0.72654252800536088589546675748062 ///< tan(36 deg)
#define TAN54 1.3763819204711735382072095819109 ///< tan(54 deg)
#define TAN72 3.0776835371752534025702905760369 ///< tan(72 deg)
#define TAN108 (-TAN72) ///< tan(108 deg)
#define TAN126 (-TAN54) ///< tan(126 deg)
#define TAN144 (-TAN36) ///< tan(144 deg)
#define TAN162 (-TAN18) ///< tan(162 deg)
#define PHI 1.6180339887498948482045868343656 ///< golden ratio = (1+sqrt(5))/2
#define INVPHI 0.61803398874989484820458683436564 ///< inverse of golden ratio (= golden ratio -1)
#define SQRPHI 2.6180339887498948482045868343656 ///< square of golden ratio (= golden ratio +1)
#define INVSQRPHI 0.38196601125010515179541316563436 ///< inverse square of golden ratio (= 2 - golden ratio)
#define TILING_EPSILON 1e-6
/*****************************************************************************/
int GetNoiseGen (const TPATTERN *TPat, const TraceThreadData *Thread)
{
int noise_gen = (TPat->Flags & NOISE_FLAGS) / NOISE_FLAG_1;
if (!noise_gen)
noise_gen = Thread->GetSceneData()->noiseGenerator;
return noise_gen;
}
/*****************************************************************************
*
* FUNCTION
*
* Evaluate_Pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
* Intersection - intersection structure
*
* OUTPUT
*
* RETURNS
*
* DBL result usual 0.0 to 1.0 but may be 2.0 in hexagon
*
* AUTHOR
*
* Adapted from Add_Pigment by Chris Young
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
DBL Evaluate_TPat (const TPATTERN *TPat, const VECTOR EPoint, const Intersection *Isection, const Ray *ray, TraceThreadData *Thread)
{
DBL value = 0.0;
/* NK 19 Nov 1999 removed Warp_EPoint call */
switch(TPat->Type)
{
case AGATE_PATTERN: value = agate_pattern (EPoint, TPat, GetNoiseGen(TPat, Thread)); break;
case BOZO_PATTERN:
case SPOTTED_PATTERN:
case BUMPS_PATTERN: value = Noise (EPoint, GetNoiseGen(TPat, Thread)); break;
case BRICK_PATTERN: value = brick_pattern (EPoint, TPat); break;
case CELLS_PATTERN: value = cells_pattern (EPoint); break;
case CHECKER_PATTERN: value = checker_pattern (EPoint); break;
case CRACKLE_PATTERN: value = crackle_pattern (EPoint, TPat, Thread); break;
case GRADIENT_PATTERN: value = gradient_pattern (EPoint, TPat); break;
case GRANITE_PATTERN: value = granite_pattern (EPoint, GetNoiseGen(TPat, Thread)); break;
case HEXAGON_PATTERN: value = hexagon_pattern (EPoint); break;
case SQUARE_PATTERN: value = square_pattern (EPoint); break;
case TRIANGULAR_PATTERN: value = triangular_pattern (EPoint); break;
case CUBIC_PATTERN: value = cubic_pattern (EPoint); break;
case JULIA_PATTERN: value = julia_pattern (EPoint, TPat); break;
case JULIA3_PATTERN: value = julia3_pattern (EPoint, TPat); break;
case JULIA4_PATTERN: value = julia4_pattern (EPoint, TPat); break;
case JULIAX_PATTERN: value = juliax_pattern (EPoint, TPat); break;
case LEOPARD_PATTERN: value = leopard_pattern (EPoint); break;
case MAGNET1M_PATTERN: value = magnet1m_pattern (EPoint, TPat); break;
case MAGNET1J_PATTERN: value = magnet1j_pattern (EPoint, TPat); break;
case MAGNET2M_PATTERN: value = magnet2m_pattern (EPoint, TPat); break;
case MAGNET2J_PATTERN: value = magnet2j_pattern (EPoint, TPat); break;
case MANDEL_PATTERN: value = mandel_pattern (EPoint, TPat); break;
case MANDEL3_PATTERN: value = mandel3_pattern (EPoint, TPat); break;
case MANDEL4_PATTERN: value = mandel4_pattern (EPoint, TPat); break;
case MANDELX_PATTERN: value = mandelx_pattern (EPoint, TPat); break;
case MARBLE_PATTERN: value = marble_pattern (EPoint, TPat, GetNoiseGen(TPat, Thread)); break;
case ONION_PATTERN: value = onion_pattern (EPoint); break;
case RADIAL_PATTERN: value = radial_pattern (EPoint); break;
case SPIRAL1_PATTERN: value = spiral1_pattern (EPoint, TPat, GetNoiseGen(TPat, Thread)); break;
case SPIRAL2_PATTERN: value = spiral2_pattern (EPoint, TPat, GetNoiseGen(TPat, Thread)); break;
case WOOD_PATTERN: value = wood_pattern (EPoint, TPat); break;
case WAVES_PATTERN: value = waves_pattern (EPoint, TPat, Thread); break;
case RIPPLES_PATTERN: value = ripples_pattern (EPoint, TPat, Thread); break;
case WRINKLES_PATTERN: value = wrinkles_pattern (EPoint, GetNoiseGen(TPat, Thread)); break;
case DENTS_PATTERN: value = dents_pattern (EPoint, GetNoiseGen(TPat, Thread)); break;
case QUILTED_PATTERN: value = quilted_pattern (EPoint, TPat); break;
case FUNCTION_PATTERN: value = function_pattern (EPoint, TPat, Thread); break;
case PLANAR_PATTERN: value = planar_pattern (EPoint); break;
case BOXED_PATTERN: value = boxed_pattern (EPoint); break;
case SPHERICAL_PATTERN: value = spherical_pattern (EPoint); break;
case CYLINDRICAL_PATTERN: value = cylindrical_pattern(EPoint); break;
case DENSITY_FILE_PATTERN:value = density_pattern (EPoint, TPat); break;
case IMAGE_PATTERN: value = image_pattern (EPoint, TPat); break;
case SLOPE_PATTERN: value = slope_pattern (EPoint, TPat, Isection); break;
case AOI_PATTERN: value = aoi_pattern (Isection, ray); break;
case PAVEMENT_PATTERN: value = pavement_pattern (EPoint, TPat); break;
case TILING_PATTERN: value = tiling_pattern (EPoint, TPat); break;
case PIGMENT_PATTERN: value = pigment_pattern (EPoint, TPat, Isection, ray, Thread); break;
case OBJECT_PATTERN: value = object_pattern (EPoint, TPat, Thread); break;
default: throw POV_EXCEPTION_STRING("Problem in Evaluate_TPat.");
}
if(TPat->Frequency != 0.0)
value = fmod(value * TPat->Frequency + TPat->Phase, 1.00001); // TODO FIXME - magic number! Should be 1.0+SOME_EPSILON (or maybe actually 1.0?)
/* allow negative Frequency */
if(value < 0.0)
value -= floor(value);
switch(TPat->Wave_Type)
{
case RAMP_WAVE:
break;
case SINE_WAVE:
value = (1.0 + cycloidal(value)) * 0.5;
break;
case TRIANGLE_WAVE:
value = Triangle_Wave(value);
break;
case SCALLOP_WAVE:
value = fabs(cycloidal(value * 0.5));
break;
case CUBIC_WAVE:
value = Sqr(value) * ((-2.0 * value) + 3.0);
break;
case POLY_WAVE:
value = pow(value, (DBL) TPat->Exponent);
break;
default:
throw POV_EXCEPTION_STRING("Unknown Wave Type.");
}
return value;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Init_TPat_Fields (TPATTERN *Tpat)
{
Tpat->Type = NO_PATTERN;
Tpat->Wave_Type = RAMP_WAVE;
Tpat->Flags = NO_FLAGS;
Tpat->References = 1;
Tpat->Exponent = 1.0;
Tpat->Frequency = 1.0;
Tpat->Phase = 0.0;
Tpat->Warps = NULL;
Tpat->Next = NULL;
Tpat->Blend_Map = NULL;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Copy_TPat_Fields (TPATTERN *New, const TPATTERN *Old)
{
*New = *Old;
/* Copy warp chain */
New->Warps = Copy_Warps(Old->Warps);
New->Blend_Map = Copy_Blend_Map(Old->Blend_Map);
/* Note, cannot copy Old->Next because we don't know what kind of
thing this is. It must be copied by Copy_Pigment, Copy_Tnormal etc.
*/
/* NK 1998 - added IMAGE_PATTERN */
if ((Old->Type == BITMAP_PATTERN) || (Old->Type == IMAGE_PATTERN))
{
New->Vals.image = Copy_Image(Old->Vals.image);
}
if (Old->Type == DENSITY_FILE_PATTERN)
{
New->Vals.Density_File = Copy_Density_File(Old->Vals.Density_File);
}
if (Old->Type == PIGMENT_PATTERN )
{
New->Vals.Pigment = Copy_Pigment(Old->Vals.Pigment);
}
if (Old->Type == OBJECT_PATTERN)
{
if(Old->Vals.Object != NULL)
{
New->Vals.Object = reinterpret_cast<ObjectPtr>(Copy_Object(Old->Vals.Object));
}
}
if (Old->Type == FUNCTION_PATTERN)
{
if (Old->Vals.Function.Fn != NULL)
{
New->Vals.Function.Fn = reinterpret_cast<void *>(Parser::Copy_Function( Old->Vals.Function.vm, (FUNCTION_PTR)(Old->Vals.Function.Fn) ));
}
}
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Destroy_TPat_Fields(TPATTERN *Tpat)
{
Destroy_Warps(Tpat->Warps);
Destroy_Blend_Map(Tpat->Blend_Map);
/* Note, cannot destroy Tpat->Next nor pattern itself because we don't
know what kind of thing this is. It must be destroied by Destroy_Pigment, etc.
*/
if ((Tpat->Type == BITMAP_PATTERN) || (Tpat->Type == IMAGE_PATTERN))
{
Destroy_Image(Tpat->Vals.image);
}
if (Tpat->Type == DENSITY_FILE_PATTERN)
{
Destroy_Density_File(Tpat->Vals.Density_File);
}
if (Tpat->Type == OBJECT_PATTERN)
{
if(Tpat->Vals.Object != NULL)
{
Destroy_Object(reinterpret_cast<ObjectPtr>(Tpat->Vals.Object));
}
}
if (Tpat->Type == PIGMENT_PATTERN)
{
if (Tpat->Vals.Pigment != NULL)
{
Destroy_Pigment( Tpat->Vals.Pigment );
}
}
if (Tpat->Type == FUNCTION_PATTERN)
{
if (Tpat->Vals.Function.Fn != NULL)
{
Parser::Destroy_Function(Tpat->Vals.Function.vm, (FUNCTION_PTR)(Tpat->Vals.Function.Fn));
}
}
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
TURB *Create_Turb()
{
TURB *New;
New = reinterpret_cast<TURB *>(POV_MALLOC(sizeof(TURB),"turbulence struct"));
Make_Vector(New->Turbulence, 0.0, 0.0, 0.0);
New->Octaves = 6;
New->Omega = 0.5;
New->Lambda = 2.0;
return(New);
}
/*****************************************************************************
*
* FUNCTION
*
* Translate_Tpattern
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Translate_Tpattern(TPATTERN *Tpattern, const VECTOR Vector)
{
TRANSFORM Trans;
if (Tpattern != NULL)
{
Compute_Translation_Transform (&Trans, Vector);
Transform_Tpattern (Tpattern, &Trans);
}
}
/*****************************************************************************
*
* FUNCTION
*
* Rotate_Tpattern
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Rotate_Tpattern(TPATTERN *Tpattern, const VECTOR Vector)
{
TRANSFORM Trans;
if (Tpattern != NULL)
{
Compute_Rotation_Transform (&Trans, Vector);
Transform_Tpattern (Tpattern, &Trans);
}
}
/*****************************************************************************
*
* FUNCTION
*
* Scale_Tpattern
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Scale_Tpattern(TPATTERN *Tpattern, const VECTOR Vector)
{
TRANSFORM Trans;
if (Tpattern != NULL)
{
Compute_Scaling_Transform (&Trans, Vector);
Transform_Tpattern (Tpattern, &Trans);
}
}
/*****************************************************************************
*
* FUNCTION
*
* Transform_Tpattern
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Transform_Tpattern(TPATTERN *Tpattern, const TRANSFORM *Trans)
{
WARP *Temp;
if (Tpattern != NULL)
{
if (Tpattern->Warps == NULL)
{
Tpattern->Warps = Create_Warp(TRANSFORM_WARP);
}
else
{
if (Tpattern->Warps->Warp_Type != TRANSFORM_WARP)
{
Temp = Tpattern->Warps;
Tpattern->Warps = Create_Warp(TRANSFORM_WARP);
Tpattern->Warps->Next_Warp = Temp;
if(Tpattern->Warps->Next_Warp != NULL)
Tpattern->Warps->Next_Warp->Prev_Warp = Tpattern->Warps;
}
}
Compose_Transforms (&( (reinterpret_cast<TRANS *>(Tpattern->Warps))->Trans), Trans);
}
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Search_Blend_Map (DBL value, const BLEND_MAP *Blend_Map, const BLEND_MAP_ENTRY **Prev, const BLEND_MAP_ENTRY **Cur)
{
BLEND_MAP_ENTRY *P, *C;
int Max_Ent=Blend_Map->Number_Of_Entries-1;
/* if greater than last, use last. */
if (value >= Blend_Map->Blend_Map_Entries[Max_Ent].value)
{
P = C = &(Blend_Map->Blend_Map_Entries[Max_Ent]);
}
else
{
P = C = &(Blend_Map->Blend_Map_Entries[0]);
while (value > C->value)
{
P = C++;
}
}
if (value == C->value)
{
P = C;
}
*Prev = P;
*Cur = C;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static const TURB *Search_For_Turb(const WARP *Warps)
{
const WARP* Temp=Warps;
if (Temp!=NULL)
{
while (Temp->Next_Warp != NULL)
{
Temp=Temp->Next_Warp;
}
if (Temp->Warp_Type != CLASSIC_TURB_WARP)
{
Temp=NULL;
}
}
return (reinterpret_cast<const TURB *>(Temp));
}
/* Tiling & Pavement */
/*****************************************************************************
*
* FUNCTIONS
*
* related to Tiling & Pavement
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* J. Grimbert
*
* DESCRIPTION
*
* New colour function by J. Grimbert
*
* Fill the X-Z plane with repeating pattern
* When there is only one kind of form, 1 is the outside, 0 is most inside
* When there is two kind of form, 0 & 1 are the most inside, 1/2 is
* the outside
*
******************************************************************************/
static DBL tiling_square (const VECTOR EPoint)
{
/*
** Classical square tiling
*/
DBL x,z;
x = fabs(EPoint[X]);
x -= floor(x);
x = 2*fabs( x-0.5 );
z = fabs(EPoint[Z]);
z -= floor(z);
z = 2*fabs( z-0.5 );
return max(x,z);
}
static DBL tiling_hexagon (const VECTOR EPoint)
{
/*
** Classical Hexagon tiling
*/
DBL x,z;
DBL dist1,dist2;
DBL answer;
x=EPoint[X];
z=EPoint[Z];
x += 0.5;
x -= 3.0*floor(x/3.0);
z -= SQRT3*floor(z/(SQRT3));
/* x,z is in { [0.0, 3.0 [, [0.0, SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3_2 )
{
z = SQRT3 - z;
}
/*
** Now only [0,3[,[0,SQRT3/2[
*/
if (x > 1.5)
{
x -= 1.5 ; /* translate */
z = SQRT3_2 -z; /* mirror */
}
/*
** And now, it is even simpler : [0,1.5],[0,SQRT3/2]
** on the bottom left corner, part of some other hexagon
** on the top right corner, center of the hexagon
*/
if ((SQRT3*x+z)<SQRT3_2)
{
x = 0.5 - x;
z = SQRT3_2 -z; /* mirror */
}
if (x > 1.0)
{
x = 2.0 -x; /* mirror */
}
/* Hexagon */
dist1 = 1.0 - ( z / SQRT3_2 );
dist2 = 1.0 - (((SQRT3 * x + z - SQRT3_2) ) / SQRT3 );
answer = max(dist1,dist2);
answer = min(1.0,answer);
answer = max(0.0,answer);
return answer;
}
static DBL tiling_triangle (const VECTOR EPoint)
{
DBL x,z;
DBL slop1;
DBL dist1,dist2;
int delta;
x=EPoint[X];
z=EPoint[Z];
delta = 0;
x -= floor(x);
z -= SQRT3*floor(z/SQRT3);
/* x,z is in { [0.0, 1.0 [, [0.0, SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3_2 )
{
z = SQRT3 - z; /* mirror */
delta = 1 - delta;
}
if (x > 0.5)
{
x = 1.0 - x; /* mirror */
}
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{
z = SQRT3_2 - z;
x = 0.5 -x;
delta = 1 - delta;
}
}
else
{
z = SQRT3_2 -z;
x = 0.5;
}
dist1 = 1.0 - (z * 2 * SQRT3 );
dist2 = 1.0 - ((SQRT3 * x - z) * SQRT3 );
return delta/2.0+(0.5)*max(dist1,dist2);
}
static DBL tiling_lozenge (const VECTOR EPoint)
{
DBL x,z;
DBL slop1;
DBL dist1,dist2;
x=EPoint[X];
z=EPoint[Z];
x -= floor(x);
z -= SQRT3*floor(z/SQRT3);
/* x,z is in { [0.0, 1.0 [, [0.0, SQRT3 [ }
** There is some mirror to reduce the problem
*/
if ( z > SQRT3_2 )
{
z -= SQRT3_2;
x += 0.5;
}
if ( (2.0*z) > SQRT3_2 )
{
z = SQRT3_2 - z;
x = 1.5 - x;
}
if (x > 0.75)
{
x -= 1.0;
}
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{
z = SQRT3_2 - z;
x = 0.5 -x;
}
}
dist1 = 1.0 - (z * 4.0 * SQRT3 / 3.0 );
dist2 = 1.0 - (fabs(SQRT3 * x - z) * SQRT3 *2.0 / 3.0);
return max(dist1,dist2);
}
static DBL tiling_rhombus (const VECTOR EPoint)
{
DBL x,z;
DBL answer;
DBL slop1;
DBL dist1,dist2;
int delta;
x=EPoint[X];
z=EPoint[Z];
delta = 0;
x += 0.5;
x -= 3.0*floor(x/3.0);
z -= SQRT3*floor(z/SQRT3);
/* x,z is in { [0.0, 3.0 [, [0.0, SQRT3 [ }
** There is some mirror to reduce the problem
*/
if ( z > SQRT3_2 )
{
z = SQRT3 -z; /* mirror */
delta = 2 - delta;
}
if (x > 1.5)
{
x -= 1.5 ; /* translate */
z = SQRT3_2 -z; /* mirror */
delta = 2 - delta;
}
/* Now in [0,1.5],[0,SQRT3/2]
** from left to right
** part of a horizontal (z=0)
** half a vertical
** part of a horizontal
*/
if (x < 0.5)
{
/* mirrror */
x = 1.0 - x;
delta = 2 - delta;
}
/*
** Let shift the [0.5,1.5],[0,SQRT3/2] to [0,1]....
*/
x -= 0.5;
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{ /* rotate the vertical to match the horizontal on the right */
dist1 = ( x / 2.0 ) + ( z * SQRT3_2 );
dist2 = ( z / 2.0 ) - ( x * SQRT3_2 );
z = dist2;
x = dist1;
delta = 1;
}
}
else
{
/* rotate the vertical to match the horizontal on the right */
dist1 = ( x / 2.0 ) + ( z * SQRT3_2 );
dist2 = ( z / 2.0 ) - ( x * SQRT3_2 );
z = dist2;
x = dist1;
delta = 1;
}
/* It may be similar to lozenge (in fact, IT IS !), now */
if ( (2.0*z) > SQRT3_2 )
{
z = SQRT3_2 - z;
x = 1.5 - x;
}
if (x > 0.75)
{
x -= 1.0;
}
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{
z = SQRT3_2 - z;
x = 0.5 -x;
}
}
dist1 = 1.0 - (z * 4.0 * SQRT3 / 3.0 );
dist2 = 1.0 - (fabs(SQRT3 * x - z) * SQRT3 *2.0 / 3.0);
answer = max(dist1,dist2);
answer /= 3.0;
answer += delta/3.0;
answer = min(1.0,answer);
answer = max(0.0,answer);
return answer;
}
static DBL tiling_rectangle (const VECTOR EPoint)
{
/*
** Tiling with rectangles
** resolve to square [0,4][0,4]
** then 16 cases
**
** +-----+--+ +
** | | | |
** +--+--+ +--+
** | | |
** +--+ +--+--+
** | | | |
** + +--+--+--+
** | | | |
** +--+-----+ +
*/
DBL x,z;
DBL delta;
DBL answer;
int valueX,valueZ;
x=EPoint[X];
z=EPoint[Z];
x -= 4.0*floor(x/4.0);
z -= 4.0*floor(z/4.0);
valueX = (int)x;
valueZ = (int)z;
delta = 1.0;
switch((valueX+valueZ*4))
{
case 0:
case 4:
z -= 1.0;
break;
case 1:
case 2:
x -= 2.0;
delta = 0.0;
break;
case 3:
x -= 3.0;
break;
case 5:
case 9:
x -= 1.0;
z -= 2.0;
break;
case 6:
case 7:
x -= 3.0;
z -= 1.0;
delta = 0.0;
break;
case 8:
z -= 2.0;
delta = 0.0;
break;
case 10:
case 14:
x -= 2.0;
z -= 3.0;
break;
case 11:
x -= 4.0;
z -= 2.0;
delta = 0.0;
break;
case 12:
case 13:
x -= 1.0;
z -= 3.0;
delta = 0.0;
break;
case 15:
x -= 3.0;
z -= 4.0;
break;
}
if (delta == 1.0)
{
x = 2*fabs( x-0.5 );
z = 2*( max(fabs( z),0.5) -0.5 );
}
else
{
x = 2*( max(fabs( x),0.5) -0.5 );
z = 2*fabs( z -0.5 );
}
answer = fabs(max(x,z)/2.0 + delta/2);
return answer;
}
static DBL tiling_octa_square (const VECTOR EPoint)
{
/*
** Tiling with a square and an octagon
*/
DBL answer;
DBL x,z;
DBL dist1,dist2;
z=EPoint[Z];
z -= (SQRT2+1.0)*floor(z/(SQRT2+1.0));
z -= SQRT2_2+0.5;
z = fabs(z);
x=EPoint[X];
x -= (SQRT2+1.0)*floor(x/(SQRT2+1.0));
x -= SQRT2_2+0.5;
x = fabs(x);
if (z > x)
{
answer = x;
x = z;
z = answer;
}
if ( (x+z) < SQRT2_2)
{
/* Square tile */
return ( (x+z)/SQRT2 );
}
dist1 = 1.0-z;
dist2 = (SQRT2+SQRT2_2-(x+z))/SQRT2;
return max(0.500000000001,max(dist1,dist2)); // TODO FIXME - magic number! Use nextafter() instead (or maybe actually 0.5)
}
static DBL tiling_square_triangle (const VECTOR EPoint)
{
DBL x,z;
DBL slop1;
DBL dist1,dist2;
int delta;
x=EPoint[X];
z=EPoint[Z];
delta = 0;
x -= floor(x);
z -= (2.0+SQRT3)*floor(z/(SQRT3+2.0));
/* x,z is in { [0.0, 1.0 [, [0.0, 2+SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3_2+1.0 )
{
z -= SQRT3_2+1.0;
x += (x>0.5)?-0.5:0.5;
}
if (x > 0.5)
{
x = 1.0 - x; /* mirror */
}
z -= 1.0;
if (z > 0.0)
{ /* triangle */
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{
z = SQRT3_2 - z;
x = 0.5 -x;
delta = 1 - delta;
}
}
else
{
z = SQRT3_2 -z;
x = 0.5;
delta = 1 - delta;
}
dist1 = 1.0 - (2 * z * SQRT3 );
dist2 = 1.0 - ((SQRT3 * x - z) * SQRT3 );
return (delta+max(dist1,dist2))/3.0;
}
else
{ /* square */
if (z < -0.5)
{
z = -1.0 -z;
}
if (x > 0.5)
{
x = 1.0 - x;
}
dist1 = 2 + 2 * SQRT3 * fabs( x ) ;
dist2 = 2 + 2 * SQRT3 * fabs( z ) ;
dist1 = min(dist1,3.0);
dist2 = min(dist2,3.0);
return (5.0000001-min(dist1,dist2))/3.0; // TODO FIXME - magic number! Should use nextafter()
}
}
static DBL tiling_hexa_triangle (const VECTOR EPoint)
{
/*
** Tiling with a hexagon and 2 triangles
*/
DBL x,z;
DBL dist1,dist2;
DBL answer=0;
int delta;
x=EPoint[X];
z=EPoint[Z];
delta = 0;
x += 0.5;
x -= 2.0*floor(x/2.0);
z -= 2.0*SQRT3*floor(z/(SQRT3*2.0));
/* x,z is in { [0.0, 2.0 [, [0.0, 2*SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3 )
{
z -= SQRT3;
x += (x<1.0)?1.0:-1.0;
}
/*
** Now only [0,2[,[0,SQRT3[
*/
if (z > SQRT3_2 )
{
z = SQRT3 - z; /* mirror */
delta = 1 - delta;
}
if (x > 1.0)
{
x = 2.0 - x; /* mirror */
}
/*
** And now, it is even simpler : [0,1],[0,SQRT3/2]
** on the bottom left corner, part of the triangle
** on the top right corner, center of the hexagon
*/
if ((SQRT3*x+z)<SQRT3_2)
{
/* Triangle */
dist1 = 1.0 - (z * 2 * SQRT3 );
dist2 = 1.0 + ((SQRT3 * x + z) - SQRT3_2 ) * SQRT3; /* really substracting */
answer = (delta + max(dist1,dist2))/3.0;
}
else
{
/* Hexagon */
dist1 = 2 + 2* (z * SQRT3 );
dist2 = 2 + 2* ((SQRT3 * x + z - SQRT3_2) ) * SQRT3_2 ;
answer = 5.0-min(dist1,dist2);
answer = max(answer,2.0000001); // TODO FIXME - magic number! Should use nextafter()
answer /= 3.0;
}
return answer;
}
static DBL tiling_square_offset (const VECTOR EPoint)
{
/*
** Tiling with a square, offset of half size
** Reduce to rectangle [0,1][0,2]
** move x,[1,2] to [0,1][0,1] with new x = x+1/2
*/
DBL x,z;
z = EPoint[Z];
z -= 2.0*floor(z/2.0);
x = EPoint[X];
if (z > 1.0)
{
x += 0.5;
z -= 1.0;
}
x -= floor(x);
x = 2*fabs( x-0.5 );
z = 2*fabs( z-0.5 );
return max(x,z);
}
static DBL tiling_square_rectangle (const VECTOR EPoint)
{
/*
** tiling with a central square and 4 rectangle (2x1)
** orbiting around the square
** Reduce to [0,3][0,3]
** then 9 cases
**
** +-----+--+
** | | |
** +--+--+ |
** | | | |
** | +--+--+
** | | |
** +--+-----+
*/
DBL x,z;
DBL delta;
int valueX,valueZ;
x = EPoint[X];
x -= 3.0*floor(x/3.0);
z = EPoint[Z];
z -= 3.0*floor(z/3.0);
valueX = (int)x;
valueZ = (int)z;
delta = 2.0;
switch((valueX+valueZ*3))
{
case 0:
case 3:
z -= 1.0;
break;
case 1:
case 2:
x -= 2.0;
delta = 1.0;
break;
case 4:
x -= 1.0;
z -= 1.0;
delta = 0.0;
break;
case 5:
case 8:
x -= 2.0;
z -= 2.0;
break;
case 6:
case 7:
x -= 1.0;
z -= 2.0;
delta = 1.0;
break;
}
if (delta == 1.0)
{
x = fabs( x);
x = 2.0*( max( x,0.5) -0.5 );
z = 2.0*fabs( z -0.5 );
}
if (delta == 2.0)
{
x = 2.0*fabs( x-0.5 );
z = fabs(z);
z = 2.0*( max(z,0.5) - 0.5 );
}
if (delta == 0.0)
{
x = 2.0*fabs( x-0.5 );
z = 2.0*fabs( z-0.5 );
}
return ((max(x,z))+delta)/3.0 ;
}
static DBL tiling_rectangle_square (const VECTOR EPoint)
{
/*
** Tiling with a central square and 4 rectangles (2x1)
** which turns around the square in both directions
** Reduce to [0,6][0,6], fold in four and back
** to 9 cases.
**
** +-----+--+
** | | |
** +--+--+ |
** | | | |
** | +--+--+
** | | |
** +--+--+--+
*/
DBL x,z;
DBL delta;
int valueX,valueZ;
x = EPoint[X];
x -= 6.0*floor(x/6.0);
x -= 3.0;
x = fabs(x);
z = EPoint[Z];
z -= 6.0*floor(z/6.0);
z -= 3.0;
z = fabs(z);
valueX = (int)x;
valueZ = (int)z;
delta = 2.0;
switch((valueX+valueZ*3))
{
case 0:
case 3:
z -= 1.0;
break;
case 1:
case 2:
x -= 2.0;
delta = 1.0;
break;
case 4:
x -= 1.0;
z -= 1.0;
delta = 0.0;
break;
case 5:
case 8:
x -= 2.0;
z -= 2.0;
break;
case 6:
case 7:
x -= 1.0;
z -= 2.0;
delta = 1.0;
break;
}
if (delta == 1.0)
{
x = fabs( x);
x = 2.0*( max(x,0.5) -0.5 );
z = 2.0*fabs( z -0.5 );
}
if (delta == 2.0)
{
x = 2.0*fabs( x-0.5 );
z = fabs(z);
z = 2.0*( max(z,0.5) - 0.5 );
}
if (delta == 0.0)
{
x = 2.0*fabs( x-0.5 );
z = 2.0*fabs( z-0.5 );
}
return ((max(x,z))+delta)/3.0 ;
}
static DBL tiling_square_internal (const VECTOR EPoint)
{
DBL answer=0;
DBL x,z;
DBL dist1,dist2;
int valueX,valueZ;
x=EPoint[X];
x *= SQRT2;
x -= 4.0 * floor(x/4.0);
x -= 2.0;
x = fabs(x);
z=EPoint[Z];
z *= SQRT2;
z -= 4.0 * floor(z/4.0);
z -= 2.0;
z = fabs(z);
valueX=(int)x;
valueZ=(int)z;
switch((valueX+valueZ*2))
{
case 0:
x -= 0.5;
x = max(x,0.0);
x *= 2.0;
z -= 0.5;
z = max(z,0.0);
z *= 2.0;
answer=max(x,z)/3.0;
break;
case 1:
answer=(2.0+fabs(1.5-x)*2.0)/3.0;
if (z>0.5)
{
dist2=(3.0-SQRT2*fabs(x-z))/3.0;
answer = max(answer,dist2);
}
break;
case 2:
answer=(1.0+fabs(1.5-z)*2.0)/3.0;
if (x>0.5)
{
dist2=(2.0-SQRT2*fabs(x-z))/3.0;
answer = max(answer,dist2);
}
break;
case 3:
if (x > z)
{
dist1=(2.0+fabs(1.5-x)*2.0)/3.0;
dist2=(3.0-SQRT2*fabs(z-x))/3.0;
answer=max(dist1,dist2);
}
else
{
dist1=(1.0+fabs(1.5-z)*2.0)/3.0;
dist2=(2.0-SQRT2*fabs(x-z))/3.0;
answer=max(dist1,dist2);
}
break;
}
return answer;
}
static DBL tiling_square_internal_5 (const VECTOR EPoint)
{
DBL answer=0;
DBL x,z;
DBL dist1,dist2;
int mirX,mirZ;
int valueX,valueZ;
mirX=mirZ=0;
x=EPoint[X];
x *= SQRT2;
x -= 4.0 * floor(x/4.0);
x -= 2.0;
mirX = (x < 0)?1:0;
x = fabs(x);
z=EPoint[Z];
z *= SQRT2;
z -= 4.0 * floor(z/4.0);
z -= 2.0;
mirZ = (z < 0)?2:3;
z = fabs(z);
valueX=(int)x;
valueZ=(int)z;
switch((valueX+valueZ*2))
{
case 0:
x -= 0.5;
x = max(x,0.0);
x *= 2.0;
z -= 0.5;
z = max(z,0.0);
z *= 2.0;
answer=(4.000001 + max(x,z))/5.0; // TODO FIXME - magic number! Should use nextafter()
break;
case 1:
answer=fabs(1.5-x)*2.0;
if (z>0.5)
{
dist2=1.0-SQRT2*fabs(x-z);
answer = max(answer,dist2);
}
answer += mirX;
answer /= 5.0;
break;
case 2:
answer=fabs(1.5-z)*2.0;
if (x>0.5)
{
dist2=1.0-SQRT2*fabs(x-z);
answer = max(answer,dist2);
}
answer += mirZ;
answer /= 5.0;
break;
case 3:
if (x > z)
{
dist1=fabs(1.5-x)*2.0;
dist2=1.0-SQRT2*fabs(z-x);
answer=max(dist1,dist2) + mirX;
}
else
{
dist1=fabs(1.5-z)*2.0;
dist2=1.0-SQRT2*fabs(x-z);
answer=max(dist1,dist2) + mirZ;
}
answer /= 5.0;
break;
}
return answer;
}
static DBL tiling_square_double (const VECTOR EPoint)
{
/*
** Tiling with a square (1x1) and a square (2x2)
** Reduce to [0,5][0,5] then 25 cases
**
** +--+ +--+--+
** | | |
** +--+--+--+
** | | |
** +--+--+ +--+
** | | | |
** + +--+--+--+
** | | | |
** +--+--+--+ +
** | | | |
** +--+ +--+--+
*/
DBL x,z;
DBL delta;
int valueX,valueZ;
x = EPoint[X];
x -= 5.0*floor(x/5.0);
z = EPoint[Z];
z -= 5.0*floor(z/5.0);
valueX = (int)x;
valueZ = (int)z;
delta = 0.50000001; // TODO FIXME - magic number! Should use nextafter()
switch((valueX+valueZ*5))
{
case 0:
delta = 0.0;
break;
case 1:
case 2:
x -= 2.0;
break;
case 3:
case 4:
case 8:
case 9:
x -= 4.0;
z -= 1.0;
break;
case 5 :
case 6 :
case 10:
case 11:
z -= 2.0;
x -= 1.0;
break;
case 7:
delta = 0.0;
x -= 2.0;
z -= 1.0;
break;
case 12:
case 13:
case 17:
case 18:
x -= 3.0;
z -= 3.0;
break;
case 14:
x -= 4.0;
z -= 2.0;
delta = 0.0;
break;
case 15:
case 20:
z -= 4.0;
break;
case 16:
x -= 1.0;
z -= 3.0;
delta = 0.0;
break;
case 21:
case 22:
x -= 2.0;
z -= 5.0;
break;
case 23:
x -= 3.0;
z -= 4.0;
delta = 0.0;
break;
case 24:
case 19:
x -= 5.0;
z -= 4.0;
break;
}
if (delta)
{
x = fabs(x);
x = 2*( max(x,0.5) -0.5 );
z = fabs(z);
z = 2*( max(z,0.5) -0.5 );
}
else
{
x = 2*fabs( x-0.5 );
z = 2*fabs( z-0.5 );
}
return fabs((max(x,z))/2.0+delta);
}
static DBL tiling_hexa_square_triangle (const VECTOR EPoint)
{
/*
** tiling with 1 hexagon, squares and triangles
*/
DBL x,z;
DBL dist1,dist2;
DBL answer=0;
x=EPoint[X];
z=EPoint[Z];
x += 0.5;
x -= (3.0+SQRT3)*floor(x/(3.0+SQRT3));
z -= 2.0*(1.0+SQRT3)*floor(z/((SQRT3+1.0)*2.0));
/* x,z is in { [0.0, 3.0+SQRT3 [, [0.0, 2*(1+SQRT3) [ }
** but there is some symmetry to simplify the testing
*/
if (x > (SQRT3_2+1.5))
{
x -= (SQRT3_2+1.5);
z += (z < SQRT3+1.0)?(SQRT3_2+0.5):(-1*(SQRT3_2+0.5));
}
if (z > (SQRT3+1.0) )
{
z -= SQRT3+1.0;
}
/*
** Now only [0, SQRT3/2+1.5 ], [0,SQRT3+1.0]
*/
if (z > (0.5+SQRT3_2 ) )
{
z = SQRT3+1.0 - z; /* mirror */
}
if (x > (1.0+SQRT3_2) )
{
x = SQRT3+2.0 - x; /* mirror */
}
/*
** And now, it is even simpler : [0,1+(SQRT3/2)],[0,1+(SQRT3/2)]
** on the top right corner, center of the hexagon
** on the bottom right, middle of square, a triangle on the left
** on the top left corner, half a triangle
** bottom
*/
if (((SQRT3*x+z)<(SQRT3_2+2.0))&&(x < 0.5+SQRT3_2))
{
/* Triangle or square */
/* rotate in the lower part */
z -= 0.5 + SQRT3_2 ;
x -= 1.0 + SQRT3_2 ;
dist1 = ( x / 2.0 ) - ( z * SQRT3_2 );
dist2 = ( z / 2.0 ) + ( x * SQRT3_2 );
z = dist2;
x = dist1;
z += 0.5 + SQRT3_2 ;
x += 1.0 + SQRT3_2 ;
if (z < 0)
{
z *= -1;
}
if (x > (1.0+SQRT3_2) )
{
x = SQRT3+2.0 - x; /* mirror */
}
}
if ((!((SQRT3*x+z)<(SQRT3_2+2.0)))&&(!(z < 0.5)))
{
/* Hexagon */
z -= 0.5;
x -= SQRT3_2;
z= fabs(z);
x= fabs(x);
dist1 = 2* z * SQRT3 ;
dist2 = ((SQRT3 * x + z ) ) * SQRT3 - 1.5;
answer = 3.0-min(dist1,dist2);
answer = max(answer,2.0000001); // TODO FIXME - magic number! Should use nextafter()
answer /= 3.0;
return answer;
}
if (z < 0.5 )
{
if ( x > SQRT3_2+0.5)
{
/* square */
x -= SQRT3_2+0.5;
z -= 0.5;
dist1 = 1.0 + z*2 * SQRT3;
dist2 = 1.0 - x*2*SQRT3;
dist1 = max(dist1,0.0);
dist2 = max(dist2,0.0);
answer = max(dist1,dist2)/3.0;
}
else
{
/* triangle */
x -= SQRT3_2 + 0.5;
x = fabs(x);
dist2 = ((SQRT3 * z + x) ) * SQRT3 +0.5;
dist1 = 2.0 - (x * 2.0 * SQRT3 );
answer = (max(dist1,dist2))/3.0;
}
}
return answer;
}
static DBL tiling_hexa_square_triangle_6 (const VECTOR EPoint)
{
/*
** tiling with 1 hexagon, squares and triangles
** all tiles get its own colour (according to its orientation)
** 1 hexagon, 3 squares, 2 triangles
*/
DBL x,z;
DBL dist1,dist2;
DBL answer=0;
int mirX=0;
int mirZ=0;
int rota=0;
x=EPoint[X];
z=EPoint[Z];
x += 0.5;
x -= (3.0+SQRT3)*floor(x/(3.0+SQRT3));
z -= 2.0*(1.0+SQRT3)*floor(z/((SQRT3+1.0)*2.0));
/* x,z is in { [0.0, 3.0+SQRT3 [, [0.0, 2*(1+SQRT3) [ }
** but there is some symmetry to simplify the testing
*/
if (x > (SQRT3_2+1.5))
{
x -= (SQRT3_2+1.5);
z += (z < SQRT3+1.0)?(SQRT3_2+0.5):(-1*(SQRT3_2+0.5));
}
if (z > (SQRT3+1.0) )
{
z -= SQRT3+1.0;
}
/*
** Now only [0, SQRT3/2+1.5 ], [0,SQRT3+1.0]
*/
if (z > (0.5+SQRT3_2 ) )
{
z = SQRT3+1.0 - z; /* mirror */
mirZ = 1 - mirZ;
}
if (x > (1.0+SQRT3_2) )
{
x = SQRT3+2.0 - x; /* mirror */
mirX = 1 - mirX;
}
/*
** And now, it is even simpler : [0,1+(SQRT3/2)],[0,1+(SQRT3/2)]
** on the top right corner, center of the hexagon
** on the bottom right, middle of square, a triangle on the left
** on the top left corner, half a triangle
** bottom
*/
if (((SQRT3*x+z)<(SQRT3_2+2.0))&&(x < 0.5+SQRT3_2))
{
/* Triangle or square */
/* rotate in the lower part */
z -= 0.5 + SQRT3_2 ;
x -= 1.0 + SQRT3_2 ;
dist1 = ( x / 2.0 ) - ( z * SQRT3_2 );
dist2 = ( z / 2.0 ) + ( x * SQRT3_2 );
z = dist2;
x = dist1;
z += 0.5 + SQRT3_2 ;
x += 1.0 + SQRT3_2 ;
rota = 1 - rota;
if (z < 0)
{
z *= -1;
}
if (x > (1.0+SQRT3_2) )
{
x = SQRT3+2.0 - x; /* mirror */
mirX = 1 - mirX;
mirZ = 1 - mirZ;
}
}
if ((!((SQRT3*x+z)<(SQRT3_2+2.0)))&&(!(z < 0.5)))
{
/* Hexagon */
z -= 0.5;
x -= SQRT3_2;
z= fabs(z);
x= fabs(x);
dist1 = 2* z * SQRT3 ;
dist2 = ((SQRT3 * x + z ) ) * SQRT3 - 1.5;
answer = 6.0 - min(dist1,dist2);
answer = max(answer,5.000001); // TODO FIXME - magic number! Should use nextafter()
answer /= 6.0;
return answer;
}
if (z < 0.5 )
{
if ( x > SQRT3_2+0.5)
{
/* square */
x -= SQRT3_2+0.5;
z -= 0.5;
dist1 = 1.0 + z*2 * SQRT3;
dist2 = 1.0 - x*2*SQRT3;
dist1 = max(dist1,0.0);
dist2 = max(dist2,0.0);
answer = (max(dist1,dist2) + rota * (1.000001 + ((mirX + mirZ) % 2)))/6.0; // TODO FIXME - magic number! Should use nextafter()
}
else
{
/* triangle */
x -= SQRT3_2 + 0.5;
x = fabs(x);
dist2 = ((SQRT3 * z + x) ) * SQRT3 +0.5;
dist1 = 2.0 - (x * 2.0 * SQRT3 );
answer = max(dist1,dist2);
if ((rota + mirX)%2)
{
answer = 2.0 + answer;
}
else
{
answer = 3.0 + answer;
}
answer /= 6.0;
}
}
return answer;
}
static DBL tiling_rectangle_pair (const VECTOR EPoint)
{
/*
** Tiling with 2 rectangles (2x1)
** Reduce to [0,4][0,4] then 16 cases
**
** +-----+--+--+
** | | | |
** +-----+ + +
** | | | |
** +-----+--+--+
** | | | |
** | | +-----+
** | | | |
** +--+--+-----+
*/
DBL x,z;
DBL delta;
DBL answer;
int valueX,valueZ;
x=EPoint[X];
z=EPoint[Z];
x -= 4.0*floor(x/4.0);
z -= 4.0*floor(z/4.0);
valueX = (int)x;
valueZ = (int)z;
delta = 1.0;
switch((valueX+valueZ*4))
{
case 0:
case 4:
z -= 1.0;
break;
case 1:
case 5:
x -= 1.0;
z -= 1.0;
break;
case 2:
case 3:
x -= 3.0;
delta = 0.0;
break;
case 6:
case 7:
x -= 3.0;
z -= 1.0;
delta = 0.0;
break;
case 8:
case 9:
x -= 1.0;
z -= 2.0;
delta = 0.0;
break;
case 12:
case 13:
x -= 1.0;
z -= 3.0;
delta = 0.0;
break;
case 10:
case 14:
x -= 2.0;
z -= 3.0;
break;
case 11:
case 15:
x -= 3.0;
z -= 3.0;
break;
}
if (delta == 1.0)
{
x = 2*fabs( x-0.5 );
z = 2*( max(fabs( z),0.5) -0.5 );
}
else
{
x = 2*( max(fabs( x),0.5) -0.5 );
z = 2*fabs( z -0.5 );
}
answer = fabs((max(x,z)+delta)/2.0);
return answer;
}
static DBL tiling_hexa_tri_right (const VECTOR EPoint)
{
DBL x,z;
DBL answer;
DBL slop1;
DBL dist1,dist2;
int zzof;
int delta;
x=EPoint[X];
z=EPoint[Z];
/* First, resume to a simple pattern */
zzof = z / SQRT3_2;
zzof /= 3;
if (z < 0)
{
zzof -= 1;
}
x += zzof / 2.0; /* right handed */
z -= 3*SQRT3_2*floor(z/(3*SQRT3_2));
x += 7.0;
x -= 7.0 *floor(x/7.0);
if ((x > 4.5) && (z > SQRT3))
{
x -= 4.5;
z -= SQRT3_2;
}
if ((x > 5.0) && (z < SQRT3_2))
{
x -= 5;
z += SQRT3;
}
if ((x > 2.5) && (z < SQRT3))
{
x -= 2.5;
z += SQRT3_2;
}
delta = 0;
zzof = z /SQRT3_2;
if ( zzof == 2)
{
zzof = 1;
z = 2 * SQRT3 - z;
delta = 1 - delta;
}
if ( (!zzof) || (x > 2.0) ||
(( z + SQRT3*x < SQRT3) || ( SQRT3*x -z > SQRT3)) )
{
/* triangle */
x -= 1.0 *floor(x/1.0);
z -= SQRT3*floor(z/SQRT3);
/* x,z is in { [0.0, 1.0 [, [0.0, SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3_2 )
{
z = SQRT3 - z; /* mirror */
delta = 1 - delta;
}
if (x > 0.5)
{
x = 1.0 - x; /* mirror */
}
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{
z = SQRT3_2 - z;
x = 0.5 -x;
delta = 1 - delta;
}
}
else
{
z = SQRT3_2 -z;
x = 0.5;
delta = 1 - delta;
}
dist1 = 1.0 - (z * 2 * SQRT3 );
dist2 = 1.0 - ((SQRT3 * x - z) * SQRT3 );
return (delta+max(dist1,dist2))/3.0;
}
else
{ /* hexagon */
z -= SQRT3_2;
if (x > 1.0)
{
x = 2.0 - x; /* mirror */
}
/* Hexagon */
dist1 = 2 + 2* (z * SQRT3 );
dist2 = 2 + 2* ((SQRT3 * x + z - SQRT3_2) ) * SQRT3_2 ;
answer = 5.0-min(dist1,dist2);
answer = max(answer, 2.000001); // TODO FIXME - magic number! Should use nextafter()
answer /= 3.0;
return answer;
}
}
static DBL tiling_hexa_tri_left (const VECTOR EPoint)
{
DBL x,z;
DBL slop1;
DBL dist1,dist2;
DBL answer;
int zzof;
int delta;
x=EPoint[X];
z=EPoint[Z];
/* First, resume to a simple pattern */
zzof = z / SQRT3_2;
zzof /= 3;
if (z < 0)
{
zzof -= 1;
}
x -= zzof / 2.0; /* left handed */
z -= 3*SQRT3_2*floor(z/(3*SQRT3_2));
x += 7.0;
x -= 7.0 *floor(x/7.0);
if ((x > 2.0) && (z < SQRT3_2))
{
x -= 2.0;
z += SQRT3;
}
if ((x > 4.5) && (z < SQRT3))
{
x -= 4.5;
z += SQRT3_2;
}
if ((x > 2.5) && (z > SQRT3))
{
x -= 2.5;
z -= SQRT3_2;
}
delta = 0;
zzof = z /SQRT3_2;
if ( zzof == 2)
{
zzof = 1;
z = 2 * SQRT3 - z;
delta = 1 - delta;
}
if ( (!zzof) || (x > 2.0) ||
(( z + SQRT3*x < SQRT3) || ( SQRT3*x -z > SQRT3)) )
{
/* triangle */
x -= 1.0 *floor(x/1.0);
z -= SQRT3*floor(z/SQRT3);
/* x,z is in { [0.0, 1.0 [, [0.0, SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3_2 )
{
z = SQRT3 - z; /* mirror */
delta = 1 - delta;
}
if (x > 0.5)
{
x = 1.0 - x; /* mirror */
}
if (x != 0.0)
{
slop1 = z/x;
if (slop1>SQRT3)
{
z = SQRT3_2 - z;
x = 0.5 -x;
delta = 1 - delta;
}
}
else
{
z = SQRT3_2 -z;
x = 0.5;
delta = 1 - delta;
}
dist1 = 1.0 - (z * 2 * SQRT3 );
dist2 = 1.0 - ((SQRT3 * x - z) * SQRT3 );
return (delta+max(dist1,dist2))/3.0;
}
else
{ /* hexagon */
z -= SQRT3_2;
if (x > 1.0)
{
x = 2.0 - x; /* mirror */
}
/* Hexagon */
dist1 = 2 + 2* (z * SQRT3 );
dist2 = 2 + 2* ((SQRT3 * x + z - SQRT3_2) ) * SQRT3_2 ;
answer = 5.0-min(dist1,dist2);
answer = max(answer, 2.000001); // TODO FIXME - magic number! Should use nextafter()
answer /= 3.0;
return answer;
}
}
static DBL tiling_square_tri (const VECTOR EPoint)
{
DBL x,z;
DBL slop1;
DBL dist1,dist2;
int delta;
int gamma,beta;
int xflop,zflop;
x=EPoint[X];
z=EPoint[Z];
delta = 0;
gamma = 0;
beta = 0;
x -= (1.0+SQRT3)*floor(x/(1.0+SQRT3));
z -= (1.0+SQRT3)*floor(z/(1.0+SQRT3));
/* x,z is in { [0.0, SQRT3+1.0 [, [0.0, SQRT3+1.0 [ }
** but there is some symmetry to simplify the testing
*/
if (z > 0.5 + SQRT3_2 )
{
z = 1.0 + SQRT3 - z; /* mirror */
delta = 1 - delta;
}
if (x > 0.5 + SQRT3_2)
{
x = 1.0 + SQRT3 - x; /* mirror */
delta = 1 - delta;
beta = 1;
}
/* x,z is in { [0.0, (SQRT3+1)/2 ], [0.0, (SQRT3+1)/2 ] }
** but there is still a symmetry and a rotation
*/
xflop = ( 2.0 * x + (SQRT3 -1.0)* 2.0 * z / ( SQRT3 + 1.0) > (SQRT3)) ? 1: 0;
zflop = ( 2.0 * z * SQRT3 + (SQRT3 -3.0)* 2.0 * x / ( SQRT3 + 1.0) > (SQRT3)) ? 1: 0;
switch (xflop + 2*zflop)
{
case 0: /* do nothing */
gamma = 2 * beta;
break;
case 1: /* rotate clockwise */
gamma = beta ? 1 + 2 * delta : 3 - 2 *delta;
slop1 = x;
x = z;
z = SQRT3_2 + 0.5 - slop1;
break;
case 2: /* rotate normal */
gamma = beta ? 3 - 2 * delta : 1 + 2 *delta;
slop1 = z;
z = x;
x = SQRT3_2 +0.5 - slop1;
break;
case 3: /* symmetry */
gamma = beta ? 0: 2 ;
x = SQRT3_2+0.5 -x;
z = SQRT3_2+0.5 -z;
break;
}
if (x == 0.0)
{
z = 0.0;
x = 0.0;
}
slop1 = (z * 2 * SQRT3) - SQRT3 + x * 2;
if (slop1 < 0)
{
/* triangle */
dist1 = -1.5 / SQRT3 * slop1;
dist2 = 2.0 * x * SQRT3;
slop1 = min(dist1,dist2);
return (gamma+1.0-slop1)/6.0;
}
else
{
/* square */
slop1 *= 1.5 / SQRT3;
slop1 = min(slop1,1.0);
if (delta)
{
slop1 *= -1;
slop1 += 6.0;
slop1 /= 6.0;
slop1 = max(slop1,5.000001/6.0); // TODO FIXME - magic number! Should use nextafter()
slop1 = min(slop1,1.0);
}
else
{
slop1 *= -1;
slop1 += 5.0;
slop1 /= 6.0;
slop1 = min(slop1,5.0/6.0);
slop1 = max(slop1,4.000001/6.0); // TODO FIXME - magic number! Should use nextafter()
}
return slop1;
}
}
static DBL tiling_dodeca_tri (const VECTOR EPoint)
{
DBL x,z;
DBL dist1,dist2,dist3,dist4,ret_value;
DBL tmpx,tmpz;
int toggle=0; /* switched each time a triangle get toggled */
x=EPoint[X];
z=EPoint[Z];
x -= (2.0+SQRT3)*floor(x/(2.0+SQRT3));
z -= (3.0+2.0*SQRT3)*floor(z/(3.0+2.0*SQRT3));
/* x,z is in { [0.0, SQRT3+2.0 [, [0.0, 2*SQRT3+3.0 [ }
** but there is some symmetry to simplify the testing
*/
if (z > SQRT3+1.5)
{
/* translate */
z -= SQRT3+1.5;
x += (x<(1.0+SQRT3_2) ? 1.0: -1.0)*(1.0+SQRT3_2);
}
if (x > 1.0+SQRT3_2)
{
x = 2.0 + SQRT3 -x;
}
if (z > 1.0+SQRT3_2)
{
z = 2.0 + SQRT3 -z;
toggle = 1 - toggle;
}
dist2 = x - SQRT3_2 - 0.5 + z * SQRT3;
if (dist2 < 0.0)
{
tmpx = x;
tmpz = z;
x = (1.0+SQRT3)/4.0 + 0.5 * tmpx - SQRT3_2 * tmpz ;
z = (3.0+SQRT3)/4.0 - SQRT3_2 * tmpx - 0.5 * tmpz ;
dist2 *= -1.0;
}
dist1 = (z * 3.0 ); /* from the bottom line */
dist3 = z - SQRT3_2 - 0.5 + x * SQRT3;
dist3 *= SQRT3;
dist2 *= SQRT3;
dist4 = (x * 3.0 ); /* from the vertical line */
if (dist3 < 0.0)
{
ret_value = max(dist3,-1.0);
ret_value += 1+toggle;
ret_value /= 3.0;
}
else
{
/* dodecagon */
ret_value = min(dist1,dist2);
ret_value = min(ret_value,dist3);
ret_value = min(ret_value,dist4);
ret_value = min(ret_value,1.0);
ret_value = 3.0000001 - ret_value; // TODO FIXME - magic number! Should use nextafter()
ret_value /= 3.0;
}
return ret_value;
}
static DBL tiling_dodeca_hex (const VECTOR EPoint)
{
DBL x,z;
DBL dist1,dist2,dist3,dist4,ret_value;
DBL dist5,dist6,dist7;
DBL tmpx,tmpz;
x=EPoint[X];
z=EPoint[Z];
x -= (3.0+SQRT3)*floor(x/(3.0+SQRT3));
z -= (3.0+3.0*SQRT3)*floor(z/(3.0+3.0*SQRT3));
/* x,z is in { [0.0, SQRT3+3.0 [, [0.0, 3*SQRT3+3.0 [ }
** but there is some symmetry to simplify the testing
*/
if (z > 1.5*SQRT3+1.5)
{
/* translate */
z -= 1.5*SQRT3+1.5;
x += (x<(1.5+SQRT3_2) ? 1.0: -1.0)*(1.5+SQRT3_2);
}
if (x > 1.5+SQRT3_2)
{
x = 3.0 + SQRT3 -x;
}
if (z > 1.0+SQRT3)
{
z = 2.0 + 2.0*SQRT3 -z;
}
dist2 = x - SQRT3_2 - 1.5 + z * SQRT3;
if (dist2 < 0.0)
{
tmpx = x;
tmpz = z;
x = (3.0+SQRT3)/4.0 + 0.5 * tmpx - SQRT3_2 * tmpz ;
z = (3.0+3.0*SQRT3)/4.0 - SQRT3_2 * tmpx - 0.5 * tmpz ;
}
dist2 = x - SQRT3_2 - 2.5 + z * SQRT3;
dist1 = (z * 2.0 ) - SQRT3; /* from the bottom line */
dist3 = z - 1.5*SQRT3 - 0.5 + x * SQRT3;
dist4 = ((x-0.5) * 2.0 ); /* from the vertical line */
if ( (dist2 >= 0.0) &&
(dist1 >= 0.0) &&
(dist3 >= 0.0) &&
(dist4 >= 0.0) )
{
/* dodecagon */
ret_value = min(dist1,dist2);
ret_value = min(ret_value,dist3);
ret_value = min(ret_value,dist4);
ret_value = min(ret_value,1.0);
ret_value = 3.000001 - ret_value; // TODO FIXME - magic number! Should use nextafter()
}
else
{
dist5 = 2*z - 2*SQRT3 - 1.0;
if (dist5 >= 0)
{
dist4 *= -1.0;
ret_value = min(dist5,dist4);
ret_value = 2.0 - ret_value;
}
else
{
dist6 = SQRT3 * x - z -SQRT3_2 +0.5;
dist7 = dist6 - 2.0;
switch((dist6 >= 0?0:1)+(dist7 >= 0.0 ?2:0))
{
case 1: /* left hexagon */
dist5 *= -1.0;
dist6 *= -1.0;
dist3 *= -1.0;
ret_value = min(dist6,dist3);
ret_value = min(ret_value,dist5);
ret_value = min(ret_value,1.0);
ret_value = 1.0 - ret_value;
break;
case 2: /* bottom hexagon */
dist1 *= -1.0;
ret_value = min(dist7,dist1);
ret_value = min(ret_value,1.0);
ret_value = 1.0 - ret_value;
break;
case 0:
default: /* slanted square */
dist2 *= -1.0;
dist7 *= -1.0;
ret_value = min(dist6,dist2);
ret_value = min(ret_value,dist7);
ret_value = 2.0 - ret_value;
break;
}
}
}
ret_value /= 3.0;
return ret_value;
}
static DBL tiling_dodeca_hex_5 (const VECTOR EPoint)
{
DBL x,z;
DBL dist1,dist2,dist3,dist4,ret_value;
DBL dist5,dist6,dist7;
DBL tmpx,tmpz;
int mirX,mirZ,rota;
mirX = mirZ = rota = 0;
x=EPoint[X];
z=EPoint[Z];
x -= (3.0+SQRT3)*floor(x/(3.0+SQRT3));
z -= (3.0+3.0*SQRT3)*floor(z/(3.0+3.0*SQRT3));
/* x,z is in { [0.0, SQRT3+3.0 [, [0.0, 3*SQRT3+3.0 [ }
** but there is some symmetry to simplify the testing
*/
if (z > 1.5*SQRT3+1.5)
{
/* translate */
z -= 1.5*SQRT3+1.5;
x += (x<(1.5+SQRT3_2) ? 1.0: -1.0)*(1.5+SQRT3_2);
}
if (x > 1.5+SQRT3_2)
{
x = 3.0 + SQRT3 -x;
mirX = 1 - mirX;
}
if (z > 1.0+SQRT3)
{
z = 2.0 + 2.0*SQRT3 -z;
mirZ = 1 - mirZ;
}
dist2 = x - SQRT3_2 - 1.5 + z * SQRT3;
if (dist2 < 0.0)
{
tmpx = x;
tmpz = z;
x = (3.0+SQRT3)/4.0 + 0.5 * tmpx - SQRT3_2 * tmpz ;
z = (3.0+3.0*SQRT3)/4.0 - SQRT3_2 * tmpx - 0.5 * tmpz ;
}
dist2 = x - SQRT3_2 - 2.5 + z * SQRT3;
dist1 = (z * 2.0 ) - SQRT3; /* from the bottom line */
dist3 = z - 1.5*SQRT3 - 0.5 + x * SQRT3;
dist4 = ((x-0.5) * 2.0 ); /* from the vertical line */
if ( (dist2 >= 0.0) &&
(dist1 >= 0.0) &&
(dist3 >= 0.0) &&
(dist4 >= 0.0) )
{
/* dodecagon */
ret_value = min(dist1,dist2);
ret_value = min(ret_value,dist3);
ret_value = min(ret_value,dist4);
ret_value = min(ret_value,1.0);
ret_value = 5.000001 - ret_value; // TODO FIXME - magic number! Should use nextafter()
}
else
{
dist5 = 2*z - 2*SQRT3 - 1.0;
if (dist5 >= 0)
{
dist4 *= -1.0;
ret_value = min(dist5,dist4);
ret_value = 2.0 - ret_value;
}
else
{
dist6 = SQRT3 * x - z -SQRT3_2 +0.5;
dist7 = dist6 - 2.0;
switch((dist6 >= 0?0:1)+(dist7 >= 0.0 ?2:0))
{
case 1: /* left hexagon */
dist5 *= -1.0;
dist6 *= -1.0;
dist3 *= -1.0;
ret_value = min(dist6,dist3);
ret_value = min(ret_value,dist5);
ret_value = min(ret_value,1.0);
ret_value = 1.0 - ret_value;
break;
case 2: /* bottom hexagon */
dist1 *= -1.0;
ret_value = min(dist7,dist1);
ret_value = min(ret_value,1.0);
ret_value = 1.0 - ret_value;
break;
case 0:
default: /* slanted square */
dist2 *= -1.0;
dist7 *= -1.0;
ret_value = min(dist6,dist2);
ret_value = min(ret_value,dist7);
ret_value = (mirZ + mirX) %2 + 3.0 - ret_value;
break;
}
}
}
ret_value /= 5.0;
return ret_value;
}
static DBL tiling_penrose_halfkite (DBL pX, DBL pZ, int depth, bool rhombs);
static DBL tiling_penrose_halfdart (DBL pX, DBL pZ, int depth, bool rhombs);
static DBL tiling_penrose_halfkite (DBL pX, DBL pZ, int depth, bool rhombs)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (z < (x - INVPHI) * TAN144)
{
return tiling_penrose_halfdart(x*PHI, z*PHI, depth-1, rhombs);
}
else
{
x -= COS36;
z -= SIN36;
DBL rotX = x*COS108 - z*SIN108;
DBL rotZ = z*COS108 + x*SIN108;
return tiling_penrose_halfkite(rotX*PHI, rotZ*PHI, depth-1, rhombs);
}
}
else if (rhombs)
{
if (z < (x - INVPHI) * TAN72)
{
DBL dist1 = abs( SIN72 * (x-INVPHI) - COS72 * z ) * 5.55; // TODO FIXME - the factor is just an empiric value
DBL dist2 = abs( SIN108 * (x-1) - COS108 * z ) * 5.55;
return max3(1.0-dist1/2,1.0-dist2/2,0.5+TILING_EPSILON);
}
else
{
DBL dist1 = abs( z ) * 5.55; // TODO FIXME - the factor is just an empiric value
DBL dist2 = abs( SIN72 * (x-INVPHI) - COS72 * z ) * 5.55;
return min(max3(0.5-dist1/2,0.5-dist2/2,0.0),0.5-TILING_EPSILON);
}
}
else
{
DBL dist1 = abs( SIN36 * x - COS36 * z ) * 4.46; // TODO FIXME - the factor is just an empiric value
DBL dist2 = abs( SIN108 * (x-1) - COS108 * z ) * 4.46;
return min(max3(0.5-dist1/2,0.5-dist2/2,0.0),0.5-TILING_EPSILON);
}
}
static DBL tiling_penrose_halfdart (DBL pX, DBL pZ, int depth, bool rhombs)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (z < (x - INVPHI) * TAN108)
{
DBL rotX = x*COS36 + z*SIN36;
DBL rotZ = z*COS36 - x*SIN36;
return tiling_penrose_halfkite(rotX*PHI, rotZ*PHI, depth-1, rhombs);
}
else
{
x -= 1;
DBL rotX = x*COS144 + z*SIN144;
DBL rotZ = z*COS144 - x*SIN144;
return tiling_penrose_halfdart(rotX*PHI, rotZ*PHI, depth-1, rhombs);
}
}
else if (rhombs)
{
DBL dist1 = abs( SIN36 * x - COS36 * z ) * 5.55; // TODO FIXME - the factor is just an empiric value
DBL dist2 = abs( SIN144 * (x-1) - COS144 * z ) * 5.55;
return min(max3(0.5-dist1/2,0.5-dist2/2,0.0),0.5-TILING_EPSILON);
}
else
{
DBL dist1 = abs( z ) * 4.46; // TODO FIXME - the factor is just an empiric value
DBL dist2 = abs( SIN144 * (x-1) - COS144 * z ) * 4.46;
return max3(1.0-dist1/2,1.0-dist2/2,0.5+TILING_EPSILON);
}
}
static DBL tiling_penrose (const VECTOR EPoint, bool rhombs, bool centerFlag)
{
// Penrose tiling
// rhombs=false: P2 ("kite and dart") Penrose tiling
// centerFlag=false: 5 darts at center forming a star
// centerFlag=true: 5 kites at center forming a regular decagon ("sun")
// rhombs=true: P3 ("rhombus") Penrose tiling
// centerFlag=false: 5 wide rhombs at center, surrounded by 5 narrow rhombs to form a regular decagon
// centerFlag=true: 5 wide rhombs at center, surrounded by 10 narrow rhombs to form a pointed star
DBL x,z;
x = EPoint[X];
z = EPoint[Z];
DBL r = sqrt(x*x+z*z);
if (r <= EPSILON)
return 1.0;
// exploit trivial mirror symmetry
z = abs(z);
// exploit rotational & mirror symmetry
if (x < r * COS36)
{
DBL rotSin;
DBL rotCos;
if (x < r *COS108)
{
rotSin = SIN144;
rotCos = COS144;
}
else
{
rotSin = SIN72;
rotCos = COS72;
}
DBL rotX = x*rotCos + z*rotSin;
DBL rotZ = z*rotCos - x*rotSin;
x = rotX;
z = abs(rotZ);
}
if (rhombs)
{
x *= INVPHI;
z *= INVPHI;
}
DBL dist = abs( SIN108 * x - COS108 * z ) / COS18;
int depth = max(0, (int)ceil(log(dist)/log(SQRPHI)));
x *= pow(INVSQRPHI,depth);
z *= pow(INVSQRPHI,depth);
if (depth % 2)
{
DBL rotX = x*COS36 + z*SIN36;
DBL rotZ = z*COS36 - x*SIN36;
x = rotX;
z = abs(rotZ);
}
depth *= 2;
if (centerFlag)
{
depth += 1;
x *= INVPHI;
z *= INVPHI;
}
return tiling_penrose_halfkite(x, z, depth, rhombs);
}
static DBL tiling_penrose1_pentagon1 (DBL pX, DBL pZ, int depth);
static DBL tiling_penrose1_pentagon2 (DBL pX, DBL pZ, int depth, bool insideQuad);
static DBL tiling_penrose1_pentagon3 (DBL pX, DBL pZ, int depth, bool insideWedge);
static DBL tiling_penrose1_star (DBL pX, DBL pZ, int depth);
static DBL tiling_penrose1_boat (DBL pX, DBL pZ, int depth, bool insideWedge);
static DBL tiling_penrose1_diamond (DBL pX, DBL pZ, int depth, bool sideA);
static void tiling_penrose1_pentagon_symmetry(DBL& x, DBL& z, DBL r)
{
z = abs(z);
if (x < r * COS36)
{
DBL rotSin;
DBL rotCos;
if (x < r *COS108)
{
rotSin = SIN144;
rotCos = COS144;
}
else
{
rotSin = SIN72;
rotCos = COS72;
}
DBL rotX = x*rotCos + z*rotSin;
DBL rotZ = z*rotCos - x*rotSin;
x = rotX;
z = abs(rotZ);
}
}
static void tiling_penrose1_pentagon_symmetry(DBL& x, DBL& z)
{
tiling_penrose1_pentagon_symmetry (x, z, sqrt(x*x+z*z));
}
static DBL tiling_penrose1_pentagon_dist (DBL pX, DBL pZ)
{
return abs( pX - 0.5/TAN36 ) * 5.55 * INVPHI; // TODO FIXME - the factor is just an empiric value
}
static DBL tiling_penrose1_pentagon1 (DBL pX, DBL pZ, int depth)
{
DBL x = pX;
DBL z = abs(pZ);
tiling_penrose1_pentagon_symmetry (x, z);
if (depth > 0)
{
if (z < (x - 0.5/TAN36) * TAN54 + 0.5)
{
DBL rotX = x - 0.5/TAN36 - INVPHI*0.5*COS72/SIN36;
DBL rotZ = z;
return tiling_penrose1_pentagon2 (rotX*PHI, rotZ*PHI, depth-1, false);
}
else
{
DBL rotX = x*COS36 + z*SIN36;
DBL rotZ = z*COS36 - x*SIN36;
return tiling_penrose1_star (rotX*PHI, rotZ*PHI, depth-1);
}
}
else
{
DBL dist = tiling_penrose1_pentagon_dist (x, z);
return min(max(1.0/6-dist/6,0.0),1.0/6-TILING_EPSILON);
}
}
static DBL tiling_penrose1_pentagon2 (DBL pX, DBL pZ, int depth, bool insideQuad)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (insideQuad)
{
if (z < (x - INVSQRPHI*0.5/SIN36) * TAN54)
{
DBL rotX = x - 0.5/SIN36;
DBL rotZ = z;
return tiling_penrose1_pentagon1 (rotX*PHI, rotZ*PHI, depth-1);
}
else if (z < (x - INVSQRPHI*0.5/SIN36) * TAN162)
{
DBL rotX = -x;
DBL rotZ = z;
return tiling_penrose1_diamond (rotX*PHI, rotZ*PHI, depth-1, true);
}
else
{
DBL rotX = x*COS108 - z*SIN108 + INVPHI*0.5/SIN36;
DBL rotZ = z*COS108 + x*SIN108;
return tiling_penrose1_pentagon2 (rotX*PHI, rotZ*PHI, depth-1, true);
}
}
else if (z < (x + 0.5/SIN36) * TAN18)
{
DBL rotX = x + 0.5/SIN36 - INVSQRPHI*0.5/SIN36;
DBL rotZ = z;
return tiling_penrose1_diamond (rotX*PHI, rotZ*PHI, depth-1, false);
}
else
{
DBL rotX = - (x*COS36 + z*SIN36) - COS72*0.5/SIN36;
DBL rotZ = (z*COS36 - x*SIN36) - SIN72*0.5/SIN36;
return tiling_penrose1_pentagon3 (rotX*PHI, rotZ*PHI, depth-1, false);
}
}
else
{
tiling_penrose1_pentagon_symmetry (x, z);
DBL dist = tiling_penrose1_pentagon_dist (x, z);
return min(max(2.0/6-dist/6,1.0/6+TILING_EPSILON),2.0/6-TILING_EPSILON);
}
}
static DBL tiling_penrose1_pentagon3 (DBL pX, DBL pZ, int depth, bool insideWedge)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (insideWedge && (x > INVSQRPHI*0.5*COS72/SIN36))
{
DBL rotX = -(x - INVSQRPHI*0.5*COS72/SIN36 - INVPHI*0.5/TAN36);
DBL rotZ = z;
return tiling_penrose1_pentagon2 (rotX*PHI, rotZ*PHI, depth-1, true);
return 1.0/6 + TILING_EPSILON;
}
else if (!insideWedge && (x < 0.5*COS108/SIN36))
{
DBL rotX = x*COS144 + z*SIN144 - 0.5/SIN36;
DBL rotZ = z*COS144 - x*SIN144;
return tiling_penrose1_pentagon2 (rotX*PHI, rotZ*PHI, depth-1, false);
}
else if (!insideWedge && (z > (x - INVSQRPHI*0.5/SIN36)*TAN126))
{
DBL rotX = - (x*COS36 - z*SIN36) - COS72*0.5/SIN36;
DBL rotZ = (z*COS36 + x*SIN36) - SIN72*0.5/SIN36;
return tiling_penrose1_pentagon3 (rotX*PHI, rotZ*PHI, depth-1, false);
}
else
{
return tiling_penrose1_boat (x*PHI, z*PHI, depth-1, insideWedge);
}
}
else
{
tiling_penrose1_pentagon_symmetry (x, z);
DBL dist = tiling_penrose1_pentagon_dist (x, z);
return min(max(3.0/6-dist/6,2.0/6+TILING_EPSILON),3.0/6-TILING_EPSILON);
}
}
static DBL tiling_penrose1_star (DBL pX, DBL pZ, int depth)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (x < INVPHI * 0.5/TAN36)
{
return tiling_penrose1_pentagon1(x*PHI, z*PHI, depth-1);
}
else
{
DBL rotX = -(x - INVPHI/TAN36);
DBL rotZ = z;
return tiling_penrose1_pentagon3(rotX*PHI, rotZ*PHI, depth-1, true);
}
}
else
{
DBL dist = abs( SIN162 * (x - PHI*0.5/SIN36) - COS162 * z) * 5.55 * INVPHI; // TODO FIXME - the factor is just an empiric value
return min(max(4.0/6-dist/6,3.0/6+TILING_EPSILON),4.0/6-TILING_EPSILON);
}
}
static DBL tiling_penrose1_boat (DBL pX, DBL pZ, int depth, bool insideWedge)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (insideWedge && (x > PHI*0.5*COS108/SIN36))
{
DBL rotX = -x;
DBL rotZ = z;
return tiling_penrose1_pentagon1 (rotX*PHI, rotZ*PHI, depth-1);
}
else
{
DBL rotX, rotZ;
if (insideWedge)
{
rotX = x;
rotZ = z;
}
else
{
rotX = x*COS72 - z*SIN72;
rotZ = z*COS72 + x*SIN72;
}
rotX += 0.5/SIN36;
return tiling_penrose1_pentagon3 (rotX*PHI, rotZ*PHI, depth-1, true);
}
}
else
{
DBL dist1 = abs( x - INVPHI*0.5*COS72/SIN36) * 5.55 * INVPHI; // TODO FIXME - the factor is just an empiric value
x = -x;
tiling_penrose1_pentagon_symmetry (x, z);
DBL dist2 = abs( SIN162 * (x - PHI*0.5/SIN36) - COS162 * z) * 5.55 * INVPHI; // TODO FIXME - the factor is just an empiric value
return min(max3(5.0/6-dist1/6,5.0/6-dist2/6,4.0/6+TILING_EPSILON),5.0/6-TILING_EPSILON);
}
}
static DBL tiling_penrose1_diamond (DBL pX, DBL pZ, int depth, bool sideA)
{
DBL x = pX;
DBL z = abs(pZ);
if (depth > 0)
{
if (sideA)
{
return tiling_penrose1_pentagon1(x*PHI, z*PHI, depth-1);
}
else
{
return tiling_penrose1_pentagon3(x*PHI, z*PHI, depth-1, true);
}
}
else
{
DBL dist = abs( SIN18 * (x + INVPHI*0.5/SIN36) - COS18 * z) * 5.55 * INVPHI; // TODO FIXME - the factor is just an empiric value
return min(max(6.0/6-dist/6,5.0/6+TILING_EPSILON),6.0/6-TILING_EPSILON);
}
}
static DBL tiling_penrose1 (const VECTOR EPoint, bool centerFlag)
{
// Penrose P1 ("pentagon, star, boat and diamond") tiling
// centerFlag=false: pentagon at center
// centerFlag=true: pentagram (star) at center
DBL x,z;
x = EPoint[X];
z = EPoint[Z];
DBL r = sqrt(x*x+z*z);
if (r <= EPSILON)
return 1.0;
tiling_penrose1_pentagon_symmetry (x, z, r);
DBL dist = x * 2 * TAN36;
int depth = max(0, (int)ceil(log(dist)/log(SQRPHI*SQRPHI)));
x *= pow(INVSQRPHI*INVSQRPHI,depth);
z *= pow(INVSQRPHI*INVSQRPHI,depth);
depth *= 4;
/*
if (centerFlag)
{
depth += 1;
x *= INVPHI;
z *= INVPHI;
}
*/
return tiling_penrose1_pentagon1(x, z, depth);
}
static unsigned char digon[]={ 0x0E, 0x0B };
static unsigned char trigon[][6]=
{
{ 0x0D, 0x05, 0x07 , 0x0D, 5,7 },
{ 0x0E, 0x0D, 0x16, 0x49, 7, 0x0B }
};
static unsigned char tetragon[][16]=
{
{ 0x0D, 5, 5, 7, 0x0D, 5, 5, 7, 0x0D, 5, 5, 7, 0x0D, 5, 5, 7 },
{ 0x0E, 0x0D, 5, 0x16, 0x49, 5, 7, 0x0B, 0x0E, 0x0D, 5, 0x16, 0x49, 5, 7, 0x0B },
{ 0x0D, 0x34, 0x7, 0x0B, 0x07, 0x0B, 0x0D, 0x34, 0x0D, 0x34, 0x7, 0x0B, 0x07, 0x0B, 0x0D, 0x34},
{ 0x0C, 0x06, 0x0C, 0x06, 0x09, 0x03, 0x09, 0x03, 0x0C, 0x06, 0x0C, 0x06, 0x09, 0x03, 0x09, 0x03 },
{ 7, 0x2C, 7, 0x2C, 0x0D, 0x83, 0x0D, 0x83, 0x2C, 7, 0x2C,7, 0x83, 0x0D, 0x83, 0x0D }
};
static unsigned char pentagon[][10]=
{
{ 0x0D, 5,5,5,7 , 0x0D, 5,5,5,7},
{ 0x0E, 0x0D,5,5,0x16, 0x49, 5,5,7,0x0B},
{ 7, 0x0C, 6, 0x0C, 0x24, 0x0D, 0x81, 3, 9, 3 },
{ 0x0D, 5, 0x34, 7, 0x0B, 15,15,15,15,15 },
{ 0x0D, 0xF0, 7, 0x0B, 0x0E , 15,15,15,15,15 },
{ 0x0E, 0x0A, 0x49, 5, 7, 0x0D, 5, 0x16, 0x0A, 0x0B },
{ 0x0B, 0x0E, 0x49, 0x16, 0x49, 7, 0x0D, 0x16, 0x49, 0x16 },
{ 0x2C, 5, 0x16, 0x0B, 0x0E, 0x0B, 0x0E, 0x49, 5, 0x83 },
{ 0x0E, 0x49, 5, 0x16, 0x0B, 0x0E, 0x49, 5, 0x16, 0x0B },
{ 0x0E, 0x0D, 0xC1, 0x16, 0x0B, 0x49, 0x34, 7, 0x0B, 0x0E },
{ 7, 0x2C, 5, 7, 0x2C, 0x0D, 0x83, 0x0D, 5, 0x83 },
{ 0x0D, 0x34, 7, 0x0D, 0xC1, 7, 0x0A, 0x0B, 0x0E, 0x0A}
};
static unsigned char hexagon[][12]=
{
{ 0x0D, 5, 5, 5, 5, 7, 0x0D, 5, 5, 5, 5, 7},
{ 0x2C, 5, 5, 5, 7, 0x0E, 0x0B, 0x0D, 5, 5, 5, 0x83 },
{ 0x0D, 0x34, 5, 5, 7, 0x0E, 7, 0x0B, 0x0D, 5, 5, 0xC1 },
{ 0x0D, 5, 0x34, 5, 7, 0x0E, 5, 7, 0x0B, 0x0D, 5, 0xC1 },
{ 0x0D, 0x83, 0x2C, 5, 5, 7 , 15,15,15,15,15,15},
{ 0x0C, 0x24, 5, 7, 0x0C, 6, 9, 3, 0x0D, 5, 0x81, 3 },
{ 7, 0x0C, 6, 0x0D, 0x14, 0x24, 0x0D, 0x81, 0x41, 7, 9, 3},
{ 0x0D, 5, 0x83, 0x2C, 5, 7, 15,15,15,15,15,15},
{ 7, 0x0C, 0x24, 7, 0x0C, 0x24, 0x0D, 0x81, 3, 0x0D, 0x81, 3},
{ 0x0C, 4, 6, 0x0C, 4, 6, 9, 1, 3, 9, 1, 3 },
{ 0x0E, 0x0D, 0x14, 6, 0x48, 6, 9, 0x12, 9, 0x41, 7, 0x0B},
{ 0x0D, 5, 0x16, 0x49, 0x16, 0x0B, 15,15,15,15,15,15},
{ 0x0D, 0x34, 5, 0x16, 0x0E, 0x0B, 0x0E, 0x0B, 0x49, 5, 0xC1, 7},
{ 0x0D, 0x34, 7, 0x16, 0x0A, 0x0D, 0x0A, 0x49, 7, 0xC1, 7, 0x0D},
{ 0x0D, 0x14, 0x82, 0x0E, 9, 3, 15,15,15,15,15,15},
{ 0x0E, 0x0D, 0xD0, 6, 9, 3, 15,15,15,15,15,15},
{ 0x0D, 0xF0, 5, 7, 0x0E, 0x0B, 0x0E, 0x0B, 0x0D, 5, 0xF0, 7},
{ 0x0E, 0x0B, 0x0D, 5, 5, 0x92, 0x68, 5, 5, 7, 0x0E, 0x0B},
{ 0x0E, 0x49, 5, 0x16, 0x0A, 0x0B, 15,15,15,15,15,15},
{ 0x0B, 0x2C, 5, 5, 0x83, 0x0E, 15,15,15,15,15,15},
{ 0x0B, 0x0A, 0x2C, 5, 5, 7, 15,15,15,15,15,15},
{ 0x2C, 5, 5, 0x16, 0x0B, 0x0E, 0x0E, 0x0B, 5, 0x83, 0x49, 5},
{ 0x0A, 0x0D, 0xC1, 0x16, 0x49, 0x34, 7, 0x0A, 0x0E, 0x0B, 0x0E, 0x0B},
{ 0x0D, 0x16, 0x0D, 5, 0x92, 0x0B, 0x0E, 0x68, 5, 7, 0x49, 7},
{ 0x0D, 0x16, 0x0D, 0x16, 0x16, 0x49, 0x16, 0x49, 0x49, 7, 0x49, 7},
{ 0x0C, 6, 0x0C, 6, 9, 0x12, 9, 0x12, 7, 0x49, 7, 0x49 },
{ 0x2C, 7, 0x2C, 7, 0x92, 0x0D, 0x92, 0x0D, 0x49, 7, 0x49, 7},
{ 0x0E, 0x49, 5, 0x16, 0x49, 7, 15,15,15,15,15,15},
{ 0x0D, 0x16, 0x0B, 0x0E, 0x49, 7, 0x16, 0x49, 5, 0x83, 0x2C, 5},
{ 7, 0x0E, 0x49, 0x34, 7, 0x49, 0x0D, 0xC1, 0x16, 0x0B, 0x0D, 0x16},
{ 0x2C, 5, 0xC1, 7, 0x0E, 0x0B, 0x0B, 0x0D, 0x34, 5, 0x83, 0x0E },
{ 0x0E, 0x0B, 0x0D, 0x34, 0xC1, 7, 15,15,15,15,15,15},
{ 0x0D, 5, 0x16, 0x2C, 7, 0x0A, 0x0A, 0x0D, 0x83, 0x49, 5, 7 },
{ 0x2C, 0xC1, 5, 7, 0x0E, 0x0B, 0x0E, 0x0B, 0x0D, 5, 0x34, 0x83 },
{ 0x0A, 0x0D, 5, 0x92, 0x68, 5, 7, 0x0A, 0x0B, 0x0E, 0x0E, 0x0B}
};
static DBL tetragonal (const VECTOR EPoint, const TPATTERN *TPat)
{
unsigned char how;
long xv,zv;
DBL return_value=0;
DBL value;
DBL value1;
DBL value2;
DBL x,y;
int lng=0;
zv = floor(y=EPoint[Z]);
xv = floor(x=EPoint[X]);
switch(TPat->Vals.Pavement.Tile)
{
case 6:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
case 1:
case 2:
case 3:
case 5:
case 6:
case 8:
case 9:
xv %= 6; if (xv < 0) { xv += 6 ;}
zv &= 0x01;
lng = 6;
break;
case 4:
case 7:
case 19:
case 20:
lng = 0;
zv %= 6; if (zv <0) { zv += 6;}
xv += 5*zv;
xv %= 6; if (xv <0) { xv += 6; }
break;
case 11:
case 18:
case 27:
lng = 0;
zv %= 6; if (zv <0) { zv += 6;}
xv += zv;
xv %= 6; if (xv <0) { xv += 6; }
break;
case 10:
case 12:
case 21:
case 22:
case 24:
case 25:
case 26:
lng = 4;
xv &= 0x03;
zv %= 3; if (zv<0) { zv += 3;}
break;
case 13:
case 32:
lng = 3;
zv &= 0x03;
xv %= 3; if (xv < 0) { xv += 3; }
break;
case 14:
lng = 3;
zv %= 6; if (zv < 0) { zv += 6; }
xv += 2 * (zv/2);
zv &= 0x01;
xv %= 3; if (xv < 0) { xv += 3; }
break;
case 15:
lng = 2;
xv %= 6; if (xv < 0) { xv+= 6; }
zv += (xv/2);
xv &= 0x01;
zv %= 3; if (zv<0) { zv += 3;}
break;
case 16:
case 17:
lng = 6;
zv %= 12; if (zv <0) { zv+=12; }
xv += zv/2;
zv &= 0x01;
xv %= 6; if (xv < 0) { xv+= 6; }
break;
case 23:
case 28:
lng = 6;
zv %= 12; if (zv <0) { zv+=12; }
xv += 4* (zv/2);
zv &= 0x01;
xv %= 6; if (xv < 0) { xv+= 6; }
break;
case 29:
case 30:
lng = 6;
zv &= 0x03;
xv += 3* (zv/2);
zv &= 0x01;
xv %= 6; if (xv < 0) { xv+= 6; }
break;
case 31:
lng = 0;
zv %= 3; if (zv <0) { zv+=3; }
xv += 4* zv;
xv %= 6; if (xv < 0) { xv+= 6; }
break;
case 33:
lng = 0;
zv %= 12; if (zv < 0) { zv+= 12; }
xv += 7*zv;
xv %= 12; if (xv < 0) { xv+= 12; }
break;
case 34:
lng = 4;
zv %= 6; if (zv<0) { zv+=6;}
xv += 2 * (zv/3);
xv &= 0x03;
zv %= 3; if (zv<0) { zv += 3;}
break;
}
how = hexagon[TPat->Vals.Pavement.Number-1][xv+zv*lng];
break;
case 5:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
case 1:
xv %= 5; if (xv <0) { xv += 5 ; }
zv &= 0x01;
break;
case 2:
case 9:
zv %= 10; if (zv <0) { zv += 10;}
xv += 3 * (zv/2);
xv %= 5; if (xv <0) { xv += 5; }
zv &= 0x01;
break;
case 10:
zv %= 10; if (zv <0) { zv += 10;}
xv += 4*(zv/2);
xv %= 5; if (xv <0) { xv += 5 ; }
zv &= 0x01;
break;
case 3:
zv %= 5; if (zv <0) { zv += 5;}
xv += 2*zv;
xv %= 5; if (xv <0) { xv += 5 ; }
zv = 0x0;
break;
case 4:
zv %= 5; if (zv <0) { zv += 5;}
xv += 2 * zv;
xv %= 5; if (xv <0) { xv += 5; }
zv = 0x00;
break;
case 5:
case 6:
case 8:
zv %= 10; if (zv <0) { zv += 10;}
xv += zv;
xv %= 10; if (xv <0) { xv += 10; }
zv = 0x00;
break;
case 11:
zv %= 10; if (zv <0) { zv += 10;}
xv += 8* zv;
xv %= 10; if (xv <0) { xv += 10; }
zv = 0x00;
break;
case 7:
zv %= 10; if (zv <0) { zv += 10;}
xv += 3*zv;
xv %= 10; if (xv <0) { xv += 10; }
zv = 0x00;
break;
}
how = pentagon[TPat->Vals.Pavement.Number-1][xv+zv*5];
break;
case 4:
xv &= 0x03;
zv &= 0x03;
how = tetragon[TPat->Vals.Pavement.Number-1][xv+zv*4];
break;
case 3:
xv %= 3; if (xv < 0) { xv += 3; }
zv &= 0x01;
how = trigon[TPat->Vals.Pavement.Number-1][xv+zv*3];
break;
case 2:
zv &= 0x01;
how = digon[zv];
break;
case 1:
default:
how = 0x0F;
break;
}
/*
** 5---1---6
** | |
** 4 2
** | |
** 8---3---7
*/
x -= floor(x);
y -= floor(y);
switch(TPat->Vals.Pavement.Form)
{
case 2:
if ((how & 0x16) == 0x16)
{
value1 = 2*x;
value2 = 2 - 2*y;
value = fabs(sqrt(value1*value1+value2*value2) - 1.0);
return_value = min(value,1.0);
return return_value;
}
if ((how & 0x2C) == 0x2C)
{
value1 = 2 - 2*x;
value2 = 2 - 2*y;
value = fabs(sqrt(value1*value1+value2*value2) - 1.0);
return_value = min(value,1.0);
return return_value;
}
if ((how & 0x49) == 0x49)
{
value1 = 2 - 2*x;
value2 = 2*y;
value = fabs(sqrt(value1*value1+value2*value2) - 1.0);
return_value = min(value,1.0);
return return_value;
}
if ((how & 0x83) == 0x83)
{
value1 = 2*x;
value2 = 2*y;
value = fabs(sqrt(value1*value1+value2*value2) - 1.0);
return_value = min(value,1.0);
return return_value;
}
break;
case 1:
if ((how & 0x16) == 0x16)
{
value1 = 2*x;
value2 = 2*y;
value = fabs(value1 - value2 + 1.0);
return_value = min(value,1.0);
return return_value;
}
if ((how & 0x2C) == 0x2C)
{
value1 = 2*x;
value2 = 2 - 2*y;
value = fabs(value2 - value1 + 1.0);
return_value = min(value,1.0);
return return_value;
}
if ((how & 0x49) == 0x49)
{
value1 = 2*x;
value2 = 2*y;
value = fabs(value2 - value1 + 1.0);
return_value = min(value,1.0);
return return_value;
}
if ((how & 0x83) == 0x83)
{
value1 = 2*x;
value2 = 2 - 2*y;
value = fabs(value1 - value2 + 1.0);
return_value = min(value,1.0);
return return_value;
}
break;
case 0:
if ((how & 0x16) == 0x16)
{
value1 = 2*x -1;
value2 = 1 - 2*y;
return_value = max(value1,value2);
value1 = 1 - 2*x;
value2 = 2*y - 1;
value = min(value1,value2);
return_value = max(return_value,value);
return return_value;
}
if ((how & 0x2C) == 0x2C)
{
value1 = 1 - 2*x;
value2 = 1 - 2*y;
return_value = max(value1,value2);
value1 = 2*x - 1;
value2 = 2*y - 1;
value = min(value1,value2);
return_value = max(return_value,value);
return return_value;
}
if ((how & 0x49) == 0x49)
{
value1 = 1 - 2*x;
value2 = 2*y - 1;
return_value = max(value1,value2);
value1 = 2*x - 1;
value2 = 1 - 2*y;
value = min(value1,value2);
return_value = max(return_value,value);
return return_value;
}
if ((how & 0x83) == 0x83)
{
value1 = 2*x -1;
value2 = 2*y -1;
return_value = max(value1,value2);
value1 = 1 - 2*x;
value2 = 1 - 2*y;
value = min(value1,value2);
return_value = max(return_value,value);
return return_value;
}
break;
default:
case 3:
break;
}
if (how & 0x01)
{
value = 2*y - 1;
return_value = max(return_value,value);
}
if (how & 0x02)
{
value = 2*x -1;
return_value = max(return_value,value);
}
if (how & 0x04)
{
value = 1 - 2*y;
return_value = max(return_value,value);
}
if (how & 0x08)
{
value = 1 - 2*x;
return_value = max(return_value,value);
}
switch(TPat->Vals.Pavement.Interior)
{
case 2:
if (how & 0x40)
{
value1 = 2 - 2*x;
value2 = 2*y;
value = 1.0- sqrt(value1*value1+value2*value2);
return_value = max(return_value,value);
}
if (how & 0x80)
{
value1 = 2*x;
value2 = 2*y;
value = 1.0- sqrt(value1*value1+value2*value2);
return_value = max(return_value,value);
}
if (how & 0x10)
{
value1 = 2*x;
value2 = 2 - 2*y;
value = 1.0- sqrt(value1*value1+value2*value2);
return_value = max(return_value,value);
}
if (how & 0x20)
{
value1 = 2 - 2*x;
value2 = 2 - 2*y;
value = 1.0- sqrt(value1*value1+value2*value2);
return_value = max(return_value,value);
}
break;
case 1:
if (how & 0x40)
{
value1 = 2 - 2*x;
value2 = 2*y;
value = 1.0- (value1+value2);
return_value = max(return_value,value);
}
if (how & 0x80)
{
value1 = 2*x;
value2 = 2*y;
value = 1.0- (value1+value2);
return_value = max(return_value,value);
}
if (how & 0x10)
{
value1 = 2*x;
value2 = 2 - 2*y;
value = 1.0- (value1+value2);
return_value = max(return_value,value);
}
if (how & 0x20)
{
value1 = 2 - 2*x;
value2 = 2 - 2*y;
value = 1.0- (value1+value2);
return_value = max(return_value,value);
}
break;
default:
case 0:
if (how & 0x10)
{
value1 = 1 - 2*x;
value2 = 2*y - 1;
value = min(value1,value2);
return_value = max(return_value,value);
}
if (how & 0x20)
{
value1 = 2*x - 1;
value2 = 2*y - 1;
value = min(value1,value2);
return_value = max(return_value,value);
}
if (how & 0x40)
{
value1 = 2*x - 1;
value2 = 1 - 2*y;
value = min(value1,value2);
return_value = max(return_value,value);
}
if (how & 0x80)
{
value1 = 1 - 2*x;
value2 = 1 - 2*y;
value = min(value1,value2);
return_value = max(return_value,value);
}
break;
}
switch(TPat->Vals.Pavement.Exterior)
{
case 2:
value1 = 2*x - 1;
value2 = 2*y - 1;
if ( (((how & 0x06) == 0x06)&&(value1>=0.0)&&(value2<=0.0)) ||
(((how & 0x0C) == 0x0C)&&(value1<=0.0)&&(value2<=0.0)) ||
(((how & 0x09) == 0x09)&&(value1<=0.0)&&(value2>=0.0)) ||
(((how & 0x03) == 0x03)&&(value1>=0.0)&&(value2>=0.0)) )
{
value = sqrt(value1*value1+value2*value2);
value = min(value,1.0);
return_value = max(return_value,value);
}
break;
case 1:
if ((how & 0x06) == 0x06)
{
value1 = 2 - 2*x;
value2 = 2*y;
value = 2.0- (value1+value2);
value = min(value,1.0);
return_value = max(return_value,value);
}
if ((how & 0x0C) == 0x0C)
{
value1 = 2*x;
value2 = 2*y;
value = 2.0- (value1+value2);
value = min(value,1.0);
return_value = max(return_value,value);
}
if ((how & 0x09) == 0x09)
{
value1 = 2*x;
value2 = 2 - 2*y;
value = 2.0- (value1+value2);
value = min(value,1.0);
return_value = max(return_value,value);
}
if ((how & 0x03) == 0x03)
{
value1 = 2 - 2*x;
value2 = 2 - 2*y;
value = 2.0- (value1+value2);
value = min(value,1.0);
return_value = max(return_value,value);
}
break;
default:
case 0:
break;
}
return return_value;
}
static unsigned short tritrigon[][6]=
{
{0x215,0x344,0x126, 0x126,0x344,0x215}
};
static unsigned short tritetragon[][8]=
{
{0x126,0x126,0x144,0x144, 0x126,0x126,0x144,0x144},
{0x611,0x344,0x126,0x423, 0x611,0x344,0x126,0x423},
{5,0,6,3, 0,5,3,6}
};
static unsigned short tripentagon[][10]=
{
{0x215,0x244,4,0x144,0x126, 0x126,0x144,4,0x244,0x215},
{0x215,0x244,0x244,0x611,0x611, 0x244,0x244,0x215,0x423,0x423},
{0x146,0x126,0x344,0x611,0x611, 0x344, 0x126,0x146,0x522,0x522},
{5,0,0x244,0x215,3, 3,0x215,0x244,0,5}
};
static unsigned short trihexagon[][12]=
{
{0x215,0x244,4,4,0x244,0x215, 0x215,0x244,4,4,0x244,0x215},
{0x413,0x522,0x144,4,0x244,0x215, 0x413,0x522,0x144,4,0x244,0x215},
{3,0x126,0x144,0,0x244,0x215, 3,0x126,0x144,0,0x244,0x215},
{0x215,0x244,4,0,6,3, 4,0x244,0x215,3,6,0},
{5,0,0x244,0x215,0x245,0x211, 5,0x211,0x245,0x215,0x244,0},
{0x245,0x211,0x215,0x244,0x244,0x211, 0x245,0x211,0x244,0x244,0x215,0x211},
{0x215,0x244,0x244,0x611, 0x522,0x146,0x146,0x522, 0x611,0x244,0x244,0x215},
{5,0,0x244,0x215, 0x146,0x122,0x122,0x146, 0x215,0x244,0,5},
{5,0,6,0x126,0x344,0x211, 5,0x211,0x344,0x126,6,0},
{0x215,0x344,0x122,0x122,0x344,0x215, 0x215,0x344,0x122,0x122,0x344,0x215},
{5,0,6,6,0,5, 6,0,5,5,0,6},
{0x691,0x3C4,0x5A2,0x5A2,0x3C4,0x691, 0x5A2,0x3C4,0x691,0x691,0x3C4,0x5A2},
};
static DBL trigonal (const VECTOR EPoint, const TPATTERN *TPat)
{
unsigned short how;
long xv,zv;
DBL return_value=0;
DBL value;
DBL value1;
DBL value2;
DBL dist1;
DBL dist2;
DBL dist3;
DBL x,z;
int lng=0;
x=EPoint[X];
z=EPoint[Z];
xv = floor(x);
zv = floor(z/SQRT3);
x -= xv;
z -= SQRT3*zv;
/* x,z is in { [0.0, 1.0 [, [0.0, SQRT3 [ }
** There is some mirror to reduce the problem
*/
zv *= 2;
xv *= 2;
if ( z > SQRT3_2 )
{
z -= SQRT3_2;
if (x>0.5)
{
x -= 0.5;
xv++;
}
else
{
x += 0.5;
xv--;
}
zv++;
}
if ((x == 0.0)||(z/x>SQRT3))
{
z = SQRT3_2 - z;
x = 0.5 -x;
xv--;
}
if ((x == 1.0)||(z/(1.0-x)>SQRT3))
{
z = SQRT3_2 - z;
x = 1.5 -x;
xv++;
}
switch(TPat->Vals.Pavement.Tile)
{
case 6:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
case 1:
case 9:
xv += 5*zv;
zv = 0;
xv %= 6; if (xv <0) { xv += 6;}
lng = 0;
break;
case 2:
case 10:
case 11:
zv &= 0x01;
xv += 3*zv;
xv %= 6; if (xv <0) { xv += 6;}
lng = 0;
break;
case 3:
xv += 14*((zv%6+((zv%6)<0?6:0))/2);
xv %= 6; if (xv <0) { xv += 6;}
lng = 6;
zv &= 0x01;
break;
case 4:
case 8:
xv += 8*((zv%6+((zv%6)<0?6:0))/2);
xv %= 6; if (xv <0) { xv += 6;}
lng = 6;
zv &= 0x01;
break;
case 5:
xv %= 6; if (xv <0) { xv += 6;}
lng = 6;
zv &= 0x01;
break;
case 6:
case 7:
xv -= ((zv%12+((zv%12)<0?12:0))/3);
xv &= 3;
lng = 4;
zv %= 3; if (zv <0) { zv +=3;}
break;
}
how = trihexagon[TPat->Vals.Pavement.Number-1][xv+zv*lng];
break;
case 5:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
case 1:
case 2:
zv &= 0x01;
xv += 5*zv;
xv %= 10; if (xv <0) { xv += 10 ; }
zv = 0x00;
break;
case 3:
zv %= 10; if (zv <0) { zv += 10; }
xv += 3*zv;
xv %= 10; if (xv <0) { xv += 10 ; }
zv = 0x00;
break;
}
how = tripentagon[TPat->Vals.Pavement.Number-1][xv];
break;
case 4:
zv &= 0x03;
xv += zv;
xv &= 0x03;
zv &= 0x01;
how = tritetragon[TPat->Vals.Pavement.Number-1][xv+zv*4];
break;
case 3:
zv &= 0x01;
xv += 3*zv;
xv %= 6; if (xv < 0) { xv += 6; }
zv = 0x00;
how = tritrigon[TPat->Vals.Pavement.Number-1][xv];
break;
case 2:
how = 0x166;
break;
case 1:
default:
how = 0x07;
break;
}
/*
** / \
** 1 \
** / 2
** / \
** -----3-----
** *3/2
*/
if (how & 0x01)
{
dist1 = 1.0 - (fabs(SQRT3 * x - z) * SQRT3 );
return_value = max(return_value,dist1);
}
if (how & 0x02)
{
dist2 = 1.0 - (fabs(SQRT3 * (1.0-x) - z) * SQRT3 );
return_value = max(return_value,dist2);
}
if (how & 0x04)
{
dist3 = 1.0 - (z * 2.0 * SQRT3 );
return_value = max(return_value,dist3);
}
switch(TPat->Vals.Pavement.Interior)
{
case 1:
dist1 = (1.0 - (fabs(SQRT3 * z + x) ));
dist2 = (1.0 - (fabs(SQRT3 * z - x + 1.0) ));
dist3 = (1.0 - (x * 2.0 ));
if (((how & 0x83) == 0x00)&&(dist1<0)&&(dist2<0))
{
value1 = (3.0 / 2.0 *(fabs(SQRT3 * z + x) ) - 2.0);
value2 = (3.0 / 2.0 *(fabs(SQRT3 * z - x + 1.0) ) - 2.0);
value = min(value1,value2);
return_value = max(return_value,value);
}
if (((how & 0x85) == 0x00)&&(dist1>0)&&(dist3>0))
{
value1 = (1.0 - 3.0 / 2.0 * (fabs(SQRT3 * z + x) ));
value2 = (1.0 - (x * 3.0 ));
value = min(value1,value2);
return_value = max(return_value,value);
}
if (((how & 0x86) == 0x00)&&(dist3<0)&&(dist2>0))
{
value1 = (1.0 - 3.0 / 2.0 *(fabs(SQRT3 * z - x + 1.0) ));
value2 = ((x * 3.0 ) - 2.0);
value = min(value1,value2);
return_value = max(return_value,value);
}
break;
case 2:
if ((how & 0x83) == 0x00)
{
dist1 = x - 0.5;
dist2 = z - SQRT3_2;
dist3 = 1.0 - (sqrt((dist1*dist1+dist2*dist2))*3.0 );
return_value = max(return_value,dist3);
}
if ((how & 0x85) == 0x00)
{
dist1 = x;
dist2 = z;
dist3 = 1.0 - (sqrt((dist1*dist1+dist2*dist2)) *3.0);
return_value = max(return_value,dist3);
}
if ((how & 0x86) == 0x00)
{
dist1 = x - 1.0;
dist2 = z ;
dist3 = 1.0 - (sqrt((dist1*dist1+dist2*dist2)) *3.0);
return_value = max(return_value,dist3);
}
break;
case 0:
if ((how & 0x83) == 0x00)
{
dist3 = 1.0 - ((SQRT3_2 - z) * 2.0 * SQRT3 );
return_value = max(return_value,dist3);
}
if ((how & 0x85) == 0x00)
{
dist2 = 1.0 - (fabs(SQRT3 * x + z) * SQRT3 );
return_value = max(return_value,dist2);
}
if ((how & 0x86) == 0x00)
{
dist1 = 1.0 - (fabs(SQRT3 * (x -1.0) - z) * SQRT3 );
return_value = max(return_value,dist1);
}
break;
}
switch(TPat->Vals.Pavement.Exterior)
{
case 2:
dist1 = (1.0 - (fabs(SQRT3 * z + x) ));
dist2 = (1.0 - (fabs(SQRT3 * z - x + 1.0) ));
dist3 = (1.0 - (x * 2.0 ));
if ( (((how & 0x03) == 0x03)&&(dist1<=0.0)&&(dist2<=0.0)) ||
(((how & 0x06) == 0x06)&&(dist2>=0.0)&&(dist3<=0.0)) ||
(((how & 0x05) == 0x05)&&(dist1>=0.0)&&(dist3>=0.0)) )
{
value1 = x - 0.5;
value2 = z - SQRT3_2/3.0;
value = 2 * SQRT3 *sqrt(value1*value1+value2*value2);
return_value = min(1.0,value);
}
break;
case 1:
/* dist1 = (1.0 - (fabs(SQRT3 * z + x) )); */
dist1 = (1.0 - (fabs(SQRT3 * x - z)*SQRT3 ));
/* dist2 = (1.0 - (fabs(SQRT3 * z - x + 1.0) )); */
dist2 = (1.0 - (fabs(SQRT3 * (1.0 -x ) -z ) *SQRT3));
/* dist3 = (1.0 - (x * 2.0 )); */
dist3 = (1.0 - (z * 2.0 * SQRT3));
value1 = (x - 0.5);
value2 = (z - SQRT3_2/3.0);
if (((how & 0x03) == 0x03)&&(dist1>=0.0)&&(dist2>=0.0))
{
value = fabs(value2 * 2.0 * SQRT3 );
return_value = min(1.0,value);
}
if (((how & 0x06) == 0x06)&&(dist2>=0.0)&&(dist3>=0.0))
{
value = fabs(SQRT3 * value1 - value2) * SQRT3 ;
return_value = min(1.0,value);
}
if (((how & 0x05) == 0x05)&&(dist1>=0.0)&&(dist3>=0.0))
{
value = fabs(SQRT3 * value1 + value2) * SQRT3 ;
return_value = min(1.0,value);
}
break;
case 0:
default:
break;
}
dist1 = (1.0 - (fabs(SQRT3 * z + x) ));
dist2 = (1.0 - (fabs(SQRT3 * z - x + 1.0) ));
dist3 = (1.0 - (x * 2.0 ));
switch(TPat->Vals.Pavement.Form)
{
case 2:
if (((how & 0x120) == 0x120)&&(dist1<0)&&(dist2<0))
{
value1 = x;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x140) == 0x140)&&(dist1>0)&&(dist3>0))
{
value1 = x - 0.5;
value2 = z- SQRT3_2;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x210) == 0x210)&&(dist1<0)&&(dist2<0))
{
value1 = x - 1.0;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x240) == 0x240)&&(dist3<0)&&(dist2>0))
{
value1 = x - 0.5;
value2 = z - SQRT3_2;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x410) == 0x410)&&(dist1>0)&&(dist3>0))
{
value1 = x - 1.0;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x420) == 0x420)&&(dist3<0)&&(dist2>0))
{
value1 = x;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
break;
case 1:
if (((how & 0x120) == 0x120)&&(dist1<0)&&(dist2<0))
{
value = -dist1 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x140) == 0x140)&&(dist1>0)&&(dist3>0))
{
value = dist1 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x210) == 0x210)&&(dist1<0)&&(dist2<0))
{
value = -dist2 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x240) == 0x240)&&(dist3<0)&&(dist2>0))
{
value = dist2 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x410) == 0x410)&&(dist1>0)&&(dist3>0))
{
value = dist3 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x420) == 0x420)&&(dist2>0)&&(dist3<0))
{
value = -dist3 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x120) == 0x120)&&(dist1<0)&&(dist2<0))
{
value = -dist1 * 2;
return_value = min(value,1.0);
return return_value;
}
break;
default:
case 0:
break;
}
return return_value;
}
/*
** open face (3 bits)
** special (1 bit)
** nexus vertex/open face (3 bits)
** unused (1 bits)
** close face (3 bits)
*/
static unsigned short hexmonogon[][6]=
{
{0x691,0x3C4,0x5A2,0x5A2,0x3C4,0x691}
};
static unsigned short hexdigon[][12]=
{
{0x691,0x3C4,0x1A2,0x1A2,0x3C4,0x691,0x5A2,0x1C4,0x6080,0x6080,0x1C4,0x5A2 }
};
static unsigned short hextrigon[][36]=
{
{
0x691,0x3C4,0x5A2, 0x5A2,0x3C4, 0x691,
0x5A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x691,0x3C4,0x5A2
},
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x691,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x691,0x2C4,0x4080, 0x1080,0x1080,0x491,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
0x491,0x1080,0x1080, 0x4080,0x2C4,0x691,
0x4A2,0x2080,0x2080, 0x4080,0x1C4,0x5A2
},
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
0x5A2,0x1C4,0x6080,0x6080,0x0C4,0x5080,0x5080,0x2C4,0x691,
0x5A2,0x1C4,0x6080,0x6080,0x0C4,0x5080,0x5080,0x2C4,0x691,
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x291, 0x291,0x3C4,0x5A2
}
};
static unsigned short hextetragon[][48]=
{
{
0x691,0x3C4,0x5A2, 0x5A2,0x3C4, 0x691,
0x5A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x691,0x3C4,0x5A2
},
{
0x691,0x2C4,0x4080, 0x1080,0x80,0x2080,
0x4080,0x2C4,0x691, 0x291,0x3C4,0x1A2,
0x4080,0x1C4,0x5A2, 0x1A2,0x3C4,0x291,
0x5A2,0x1C4,0x4080, 0x2080,0x80,0x1080,
0x691,0x2C4,0x4080, 0x1080,0x80,0x2080,
0x4080,0x2C4,0x691, 0x291,0x3C4,0x1A2,
0x4080,0x1C4,0x5A2, 0x1A2,0x3C4,0x291,
0x5A2,0x1C4,0x4080, 0x2080,0x80,0x1080
},
{
0x691,0x2C4,0x5080, 0x5080,0x0C4,0x6080,
0x6080,0x0C4,0x5080, 0x5080,0x2C4,0x691,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x1A2,
0x1A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
0x691,0x2C4,0x5080, 0x5080,0x0C4,0x6080,
0x6080,0x0C4,0x5080, 0x5080,0x2C4,0x691,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x1A2,
0x1A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
},
{
0x691,0x3C4,0x5A2, 0x4A2,0x3080,0x491,
0x1A2,0x3C4,0x691, 0x691,0x3C4,0x5A2,
0x6080,0x1C4,0x5A2, 0x1A2,0x3C4,0x691,
0x5A2,0x1C4,0x6080, 0x6080,0x1C4,0x5A2,
0x491,0x3080,0x0A2, 0x5A2,0x1C4,0x6080,
0x4A2,0x3080,0x491, 0x491,0x3080,0x0A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2
},
{
0x691,0x3C4,0x1A2, 0x5A2,0x1C4,0x6080,
0x5080,0x2C4,0x691, 0x491,0x3080,0x0A2,
0x291,0x3C4,0x5A2, 0x4A2,0x3080,0x091,
0x5A2,0x3C4,0x291, 0x691,0x2C4,0x5080,
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x1A2,0x3C4,0x691, 0x091,0x3080,0x4A2,
0x6080,0x1C4,0x5A2, 0x0A2,0x3080,0x491,
0x5A2,0x1C4,0x6080, 0x6080,0x1C4,0x5A2
},
{
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x491,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x691,0x2C4,0x4080, 0x1080,0x1080,0x491,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
0x491,0x1080,0x1080,0x4080,0x2C4,0x691,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2,
0x491,0x3080,0x0A2, 0x5A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2
},
{
0x691,0x3C4,0x5A2, 0x1A2,0x3C4,0x691, 0x091,0x3080,0x0A2, 0x5A2,0x3C4,0x291,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2,0x4A2,0x3080,0x491, 0x691,0x2C4,0x5080,
0x091,0x3080,0x0A2, 0x5A2,0x3C4,0x291, 0x691,0x3C4,0x5A2, 0x1A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x691,0x2C4,0x5080,0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2
}
};
static unsigned short hexpentagon[][60]=
{ /* 0 */
{
0x691,0x3C4,0x5A2, 0x5A2,0x3C4, 0x691,
0x5A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x691,0x3C4,0x5A2
},
/* 1 */
{
0x6080,0x1C4,0x5A2, 0x1A2,0x3C4,0x691,
0x5A2,0x1C4,0x6080, 0x6080,0x1C4,0x5A2 ,
0x491,0x3080,0x0A2, 0x5A2,0x1C4,0x6080,
0x4A2,0x3080,0x491, 0x491,0x3080,0x0A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x4A2,0x3080,0x491,
0x1A2,0x3C4,0x691, 0x691,0x3C4,0x5A2
},
/* 2 */
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4, 0x691,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x691,0x2C4,0x4080, 0x1080,0x1080,0x491,
0x5A2,0x3C4,0x691, 0x091,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x091, 0x691,0x3C4,0x5A2,
0x491,0x1080,0x1080,0x4080,0x2C4,0x691,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2
},
/* 3 */
{
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x491,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x691,0x2C4,0x4080, 0x1080,0x1080,0x491,
0x5A2,0x3C4,0x691, 0x091,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x091, 0x691,0x3C4,0x5A2,
0x491,0x1080,0x1080,0x4080,0x2C4,0x691,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2,
0x491,0x3080,0x0A2, 0x5A2,0x3C4, 0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2
},
/* 4 */
{
0x6080,0x1C4,0x5A2, 0x0A2,0x3080,0x491,
0x5A2,0x1C4,0x6080, 0x6080,0x1C4,0x5A2,
0x491,0x3080,0x0A2, 0x5A2,0x1C4,0x6080,
0x4A2,0x3080,0x491, 0x491,0x3080,0x0A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x4A2,0x3080,0x491,
0x5A2,0x3C4,0x691, 0x691,0x3C4,0x5A2,
0x491,0x3080,0x4A2, 0x5A2,0x3C4,0x691,
0x0A2,0x3080,0x491, 0x491,0x3080,0x4A2,
},
/* 5 */
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4, 0x691,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x491,0x1080,0x080, 0x080,0x1080,0x491,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2,
0x491,0x3080,0x0A2, 0x5A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x491,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x491,0x1080,0x080, 0x080,0x1080,0x491,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2
},
/* 6 */
{
0x691,0x2C4,0x4080, 0x1080,0x1080, 0x491,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
0x491,0x1080,0x1080,0x4080,0x2C4,0x691,
0x4A2,0x2080,0x080, 0x080,0x2080,0x4A2,
0x491,0x1080,0x080, 0x080,0x1080,0x491,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2,
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x691,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x491,0x1080,0x080, 0x080,0x1080,0x491,
0x4A2,0x2080,0x080, 0x080,0x2080,0x4A2
},
/* 7 */
{
0x6080,0x1C4,0x5A2,
0x5A2,0x1C4,0x4080,
0x691,0x2C4,0x4080,
0x4080,0x2C4,0x691,
0x4080,0x1C4,0x5A2,
0x5A2,0x1C4,0x6080,
0x691,0x3C4,0x1A2,
0x5A2,0x1C4,0x6080,
0x491,0x3080,0x0A2,
0x4A2,0x3080,0x091,
0x491,0x1080,0x1080,
0x4A2,0x2080,0x2080,
0x691,0x3C4,0x1A2,
0x1A2,0x3C4,0x691,
0x2080,0x2080,0x4A2,
0x1080,0x1080,0x491,
0x091,0x3080,0x4A2,
0x0A2,0x3080,0x491,
0x6080,0x1C4,0x5A2,
0x1A2,0x3C4,0x691
},
/* 8 */
{
0x6080,0x0C4,0x5080, 0x5080,0x2C4, 0x291,
0x5A2,0x3C4,0x291, 0x291,0x2C4,0x5080,
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x5080,0x2C4,0x691, 0x091,0x3080,0x4A2,
0x091,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x491,
0x5A2,0x1C4,0x6080, 0x6080,0x1C4,0x5A2,
0x691,0x3C4,0x1A2, 0x5A2,0x1C4,0x6080,
0x1A2,0x3C4,0x291, 0x691,0x3C4,0x1A2
},
/* 9 */
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x691,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2,
0x291,0x3C4,0x1A2, 0x1A2,0x3C4,0x291,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x5080,
0x491,0x3080,0x0A2, 0x5A2,0x3C4,0x691,
0x6A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x491,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2,
0x291,0x3C4,0x1A2, 0x1A2,0x3C4,0x291,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x5080,
},
/* 10 */
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x691,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x491,0x1080,0x80, 0x80,0x1080,0x091,
0x4A2,0x2080,0x2080, 0x4080,0x0C4,0x5080,
0x691,0x3C4,0x1A2, 0x5A2,0x3C4,0x291,
0x5080,0x2C4,0x691, 0x691,0x2C4,0x5080,
0x291,0x3C4,0x5A2, 0x1A2,0x3C4,0x691,
0x5080,0x0C4,0x4080, 0x2080,0x2080,0x4A2,
0x091,0x1080,0x80, 0x80,0x1080,0x491,
0x4A2,0x2080,0x2080, 0x4080,0x1C4,0x5A2
},
/* 11 */
{
0x291,0x3C4,0x5A2, 0x1A2,0x3C4,0x691,
0x4080,0x0C4,0x4080, 0x2080,0x2080,0x4A2,
0x4080,0x0C4,0x4080, 0x1080,0x1080,0x491,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x5A2,
0x491,0x1080,0x1080,0x4080,0x0C4,0x4080,
0x4A2,0x2080,0x2080,0x4080,0x0C4,0x4080,
0x691,0x3C4,0x1A2, 0x5A2,0x3C4,0x291,
0x1A2,0x3C4,0x691, 0x491,0x1080,0x1080,
0x2080,0x2080,0x4A2, 0x4A2,0x2080,0x2080,
0x1080,0x1080,0x491, 0x691,0x3C4,0x1A2
},
/* 12 */
{
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x5080,0x2C4,0x691, 0x091,0x3080,0x4A2,
0x291,0x3C4,0x5A2, 0x0A2,0x3080,0x491,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2,
0x291,0x3C4,0x1A2, 0x1A2,0x3C4,0x291,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x5080,
0x491,0x3080,0x0A2, 0x5A2,0x3C4,0x291,
0x4A2,0x3080,0x091, 0x691,0x2C4,0x5080,
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x5A2
},
/* 13 */
{
0x691,0x3C4,0x5A2, 0x5A2,0x3C4,0x691,
0x5A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x091,
0x4A2,0x3080,0x091, 0x691,0x2C4,0x5080,
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x291,
0x5080,0x2C4,0x291, 0x291,0x2C4,0x5080,
0x291,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x5080,0x2C4,0x691, 0x091,0x3080,0x4A2,
0x091,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x691,0x3C4,0x5A2
},
/* 14 */
{
0x291,0x3C4,0x5A2, 0x5A2,0x3C4,0x691,
0x5A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2,0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491,0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2,0x4A2,0x3080,0x091,
0x4A2,0x3080,0x091,0x691,0x2C4,0x5080,
0x691,0x2C4,0x5080,0x5080,0x2C4,0x291,
0x5080,0x2C4,0x291,0x291,0x2C4,0x5080,
0x291,0x2C4,0x5080,0x5080,0x2C4,0x691,
0x5080,0x2C4,0x691,0x291,0x3C4,0x5A2
},
/* 15 */
{
0x691,0x2C4,0x5080, 0x5080,0x0C4,0x4080,
0x1A2,0x3C4,0x691, 0x291,0x2C4,0x4080,
0x2080,0x2080,0x4A2,0x5A2,0x3C4,0x691,
0x1080,0x1080,0x491,0x491,0x3080,0x4A2,
0x091,0x3080,0x4A2, 0x4A2,0x3080,0x091,
0x4A2,0x3080,0x491, 0x491,0x1080,0x1080,
0x691,0x3C4,0x5A2, 0x4A2,0x2080,0x2080,
0x4080,0x2C4,0x291, 0x691,0x3C4,0x1A2,
0x4080,0x0C4,0x5080,0x5080,0x2C4,0x691,
0x5A2,0x3C4,0x291, 0x291,0x3C4,0x5A2
},
/* 16 */
{
0x4080,0x1C4,0x1A2, 0x1A2,0x1C4,0x4080,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x4080,
0x691,0x3C4,0x1A2, 0x5A2,0x3C4,0x691,
0x1A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x2080,0x2080,0x4A2,0x4A2,0x3080,0x091,
0x1080,0x1080,0x491,0x491,0x1080,0x1080,
0x091,0x3080,0x4A2, 0x4A2,0x2080,0x2080,
0x4A2,0x3080,0x491, 0x691,0x3C4,0x1A2,
0x691,0x3C4,0x5A2, 0x1A2,0x3C4,0x691,
0x4080,0x0C4,0x6080,0x6080,0x1C4,0x5A2
},
/* 17 */
{
0x291,0x3C4,0x1A2, 0x1A2,0x3C4,0x291,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x5080,
0x691,0x3C4,0x1A2, 0x5A2,0x3C4,0x691,
0x5080,0x2C4,0x691, 0x491,0x3080,0x4A2,
0x091,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x091,
0x4A2,0x3080,0x491, 0x691,0x2C4,0x5080,
0x691,0x3C4,0x5A2, 0x1A2,0x3C4,0x691,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2
},
/* 18 */
{
0x091,0x3080,0x4A2, 0x5A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x091,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x5080,
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x691,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2,
0x091,0x3080,0x0A2, 0x5A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x4A2,0x3080,0x091,
0x5080,0x2C4,0x691, 0x691,0x2C4,0x5080
},
/* 19 */
{
0x691,0x3C4,0x1A2, 0x1A2,0x3C4,0x691,
0x5A2,0x1C4,0x4080, 0x2080,0x2080,0x4A2,
0x691,0x2C4,0x4080, 0x1080,0x1080,0x091,
0x5080,0x2C4,0x691, 0x291,0x2C4,0x5080,
0x091,0x3080,0x4A2, 0x5A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x4A2,0x3080,0x091,
0x5080,0x2C4,0x291, 0x691,0x2C4,0x5080,
0x091,0x1080,0x1080,0x4080,0x2C4,0x691,
0x4A2,0x2080,0x2080,0x4080,0x1C4,0x5A2
},
/* 20 */
{
0x291,0x3C4,0x5A2, 0x5A2,0x3C4,0x691,
0x5A2,0x3C4,0x691, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x091,
0x4A2,0x3080,0x091, 0x691,0x2C4,0x5080,
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x5080,0x2C4,0x691, 0x091,0x3080,0x4A2,
0x091,0x3080,0x4A2, 0x4A2,0x3080,0x091,
0x4A2,0x3080,0x091, 0x691,0x2C4,0x5080,
0x691,0x2C4,0x5080, 0x5080,0x2C4,0x691,
0x5080,0x2C4,0x691, 0x291,0x3C4,0x5A2
},
/* 21 */
{
0x691,0x3C4,0x1A2, 0x5A2,0x3C4,0x291,
0x5080,0x2C4,0x691, 0x691,0x2C4,0x5080,
0x291,0x3C4,0x5A2, 0x1A2,0x3C4,0x691,
0x5080,0x0C4,0x6080,0x6080,0x1C4,0x5A2,
0x091,0x3080,0x0A2, 0x5A2,0x3C4,0x691,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x491,0x3080,0x4A2, 0x4A2,0x3080,0x491,
0x4A2,0x3080,0x491, 0x491,0x3080,0x4A2,
0x691,0x3C4,0x5A2, 0x0A2,0x3080,0x091,
0x5A2,0x1C4,0x6080, 0x6080,0x0C4,0x5080
}
};
static DBL hexagonal (const VECTOR EPoint, const TPATTERN *TPat)
{
unsigned short how;
long xv,zv;
DBL return_value=0;
DBL value;
DBL value1;
DBL value2;
DBL dist1;
DBL dist2;
DBL dist3;
DBL x,z;
int lng;
x=EPoint[X];
z=EPoint[Z];
xv = floor(x);
zv = floor(z/SQRT3);
x -= xv;
z -= SQRT3*zv;
/* x,z is in { [0.0, 1.0 [, [0.0, SQRT3 [ }
** There is some mirror to reduce the problem
*/
zv *= 2;
xv *= 2;
if ( z > SQRT3_2 )
{
z -= SQRT3_2;
if (x>0.5)
{
x -= 0.5;
xv++;
}
else
{
x += 0.5;
xv--;
}
zv++;
}
if ((x == 0.0)||(z/x>SQRT3))
{
z = SQRT3_2 - z;
x = 0.5 -x;
xv--;
}
if ((x == 1.0)||(z/(1.0-x)>SQRT3))
{
z = SQRT3_2 - z;
x = 1.5 -x;
xv++;
}
switch(TPat->Vals.Pavement.Tile)
{
case 5:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
case 2:
case 3:
case 5:
case 6:
case 19:
zv %= 10; if (zv < 0) { zv += 10; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 60 */
zv = 0;
break;
case 1:
case 4:
case 9:
zv -= 2*(((xv%30+(xv%30<0?30:0))/6));
zv %= 10; if (zv < 0) { zv += 10; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 60 */
zv = 0;
break;
case 7:
zv -= 7*(((xv%60+(xv%60<0?60:0))/3));
zv %= 20; if (zv < 0) { zv += 20; }
xv %= 3; if (xv < 0) { xv += 3; }
xv += 3*zv; /* 60 */
zv = 0;
break;
case 8:
case 10:
case 13:
case 14:
case 15:
case 17:
case 20:
case 21:
zv += 2*(((xv%30+(xv%30<0?30:0))/6));
zv %= 10; if (zv < 0) { zv += 10; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 60 */
zv = 0;
break;
case 11:
case 16:
zv -= 6*(((xv%30+(xv%30<0?30:0))/6));
zv %= 10; if (zv < 0) { zv += 10; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 60 */
zv = 0;
break;
case 12:
case 18:
zv += 6*(((xv%30+(xv%30<0?30:0))/6));
zv %= 10; if (zv < 0) { zv += 10; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 60 */
zv = 0;
break;
}
how = hexpentagon[TPat->Vals.Pavement.Number-1][xv];
break;
case 4:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
zv &= 0x07;
xv %= 6; if(xv <0) { xv += 6; }
xv += 6*zv; /* 48 */
zv = 0;
break;
case 3:
zv -= 2*(((xv%24+(xv%24<0?24:0))/6));
zv %= 8; if (zv < 0) { zv += 8; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 48 */
zv = 0;
break;
case 2:
zv &= 0x01;
xv %= 12; if (xv < 0) { xv += 12; }
xv += 12*zv; /* 24 */
zv = 0;
break;
case 5:
case 4:
zv -= 2*(((xv%24+(xv%24<0?24:0))/6));
zv %= 8; if (zv < 0) { zv += 8; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 48 */
zv = 0;
break;
case 1:
zv += 2*(((xv%12+(xv%12<0?12:0))/6));
zv %= 8; if (zv < 0) { zv += 8; }
xv %= 6; if (xv < 0) { xv += 6; }
xv += 6*zv; /* 48 */
zv = 0;
break;
case 6:
zv %= 4; if (zv < 0) { zv += 4; }
xv %= 12; if (xv < 0) { xv += 12; }
xv += 12*zv; /* 48 */
zv = 0;
break;
}
how = hextetragon[TPat->Vals.Pavement.Number-1][xv];
break;
case 3:
switch(TPat->Vals.Pavement.Number-1)
{
case 0:
zv %= 6; if(zv <0) { zv += 6; }
xv %= 6; if(xv <0) { xv += 6; }
xv += 6*zv;
zv = 0;
break;
case 1:
zv += 2*(((xv%18+(xv%18<0?18:0))/6));
zv %= 6; if(zv <0) { zv += 6; }
xv %= 6; if(xv <0) { xv += 6; }
xv += 6*zv;
zv = 0;
break;
case 2:
zv &= 0x01;
xv %= 18; if (xv < 0) { xv += 18; }
xv += 18*zv;
zv = 0x00;
break;
}
how = hextrigon[TPat->Vals.Pavement.Number-1][xv];
break;
case 2:
zv &= 0x01;
xv %= 6; if (xv < 0) { xv += 6; }
how = hexdigon[TPat->Vals.Pavement.Number-1][xv+6*zv];
break;
case 1:
default:
zv &= 0x01;
xv += 3*zv;
xv %= 6; if (xv <0) { xv += 6;}
lng = 0;
how = hexmonogon[TPat->Vals.Pavement.Number-1][xv];
break;
}
/*
** / \
** 1 \
** / 2
** / \
** -----3-----
** height = sqrt(3)/2
*/
if (how & 0x01)
{
dist1 = 1.0 - (fabs(SQRT3 * x - z) * SQRT3 );
return_value = max(return_value,dist1);
}
if (how & 0x02)
{
dist2 = 1.0 - (fabs(SQRT3 * (1.0-x) - z) * SQRT3 );
return_value = max(return_value,dist2);
}
if (how & 0x04)
{
dist3 = 1.0 - (z * 2.0 * SQRT3 );
return_value = max(return_value,dist3);
}
switch(TPat->Vals.Pavement.Interior)
{
case 1:
dist1 = (1.0 - (fabs(SQRT3 * z + x) ));
dist2 = (1.0 - (fabs(SQRT3 * z - x + 1.0) ));
dist3 = (1.0 - (x * 2.0 ));
if ( (((how & 0x83) == 0x00)||((how & 0x4000) == 0x4000)) &&
(dist1<0)&&(dist2<0) )
{
value1 = (3.0 / 2.0 *(fabs(SQRT3 * z + x) ) - 2.0);
value2 = (3.0 / 2.0 *(fabs(SQRT3 * z - x + 1.0) ) - 2.0);
value = min(value1,value2);
return_value = max(return_value,value);
}
if ((((how & 0x85) == 0x00)||((how & 0x2000) == 0x2000))
&&(dist1>0)&&(dist3>0))
{
value1 = (1.0 - 3.0 / 2.0 * (fabs(SQRT3 * z + x) ));
value2 = (1.0 - (x * 3.0 ));
value = min(value1,value2);
return_value = max(return_value,value);
}
if ((((how & 0x86) == 0x00)||((how & 0x1000) == 0x1000))
&&(dist3<0)&&(dist2>0))
{
value1 = (1.0 - 3.0 / 2.0 *(fabs(SQRT3 * z - x + 1.0) ));
value2 = ((x * 3.0 ) - 2.0);
value = min(value1,value2);
return_value = max(return_value,value);
}
break;
case 2:
if (((how & 0x83) == 0x00)||((how & 0x4000) == 0x4000))
{
dist1 = x - 0.5;
dist2 = z - SQRT3_2;
dist3 = 1.0 - (sqrt((dist1*dist1+dist2*dist2))*3.0 );
return_value = max(return_value,dist3);
}
if (((how & 0x85) == 0x00)||((how & 0x2000) == 0x2000))
{
dist1 = x;
dist2 = z;
dist3 = 1.0 - (sqrt((dist1*dist1+dist2*dist2)) *3.0);
return_value = max(return_value,dist3);
}
if (((how & 0x86) == 0x00)||((how & 0x1000) == 0x1000))
{
dist1 = x - 1.0;
dist2 = z ;
dist3 = 1.0 - (sqrt((dist1*dist1+dist2*dist2)) *3.0);
return_value = max(return_value,dist3);
}
break;
case 0:
if (((how & 0x83) == 0x00)||((how & 0x4000) == 0x4000))
{
dist3 = 1.0 - ((SQRT3_2 - z) * 2.0 * SQRT3 );
return_value = max(return_value,dist3);
}
if (((how & 0x85) == 0x00)||((how & 0x2000) == 0x2000))
{
dist2 = 1.0 - (fabs(SQRT3 * x + z) * SQRT3 );
return_value = max(return_value,dist2);
}
if (((how & 0x86) == 0x00)||((how & 0x1000) == 0x1000))
{
dist1 = 1.0 - (fabs(SQRT3 * (x -1.0) - z) * SQRT3 );
return_value = max(return_value,dist1);
}
break;
}
dist1 = (1.0 - (fabs(SQRT3 * z + x) ));
dist2 = (1.0 - (fabs(SQRT3 * z - x + 1.0) ));
dist3 = (1.0 - (x * 2.0 ));
switch(TPat->Vals.Pavement.Form)
{
case 2:
if (((how & 0x120) == 0x120)&&(dist1<0)&&(dist2<0))
{
value1 = x;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x140) == 0x140)&&(dist1>0)&&(dist3>0))
{
value1 = x - 0.5;
value2 = z- SQRT3_2;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x210) == 0x210)&&(dist1<0)&&(dist2<0))
{
value1 = x - 1.0;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x240) == 0x240)&&(dist3<0)&&(dist2>0))
{
value1 = x - 0.5;
value2 = z - SQRT3_2;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x410) == 0x410)&&(dist1>0)&&(dist3>0))
{
value1 = x - 1.0;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x420) == 0x420)&&(dist3<0)&&(dist2>0))
{
value1 = x;
value2 = z;
value = 2.0*SQRT3*(sqrt(value1*value1+value2*value2 ) - SQRT3/3.0 );
value = max(value,0.0);
return_value = min(value,1.0);
return return_value;
}
break;
case 1:
if (((how & 0x120) == 0x120)&&(dist1<0)&&(dist2<0))
{
value = -dist1 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x140) == 0x140)&&(dist1>0)&&(dist3>0))
{
value = dist1 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x210) == 0x210)&&(dist1<0)&&(dist2<0))
{
value = -dist2 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x240) == 0x240)&&(dist3<0)&&(dist2>0))
{
value = dist2 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x410) == 0x410)&&(dist1>0)&&(dist3>0))
{
value = dist3 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x420) == 0x420)&&(dist2>0)&&(dist3<0))
{
value = -dist3 * 2;
return_value = min(value,1.0);
return return_value;
}
if (((how & 0x120) == 0x120)&&(dist1<0)&&(dist2<0))
{
value = -dist1 * 2;
return_value = min(value,1.0);
return return_value;
}
break;
default:
case 0:
break;
}
return return_value;
}
/*****************************************************************************
*
* FUNCTION
*
* tiling_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* J. Grimbert
*
* DESCRIPTION
*
* Classical tiling patterns
*
* CHANGES
*
*
******************************************************************************/
static DBL tiling_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
switch(TPat->Vals.Tiling.Pattern)
{
case 27: return tiling_penrose(EPoint, true, false);
case 26: return tiling_penrose(EPoint, false, false);
case 25: return tiling_penrose1(EPoint, false);
case 24: return tiling_dodeca_hex_5(EPoint);
case 23: return tiling_dodeca_hex(EPoint);
case 22: return tiling_dodeca_tri(EPoint);
case 21: return tiling_square_tri(EPoint);
case 20: return tiling_hexa_tri_left(EPoint);
case 19: return tiling_hexa_tri_right(EPoint);
case 18: return tiling_rectangle_pair(EPoint);
case 17: return tiling_hexa_square_triangle_6(EPoint);
case 16: return tiling_hexa_square_triangle(EPoint);
case 15: return tiling_square_double(EPoint);
case 14: return tiling_square_internal_5(EPoint);
case 13: return tiling_square_internal(EPoint);
case 12: return tiling_rectangle_square(EPoint);
case 11: return tiling_square_rectangle(EPoint);
case 10: return tiling_square_offset(EPoint);
case 9: return tiling_hexa_triangle(EPoint);
case 8: return tiling_square_triangle(EPoint);
case 7: return tiling_octa_square(EPoint);
case 6: return tiling_rectangle(EPoint);
case 5: return tiling_rhombus(EPoint);
case 4: return tiling_lozenge(EPoint);
case 3: return tiling_triangle(EPoint);
case 2: return tiling_hexagon(EPoint);
case 1:
default:
return tiling_square(EPoint);
}
}
/*****************************************************************************
*
* FUNCTION
*
* tiling_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* J. Grimbert
*
* DESCRIPTION
*
* Classical tiling patterns
*
* CHANGES
*
*
******************************************************************************/
static DBL pavement_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
switch(TPat->Vals.Pavement.Side)
{
case 6:
return hexagonal(EPoint,TPat);
case 4:
return tetragonal(EPoint,TPat);
case 3:
default:
return trigonal(EPoint,TPat);
}
}
/*****************************************************************************
*
* FUNCTION
*
* agate_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
* Oct 1994 : adapted from agate pigment by [CY]
*
******************************************************************************/
static DBL agate_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator)
{
register DBL noise, turb_val;
const TURB* Turb;
Turb=Search_For_Turb(TPat->Warps);
turb_val = TPat->Vals.Agate_Turb_Scale * Turbulence(EPoint,Turb,noise_generator);
noise = 0.5 * (cycloidal(1.3 * turb_val + 1.1 * EPoint[Z]) + 1.0);
if (noise < 0.0)
{
noise = 0.0;
}
else
{
noise = min(1.0, noise);
noise = pow(noise, 0.77);
}
return(noise);
}
/*****************************************************************************
*
* FUNCTION
*
* boxed_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* -
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL boxed_pattern (const VECTOR EPoint)
{
register DBL value;
value = max(fabs(EPoint[X]), max(fabs(EPoint[Y]), fabs(EPoint[Z])));
CLIP_DENSITY(value);
return(value);
}
/*****************************************************************************
*
* FUNCTION
*
* brick_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value exactly 0.0 or 1.0
*
* AUTHOR
*
* Dan Farmer
*
* DESCRIPTION
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL brick_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int ibrickx, ibricky, ibrickz;
DBL brickheight, brickwidth, brickdepth;
DBL brickmortar, mortarheight, mortarwidth, mortardepth;
DBL brickx, bricky, brickz;
DBL x, y, z, fudgit;
fudgit=EPSILON+TPat->Vals.Brick.Mortar;
x = EPoint[X]+fudgit;
y = EPoint[Y]+fudgit;
z = EPoint[Z]+fudgit;
brickwidth = TPat->Vals.Brick.Size[X];
brickheight = TPat->Vals.Brick.Size[Y];
brickdepth = TPat->Vals.Brick.Size[Z];
brickmortar = (DBL)TPat->Vals.Brick.Mortar;
mortarwidth = brickmortar / brickwidth;
mortarheight = brickmortar / brickheight;
mortardepth = brickmortar / brickdepth;
/* 1) Check mortar layers in the X-Z plane (ie: top view) */
bricky = y / brickheight;
ibricky = (int) bricky;
bricky -= (DBL) ibricky;
if (bricky < 0.0)
{
bricky += 1.0;
}
if (bricky <= mortarheight)
{
return(0.0);
}
bricky = (y / brickheight) * 0.5;
ibricky = (int) bricky;
bricky -= (DBL) ibricky;
if (bricky < 0.0)
{
bricky += 1.0;
}
/* 2) Check ODD mortar layers in the Y-Z plane (ends) */
brickx = (x / brickwidth);
ibrickx = (int) brickx;
brickx -= (DBL) ibrickx;
if (brickx < 0.0)
{
brickx += 1.0;
}
if ((brickx <= mortarwidth) && (bricky <= 0.5))
{
return(0.0);
}
/* 3) Check EVEN mortar layers in the Y-Z plane (ends) */
brickx = (x / brickwidth) + 0.5;
ibrickx = (int) brickx;
brickx -= (DBL) ibrickx;
if (brickx < 0.0)
{
brickx += 1.0;
}
if ((brickx <= mortarwidth) && (bricky > 0.5))
{
return(0.0);
}
/* 4) Check ODD mortar layers in the Y-X plane (facing) */
brickz = (z / brickdepth);
ibrickz = (int) brickz;
brickz -= (DBL) ibrickz;
if (brickz < 0.0)
{
brickz += 1.0;
}
if ((brickz <= mortardepth) && (bricky > 0.5))
{
return(0.0);
}
/* 5) Check EVEN mortar layers in the X-Y plane (facing) */
brickz = (z / brickdepth) + 0.5;
ibrickz = (int) brickz;
brickz -= (DBL) ibrickz;
if (brickz < 0.0)
{
brickz += 1.0;
}
if ((brickz <= mortardepth) && (bricky <= 0.5))
{
return(0.0);
}
/* If we've gotten this far, color me brick. */
return(1.0);
}
/*****************************************************************************
*
* FUNCTION
*
* cells_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* John VanSickle
*
* DESCRIPTION
*
* "cells":
*
* New colour function by John VanSickle,
* vansickl@erols.com
*
* Assigns a pseudorandom value to each unit cube. The value for the cube in
* which the evaluted point lies is returned.
*
* All "cells" specific source code and examples are in the public domain.
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL cells_pattern (const VECTOR EPoint)
{
/* select a random value based on the cube from which this came. */
/* floor the values, instead of just truncating - this eliminates duplicated cells
around the axes */
return min(PatternRands(Hash3d((int)floor(EPoint[X]+EPSILON), (int)floor(EPoint[Y]+EPSILON), (int)floor(EPoint[Z]+EPSILON))), 1.0);
}
/*****************************************************************************
*
* FUNCTION
*
* checker_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value exactly 0.0 or 1.0
*
* AUTHOR
*
* POV-Team
*
* DESCRIPTION
*
* CHANGES
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL checker_pattern (const VECTOR EPoint)
{
int value;
value = (int)(floor(EPoint[X]+EPSILON) +
floor(EPoint[Y]+EPSILON) +
floor(EPoint[Z]+EPSILON));
if (value & 1)
{
return (1.0);
}
else
{
return (0.0);
}
}
/*****************************************************************************
*
* FUNCTION
*
* crackle_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Jim McElhiney
*
* DESCRIPTION
*
* "crackle":
*
* New colour function by Jim McElhiney,
* CompuServe 71201,1326, aka mcelhiney@acm.org
*
* Large scale, without turbulence, makes a pretty good stone wall.
* Small scale, without turbulence, makes a pretty good crackle ceramic glaze.
* Highly turbulent (with moderate displacement) makes a good marble, solving
* the problem of apparent parallel layers in Perlin's method.
* 2 octaves of full-displacement turbulence make a great "drizzled paint"
* pattern, like a 1950's counter top.
* Rule of thumb: put a single colour transition near 0 in your colour map.
*
* Mathematically, the set crackle(p)=0 is a 3D Voronoi diagram of a field of
* semirandom points, and crackle(p)>0 is distance from set along shortest path.
* (A Voronoi diagram is the locus of points equidistant from their 2 nearest
* neighbours from a set of disjoint points, like the membranes in suds are
* to the centres of the bubbles).
*
* All "crackle" specific source code and examples are in the public domain.
*
* CHANGES
* Oct 1994 : adapted from pigment by [CY]
* Other changes: enhanced by Ron Parker, Integer math by Nathan Kopp
*
******************************************************************************/
static int IntPickInCube(int tvx, int tvy, int tvz, VECTOR p1);
static DBL crackle_pattern (const VECTOR EPoint, const TPATTERN *TPat, TraceThreadData *Thread)
{
DBL sum, minsum, minsum2, minsum3, tf;
int minVecIdx = 0;
VECTOR dv;
int flox, floy, floz;
DBL Metric = TPat->Vals.Crackle.Metric;
DBL Offset = TPat->Vals.Crackle.Offset;
bool UseSquare = ( Metric == 2);
bool UseUnity = ( Metric == 1);
/*
* This uses floor() not FLOOR, so it will not be a mirror
* image about zero in the range -1.0 to 1.0. The viewer
* won't see an artefact around the origin.
*/
flox = (int)floor(EPoint[X] - EPSILON);
floy = (int)floor(EPoint[Y] - EPSILON);
floz = (int)floor(EPoint[Z] - EPSILON);
/*
* Check to see if the input point is in the same unit cube as the last
* call to this function, to use cache of cubelets for speed.
*/
Crackle_Cell_Coord ccoord(flox, floy, floz);
Thread->Stats()[CrackleCache_Tests]++;
Crackle_Cache_Entry dummy_entry;
Crackle_Cache_Entry* entry = &dummy_entry;
// search for this hash value in the cache
Crackle_Cache_Type::iterator iter = Thread->Crackle_Cache.find(ccoord);
if (iter == Thread->Crackle_Cache.end())
{
/*
* No, not same unit cube. Calculate the random points for this new
* cube and its 80 neighbours which differ in any axis by 1 or 2.
* Why distance of 2? If there is 1 point in each cube, located
* randomly, it is possible for the closest random point to be in the
* cube 2 over, or the one two over and one up. It is NOT possible
* for it to be two over and two up. Picture a 3x3x3 cube with 9 more
* cubes glued onto each face.
*/
// generate a new cache entry, but only if the size of the cache is reasonable.
// having to re-calculate entries that would have been cache hits had we not
// skipped on adding an entry is less expensive than chewing up immense amounts
// of RAM and finally hitting the swapfile. unfortunately there's no good way
// to tell how much memory is 'too much' for the cache, so we just use a hard-
// coded number for now (ideally we should allow the user to configure this).
// keep in mind that the cache memory usage is per-thread, so the more threads,
// the more RAM. if we don't do the insert, entry will point at a local variable.
if (Thread->Crackle_Cache.size() * sizeof(Crackle_Cache_Type::value_type) < 30 * 1024 * 1024)
{
iter = Thread->Crackle_Cache.insert(Thread->Crackle_Cache.end(), Crackle_Cache_Type::value_type(ccoord, Crackle_Cache_Entry()));
entry = &iter->second;
entry->last_used = Thread->ProgressIndex();
}
// see InitializeCrackleCubes() below.
int *pc = CrackleCubeTable;
for (int i = 0; i < 81; i++, pc += 3)
IntPickInCube(flox + pc[X], floy + pc[Y], floz + pc[Z], entry->data[i]);
}
else
{
Thread->Stats()[CrackleCache_Tests_Succeeded]++;
entry = &iter->second;
}
// Find the 3 points with the 3 shortest distances from the input point.
// Set up the loop so the invariant is true: minsum <= minsum2 <= minsum3
VSub(dv, entry->data[0], EPoint);
if(UseSquare)
{
minsum = VSumSqr(dv);
VSub(dv, entry->data[1], EPoint);
minsum2 = VSumSqr(dv);
VSub(dv, entry->data[2], EPoint);
minsum3 = VSumSqr(dv);
}
else if(UseUnity)
{
minsum = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
VSub(dv, entry->data[1], EPoint);
minsum2 = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
VSub(dv, entry->data[2], EPoint);
minsum3 = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
}
else
{
minsum = pow(fabs(dv[X]), Metric) +
pow(fabs(dv[Y]), Metric) +
pow(fabs(dv[Z]), Metric);
VSub(dv, entry->data[1], EPoint);
minsum2 = pow(fabs(dv[X]), Metric) +
pow(fabs(dv[Y]), Metric) +
pow(fabs(dv[Z]), Metric);
VSub(dv, entry->data[2], EPoint);
minsum3 = pow(fabs(dv[X]), Metric) +
pow(fabs(dv[Y]), Metric) +
pow(fabs(dv[Z]), Metric);
}
// sort the 3 computed sums
if(minsum2 < minsum)
{
tf = minsum; minsum = minsum2; minsum2 = tf;
minVecIdx = 1;
}
if(minsum3 < minsum)
{
tf = minsum; minsum = minsum3; minsum3 = tf;
minVecIdx = 2;
}
if(minsum3 < minsum2)
{
tf = minsum2; minsum2 = minsum3; minsum3 = tf;
}
// Loop for the 81 cubelets to find closest and 2nd closest.
for(int i = 3; i < 81; i++)
{
VSub(dv, entry->data[i], EPoint);
if(UseSquare)
sum = VSumSqr(dv);
else if(UseUnity)
sum = fabs(dv[X]) + fabs(dv[Y]) + fabs(dv[Z]);
else
sum = pow(fabs(dv[X]), Metric) +
pow(fabs(dv[Y]), Metric) +
pow(fabs(dv[Z]), Metric);
if(sum < minsum)
{
minsum3 = minsum2;
minsum2 = minsum;
minsum = sum;
minVecIdx = i;
}
else if(sum < minsum2)
{
minsum3 = minsum2;
minsum2 = sum;
}
else if( sum < minsum3 )
{
minsum3 = sum;
}
}
if (Offset)
{
if(UseSquare)
{
minsum += Offset*Offset;
minsum2 += Offset*Offset;
minsum3 += Offset*Offset;
}
else if (UseUnity)
{
minsum += Offset;
minsum2 += Offset;
minsum3 += Offset;
}
else
{
minsum += pow( Offset, Metric );
minsum2 += pow( Offset, Metric );
minsum3 += pow( Offset, Metric );
}
}
if(TPat->Vals.Crackle.IsSolid)
{
tf = Noise( entry->data[minVecIdx], GetNoiseGen(TPat, Thread) );
}
else if(UseSquare)
{
tf = TPat->Vals.Crackle.Form[X]*sqrt(minsum) +
TPat->Vals.Crackle.Form[Y]*sqrt(minsum2) +
TPat->Vals.Crackle.Form[Z]*sqrt(minsum3);
}
else if(UseUnity)
{
tf = TPat->Vals.Crackle.Form[X]*minsum +
TPat->Vals.Crackle.Form[Y]*minsum2 +
TPat->Vals.Crackle.Form[Z]*minsum3;
}
else
{
tf = TPat->Vals.Crackle.Form[X]*pow(minsum, 1.0/Metric) +
TPat->Vals.Crackle.Form[Y]*pow(minsum2, 1.0/Metric) +
TPat->Vals.Crackle.Form[Z]*pow(minsum3, 1.0/Metric);
}
return max(min(tf, 1.), 0.);
}
/*****************************************************************************
*
* FUNCTION
*
* cylindrical_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* -
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL cylindrical_pattern (const VECTOR EPoint)
{
register DBL value;
value = sqrt(Sqr(EPoint[X]) + Sqr(EPoint[Z]));
CLIP_DENSITY(value);
return(value);
}
/*****************************************************************************
*
* FUNCTION
*
* density_pattern
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* CHANGES
*
* Dec 1996 : Creation.
*
******************************************************************************/
inline float intp3(float t, float fa, float fb, float fc, float fd)
{
float b,d,e,f;
b = (fc - fa) * 0.5;
d = (fd - fb) * 0.5;
e = 2.0 * (fb - fc) + b + d;
f = -3.0 * (fb - fc) - 2.0 * b - d;
return ((e * t + f) * t + b) * t + fb;
}
inline float intp3_2(float t, float fa, float fb, float fc, float fd)
{
float b,e,f;
e = fd - fc - fa + fb;
f = fa - fb - e;
b = fc - fa;
return ((e * t + f) * t + b) * t + fb;
}
#define zmax(i,imax) (((i)<0)?(imax-1):((i) % (imax)))
static DBL density_pattern(const VECTOR EPoint, const TPATTERN *TPat)
{
size_t x, y, z;
size_t x1, y1, z1;
size_t x2, y2, z2;
DBL Ex, Ey, Ez;
DBL xx, yy, zz;
DBL xi, yi;
DBL f111, f112, f121, f122, f211, f212, f221, f222;
float intpd2[4][4];
DBL density = 0.0;
DENSITY_FILE_DATA *Data;
size_t k0, k1, k2, k3, i,j,ii,jj;
Ex=EPoint[X];
Ey=EPoint[Y];
Ez=EPoint[Z];
if((TPat->Vals.Density_File != NULL) && ((Data = TPat->Vals.Density_File->Data) != NULL) &&
(Data->Sx) && (Data->Sy) && (Data->Sz))
{
/* if(Data->Cyclic == true)
{
Ex -= floor(Ex);
Ey -= floor(Ey);
Ez -= floor(Ez);
}
*/
if((Ex >= 0.0) && (Ex < 1.0) && (Ey >= 0.0) && (Ey < 1.0) && (Ez >= 0.0) && (Ez < 1.0))
{
switch (TPat->Vals.Density_File->Interpolation % 10)
{
case NO_INTERPOLATION:
x = (size_t)(Ex * (DBL)Data->Sx);
y = (size_t)(Ey * (DBL)Data->Sy);
z = (size_t)(Ez * (DBL)Data->Sz);
if ((x < 0) || (x >= Data->Sx) || (y < 0) || (y >= Data->Sy) || (z < 0) || (z >= Data->Sz))
density = 0.0;
else
{
if(Data->Type == 4)
density = (DBL)Data->Density32[z * Data->Sy * Data->Sx + y * Data->Sx + x] / (DBL)UINT_MAX;
else if(Data->Type==2)
density = (DBL)Data->Density16[z * Data->Sy * Data->Sx + y * Data->Sx + x] / (DBL)USHRT_MAX;
else if(Data->Type == 1)
density = (DBL)Data->Density8[z * Data->Sy * Data->Sx + y * Data->Sx + x] / (DBL)UCHAR_MAX;
}
break;
case TRILINEAR_INTERPOLATION:
xx = Ex * (DBL)(Data->Sx );
yy = Ey * (DBL)(Data->Sy );
zz = Ez * (DBL)(Data->Sz );
x1 = (size_t)xx;
y1 = (size_t)yy;
z1 = (size_t)zz;
x2 = (x1 + 1) % Data->Sx;
y2 = (y1 + 1) % Data->Sy;
z2 = (z1 + 1) % Data->Sz;
xx -= floor(xx);
yy -= floor(yy);
zz -= floor(zz);
xi = 1.0 - xx;
yi = 1.0 - yy;
if(Data->Type == 4)
{
f111 = (DBL)Data->Density32[z1 * Data->Sy * Data->Sx + y1 * Data->Sx + x1] / (DBL)UINT_MAX;
f112 = (DBL)Data->Density32[z1 * Data->Sy * Data->Sx + y1 * Data->Sx + x2] / (DBL)UINT_MAX;
f121 = (DBL)Data->Density32[z1 * Data->Sy * Data->Sx + y2 * Data->Sx + x1] / (DBL)UINT_MAX;
f122 = (DBL)Data->Density32[z1 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)UINT_MAX;
f211 = (DBL)Data->Density32[z2 * Data->Sy * Data->Sx + y1 * Data->Sx + x1] / (DBL)UINT_MAX;
f212 = (DBL)Data->Density32[z2 * Data->Sy * Data->Sx + y1 * Data->Sx + x2] / (DBL)UINT_MAX;
f221 = (DBL)Data->Density32[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x1] / (DBL)UINT_MAX;
f222 = (DBL)Data->Density32[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)UINT_MAX;
}
else if(Data->Type == 2)
{
f111 = (DBL)Data->Density16[z1 * Data->Sy * Data->Sx + y1 * Data->Sx + x1] / (DBL)USHRT_MAX;
f112 = (DBL)Data->Density16[z1 * Data->Sy * Data->Sx + y1 * Data->Sx + x2] / (DBL)USHRT_MAX;
f121 = (DBL)Data->Density16[z1 * Data->Sy * Data->Sx + y2 * Data->Sx + x1] / (DBL)USHRT_MAX;
f122 = (DBL)Data->Density16[z1 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)USHRT_MAX;
f211 = (DBL)Data->Density16[z2 * Data->Sy * Data->Sx + y1 * Data->Sx + x1] / (DBL)USHRT_MAX;
f212 = (DBL)Data->Density16[z2 * Data->Sy * Data->Sx + y1 * Data->Sx + x2] / (DBL)USHRT_MAX;
f221 = (DBL)Data->Density16[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x1] / (DBL)USHRT_MAX;
f222 = (DBL)Data->Density16[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)USHRT_MAX;
}
else if(Data->Type == 1)
{
f111 = (DBL)Data->Density8[z1 * Data->Sy * Data->Sx + y1 * Data->Sx + x1] / (DBL)UCHAR_MAX;
f112 = (DBL)Data->Density8[z1 * Data->Sy * Data->Sx + y1 * Data->Sx + x2] / (DBL)UCHAR_MAX;
f121 = (DBL)Data->Density8[z1 * Data->Sy * Data->Sx + y2 * Data->Sx + x1] / (DBL)UCHAR_MAX;
f122 = (DBL)Data->Density8[z1 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)UCHAR_MAX;
f211 = (DBL)Data->Density8[z2 * Data->Sy * Data->Sx + y1 * Data->Sx + x1] / (DBL)UCHAR_MAX;
f212 = (DBL)Data->Density8[z2 * Data->Sy * Data->Sx + y1 * Data->Sx + x2] / (DBL)UCHAR_MAX;
f221 = (DBL)Data->Density8[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x1] / (DBL)UCHAR_MAX;
f222 = (DBL)Data->Density8[z2 * Data->Sy * Data->Sx + y2 * Data->Sx + x2] / (DBL)UCHAR_MAX;
}
density = ((f111 * xi + f112 * xx) * yi + (f121 * xi + f122 * xx) * yy) * (1.0 - zz) +
((f211 * xi + f212 * xx) * yi + (f221 * xi + f222 * xx) * yy) * zz;
break;
case TRICUBIC_INTERPOLATION:
default:
xx = Ex * (DBL)(Data->Sx);
yy = Ey * (DBL)(Data->Sy);
zz = Ez * (DBL)(Data->Sz);
x1 = (size_t)xx;
y1 = (size_t)yy;
z1 = (size_t)zz;
xx -= floor(xx);
yy -= floor(yy);
zz -= floor(zz);
k0 = zmax(-1+z1, Data->Sz );
k1 = zmax( z1, Data->Sz );
k2 = zmax( 1+z1, Data->Sz );
k3 = zmax( 2+z1, Data->Sz );
if(Data->Type == 4)
{
for(i = 0; i < 4; i++)
{
ii = zmax(i + x1 - 1, Data->Sx);
for(j = 0; j < 4; j++)
{
jj = zmax(j + y1 - 1, Data->Sy);
intpd2[i][j] = intp3(zz,
Data->Density32[k0 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UINT_MAX,
Data->Density32[k1 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UINT_MAX,
Data->Density32[k2 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UINT_MAX,
Data->Density32[k3 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UINT_MAX);
}
}
}
else if(Data->Type == 2)
{
for(i = 0; i < 4; i++)
{
ii = zmax(i + x1 - 1, Data->Sx);
for(j = 0; j < 4; j++)
{
jj = zmax(j + y1 - 1, Data->Sy);
intpd2[i][j] = intp3(zz,
Data->Density16[k0 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)USHRT_MAX,
Data->Density16[k1 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)USHRT_MAX,
Data->Density16[k2 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)USHRT_MAX,
Data->Density16[k3 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)USHRT_MAX);
}
}
}
else if(Data->Type == 1)
{
for(i = 0; i < 4; i++)
{
ii = zmax(i + x1 - 1, Data->Sx);
for(j = 0; j < 4; j++)
{
jj = zmax(j + y1 - 1, Data->Sy);
intpd2[i][j] = intp3(zz,
Data->Density8[k0 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UCHAR_MAX,
Data->Density8[k1 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UCHAR_MAX,
Data->Density8[k2 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UCHAR_MAX,
Data->Density8[k3 * Data->Sy * Data->Sx + jj * Data->Sx + ii] / (DBL)UCHAR_MAX);
}
}
}
for(i = 0; i < 4; i++)
intpd2[0][i] = intp3(yy, intpd2[i][0], intpd2[i][1], intpd2[i][2], intpd2[i][3]);
density = intp3(xx, intpd2[0][0], intpd2[0][1], intpd2[0][2], intpd2[0][3]);
break;
}
}
else
density = 0.0;
}
if (density < 0.0)
density = 0.0;
return density;
}
/*****************************************************************************
*
* FUNCTION
*
* dents_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION : Note this pattern is only used for pigments and textures.
* Normals have a specialized pattern for this.
*
* CHANGES
* Nov 1994 : adapted from normal by [CY]
*
******************************************************************************/
static DBL dents_pattern (const VECTOR EPoint, int noise_generator)
{
DBL noise;
noise = Noise (EPoint, noise_generator);
return(noise * noise * noise);
}
/*****************************************************************************
*
* FUNCTION
*
* function_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static DBL function_pattern (const VECTOR EPoint, const TPATTERN *TPat, TraceThreadData *Thread)
{
DBL value;
if(Thread->functionPatternContext[TPat->Vals.Function.Data] == NULL)
Thread->functionPatternContext[TPat->Vals.Function.Data] = Thread->functionContext->functionvm->NewContext(const_cast<TraceThreadData *>(Thread));
FPUContext *ctx = Thread->functionPatternContext[TPat->Vals.Function.Data];
ctx->SetLocal(X, EPoint[X]);
ctx->SetLocal(Y, EPoint[Y]);
ctx->SetLocal(Z, EPoint[Z]);
value = POVFPU_Run(ctx, *(reinterpret_cast<const FUNCTION*>(TPat->Vals.Function.Fn)));
return ((value > 1.0) ? fmod(value, 1.0) : value);
}
/*****************************************************************************
*
* FUNCTION
*
* gradient_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* Gradient Pattern - gradient based on the fractional values of
* x, y or z, based on whether or not the given directional vector is
* a 1.0 or a 0.0.
* The basic concept of this is from DBW Render, but Dave Wecker's
* only supports simple Y axis gradients.
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL gradient_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
DBL Result;
VDot( Result, EPoint, TPat->Vals.Gradient );
/* Mod to keep within [0.0,1.0] range */
return ((Result > 1.0) ? fmod(Result, 1.0) : Result);
}
/*****************************************************************************
*
* FUNCTION
*
* granite_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* Granite - kind of a union of the "spotted" and the "dented" textures,
* using a 1/f fractal noise function for color values. Typically used
* with small scaling values. Should work with colour maps for pink granite.
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL granite_pattern (const VECTOR EPoint, int noise_generator)
{
register int i;
register DBL temp, noise = 0.0, freq = 1.0;
VECTOR tv1,tv2;
VScale(tv1,EPoint,4.0);
for (i = 0; i < 6 ; freq *= 2.0, i++)
{
VScale(tv2,tv1,freq);
if(noise_generator==1)
{
temp = 0.5 - Noise (tv2, noise_generator);
temp = fabs(temp);
}
else
{
temp = 1.0 - 2.0 * Noise (tv2, noise_generator);
temp = fabs(temp);
if (temp>0.5) temp=0.5;
}
noise += temp / freq;
}
return(noise);
}
/*****************************************************************************
*
* FUNCTION
*
* hexagon_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value exactly 0.0, 1.0 or 2.0
*
* AUTHOR
*
* Ernest MacDougal Campbell III
*
* DESCRIPTION
*
* TriHex pattern -- Ernest MacDougal Campbell III (EMC3) 11/23/92
*
* Creates a hexagon pattern in the XZ plane.
*
* This algorithm is hard to explain. First it scales the point to make
* a few of the later calculations easier, then maps some points to be
* closer to the Origin. A small area in the first quadrant is subdivided
* into a 6 x 6 grid. The position of the point mapped into that grid
* determines its color. For some points, just the grid location is enough,
* but for others, we have to calculate which half of the block it's in
* (this is where the atan2() function comes in handy).
*
* CHANGES
*
* Nov 1992 : Creation.
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
const DBL xfactor = 0.5; /* each triangle is split in half for the grid */
const DBL zfactor = 0.866025404; /* sqrt(3)/2 -- Height of an equilateral triangle */
static DBL hexagon_pattern (const VECTOR EPoint)
{
int xm, zm;
int brkindx;
DBL xs, zs, xl, zl, value = 0.0;
DBL x=EPoint[X];
DBL z=EPoint[Z];
/* Keep all numbers positive. Also, if z is negative, map it in such a
* way as to avoid mirroring across the x-axis. The value 5.196152424
* is (sqrt(3)/2) * 6 (because the grid is 6 blocks high)
*/
x = fabs(x);
/* Avoid mirroring across x-axis. */
z = z < 0.0 ? 5.196152424 - fabs(z) : z;
/* Scale point to make calcs easier. */
xs = x/xfactor;
zs = z/zfactor;
/* Map points into the 6 x 6 grid where the basic formula works. */
xs -= floor(xs/6.0) * 6.0;
zs -= floor(zs/6.0) * 6.0;
/* Get a block in the 6 x 6 grid. */
xm = (int) FLOOR(xs) % 6;
zm = (int) FLOOR(zs) % 6;
switch (xm)
{
/* These are easy cases: Color depends only on xm and zm. */
case 0:
case 5:
switch (zm)
{
case 0:
case 5: value = 0; break;
case 1:
case 2: value = 1; break;
case 3:
case 4: value = 2; break;
}
break;
case 2:
case 3:
switch (zm)
{
case 0:
case 1: value = 2; break;
case 2:
case 3: value = 0; break;
case 4:
case 5: value = 1; break;
}
break;
/* These cases are harder. These blocks are divided diagonally
* by the angled edges of the hexagons. Some slope positive, and
* others negative. We flip the x value of the negatively sloped
* pieces. Then we check to see if the point in question falls
* in the upper or lower half of the block. That info, plus the
* z status of the block determines the color.
*/
case 1:
case 4:
/* Map the point into the block at the origin. */
xl = xs-xm;
zl = zs-zm;
/* These blocks have negative slopes so we flip it horizontally. */
if (((xm + zm) % 2) == 1)
{
xl = 1.0 - xl;
}
/* Avoid a divide-by-zero error. */
if (xl == 0.0)
{
xl = 0.0001; // TODO FIXME - magic number! Should be SOME_EPSILON I guess, or use nextafter()
}
/* Is the angle less-than or greater-than 45 degrees? */
brkindx = (zl / xl) < 1.0;
/* was...
* brkindx = (atan2(zl,xl) < (45 * M_PI_180));
* ...but because of the mapping, it's easier and cheaper,
* CPU-wise, to just use a good ol' slope.
*/
switch (brkindx)
{
case true:
switch (zm)
{
case 0:
case 3: value = 0; break;
case 2:
case 5: value = 1; break;
case 1:
case 4: value = 2; break;
}
break;
case false:
switch (zm)
{
case 0:
case 3: value = 2; break;
case 2:
case 5: value = 0; break;
case 1:
case 4: value = 1; break;
}
break;
}
}
value = fmod(value, 3.0);
return(value);
}
/*****************************************************************************
*
* FUNCTION
*
* cubic_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value exactly 0.0, 1.0, 2.0, 3.0, 4.0 or 5.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* Creates a cubic pattern. The six texture elements are mapped to the six
* pyramids centered on the six axes.
*
* CHANGES
*
* Nov 2007 : Creation.
*
******************************************************************************/
static DBL cubic_pattern (const VECTOR EPoint)
{
const DBL x = EPoint[X], y = EPoint[Y], z = EPoint[Z];
const DBL ax = fabs(x), ay = fabs(y), az = fabs(z);
if(x >= 0 && x >= ay && x >= az) return 0.0;
if(y >= 0 && y >= ax && y >= az) return 1.0;
if(z >= 0 && z >= ax && z >= ay) return 2.0;
if(x < 0 && x <= -ay && x <= -az) return 3.0;
if(y < 0 && y <= -ax && y <= -az) return 4.0;
return 5.0;
}
/*****************************************************************************
*
* FUNCTION
*
* square_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value exactly 0.0, 1.0, 2.0 or 3.0
*
* AUTHOR
*
* J. Grimbert
*
* DESCRIPTION
* Paving the XZ plan with 4 'colours', in square
*
* CHANGES
*
******************************************************************************/
static DBL square_pattern (const VECTOR EPoint)
{
int valueX,valueZ;
valueX = (int)(floor(EPoint[X]));
valueZ = (int)(floor(EPoint[Z]));
if (valueX & 1)
{
if (valueZ & 1)
{
return (2.0);
}
else
{
return (3.0);
}
}
else
{
if (valueZ & 1)
{
return (1.0);
}
else
{
return (0.0);
}
}
}
/*****************************************************************************
*
* FUNCTION
*
* triangular_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value exactly 0.0, 1.0, 2.0, 3.0, 4.0 or 5.0
*
* AUTHOR
*
* J. Grimbert
*
* DESCRIPTION
* Paving the XZ plan with 6 'colours', in triangle around the origin
*
* CHANGES
*
******************************************************************************/
static DBL triangular_pattern (const VECTOR EPoint)
{
DBL answer;
DBL x,z;
DBL xs,zs;
int a,b;
DBL k,slop1,slop2;
int mask;
x=EPoint[X];
z=EPoint[Z];
/* Fold the space to a basic rectangle */
xs = x-3.0*floor(x/3.0);
zs = z-SQRT3*floor(z/SQRT3);
/* xs,zs is in { [0.0, 3.0 [, [0.0, SQRT3 [ }
** but there is some symmetry to simplify the testing
*/
a = (int)floor(xs);
xs -= a;
b = (zs <SQRT3_2 ? 0: 1);
if (b)
{
zs = SQRT3 - zs; /* mirror */
}
k = 1.0 - xs;
if ((xs != 0.0)&&( k != 0.0 )) /* second condition should never occurs */
{
slop1 = zs/xs;
slop2 = zs/k; /* just in case */
switch( (slop1<SQRT3?1:0)+(slop2<SQRT3?2:0))
{
case 3:
answer = 0.0;
break;
case 2:
answer = 1.0;
break;
case 1:
answer = 3.0;
break;
}
}
else
{
answer = 1.0;
}
mask = (int) answer;
answer = (mask & 1) ? fmod(answer+2.0*a,6.0): fmod(6.0+answer-2.0*a,6.0);
if (b)
{
answer = 5.0 - answer;
}
return answer;
}
/*****************************************************************************
*
* FUNCTION
*
* julia_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL julia_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, dist2, mindist2,
cr = TPat->Vals.Fractal.Coord[U], ci = TPat->Vals.Fractal.Coord[V];
a = EPoint[X]; a2 = Sqr(a);
b = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
b = 2.0 * a * b + ci;
a = a2 - b2 + cr;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* julia3_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL julia3_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, dist2, mindist2,
cr = TPat->Vals.Fractal.Coord[U], ci = TPat->Vals.Fractal.Coord[V];
a = EPoint[X]; a2 = Sqr(a);
b = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
b = 3.0*a2*b - b2*b + ci;
a = a2*a - 3.0*a*b2 + cr;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* julia4_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL julia4_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, dist2, mindist2,
cr = TPat->Vals.Fractal.Coord[U], ci = TPat->Vals.Fractal.Coord[V];
a = EPoint[X]; a2 = Sqr(a);
b = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
b = 4.0 * (a2*a*b - a*b2*b) + ci;
a = a2*a2 - 6.0*a2*b2 + b2*b2 + cr;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* juliax_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL juliax_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col, exponent;
DBL a, b, cf=0, x, y, dist2, mindist2,
cr = TPat->Vals.Fractal.Coord[U], ci = TPat->Vals.Fractal.Coord[V];
int* binomial_coeff;
a = x = EPoint[X];
b = y = EPoint[Y];
mindist2 = a*a+b*b;
it_max = TPat->Vals.Fractal.Iterations;
exponent = TPat->Vals.Fractal.Exponent;
binomial_coeff = &BinomialCoefficients[(exponent+1)*exponent/2];
for (col = 0; col < it_max; col++)
{
// Calculate (a+bi)^exponent
DBL new_a = pow(a, exponent);
for(int k=2; k<=exponent; k+=2)
{
new_a += binomial_coeff[k]*pow(a, exponent-k)*pow(b, k);
}
DBL new_b = 0;
for(int l=1; l<=exponent; l+=2)
{
new_b += binomial_coeff[l]*pow(a, exponent-l)*pow(b, l);
}
a = new_a + cr;
b = new_b + ci;
dist2 = a*a+b*b;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* leopard_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Scott Taylor
*
* DESCRIPTION
*
* CHANGES
*
* Jul 1991 : Creation.
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL leopard_pattern (const VECTOR EPoint)
{
register DBL value, temp1, temp2, temp3;
/* This form didn't work with Zortech 386 compiler */
/* value = Sqr((sin(x)+sin(y)+sin(z))/3); */
/* So we break it down. */
temp1 = sin(EPoint[X]);
temp2 = sin(EPoint[Y]);
temp3 = sin(EPoint[Z]);
value = Sqr((temp1 + temp2 + temp3) / 3.0);
return(value);
}
/*****************************************************************************
*
* FUNCTION
*
* magnet1m_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL magnet1m_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, x, y, tmp, tmp1r, tmp1i, tmp2r, tmp2i, dist2, mindist2;
x = EPoint[X];
y = EPoint[Y];
a = a2 = 0;
b = b2 = 0;
mindist2 = 10000;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
tmp1r = a2-b2 + x-1;
tmp1i = 2*a*b + y;
tmp2r = 2*a + x-2;
tmp2i = 2*b + y;
tmp = tmp2r*tmp2r + tmp2i*tmp2i;
a = (tmp1r*tmp2r + tmp1i*tmp2i) / tmp;
b = (tmp1i*tmp2r - tmp1r*tmp2i) / tmp;
b2 = b*b;
b = 2*a*b;
a = a*a-b2;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
tmp1r = a-1;
if(dist2 > 10000.0 || tmp1r*tmp1r+b2 < 1/10000.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* magnet1j_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL magnet1j_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, tmp, tmp1r, tmp1i, tmp2r, tmp2i, dist2, mindist2,
cr = TPat->Vals.Fractal.Coord[U], ci = TPat->Vals.Fractal.Coord[V];
a = EPoint[X]; a2 = Sqr(a);
b = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
tmp1r = a2-b2 + cr-1;
tmp1i = 2*a*b + ci;
tmp2r = 2*a + cr-2;
tmp2i = 2*b + ci;
tmp = tmp2r*tmp2r + tmp2i*tmp2i;
a = (tmp1r*tmp2r + tmp1i*tmp2i) / tmp;
b = (tmp1i*tmp2r - tmp1r*tmp2i) / tmp;
b2 = b*b;
b = 2*a*b;
a = a*a-b2;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
tmp1r = a-1;
if(dist2 > 10000.0 || tmp1r*tmp1r+b2 < 1/10000.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* magnet2m_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL magnet2m_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, x, y, tmp, tmp1r, tmp1i, tmp2r, tmp2i,
c1r, c2r, c1c2r, c1c2i, dist2, mindist2;
x = EPoint[X];
y = EPoint[Y];
a = a2 = 0;
b = b2 = 0;
mindist2 = 10000;
c1r = x-1; c2r = x-2;
c1c2r = c1r*c2r-y*y;
c1c2i = (c1r+c2r)*y;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
tmp1r = a2*a-3*a*b2 + 3*(a*c1r-b*y) + c1c2r;
tmp1i = 3*a2*b-b2*b + 3*(a*y+b*c1r) + c1c2i;
tmp2r = 3*(a2-b2) + 3*(a*c2r-b*y) + c1c2r + 1;
tmp2i = 6*a*b + 3*(a*y+b*c2r) + c1c2i;
tmp = tmp2r*tmp2r + tmp2i*tmp2i;
a = (tmp1r*tmp2r + tmp1i*tmp2i) / tmp;
b = (tmp1i*tmp2r - tmp1r*tmp2i) / tmp;
b2 = b*b;
b = 2*a*b;
a = a*a-b2;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
tmp1r = a-1;
if(dist2 > 10000.0 || tmp1r*tmp1r+b2 < 1/10000.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* magnet2j_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL magnet2j_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, tmp, tmp1r, tmp1i, tmp2r, tmp2i, c1r,c2r,c1c2r,c1c2i,
cr = TPat->Vals.Fractal.Coord[U], ci = TPat->Vals.Fractal.Coord[V],
dist2, mindist2;
a = EPoint[X]; a2 = Sqr(a);
b = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
c1r = cr-1, c2r = cr-2;
c1c2r = c1r*c2r-ci*ci;
c1c2i = (c1r+c2r)*ci;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
tmp1r = a2*a-3*a*b2 + 3*(a*c1r-b*ci) + c1c2r;
tmp1i = 3*a2*b-b2*b + 3*(a*ci+b*c1r) + c1c2i;
tmp2r = 3*(a2-b2) + 3*(a*c2r-b*ci) + c1c2r + 1;
tmp2i = 6*a*b + 3*(a*ci+b*c2r) + c1c2i;
tmp = tmp2r*tmp2r + tmp2i*tmp2i;
a = (tmp1r*tmp2r + tmp1i*tmp2i) / tmp;
b = (tmp1i*tmp2r - tmp1r*tmp2i) / tmp;
b2 = b*b;
b = 2*a*b;
a = a*a-b2;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
tmp1r = a-1;
if(dist2 > 10000.0 || tmp1r*tmp1r+b2 < 1/10000.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* mandel_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* submitted by user, name lost (sorry)
*
* DESCRIPTION
*
* The mandel pattern computes the standard Mandelbrot fractal pattern and
* projects it onto the X-Y plane. It uses the X and Y coordinates to compute
* the Mandelbrot set.
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
* May 2001 : updated with code from Warp [trf]
*
******************************************************************************/
static DBL mandel_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, x, y, dist2, mindist2;
a = x = EPoint[X]; a2 = Sqr(a);
b = y = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
b = 2.0 * a * b + y;
a = a2 - b2 + x;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* mandel3_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL mandel3_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, x, y, dist2, mindist2;
a = x = EPoint[X]; a2 = Sqr(a);
b = y = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
b = 3.0*a2*b - b2*b + y;
a = a2*a - 3.0*a*b2 + x;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* mandel4_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL mandel4_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col;
DBL a, b, cf, a2, b2, x, y, dist2, mindist2;
a = x = EPoint[X]; a2 = Sqr(a);
b = y = EPoint[Y]; b2 = Sqr(b);
mindist2 = a2+b2;
it_max = TPat->Vals.Fractal.Iterations;
for (col = 0; col < it_max; col++)
{
b = 4.0 * (a2*a*b - a*b2*b) + y;
a = a2*a2 - 6.0*a2*b2 + b2*b2 + x;
a2 = Sqr(a);
b2 = Sqr(b);
dist2 = a2+b2;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* mandelx_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Nieminen Juha
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL mandelx_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
int it_max, col, exponent;
DBL a, b, cf=0, x, y, dist2, mindist2;
int* binomial_coeff;
a = x = EPoint[X];
b = y = EPoint[Y];
mindist2 = a*a+b*b;
it_max = TPat->Vals.Fractal.Iterations;
exponent = TPat->Vals.Fractal.Exponent;
binomial_coeff = &BinomialCoefficients[(exponent+1)*exponent/2];
for (col = 0; col < it_max; col++)
{
// Calculate (a+bi)^exponent
DBL new_a = pow(a, exponent);
for(int k=2; k<=exponent; k+=2)
{
new_a += binomial_coeff[k]*pow(a, exponent-k)*pow(b, k);
}
DBL new_b = 0;
for(int l=1; l<=exponent; l+=2)
{
new_b += binomial_coeff[l]*pow(a, exponent-l)*pow(b, l);
}
a = new_a + x;
b = new_b + y;
dist2 = a*a+b*b;
if(dist2 < mindist2) mindist2 = dist2;
if(dist2 > 4.0)
{
cf = fractal_exterior_color(TPat, col, a, b);
break;
}
}
if(col == it_max)
cf = fractal_interior_color(TPat, col, a, b, mindist2);
return(cf);
}
/*****************************************************************************
*
* FUNCTION
*
* marble_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL marble_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator)
{
register DBL turb_val;
const TURB *Turb;
if ((Turb=Search_For_Turb(TPat->Warps)) != NULL)
{
turb_val = Turb->Turbulence[X] * Turbulence(EPoint,Turb,noise_generator);
}
else
{
turb_val = 0.0;
}
return(EPoint[X] + turb_val);
}
/*****************************************************************************
*
* FUNCTION
*
* object_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static DBL object_pattern (const VECTOR EPoint, const TPATTERN *TPat, TraceThreadData *Thread)
{
if(TPat->Vals.Object != NULL)
{
if(Inside_Object(EPoint, TPat->Vals.Object, Thread))
return 1.0;
else
return 0.0;
}
return 0.0;
}
/*****************************************************************************
*
* FUNCTION
*
* onion_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Scott Taylor
*
* DESCRIPTION
*
* CHANGES
*
* Jul 1991 : Creation.
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL onion_pattern (const VECTOR EPoint)
{
/* The variable noise is not used as noise in this function */
register DBL noise;
/*
This ramp goes 0-1,1-0,0-1,1-0...
noise = (fmod(sqrt(Sqr(x)+Sqr(y)+Sqr(z)),2.0)-1.0);
if (noise<0.0) {noise = 0.0-noise;}
*/
/* This ramp goes 0-1, 0-1, 0-1, 0-1 ... */
noise = (fmod(sqrt(Sqr(EPoint[X])+Sqr(EPoint[Y])+Sqr(EPoint[Z])), 1.0));
return(noise);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static DBL pigment_pattern (const VECTOR EPoint, const TPATTERN *TPat, const Intersection *isect, const Ray *ray, TraceThreadData *Thread)
{
DBL value;
Colour Col;
int colour_found=false;
if (TPat->Vals.Pigment)
// TODO ALPHA - we're discarding transparency information, so maybe we want to pre-multiply if there's alpha in there?
colour_found = Compute_Pigment(Col, TPat->Vals.Pigment, EPoint, isect, ray, Thread);
if(!colour_found)
value = 0.0;
else
value = Col.greyscale();
return value ;
}
/*****************************************************************************
*
* FUNCTION
*
* planar_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* -
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL planar_pattern (const VECTOR EPoint)
{
register DBL value = fabs(EPoint[Y]);
CLIP_DENSITY(value);
return value;
}
/*****************************************************************************
*
* FUNCTION
*
* quilted_pattern
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dan Farmer & Chris Young
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static DBL quilted_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
VECTOR value;
DBL t;
value[X] = EPoint[X]-FLOOR(EPoint[X])-0.5;
value[Y] = EPoint[Y]-FLOOR(EPoint[Y])-0.5;
value[Z] = EPoint[Z]-FLOOR(EPoint[Z])-0.5;
t = sqrt(value[X]*value[X]+value[Y]*value[Y]+value[Z]*value[Z]);
t = quilt_cubic(t, TPat->Vals.Quilted.Control0, TPat->Vals.Quilted.Control1);
value[X] *= t;
value[Y] *= t;
value[Z] *= t;
return((fabs(value[X])+fabs(value[Y])+fabs(value[Z]))/3.0);
}
/*****************************************************************************
*
* FUNCTION
*
* radial_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Chris Young -- new in vers 2.0
*
* DESCRIPTION
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL radial_pattern (const VECTOR EPoint)
{
register DBL value;
if ((fabs(EPoint[X])<0.001) && (fabs(EPoint[Z])<0.001))
{
value = 0.25;
}
else
{
value = 0.25 + (atan2(EPoint[X],EPoint[Z]) + M_PI) / TWO_M_PI;
}
return(value);
}
/*****************************************************************************
*
* FUNCTION
*
* ripples_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION : Note this pattern is only used for pigments and textures.
* Normals have a specialized pattern for this.
*
* CHANGES
*
* Nov 1994 : adapted from normal by [CY]
*
******************************************************************************/
static DBL ripples_pattern (const VECTOR EPoint, const TPATTERN *TPat, const TraceThreadData *Thread)
{
register unsigned int i;
register DBL length, index;
DBL scalar =0.0;
VECTOR point;
for (i = 0 ; i < Thread->numberOfWaves ; i++)
{
VSub (point, EPoint, *Thread->waveSources[i]);
VLength (length, point);
if (length == 0.0)
length = 1.0;
index = length * TPat->Frequency + TPat->Phase;
scalar += cycloidal(index);
}
scalar = 0.5*(1.0+(scalar / (DBL)Thread->numberOfWaves));
return(scalar);
}
/*****************************************************************************
*
* FUNCTION
*
* slope_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
* Intersection - intersection struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0, 0.0 if normal is NULL
*
* AUTHOR
*
* -hdf-
*
* DESCRIPTION :
*
* calculates the surface slope from surface normal vector
*
* CHANGES
*
* Apr 1998 : written by H.-D. Fink
* May 1998 : modified by M.C. Andrews - now combines slope and 'gradient'.
*
******************************************************************************/
static DBL slope_pattern (const VECTOR EPoint, const TPATTERN *TPat, const Intersection *Isection)
{
DBL value, value1, value2;
if (Isection == NULL) return 0.0; /* just in case ... */
if (TPat->Vals.Slope.Point_At)
{
VECTOR vect;
VSub(vect,TPat->Vals.Slope.Slope_Vector,Isection->IPoint);
VNormalizeEq(vect);
VDot(value1, Isection->PNormal, vect);
}
else
{
if (TPat->Vals.Slope.Slope_Base > 0)
/* short case 1: slope vector in x, y or z direction */
value1 = Isection->PNormal[TPat->Vals.Slope.Slope_Base - 1];
else if (TPat->Vals.Slope.Slope_Base < 0)
/* short case 2: slope vector in negative x, y or z direction */
value1 = -Isection->PNormal[-TPat->Vals.Slope.Slope_Base - 1];
else
/* projection slope onto normal vector */
VDot(value1, Isection->PNormal, TPat->Vals.Slope.Slope_Vector);
}
/* Clamp to 1.0. */
/* should never be necessary since both vectors are normalized */
if (value1 > 1.0) value1 = 1.0;
else if (value1 < -1.0) value1 = -1.0;
value1 = asin(value1) / M_PI * 2;
value1 = (value1 + 1.0) * 0.5; /* normalize to [0..1] interval */
/* If set, use offset and scalings for slope and altitude. */
if (0.0 != TPat->Vals.Slope.Slope_Mod[V])
{
value1 = (value1 - TPat->Vals.Slope.Slope_Mod[U]) / TPat->Vals.Slope.Slope_Mod[V];
}
if (!TPat->Vals.Slope.Altit_Len)
{
/* Clamp to 1.0. */
if ( value1 == 1.0 )
{
value1= value1- EPSILON;
}
else
{
value1 = (value1 < 0.0) ? 1.0 + fmod(value1, 1.0) : fmod(value1, 1.0);
}
return value1; /* no altitude defined */
}
/* Calculate projection of Epoint along altitude vector */
if (TPat->Vals.Slope.Altit_Base > 0)
/* short case 1: altitude vector in x, y or z direction */
value2 = EPoint[TPat->Vals.Slope.Altit_Base - 1];
else if (TPat->Vals.Slope.Altit_Base < 0)
/* short case 2: altitude vector in negative x, y or z direction */
value2 = -EPoint[-TPat->Vals.Slope.Altit_Base - 1];
else
/* projection of Epoint along altitude vector */
VDot(value2, EPoint, TPat->Vals.Slope.Altit_Vector);
if (0.0 != TPat->Vals.Slope.Altit_Mod[V])
{
value2 = (value2 - TPat->Vals.Slope.Altit_Mod[U]) / TPat->Vals.Slope.Altit_Mod[V];
}
value = TPat->Vals.Slope.Slope_Len * value1 + TPat->Vals.Slope.Altit_Len * value2;
/* Clamp to 1.0. */
if ( value - 1.0 < EPSILON && value >= 1.0 )
{
/* 1.0 is a very common value to get *exactly*. We don't want to wrap
it to the bottom end of the map. */
value = value - EPSILON;
}
else
{
value = (value < 0.0) ? 1.0 + fmod(value, 1.0) : fmod(value, 1.0);
}
return value;
}
/*****************************************************************************
*
* FUNCTION
*
* aoi_pattern
*
* INPUT
*
* Intersection - intersection struct
* Ray - Ray information
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* J. Grimbert
*
* DESCRIPTION
*
* Return a value related to angle of incidence
* (angle between the normal at the intersection and the ray)
*
* CHANGES
*
* Mar 2010 : modified by [CLi]
*
******************************************************************************/
static DBL aoi_pattern (const Intersection *Isection, const Ray *ray)
{
VECTOR a, b;
DBL cosAngle, angle;
if ((Isection == NULL) || (ray == NULL))
return 0.0;
VNormalize(a, Isection->PNormal);
VNormalize(b, ray->Direction);
VDot(cosAngle, a, b);
// clip to [-1.0; 1.0], just to be sure
// (should never be necessary since both vectors are normalized)
cosAngle = clip(cosAngle, -1.0, 1.0);
angle = acos(cosAngle) / M_PI;
return angle;
}
/*****************************************************************************
*
* FUNCTION
*
* spiral1_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
* Spiral whirles around z-axis.
* The number of "arms" is defined in the TPat.
*
* CHANGES
*
* Aug 1994 : Creation.
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL spiral1_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator)
{
DBL rad, phi, turb_val;
DBL x = EPoint[X];
DBL y = EPoint[Y];
DBL z = EPoint[Z];
const TURB *Turb;
if ((Turb=Search_For_Turb(TPat->Warps)) != NULL)
{
turb_val = Turb->Turbulence[X] * Turbulence(EPoint,Turb,noise_generator);
}
else
{
turb_val = 0.0;
}
/* Get distance from z-axis. */
rad = sqrt(x * x + y * y);
/* Get angle in x,y-plane (0...2 PI). */
if (rad == 0.0)
{
phi = 0.0;
}
else
{
if (x < 0.0)
{
phi = 3.0 * M_PI_2 - asin(y / rad);
}
else
{
phi = M_PI_2 + asin(y / rad);
}
}
return(z + rad + (DBL)TPat->Vals.Arms * phi / TWO_M_PI + turb_val);
}
/*****************************************************************************
*
* FUNCTION
*
* spiral2_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
* Spiral whirles around z-axis.
* The number of "arms" is defined in the TPat.
*
* CHANGES
*
* Aug 1994 : Creation.
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL spiral2_pattern (const VECTOR EPoint, const TPATTERN *TPat, int noise_generator)
{
DBL rad, phi, turb_val;
DBL x = EPoint[X];
DBL y = EPoint[Y];
DBL z = EPoint[Z];
const TURB *Turb;
if ((Turb=Search_For_Turb(TPat->Warps)) != NULL)
{
turb_val = Turb->Turbulence[X] * Turbulence(EPoint,Turb,noise_generator);
}
else
{
turb_val = 0.0;
}
/* Get distance from z-axis. */
rad = sqrt(x * x + y * y);
/* Get angle in x,y-plane (0...2 PI) */
if (rad == 0.0)
{
phi = 0.0;
}
else
{
if (x < 0.0)
{
phi = 3.0 * M_PI_2 - asin(y / rad);
}
else
{
phi = M_PI_2 + asin(y / rad);
}
}
turb_val = Triangle_Wave(z + rad + (DBL)TPat->Vals.Arms * phi / TWO_M_PI +
turb_val);
return(Triangle_Wave(rad) + turb_val);
}
/*****************************************************************************
*
* FUNCTION
*
* spherical_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* -
*
* DESCRIPTION
*
* -
*
* CHANGES
*
* -
*
******************************************************************************/
static DBL spherical_pattern (const VECTOR EPoint)
{
register DBL value;
VLength(value, EPoint);
CLIP_DENSITY(value);
return(value);
}
/*****************************************************************************
*
* FUNCTION
*
* waves_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION : Note this pattern is only used for pigments and textures.
* Normals have a specialized pattern for this.
*
* CHANGES
*
* Nov 1994 : adapted from normal by [CY]
*
******************************************************************************/
static DBL waves_pattern (const VECTOR EPoint, const TPATTERN *TPat, const TraceThreadData *Thread)
{
register unsigned int i;
register DBL length, index;
DBL scalar = 0.0;
VECTOR point;
for (i = 0 ; i < Thread->numberOfWaves ; i++)
{
VSub (point, EPoint, *Thread->waveSources[i]);
VLength (length, point);
if (length == 0.0)
{
length = 1.0;
}
index = length * TPat->Frequency * Thread->waveFrequencies[i] + TPat->Phase;
scalar += cycloidal(index)/Thread->waveFrequencies[i];
}
scalar = 0.2*(2.5+(scalar / (DBL)Thread->numberOfWaves));
return(scalar);
}
/*****************************************************************************
*
* FUNCTION
*
* wood_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
* TPat -- Texture pattern struct
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION
*
* CHANGES
*
* Oct 1994 : adapted from pigment by [CY]
*
******************************************************************************/
static DBL wood_pattern (const VECTOR EPoint, const TPATTERN *TPat)
{
register DBL length;
VECTOR WoodTurbulence;
VECTOR point;
DBL x=EPoint[X];
DBL y=EPoint[Y];
const TURB *Turb;
if ((Turb=Search_For_Turb(TPat->Warps)) != NULL)
{
DTurbulence (WoodTurbulence, EPoint,Turb);
point[X] = cycloidal((x + WoodTurbulence[X]) * Turb->Turbulence[X]);
point[Y] = cycloidal((y + WoodTurbulence[Y]) * Turb->Turbulence[Y]);
}
else
{
point[X] = 0.0;
point[Y] = 0.0;
}
point[Z] = 0.0;
point[X] += x;
point[Y] += y;
/* point[Z] += z; Deleted per David Buck -- BP 7/91 */
VLength (length, point);
return(length);
}
/*****************************************************************************
*
* FUNCTION
*
* wrinkles_pattern
*
* INPUT
*
* EPoint -- The point in 3d space at which the pattern
* is evaluated.
*
* OUTPUT
*
* RETURNS
*
* DBL value in the range 0.0 to 1.0
*
* AUTHOR
*
* POV-Ray Team
*
* DESCRIPTION : Note this pattern is only used for pigments and textures.
* Normals have a specialized pattern for this.
*
* CHANGES
*
* Nov 1994 : adapted from normal by [CY]
*
******************************************************************************/
static DBL wrinkles_pattern (const VECTOR EPoint, int noise_generator)
{
register int i;
DBL lambda = 2.0;
DBL omega = 0.5;
DBL value;
VECTOR temp;
DBL noise;
if(noise_generator>1)
{
noise = Noise(EPoint, noise_generator)*2.0-0.5;
value = min(max(noise,0.0),1.0);
}
else
{
value = Noise(EPoint, noise_generator);
}
for (i = 1; i < 10; i++)
{
VScale(temp,EPoint,lambda);
if(noise_generator>1)
{
noise = Noise(temp, noise_generator)*2.0-0.5;
value += omega * min(max(noise,0.0),1.0);
}
else
{
value += omega * Noise(temp, noise_generator);
}
lambda *= 2.0;
omega *= 0.5;
}
return(value/2.0);
}
/*****************************************************************************
*
* FUNCTION
*
* IntPickInCube(tvx,tvy,tvz, p1)
* a version of PickInCube that takes integers for input
*
* INPUT
*
* ?
*
* OUTPUT
*
* RETURNS
*
* long integer hash function used, to speed up cacheing.
*
* AUTHOR
*
* original PickInCube by Jim McElhiney
* this integer one modified by Nathan Kopp
*
* DESCRIPTION
*
* A subroutine to go with crackle.
*
* Pick a random point in the same unit-sized cube as tv, in a
* predictable way, so that when called again with another point in
* the same unit cube, p1 is picked to be the same.
*
* CHANGES
*
******************************************************************************/
static int IntPickInCube(int tvx, int tvy, int tvz, VECTOR p1)
{
size_t seed;
seed = size_t(Hash3d(tvx&0xFFF,tvy&0xFFF,tvz&0xFFF));
p1[X] = tvx + PatternRands(seed);
p1[Y] = tvy + PatternRands(seed + 1);
p1[Z] = tvz + PatternRands(seed + 2);
return (int)seed;
}
/*****************************************************************************
*
* FUNCTION
*
* PickInCube(tv, p1)
*
* INPUT
*
* ?
*
* OUTPUT
*
* RETURNS
*
* long integer hash function used, to speed up cacheing.
*
* AUTHOR
*
* Jim McElhiney
*
* DESCRIPTION
*
* A subroutine to go with crackle.
*
* Pick a random point in the same unit-sized cube as tv, in a
* predictable way, so that when called again with another point in
* the same unit cube, p1 is picked to be the same.
*
* CHANGES
*
******************************************************************************/
int PickInCube(const VECTOR tv, VECTOR p1)
{
size_t seed;
VECTOR flo;
/*
* This uses floor() not FLOOR, so it will not be a mirror
* image about zero in the range -1.0 to 1.0. The viewer
* won't see an artefact around the origin.
*/
flo[X] = floor(tv[X] - EPSILON);
flo[Y] = floor(tv[Y] - EPSILON);
flo[Z] = floor(tv[Z] - EPSILON);
seed = size_t(Hash3d((int)flo[X], (int)flo[Y], (int)flo[Z]));
p1[X] = flo[X] + PatternRands(seed);
p1[Y] = flo[Y] + PatternRands(seed + 1);
p1[Z] = flo[Z] + PatternRands(seed + 2);
return (int)seed;
}
/*****************************************************************************
*
* FUNCTION
*
* NewHash(tvx, tvy, tvz)
*
* INPUT
*
* 3D integer coordinates of the cell
*
* OUTPUT
*
* RETURNS
*
* long integer hash value
*
* AUTHOR
*
* Christoph Hormann based on MechSim Hash function by Daniel Jungmann
*
* DESCRIPTION
*
* New Hash function for the crackle pattern.
*
* CHANGES
*
* -- Aug 2005 : Creation
*
******************************************************************************/
#ifndef HAVE_BOOST_HASH
static unsigned long int NewHash(long int tvx, long int tvy, long int tvz)
{
unsigned long int seed;
long int r;
tvx *= 73856093L;
tvy *= 19349663L;
tvz *= 83492791L;
r = tvx ^ tvy ^ tvz;
seed = abs(r);
if (tvx<0) seed += LONG_MAX/2;
if (tvy<0) seed += LONG_MAX/4;
if (tvz<0) seed += LONG_MAX/8;
return (seed);
}
#endif
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
const DBL INV_SQRT_3_4 = 1.154700538;
DBL quilt_cubic(DBL t, DBL p1, DBL p2)
{
DBL it=(1-t);
DBL itsqrd=it*it;
/* DBL itcubed=it*itsqrd; */
DBL tsqrd=t*t;
DBL tcubed=t*tsqrd;
DBL val;
/* Originally coded as...
val= (DBL)(itcubed*n1+(tcubed)*n2+3*t*(itsqrd)*p1+3*(tsqrd)*(it)*p2);
re-written by CEY to optimise because n1=0 n2=1 always.
*/
val = (tcubed + 3.0*t*itsqrd*p1 + 3.0*tsqrd*it*p2) * INV_SQRT_3_4;
return(val);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static DBL fractal_exterior_color(const TPATTERN *TPat, int iters, DBL a, DBL b)
{
switch(TPat->Vals.Fractal.exterior_type)
{
case 0:
return (DBL)TPat->Vals.Fractal.efactor;
case 1:
return (DBL)iters / (DBL)TPat->Vals.Fractal.Iterations;
case 2:
return a * (DBL)TPat->Vals.Fractal.efactor;
case 3:
return b * (DBL)TPat->Vals.Fractal.efactor;
case 4:
return a*a * (DBL)TPat->Vals.Fractal.efactor;
case 5:
return b*b * (DBL)TPat->Vals.Fractal.efactor;
case 6:
return sqrt(a*a+b*b) * (DBL)TPat->Vals.Fractal.efactor;
case 7: // range 0.. (n-1)/n
return (DBL)( iters % (unsigned int)TPat->Vals.Fractal.efactor )/(DBL)TPat->Vals.Fractal.efactor;
case 8: // range 0.. 1
return (DBL)( iters % (unsigned int)(1+TPat->Vals.Fractal.efactor) )/(DBL)TPat->Vals.Fractal.efactor;
}
return 0;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
static DBL fractal_interior_color(const TPATTERN *TPat, int /*iters*/, DBL a, DBL b, DBL mindist2)
{
switch(TPat->Vals.Fractal.interior_type)
{
case 0:
return (DBL)TPat->Vals.Fractal.ifactor;
case 1:
return sqrt(mindist2) * (DBL)TPat->Vals.Fractal.ifactor;
case 2:
return a * (DBL)TPat->Vals.Fractal.ifactor;
case 3:
return b * (DBL)TPat->Vals.Fractal.ifactor;
case 4:
return a*a * (DBL)TPat->Vals.Fractal.ifactor;
case 5:
return b*b * (DBL)TPat->Vals.Fractal.ifactor;
case 6:
return a*a+b*b * (DBL)TPat->Vals.Fractal.ifactor;
}
return 0;
}
/*****************************************************************************
*
* FUNCTION
*
* Create_Density_File
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Create a density file structure.
*
* CHANGES
*
* Dec 1996 : Creation.
*
******************************************************************************/
DENSITY_FILE *Create_Density_File()
{
DENSITY_FILE *New;
New = reinterpret_cast<DENSITY_FILE *>(POV_MALLOC(sizeof(DENSITY_FILE), "density file"));
New->Interpolation = NO_INTERPOLATION;
New->Data = reinterpret_cast<DENSITY_FILE_DATA *>(POV_MALLOC(sizeof(DENSITY_FILE_DATA), "density file data"));
New->Data->References = 1;
New->Data->Name = NULL;
New->Data->Sx =
New->Data->Sy =
New->Data->Sz = 0;
New->Data->Type = 0;
New->Data->Density32 = NULL;
New->Data->Density16 = NULL;
New->Data->Density8 = NULL;
return (New);
}
/*****************************************************************************
*
* FUNCTION
*
* Copy_Density_File
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Copy a density file structure.
*
* CHANGES
*
* Dec 1996 : Creation.
*
******************************************************************************/
DENSITY_FILE *Copy_Density_File(DENSITY_FILE *Old)
{
DENSITY_FILE *New;
if (Old != NULL)
{
New = reinterpret_cast<DENSITY_FILE *>(POV_MALLOC(sizeof(DENSITY_FILE), "density file"));
*New = *Old;
New->Data->References++;
}
else
{
New=NULL;
}
return(New);
}
/*****************************************************************************
*
* FUNCTION
*
* Destroy_Density_File
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* Dieter Bayer
*
* DESCRIPTION
*
* Destroy a density file structure.
*
* CHANGES
*
* Dec 1996 : Creation.
*
******************************************************************************/
void Destroy_Density_File(DENSITY_FILE *Density_File)
{
if(Density_File != NULL)
{
if((--(Density_File->Data->References)) == 0)
{
POV_FREE(Density_File->Data->Name);
if(Density_File->Data->Type == 4)
{
POV_FREE(Density_File->Data->Density32);
}
else if(Density_File->Data->Type == 2)
{
POV_FREE(Density_File->Data->Density16);
}
else if(Density_File->Data->Type == 1)
{
POV_FREE(Density_File->Data->Density8);
}
POV_FREE(Density_File->Data);
}
POV_FREE(Density_File);
}
}
void Read_Density_File(IStream *file, DENSITY_FILE *df)
{
size_t x, y, z, sx, sy, sz, len;
if (df == NULL)
return;
/* Allocate and read density file. */
if((df != NULL) && (df->Data->Name != NULL))
{
sx = df->Data->Sx = readushort(file);
sy = df->Data->Sy = readushort(file);
sz = df->Data->Sz = readushort(file);
file->seekg(0, IOBase::seek_end);
len = file->tellg() - 6;
file->seekg(6);
// figure out the data size
if((sx * sy * sz * 4) == len)
{
df->Data->Type = 4;
unsigned int *map = reinterpret_cast<unsigned int *>(POV_MALLOC(sx * sy * sz * sizeof(unsigned int), "media density file data 32 bit"));
for (z = 0; z < sz; z++)
{
for (y = 0; y < sy; y++)
{
for (x = 0; x < sx; x++)
map[z * sy * sx + y * sx + x] = readuint(file);
}
}
df->Data->Density32 = map;
}
else if((sx * sy * sz * 2) == len)
{
df->Data->Type = 2;
unsigned short *map = reinterpret_cast<unsigned short *>(POV_MALLOC(sx * sy * sz * sizeof(unsigned short), "media density file data 16 bit"));
for (z = 0; z < sz; z++)
{
for (y = 0; y < sy; y++)
{
for (x = 0; x < sx; x++)
map[z * sy * sx + y * sx + x] = readushort(file);
}
}
df->Data->Density16 = map;
}
else if((sx * sy * sz) == len)
{
df->Data->Type = 1;
unsigned char *map = reinterpret_cast<unsigned char *>(POV_MALLOC(sx * sy * sz * sizeof(unsigned char), "media density file data 8 bit"));
for (z = 0; z < sz; z++)
{
for (y = 0; y < sy; y++)
file->read(&(map[z * sy * sx + y * sx]), sizeof(unsigned char) * sx);
}
df->Data->Density8 = map;
}
else
throw POV_EXCEPTION_STRING("Invalid density file size");
if (file != NULL)
{
delete file;
}
}
}
static unsigned short readushort(IStream *infile)
{
short i0 = 0, i1 = 0;
if ((i0 = infile->Read_Byte ()) == EOF || (i1 = infile->Read_Byte ()) == EOF)
{
throw POV_EXCEPTION_STRING("Error reading density_file");
}
return (((unsigned short)i0 << 8) | (unsigned short)i1);
}
static unsigned int readuint(IStream *infile)
{
int i0 = 0, i1 = 0, i2 = 0, i3 = 0;
if ((i0 = infile->Read_Byte ()) == EOF || (i1 = infile->Read_Byte ()) == EOF ||
(i2 = infile->Read_Byte ()) == EOF || (i3 = infile->Read_Byte ()) == EOF)
{
throw POV_EXCEPTION_STRING("Error reading density_file");
}
return (((unsigned int)i0 << 24) | ((unsigned int)i1 << 16) | ((unsigned int)i2 << 8) | (unsigned int)i3);
}
static void InitializeBinomialCoefficients(void)
{
int* ptr = BinomialCoefficients;
*ptr = 1; ++ptr;
for(unsigned n=1; n<=FRACTAL_MAX_EXPONENT; ++n)
{
*ptr = 1; ++ptr;
for(unsigned k=1; k<n; ++k)
{
*ptr = *(ptr-(n+1)) + *(ptr-n); ++ptr;
}
*ptr = 1; ++ptr;
}
ptr = BinomialCoefficients+1;
for(unsigned m=1; m<=FRACTAL_MAX_EXPONENT; ++m)
{
++ptr;
for(unsigned k=1; k<m; ++k)
{
if((k&2)!=0) *ptr = -(*ptr);
++ptr;
}
if((m&2)!=0) *ptr = -(*ptr);
++ptr;
}
}
static void InitialiseCrackleCubeTable(void)
{
int *p = CrackleCubeTable;
// the crackle cube table is a list of offsets in the range -2 ... 2 which
// are applied to the EPoint while evaluating the Crackle pattern, in order
// to look up points in close-by cubes. consider the EPoint to be in a cube
// at the center of a 3x3 grid of cubes; candidate cubes are that are within
// a "3d knight move" away (i.e. not more than 2 units). we use a lookup table
// to speed up iteration of the cube list by avoiding branch tests.
for(int addx = -2; addx <= 2; addx++)
{
for(int addy = -2; addy <= 2; addy++)
{
for(int addz = -2; addz <= 2; addz++)
{
if((abs(addx) == 2) + (abs(addy) == 2) + (abs(addz) == 2) <= 1)
{
*p++ = addx;
*p++ = addy;
*p++ = addz;
}
}
}
}
}
// This should be called once, at povray start
void InitializePatternGenerators(void)
{
InitializeBinomialCoefficients();
InitialiseCrackleCubeTable();
}
}