POV-Ray : Newsgroups : povray.general : Post something : Re: Post something Server Time
22 Mar 2026 02:12:21 EDT (-0400)
  Re: Post something  
From: Bald Eagle
Date: 21 Mar 2026 10:20:00
Message: <web.69bea80a4fed62631f9dae3025979125@news.povray.org>
One of the things that I have sustained an active interest in over the past
several years is the creation of procedural patterns.

Doing this in SDL to create pigment {function {}} patterns can be challenging
due to the scalar-only nature of the function parser / virtual machine.

During experimentation with infinitely tiling a plane or filling space, it
became readily apparent that the stock modulo function - mod (N, M) - did not
remain consistent across the -value|0|+value transition.

So I crafted my own.   And then another.   And then another.
So which one was "right"?  Apparently this is one of those situation-dependent
functions like pow (0, 0).

So I did some investigating and there are a number of different ways to perform
modular arithmetic so that the result has the specific characteristics that you
need in your given situation.  And here's an important note: you may need to use
different behaviours in different parts of your equations.

I discovered that my custom-rolled fmod () function usually worked for what I
needed, but when applied in a blanket manner was inappropriate for certain parts
of my patterns.   So I use fmod () some places, and stock mod () in others.

Here's a small starting library.  I'm sure there are more variations.

// MODULO_LIB.inc
// Behavioral Modulo Library for POV-Ray SDL
// Guarded, scalar-only, function-safe

#ifndef (MODULO_LIB_INC)
#declare MODULO_LIB_INC = yes;

// --- HARD MODULO ---
#declare MOD_HARD_BASIC = function (V, P) { mod(V, P) };

// --- ABSOLUTE MODULO ---
#declare MOD_ABS_BASIC = function (V, P) { mod(abs(V), P) };

// --- PHASE-CORRECTED ABS MODULO ---
#declare MOD_ABS_PHASE = function (V, P)
{ select(V, 1 - mod(abs(V), P), mod(abs(V), P)) };

// --- CENTERED MODULO ---
#declare MOD_CENTER_BASIC = function (V, P)
{ mod(V + P/2, P) - P/2 };

// --- TRIANGLE MODULO ---
#declare MOD_TRI_BASIC = function (V, P)
{ abs(mod(V, 2*P) - P) };

// --- SMOOTH MODULO ---
#declare MOD_SMOOTH_BASIC = function (V, P)
{ P * (0.5 - 0.5*cos(2*pi*V/P)) };

#declare MOD_SMOOTH_SIGNED = function (V, P)
{ V - P * sin(2*pi*V/P)/(2*pi) };

// --- NESTED MODULO ---
#declare MOD_NEST_BASIC = function (V, A, B)
{ mod(mod(V, A), B) };

#declare MOD_NEST_ABS = function (V, A, B)
{ mod(mod(abs(V), A), B) };

#declare MOD_NEST_PHASE = function (V, A, B)
{ select(V, B - mod(mod(abs(V), A), B), mod(mod(abs(V), A), B)) };

// --- LOGIC MODULO ---
#declare MOD_LOGIC_PARITY = function (V, P)
{ mod(floor(abs(V)/P), 2) };

#declare MOD_LOGIC_QUANTIZED = function (V, P, S)
//{ round(mod(V, P)/S)*S };
{ int(mod(V, P)/S)*S };

// --- WINDOWED / CLAMPED ---
#declare MOD_LOGIC_WINDOW = function (V, P)
{ select(V, mod(abs(V), P), 0) };

#declare MOD_LOGIC_CLAMP = function (V, P, C)
{ min(mod(V, P), C) };

// --- METRIC HELPERS ---
#declare MOD_METRIC_RADIAL = function (R, P)
{ mod(R, P) };

#declare MOD_METRIC_ANGLE = function (A, P)
{ mod(A, P) };

#end
// *** end of file ***


Post a reply to this message


Attachments:
Download 'modulo_lib_full_demo.png' (53 KB)

Preview of image 'modulo_lib_full_demo.png'
modulo_lib_full_demo.png


 

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.