Copyright (C) 2020 by Abderrahman Taha This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021101301 USA
Author: Abderrahman Taha (taha_ab@yahoo.fr)
GitHub: https://github.com/parisolab/mathmod
Home:https://sourceforge.net/projects/mathmod
FaceBook:https://www.facebook.com/parisolab/
Twitter :https://twitter.com/parisolab
f ( x , y , z ) = 0
"Name" 
The script name is required and must be unique for each script. It's used to identify a script when stored in a collection file. 
"Component" 
A mathematical object can be a composition of more than one mathematical equation. To help identify each component in a set of mathematically defined surfaces, you must give each component a name (not necessarily unique though). 
"Fxyz" 
implicit equations 
"Xmax", "Xmin", "Ymax", "Ymin", "Zmax", "Zmin" 
Isosurface definition domain limits. 
"Fx","Fy","Fz" 
Parametric equations in the 3D space. "Fw" is required as the fourth dimension ("Param4D") 
"Umax","Umin","Vmax","Vmin" 
Domain limits for u and v parameters. 
"Funct" 
User defined functions. Example:
"Funct": ["Si=sinx", "Co=cos(y), "SC=Si(x,y,z,t)*Co(x,y,z,t)"]

"Const" 
User defined Constantes. Example:
"Const": ["N=5", "P=pi/2", "E=N*P"]

"Cnd" 
An implicit equation (according to x,y and z) to characterize a region in 3D space. The number of equations must be the same as the number of components.
Example for an object including three components:
"Cnd":["x>0", "", "y<0"]
See the "Models_Intersection" script 
"Grid" 
User defined grid values. The number of grid values is related to the number of components.
Isosurfaces require one grid value for each component (ie: the same grid value for "x", "y" and "z") but parametric surfaces require two (ie one for "u" and one for "v")
Example for a parametric surface with one component:
"Grid":["100", "150"]
See the "Models_Intersection" script 
"Sliders" 
Sliders are useful for interactive modification of one or more parameter used in the script. Example:
"Sliders": { "Name": ["N","R"], "Min": ["0","0"], "Max": ["50","50"], "Step": ["1","1"], "Position": ["10","16"] }
Function used in the The_Dome_v1 script 
"Description" 
You can give it another name (ie: "Infos" , ...) or delete it from the script (relevant for the user not the program). Example:
"Description": ["Blobby Torus by Abderrahman Taha 07/10/2019"]

"Vect" 
(experimental) Define a set of variables (type double). For example, to create 10 variables, use:
"Vect":["10"]

"Texture": { "Name": "Lines", "Noise": "NoiseW(x,y,z,(1),(2),(0))", "Colors": [ "R=cos((x*x+y*y+z*z)*pi)", "G=cos((x*x+y*y+z*z)*pi)*cos(x*pi)", "B=sin(y*pi)*cos(x*pi)", "T=1" }
"Pigment": { "Gradient": "3*atan((x*x*y*z)*pi)*cos(y*y*z*pi)", "Name": "Pigment", "Noise": "NoiseW(x,y,z,(1),(2),(0))", "Colors": [ { "Color": { "Name": "Gold", "Vrgba": ["V=0/10","R=9/10","G=7/10","B=1/10","A=1"] } }, { "Color": { "Name": "Red", "Vrgba": ["V=3/10","R=1","G=1/10","B=31/100","A=1"] } }, { "Color": { "Name": "Green", "Vrgba": ["V=5/10","R=1/10","G=7/10","B=1/10","A=1"] } } ] }
NoiseP 
Function used in the "Perlin_Schwarz" script 
NoiseW 
Function used in the "CellNoiseSchwarz" script 
f_hex_y 
Function used in "Wall_Pattern_..." scripts (5 scripts in total) 
fmesh 
Function used in the "Straw Basket_02" script 
fhelix1 

fhelix2 

CmpId(0) 
Return the compound ID. Available only inside the "Funct" objects array. Example:
"Funct": [ "Yx=(k1+k0*cos(u))*cos(v)*CmpId(0)", "Yy=(k1+k0*cos(u))*sin(v)", "Yz=k0*sin(u)", ... ]Used in the "Chained_Sinusoid" script. 
ThreadId 
Return the Thread ID. Example: To draw the isosurface portion calculated by the thread number 1
"Fxyz": [" if(ThreadId=1, cos(x) + cos(y) + cos(z), 0)"] 
max_ijk 
Refers to the Grid maximum value. Example:
"Grid": ["150"] > max_ijk=150 
i_indx,j_indx,k_indx 
The index of the current voxel being evaluated 
indx 
Return the current vertex index. 
max_ijk 
Refers to the Grid maximum value. Example:
"Grid": ["150"] > max_ijk=150 
x_sup,y_sup,z_sup,x_inf,y_inf,z_inf 
The isosurface definition domaine limits.
"Xmin": ["10"] , "Xmax": ["pi"] > x_inf=0 and x_sup=pi 
x_step,y_step,z_step 
x_step=(x_supx_inf)/max_ijk 
cmpId 
The compound ID. 
ThreadId 
Return the Thread ID 
i_indx , j_indx 
Return the current i and j indexes. 
max_i , max_j 
Return the grid values. Example:
"Grid": ["150","200"] > In this case: max_i=150 and max_j=200 
indx 
Return the current index (ie: indx=i*max_j+j) 
cmpId 
Return the compound ID. Available only inside the "Texture" object. Example:
"Texture": { "Colors": [ "R=if(cmpId = (130), (6/10), (7/10))", "G=if((cmpId = 130), (1/10), (5/10))", "B=if((cmpId = 130), (3/10), (0))", "T=if((cmpId = 130), (7/10), (1))" ], "Name": "Gold", "Noise": "" }Used in the "BlackHole" script. 
"Vect" 
(Experimental) Define a set of variables (type double). (Script example) 
csd(N) 
(Experimental) Return the value of the variable at the index N. (Script example) 
psh(N, val) 
(Experimental) Save the value "val" into the variable at index N. (Script example) 
The function string understood by MathMod is very similar (but not completely identical in all aspects) to mathematical expressions in the C/C++ languages. Arithmetic float expressions can be created from float literals, variables or functions using the following operators in this order of precedence:
List of mathematic operators:
() 
expressions in parentheses first 
A unit 
a unit multiplier (if one has been added) 
A^B 
exponentiation (A raised to the power B) 
A 
unary minus 
!A 
unary logical not (result is 1 if int(A) is 0, else 0) 
A*B A/B A%B 
multiplication, division and modulo 
A+B AB 
addition and subtraction 
A=B A<B A<=B 
comparison between A and B (result is either 0 or 1) 
A&B 
result is 1 if int(A) and int(B) differ from
0, else 0.Note: Regardless of the values, both operands are always evaluated. However, if the expression is optimized, it may be changed such that only one of the operands is evaluated, according to standard shortcut logical operation semantics. 
AB 
result is 1 if int(A) or int(B) differ from 0,
else 0.Note: Regardless of the values, both operands are always evaluated. However, if the expression is optimized, it may be changed such that only one of the operands is evaluated, according to standard shortcut logical operation semantics. 
List of mathematical functions:
abs(A) 
Absolute value (magnitude) of A.
With real numbers, if A is negative, returns A otherwise returns A.
With complex numbers, equivalent to hypot(real(x),imag(x)) . 
acos(A) 
Arccosine of A. Returns the angle, measured in radians, whose cosine is A. 
acosh(A) 
Same as acos() but for hyperbolic cosine. 
arg(A) 
Phase angle of complex number A. Equivalent to atan2(imag(x),real(x)) . 
asin(A) 
Arcsine of A. Returns the angle, measured in radians, whose sine is A. 
asinh(A) 
Same as asin() but for hyperbolic sine. 
atan(A) 
Arctangent of (A). Returns the angle, measured in radians, whose tangent is A. 
atan2(A,B) 
Principal arctangent of A/B, using the signs of the two arguments to determine the quadrant of the result. Returns the solution to the two expressions hypot(A,B)*sin(x)=A, hypot(A,B)*cos(x)=B. The return value is in range pi to pi, inclusive. 
atanh(A) 
Same as atan() but for hyperbolic tangent. 
cbrt(A) 
Cube root of A. Returns a solution to expression pow(x,3)=A. 
conj(A) 
Complex conjugate of A. Equivalent to real(x)  1i*imag(x) or polar(abs(x),arg(x)) . 
ceil(A) 
Ceiling of A. Returns the smallest integer not smaller than A. Rounds up to the next higher integer. E.g. 2.9, 2.5 and 2.1 are rounded to 2.0, and 2.9, 2.5 and 2.1 are rounded to 3.0. 
cos(A) 
Cosine of A. Returns the cosine of the angle A, where A is measured in radians. 
cosh(A) 
Same as cos() but for hyperbolic cosine. 
cot(A) 
Cotangent of A. Equivalent to 1/tan(A) . 
eval(...) 
This a recursive call to the function to be evaluated. The
number of parameters must be the same as the number of parameters
taken by the function. Must be called inside if() to avoid
infinite recursion. 
exp(A) 
Exponential of A. Returns the value of e raised to the power A where e is the base of the natural logarithm, i.e. the nonrepeating value approximately equal to 2.71828182846. 
exp2(A) 
Base 2 exponential of A. Equivalent to pow(2,A) . 
floor(A) 
Floor of A. Returns the largest integer not greater than A. Rounds down to the next lower integer. E.g. 2.9, 2.5 and 2.1 are rounded to 3.0, and 2.9, 2.5 and 2.1 are rounded to 2.0. 
hypot(A,B) 
Euclidean distance function. Equivalent to sqrt(A^2+B^2) . 
if(A,B,C) 
If int(A) differs from 0, the return value of this function is B,
else C. Only the parameter which needs to be evaluated is
evaluated, the other parameter is skipped; this makes it safe to
use eval() in them. 
imag(A) 
Return the imaginary part of complex number A. Equivalent to abs(A)*sin(arg(A)) . 
int(A) 
Rounds A to the closest integer. Equidistant values are rounded away from zero. E.g. 2.9 and 2.5 are rounded to 3.0; 2.1 is rounded to 2.0, and 2.9 and 2.5 are rounded to 3.0; 2.1 is rounded to 2.0. 
log(A) 
Natural (base e) logarithm of A. Returns the solution to expression exp(x)=A. 
log2(A) 
Base 2 logarithm of A. Equivalent to log(A)/log(2) . 
log10(A) 
Base 10 logarithm of A. 
max(A,B) 
If A>B, the result is A, else B. 
min(A,B) 
If A<B, the result is A, else B. 
real(A) 
Return the real part of complex number A. Equivalent to abs(A)*cos(arg(A)) . 
polar(A,B) 
Returns a complex number from magnitude A, phase angle B (in radians).
Equivalent to real(A)*(cos(real(B))+1i*sin(real(B))) . 
sec(A) 
Secant of A. Equivalent to 1/cos(A) . 
sin(A) 
Sine of A. Returns the sine of the angle A, where A is measured in radians. 
sinh(A) 
Same as sin() but for hyperbolic sine. 
sqrt(A) 
Square root of A. Returns a solution to expression pow(x,2)=A. 
tan(A) 
Tangent of A. Returns the tangent of the angle A, where A is measured in radians. 
tanh(A) 
Same as tan() but for hyperbolic tangent. 
trunc(A) 
Truncated value of A. Returns an integer corresponding to the value of A without its fractional part. E.g. 2.9, 2.5 and 2.1 are rounded to 2.0, and 2.9, 2.5 and 2.1 are rounded to 2.0. 
"mathmodconfig.js" file is the main source for MathMod's parameters settings.
MathMod uses an integrated configuration file but it can generate a copy for you when needed. Here is how:
mathmod MyfolderPath/myfolder
(replace "MyfolderPath" by the complete path to "myfolder")mathmod MyfolderPath/myfolder
, MathMod will use "mathmodcollection.js" in myfolder as it's configuration file and "mathmodcollection.js" as it's integrated scripts collection."Parameters": {
"IsoMaxGrid": 500,
"InitIsoGrid": 40,
"ParMaxGrid": 5000,
"InitParGrid": 50
} 
Maximum and current grid value setting for iso/parametric surfaces. "IsoMaxGrid" and "ParMaxGrid" can be set from the GUI (See attached image) 
"StartOptions": {
"Model": "CloseIso_1"
} 
Set the first script to be rendered when MathMod starts (by default it's the "CloseIso_1" script) 
"Localization": {
"AutomaticDetection": true,
"DotSymbol": "."
} 

"OpenGlConfig": {
"GL_SPECULAR": [50, 50, 50, 100],
"GL_SHININESS": 110
} 
OpenGL setting for MathMod's 3D viewer window. OpenGL settings can also be modified from the GUI (see attached image) 
"ThreadsConfig": {
"AutoDetect": true,
"ThreadsNumber": 8,
"MinThreadsNumber": 1,
"MaxThreadsNumber": 64
} 
image 
"WindowPosition": {
"ControlX": 20,
"ControlY": 20,
"GlwinX": 580,
"GlwinY": 20
} 

"WindowSize": {
"ControlH": 750,
"ControlW": 538,
"GlwinH": 750,
"GlwinW": 750
} 

"CalculFactorConfig": {
"FactX": 4,
"FactY": 4,
"FactZ": 4
} 
Only for isosurfaces: sets a cube of (4*4*4) points to be calculated "at once". 
"Styles": {
"PredefinedStyle": [ "Default", "Fusion", "Windows","WindowsXp"],
"UsedStyle": "Fusion"
} 
By default, MathMod uses the dark mode "Fusion". image 
"Themes": {
"PredefinedThemes": [ "Default", "Dark", "MyTheme"],
"UsedTheme": "Dark",
"MyTheme": {
"Window":[53,53,53],
"WindowText":[255, 255, 255],
"Base":[15,15,15],
"AlternateBase":[53,53,53],
"ToolTipBase":[255, 255, 255],
"ToolTipText":[255, 255, 255],
"Text":[2, 2, 255],
"Button":[53,53,53],
"ButtonText":[255, 255, 255],
"BrightText":[255, 0, 0],
"Highlight":[142,45,197],
"HighlightedText":[0, 0, 0]
}
} 
By default, MathMod uses the dark mode "Fusion". To test other themes, use the "look And feel" page in the "Configurations Options" window. image 
MathMod is home to many interesting animations and transitions. The morph effect take place with the use of the "t" parameter and the morph effect activation (and deactivation) with "CtRl+p". The Morph transition lets you create a seamless object animation from one "t" time parametr value to another. Example:
{ "Param3D": { "Description": ["Sinus Animation by Abderrahman Taha"], "Name": ["SinusPar"], "Component": ["Sinus"], "Fx": ["u"], "Fy": ["v"], "Fz": ["sin(t+3*pi*((u)^2+(v)^2))/10"], "Umax": ["1"], "Umin": ["1"], "Vmax": ["1"], "Vmin": ["1"] } }
{ "Iso3D": { "Description": ["Models Intersection by Abderrahman Taha 20/02/2020"], "Name": ["Models_Intersection"], "Component": ["Schwarz","Plan"], "Cnd": ["(xy(3/2)*z<0)",""], "Fxyz": ["cos(x4*sin(t*pi))+cos(y)+cos(z)","xy(3/2)*z(1/100)"], "Grid": ["30","20"], "Xmax": ["4+4*sin(t*pi)","6"], "Xmin": ["4+4*sin(t*pi)","6"], "Ymax": ["4","6"], "Ymin": ["4","6"], "Zmax": ["4","6"], "Zmin": ["4","6"] } }See attached image
{ "Iso3D": { "Description": ["CellNoiseSchwarz by Abderrahman Taha 08/03/2020"], "Name": ["CellNoiseSchwarz"], "Component": ["Schwarz"], "Fxyz": ["cos(x)+cos(y)+cos(z)NoiseW(x,y,z,(1),(2),(0))"], "Xmax": ["4"], "Xmin": ["4"], "Ymax": ["4"], "Ymin": ["4"], "Zmax": ["4"], "Zmin": ["4" ] }, "Texture": { "Colors": ["R=cos(x)*sin(z)+3/10","G=sin(x)*cos(y)+3/10","B=sin(y)*cos(z)+3/10","T=1"], "Name": "Lines3", "Noise": "NoiseW(x,y,z,(1),(2),(0))" } }See attached image
{ "Iso3D": { "Description": ["The Dome by Abderrahman Taha 10/08/2018"], "Name": ["The_Dome_v1"], "Component": ["The_Dome_01"], "Const": ["c=1/1000","Th=6/10","N=10","R=16"], "Funct": [ "Scherk=sinh(x)*sinh(y)4*sin(z)", "Scherk2=Scherk(N*atan2(x,sqrt(y*y+z*z)),(sqrt(x*x+y*y+z*z)R),N*atan2(z,y),t)", "IsoExterior=Scherk2(x,y,z,t)", "DFx=((IsoExterior(x+c,y,z,t)IsoExterior(x,y,z,t))/c)", "DFy=((IsoExterior(x,y+c,z,t)IsoExterior(x,y,z,t))/c)", "DFz=((IsoExterior(x,y,z+c,t)IsoExterior(x,y,z,t))/c)", "Rapp=x/sqrt(x*x+y*y+z*z)", "Iso3=(IsoExterior(x Th*Rapp(DFx(x,y,z,t),DFy(x,y,z,t),DFz(x,y,z,t),t),yTh*Rapp(DFy(x,y,z,t),DFx(x,y,z,t),DFz(x,y,z,t),t),zTh*Rapp(DFz(x,y,z,t),DFx(x,y,z,t),DFy(x,y,z,t),t), t))", "Iso2=(IsoExterior(x+ Th*Rapp(DFx(x,y,z,t),DFy(x,y,z,t),DFz(x,y,z,t),t),y+Th*Rapp(DFy(x,y,z,t),DFx(x,y,z,t),DFz(x,y,z,t),t),z+Th*Rapp(DFz(x,y,z,t),DFx(x,y,z,t),DFy(x,y,z,t),t), t))", "TickIsoExterior=(Iso2(x,y,z,t)*Iso3(x,y,z,t))" ], "Fxyz": ["if((sqrt(x*x+y*y+z*z)24) < (0),TickIsoExterior(z,y,x,t),(1))"], "Xmax": ["27"], "Xmin": ["27"], "Ymax": ["27"], "Ymin": ["27"], "Zmax": ["18"], "Zmin": ["18"] }, "Sliders": { "Max": ["50","50"], "Min": ["0","0"], "Name": ["N","R"], "Position": ["10","16"], "Step": ["1","1"] }, "Texture": { "Colors": ["R=(7/10)*(cos(x)*cos(y)*cos(z))^(1/10)","G=(7/10)","B=(7/10)","T=1"], "Name": "Lines", "Noise": "" } }See attached image
{ "Name": "Pariso_02", "ParIso": [ { "Param3D": { "Description": ["Blobby Torus by Abderrahman Taha 07/10/2019"], "Name": ["Blobby_Torus"], "Component": ["BlobbyTorus"], "Funct": ["G1=(8+(sin(2*(uv+t+sin(vu)))+3)*cos(u))*cos(v)","G2=(8+(sin(2*(uv+t+sin(vu)))+3)*cos(u))*sin(v)","G3=((sin(2*(uv+t+sin(vu)))+3)*sin(u))"], "Fx": ["G1(u,v,t)"], "Fy": ["G2(u,v,t)"], "Fz": ["G3(u,v,t)10"], "Grid": ["100","200"], "Umax": ["2*pi"], "Umin": ["0"], "Vmax": ["2*pi"], "Vmin": ["0"] }, "Texture": { "Colors": ["R= if((abs(7*u)%pi/2 & abs(7*v)%pi/3),(6/10),1) ","G= if((abs(7*u)%pi/2 abs(7*v)%pi/3),(8/10),(4/10)) ","B= if((abs(7*u)%pi/2 abs(7*v)%pi/3),(6/10),(1/10)) ","T=1"], "Name": "Candy", "Noise": "1" } }, { "Iso3D": { "Description": ["Models Intersection by Abderrahman Taha 04/11/2019"], "Name": ["Models_Intersection"], "Component": ["Schwarz","Plan"], "Cnd": ["(xy(3/2)*z<0)",""], "Fxyz": ["cos(x4*sin(t*pi))+cos(y)+cos(z)","xy(3/2)*z(1/100)"], "Xmax": ["4+4*sin(t*pi)","6"], "Xmin": ["4+4*sin(t*pi)","6"], "Ymax": ["4","6"], "Ymin": ["4","6"], "Zmax": ["4","6"], "Zmin": ["4","6"] } } ] }See attached image
{ "Iso3D": { "Description": ["Arena_02 using user defined variables by Abderrahman Taha 27/06/2020"], "Name": ["Arena_02"], "Component": ["Arena"], "Const": ["c=1/10000", "th=6/10", "N=10"], "Vect": ["4"], "Funct": ["Scherk=sinh(x)*sinh(y)4*sin(z)", "IsoExterior =Scherk(x,sqrt(y*y+z*z)(16),N*atan2(z,y),t)", "DFx=((IsoExterior(x+c,y,z,t)IsoExterior(x,y,z,t))/c)", "DFy=((IsoExterior(x,y+c,z,t)IsoExterior(x,y,z,t))/c)", "DFz=((IsoExterior(x,y,z+c,t)IsoExterior(x,y,z,t))/c)", "Rapp=(th/sqrt(x*x+y*y+z*z))", "ThickIsoExterior= psh(0, DFx(x,y,z,t)) * psh(1, DFy(x,y,z,t)) * psh(2, DFz(x,y,z,t)) * (psh(3, Rapp(csd(0) , csd(1) , csd(2),t))) * (IsoExterior(xcsd(0)*csd(3) ,ycsd(1)*csd(3),zcsd(2)*csd(3),t))*(IsoExterior(x+csd(0)*csd(3) ,y+csd(1)*csd(3),z+csd(2)*csd(3),t))"], "Fxyz": ["if((sqrt(x*x+y*y+z*z)  27) < 0 & abs(x) < (99/10) ,ThickIsoExterior(x,y,z,t), 1)"], "Xmax": ["10"], "Xmin": ["10"], "Ymax": ["28"], "Ymin": ["28"], "Zmax": ["28"], "Zmin": ["28"] } }See attached image