Povray - Open Source --- MA_Helpers


Published: 29.12.2024
Status: beta

When working with Povray I am missing many functions which are common in other programming languages. To sort arrays, handle strings, convert variable-types, lovely regular expressions, for all of that for example PHP provides about hundred functions.

To handle strings Povray provides two helpful function only:
substr() and strlen(). Thats it. Maybe in addition concat(), but thats it finally.

These are far away what I needed, so in the past years I coded many macros by hand. Costs much time but maybe it will save otherones time by publishing them here.

Without ma_helpers.inc no one of my bigger scripts will work!

The file has to be included everywhere, otherwise you can count the error-messages. Despite its size of nearly 3000 rows (October 2024) it doesnt lower the render-performance, not even a second of parse-time will come on top.

For a more detailed documentation of the macros and what finally will be the result see the sourcecode.

Variables
In the upper part of the file are some dozens variables located to control and modify the behavior of the macros. Before you copy-paste the macros into your code and modify them have a look into the file. Also in some of my other scripts the existense of this variables is mandatory.

Cam* and Lig*
All Variables:
CamLocation, CamLookAt, CamAngle, CamRotate, CamSky, CamType, LigVector, LigColor, LigIntensity, LigRotate

The values of this variables come to live in the macro MA_CameraAndLight_Set(). With their help all parameters of camera and light can be changed multiple times without calling the original povray-function every time. Also some nice things like automatically fade-in and -out will become possible (later, under construction).

Simple example:
#declare CamAngle = 60;
doSomething()
#declare CamRotate = <10,0,0>;
MA_CameraAndLight_Set()

Debug and Logfile

MA_Terminal*   ( mText [, mValue] )
MA_Terminal    ( mText )
MA_Terminal_S  ( mText, mValue )
MA_Terminal_F  ( mText, mValue )
MA_Terminal_V  ( mText, mValue )
MA_Terminal_AS ( mText, mValue )
MA_Terminal_AF ( mText, mValue )

MA_Terminal() sends a simple text/string to the terminal. If you like to concat a variable behind it use some of the other macros. Povray isnt able to convert types by itself so for every variable-type exists its own macro. So use MA_Terminal_S() for strings, _F for float, _AS for string-arrays and so on.
Is a nice to have in complex scripts to output the value of variables fast and easy.

MA_Error ( mMacro, mText )
Sends an error-message to the terminal and raises a real #error by povray itself.

MA_Warning ( mMacro, mText )
Sends a warning to the terminal.

MA_Notice ( mMacro, mText )
Sends a simple notice to the terminal.
Very similar to MA_Terminal_S but the parameters are the same as for warning and error (them above).

MA_Deprecated ( mOldMacro, mNewMacro )
Often I modify macros or their parameters gets changed. In this case older scripts will stop working or I have to search for all usages in all scripts and correct them immediately. With MA_Deprecated() I can let exist the older macros but inside them I call the new ones and sends an ugly long text to the terminal (that normaly ist well formatted when I use it).

#macro Old_Macro  (mVar1, mVar2)
	MA_Deprecated ("Old_Macro", "New_Macro")
	New_Macro (mVar1, mVar2 + 4711)
#end

Text in the terminal:
*** MA => *** DEPRECATED ***: Macro 'Old_Macro' is old and risky, use 'New_Macro' instead!!!

MA_Finish ()
Sends some statistic-data to the terminal. At the moment the number of warnings and deprecated-messages.
Should used - if at all - at the end of the executed script.

Important
I use this macros often in my scripts. Somewhen in the future I like to output their content into a logfile. With this small helper-macros I only need to modify them instead of hundreds of lines in dozens of scripts.

The disadvantage of using them clearly is that they do not spit out the real linenumbers. If you like to get informed about the linenumber and the calling file you should forget most of the above macros and make use of povray-directives #debug, #warning and #error.

See: http://povray.org/documentation/3.7.0/r3_3.html#r3_3_2_7_1

Specialities
MA_CameraAndLight_Prepare ()
Prepares all variables for camera and light. Should be called after every change of one of the Cam and Lig Variables (see above).

MA_CameraAndLight_Set ()
Uses all variables beginning with Cam* and Lig* and calls the povray-functions camera{} and light{}. Together with some other lines of code a few nice effects can come to live. This macro only needs to be called once at the end of the main exectuted script.
An example how to use both of the functions will follow.

MA_RenderStyle_Set ( mStyle )
Allowes lower levels of quality during creation of objects. I will use it in as many objects as possible to lower rendering-times during development, when not everything has to reflect light or every small screw has to cast shadows.

Small example:
MA_RenderStyle_Set("hell")
//MA_RenderStyle_Set("dev")
sphere { 0,1
	texture {
		#if (RS_Dev)	pidgment { color Gray10 }	#end
		#if (RS_Tec)	pidgment { color Green }	#end
		#if (RS_Real)	pidgment { color Silver }	#end
		#if (RS_Hell)	pidgment { color Silver2 }	#end
	}
}

MA_RenderStyle_Reset ()
Resets the RenderStyle to the last value. If only on specific object should rendered in highest details, RS will set to a lower level and shortly befor calling the desired object set to a higher value.

Example:
MA_RenderStyle_Set("real") // or "dev", whatever.
object { Get_far_away_object__No_need_to_be_too_detailed() }
MA_RenderStyle_Set("hell")
object { Get_something_very_near_with_all_possible_details() }
MA_RenderStyle_Reset()
object { Get_another_far_away_object() }

MA_GetParam_* ( xParams, xParamName, mDefault ) => float/string/vector/boolean
MA_GetParam_S ( xParams, xParamName, mDefault ) => string
MA_GetParam_F ( xParams, xParamName, mDefault ) => float
MA_GetParam_V ( xParams, xParamName, mDefault ) => vector
MA_GetParam_B ( xParams, xParamName ) => boolean

Povray doesnt know about optional parameters or other useful ways to send a variable number of values/parameters to a macro. This problem solves MA_GetParam_*() in an old-fashion way.

Similar to CSS parameters and values become separated with a colon (:). This pairs will arranged by semicolon (;) with other pairs and saved in one string-variable. This string can be send to macros which uses the MA_GetParam_*()-Makros to pick out whats needed. Especially if macros call other macros and are out of range from the outside this method its useful to pass them to sub-macros.

At the bottom of the include-file ma_helpers you can find an example and my Spaceship Tussi has to deal with it heavily.

Here only a small example:
#declare myParams = "position: <0,1.5,0>; color: <0,0,1>; scale-y: 1.5; text: - povray -; reflection";
#macro ShowSphere (mParams) 
	#local mPos         = MA_GetParam_V(mParams, "position",   <0,5,0>  );
	#local mColor       = MA_GetParam_V(mParams, "color",      <0,0,0>  );
	#local mScaleY      = MA_GetParam_F(mParams, "scale-y",    1        );
	#local mText        = MA_GetParam_S(mParams, "text",       "-none-" );
	#local mReflection  = MA_GetParam_B(mParams, "reflection"           );
	#ifndef( Shapes_Temp) #include "shapes.inc" #end
	union {
		sphere { 0, 1
			texture { pigment { color mColor } }
			#if (mReflection) finish { reflection 0.1 phong 1} #end
		}
		object {
			Circle_Text_Valigned (
				"timrom.ttf", mText, 0.5, 0.0005, 0.05, 1, 1, Align_Center, -90, -90
			)     
			texture {	pigment{ color rgb <1,0,0> }	}
			rotate<90,0,0>
		}
		scale <1, mScaleY, 1> translate mPos
	}
#end
ShowSphere (myParams)

MA_GetSlope ( xValue, mType, mIterations, mOffset ) => float

Returns different types of slopes. In animations it adjusts hard/linear movements, maybe to simulate jumping balls or accelerate objects more naturally.

Use Value as a range from 0 to 1 and define the type of slope with Type. A cosine rises more slowly at the beginning than linear, overtakes it at 0.5 and slows down to 1 more cozy. The return-value always will between 0 and 1 also and should used as a multiplier. For cosine the german translation cosinus also can be used.

That happes for Iteration = 1 once. If it hast to go down to 0 again use Iteration = 2, for 2 times up and once down use "3", and so on.

With Offset the start-value can be shifted, values from 0 to 2 are useful. Offset = 0 starts at the bottom or value = 0 , Offset = 1 above, Offset = 0.5 more or less in the middle (depends on Type), but definitely on the way upwards.

At the lower right all possible values for Type, the colors are used in the picture and the anim-gif. In the pictures Iterations = 4 was used, in the animation 2. The sourcecode of the animation can be found as example at the bottom of the include-file (slope-2).

A special type is bool, that is = 1 if xValue > 0.

In the near future some more slopes will be added, maybe a step-like one, that jumps like stairs from one value to the other.
Next version.

MA_GetSlope_ByString  ( xValue, mTypeMixed ) => float

round
linear
cosine
cosine+
cosine++
bounce+
bounce-
bool
Same functionality as MA_GetSlope(), but the three slope-parameters can delivered in a colon- or semicolon-separated string. Included optional parameters, iterations and offset can be leaved out.
MA_Terminal_F ("slope-1", MA_GetSlope_ByString(0.7, "linear,1,0"))
MA_Terminal_F ("slope-2", MA_GetSlope_ByString(0.7, "cosine+;4;-0.5"))
MA_Terminal_F ("slope-3", MA_GetSlope_ByString(0.7, "bounce+"))         //bounce+,1,0
#local mySlope = MA_GetSlope_ByString(0.7, "");                         //linear, 1,0

This macro I need in some of my Screenplay-Macros, less in others scripts.

MA_SetClock ( mValue )
Sets the global variable MA_Clock either to the povray-constant clock (if clock_on = true) or the Value. Subsequently MA_Clock can be used in animations or simply create a single picture.

Not longer needed:
#if (clock_on = false)
	#local myClock = 0.5;
#else
	#local myClock = clock;
#end
object { sphere { 0,1 } translate <0, 5 * myClock, 0> }

Instead use:
MA_SetClock(0.5)
object { sphere { 0,1 } translate <0, 5 * MA_Clock, 0> }

MA_OutputArrayString      ( mArray, xFile, mOverwrite, mComment )
MA_OutputArrayString_Base ( mArray, xFile, mOverwrite, mComment, mHighestIndex )
Saves a string-array well formatted into a textfile. Really nice if you like to see what really happens in it. If you save more than one array in one file you can comapare the content befor and after other operations, maybe after sorting. For that at the first time set Overwrite = true and the others false. The Comment will be saved above the array and helps with identification.

MA_Include ( mFile, mBasePath ) => string
Tries to include the given file. Searches in path set in MA_Include_Folders. The given BasePath is the start-point. If its the same as the executed script set mBasePath = "", otherwise dont forget the slash at the end ("subfolder/").
Returns the path where the file was found, otherwise "-1" as a string.

#local mFolderSkyfakes = MA_Include("ma_skyfakes.inc", "");
#if (mFolderSkyfakes != "-1")
	MA_Terminal("Skyfakes found")
	#include concat(mFolderSkyfakes, "ma_skyfakes_textures.inc")
#else
	MA_Terminal("Skyfakes NOT found")
#end

Strings

MA_String_Pad ( xString, mLength, xPadChar, mPadPos ) => string
Adds at the beginning or the end the PadChar, till the wished Length is reached.
#local Test = MA_String_Pad("Bongo", 10, "-", "l");     // returns "-----Bongo"
#local Test = MA_String_Pad("Bongo",  8, "-", "right"); // returns "Bongo---"

MA_String_Trim ( mParam ) => string
Removes spaces at the beginning and the end.

MA_String_TrimChar ( mParam, mChar ) => string
Removes the give Char at the beginning and the end.

Mixed

Mixed variables in my world are vectors that are stored as strings. I need this often to store strings, numbers, and vectors in a string array. A Vector <1,2,3.3> becomes Mixed "1,2,3.3".

MA_Mixed_SumValues ( mMixed1, mMixed2 ) => string/mixed

Sums the contents of both mixed variables.

#local m1   = "1,2,300";
#local m2   = "3, 4.5, -17";
#local mSum = MA_Mixed_SumValues (m1, m2);  //will return string "4, 6.5, 283"

Arrays - 1D

MA_Array_FindString ( mString, mArray ) => boolean
Searches in the given 1D array for a string. Returns true it it was found, otherwise false. I use this sometimes to avoid nested If-Blocks.

#local City = "cologne";
#if (MA_Array_FindString(City, array[3] { "Bielefeld", "Cologne", "Posemuckel" }))
	MA_Terminal_T ("Yes man")
#end
// or ...
#if (!MA_Array_FindString(City, array[3] { "Bielefeld", "Cologne", "Posemuckel" })) ...

MA_Array_Merge ( mArray1, mArray2 ) => array
Merges two 1D arrays. This macro can be used for every types of array (string, float, vector).

MA_Array_Cut ( mArray, mIndexFirst, mIndexLast, mRows ) => array
Cuts 1D arrays, doesnt matter which datatype.
Use IndexFirst and Rows OR IndexFirst and IndexLast and set the not used parameter = 0.

Arrays - 2D

MA_Array2D_Merge( xArray1, xArray2 ) => 2d-array
Merges two 2D arrays without sorting them.
Can be used with all types of variables inside the arrays.

MA_ArrayString2D_FindRow ( mArray, mString, mCol ) => float

Searches in the given 2D string-array for a String in the given Col.
If the string is found the macro returns the index of the row (0-based) or -1 if nothing was found.

#declare test = array[4][2] {
	{ "berlin",  "3000000" }
	{ "hamburg", "2000000" }
	{ "cologne", "1000000" }
	{ "munich",   "500000" }
}
MA_Terminal_F("found row", MA_ArrayString2D_FindRow ( test, "cologne", 0)) //Output: 2

MA_ArrayString2D_FindRow_Multi ( mArray, mString1, mString2, mCol1, mCol2, mIndexFirst, mIndexLast ) => float

Similar to MA_ArrayString2D_FindRow, but it searches for 2 different values in 2 different columns, both values must match.

MA_ArrayString2D_Sort( mArrayOld, mColSort, xDirection, xCompType ) => 2d-array
Sorts 2D string-arrays by defining the colum ColSort as reference (array-index 0-x), the Direction ("asc" or "desc") and the type of compare CompType ("string" or "float"). Its only possible to sort string-arrays, nevertheless they can handled/compared as floats, because this can end in totally different results (as a string the "10" is smaller than "2").

MA_ArrayString2D_MergeAndSort( xArray1, xArray2, mColSort, xDirection, xCompType ) => 2d-array
A simple concatentation of both 2D array-macros. At first merge than sort.

Converts

MA_String2Array ( mString, mSep, mTrim ) => array
Converts a string to a string-array by using the separator Sep to split the string.
Use Trim (true/false) to delete leading or trailing spaces.

MA_ArrayString2String ( mArray, mSep ) => string
Converts a string-array to a string, separated by the char Sep, like the PHP-Function implode().

MA_ArrayFloat2String ( mArray, mSep ) => string
Converts a float-array to a string, separated by the char Sep.

MA_String2Vector ( mString ) => vector
Converts a comma-separated string to a vector, maybe found chars < and > gets removed.

MA_ArrayString2Vector ( mArray ) => vector
Converts a string-array to a vector.

MA_Vector2String      ( mVector ) => string
MA_Vector2String_Base ( mVector, mDimensions, mDigits ) => string

Converts vectors to strings. MA_Vector2String() uses default-parameters for Dimensions and Digits, MA_Vector2String_Base() allows parameters for them.

MA_Deg2Vector*  ( mRA, mDE, mRadius ) => vector

Starfield with real existing stars
MA_Deg2Vector00 ( mRA, mDE, mRadius ) => vector
MA_Deg2Vector10 ( mRA, mDE, mRadius ) => vector
MA_Deg2Vector01 ( mRA, mDE, mRadius ) => vector
MA_Deg2Vector11 ( mRA, mDE, mRadius ) => vector

Converts right ascension RA and declination DE together with the distance Radius to a vector.

Normally the values for RA ranges from -180 to 180 and DE from -90 to 90 degree, but that can differ from the source where you get the data from. If the data contains only positive values for RA and DE use the macro MA_Deg2Vector00(), in all other cases the both digits at the end stands for a true/false, if the values have to shifted to the positive range. MA_Deg2Vector10() will add 180 to all RA values, MA_Deg2Vector01() will add 90 to all DE values, and so on.

Internally the macro calculates with radians, which only works with positive values.

MA_Vector2Deg ( mVector ) => array
THIS MACRO IS LEFT !!!
Who ever knows how to invers the following calculation ... I really would like to get the solution.

#macro MA_Deg2Vector  (mRA, mDE, mRadius)
	#local mRect	= radians(mRA + MA_Deg2Vector_RA_Offset);
	#local mDecl	= radians(mDE);
	//Here we have the critical lines
	#local mPosX	= mRadius * sin(mDecl) * cos (mRect);
	#local mPosY	= mRadius * cos(mDecl);
	#local mPosZ	= mRadius * sin(mDecl) * sin (mRect);
	#local mVector	= <mPosX, mPosY * -1, mPosZ>;
	mVector
#end

Repaired or complemented Povray-Macros

MA_Circle_Text_Valigned ( ... ) => object

The macro Circle_Text_Valigned is available in the povray-own include-file shapes.inc, but it has a little bug inside. Whe using it in a specific way, with the text outside of a cylinder, the text ist too far away from the object, that I corrected.
I am not totally sure if its a bug or a mis-use by myself, so I created this macro, which is to 99% a copy of the original, with only a few lines modified. Parameter and return-value are the same.

See also Shapes.inc in the povray-documentation.

Example:
union {
	cylinder {
		<0,0,0>, <0,2,0> 1
		texture { pigment { color rgb <1,1,0> transmit 0.2 } }
	}
	object {
		//Circle_Text_Valigned (
		MA_Circle_Text_Valigned (
			"timrom.ttf", "huhu", 0.5, 0.0005, 0.05, 1, 1, Align_Center, -90, -90
		)
		texture { pigment { color rgb <0.5,0,0> }	}
		rotate<90,0,0>
		translate <0,1,0>
	}
}

Experimental / Development
There is no guarantee by myself, that the following macros will survive a long time.
Use them on your own risk.

MA_Testarea      ( mAll )
MA_Testarea_Base ( mXN, mXP, mZN, mZP )

Shows a chess-like testbed.
The parameters defines the number of tiles in the different directions (x-axis negative, x-axis potitive, the same for z).

MA_CenterMarker      ( mLengthAxes )
MA_CenterMarker_Base ( mRadiusSphere, mThicknessAxes, mLengthAxes, mAxes )

Marks <0,0,0> with a sphere and the axes with lines.

Download
ma_helpers.7z => 560 kB 7-Zip - Version 1.0 from 29th December 2024
ma_helpers.zip => 580 kB Zip - for the Ladies

Comments

No comments at all, sorry.
* E-Mail and Website optional, E-Mail will not get published, use this only if you like to get an answer.
the german site
the english site
both sites