### Project : Mandelbrot Set
### Date : 2021-12-25
### Mandelbrot - Colorized and Animated
### 2019-02-25 Bert Mariani
###
### MyApp.ProcessEvents() ###<<< EXEC the Draw MonaLisa between each step of array sorting
###
###--------------------------------------------------------------------
#
# Use mylibMandel.c as input to VisualStudio-2019-Community
# Use buildvc-2.bat batch to Build the mylibMandel.dll required
#
###--------------------------------------------------------------------
### OUTPUT
#
#* *********************************************************************
# ** Visual Studio 2017 Developer Command Prompt v15.9.9
# ** Copyright (c) 2017 Microsoft Corporation
# **********************************************************************
# Microsoft (R) C/C++ Optimizing Compiler Version 19.16.27027.1 for x86
# Copyright (C) Microsoft Corporation. All rights reserved.
#
# mylibMandel.c
# Microsoft (R) Incremental Linker Version 14.16.27027.1
# Copyright (C) Microsoft Corporation. All rights reserved.
#
# Press any key to continue . . .
#
###--------------------------------------------------------------------
### DIRECTORY
#
# C:\MyStuff\AA-Mandelbrot-2>dir
# Volume in drive C has no label.
# Volume Serial Number is 4EAE-5066
#
# Directory of C:\MyStuff\AA-Mandelbrot-2
#
# 2020-10-22 06:39 PM
.
# 2020-10-22 06:39 PM ..
# 2020-10-22 05:50 PM 257 buildvc-2.bat
# 2020-10-22 06:33 PM 19,895 Mandelbrot-10.ring
# 2019-05-25 03:41 PM 6,047 mylibMandel.c
# 2020-10-22 06:28 PM 420,352 mylibMandel.dll
# 2020-10-22 06:28 PM 695 mylibMandel.exp
# 2020-10-22 06:28 PM 1,846,236 mylibMandel.ilk
# 2020-10-22 06:28 PM 1,766 mylibMandel.lib
# 2020-10-22 06:28 PM 6,524,928 mylibMandel.pdb
# 9 File(s) 8,820,300 bytes
# 2 Dir(s) 164,299,460,608 bytes free
#
###--------------------------------------------------------------------
### BATCH Script
###
# :: buildvc-2.bat
#
# cls
# call c:\ring\language\src\locatevc.bat
# cl /c /DEBUG mylibMandel.c -I"c:\ring\language\include"
# link /DEBUG mylibMandel.obj c:\ring\lib\ring.lib /DLL /OUT:mylibMandel.dll /SUBSYSTEM:CONSOLE,"5.01"
# del mylibMandel.obj
# pause
#
###--------------------------------------------------------------------
//================================
Load "guilib.ring"
load "stdlib.ring"
? "Loading Library"
if iswindows()
LoadLib("mylibMandel.dll")
but ismacosx()
LoadLib("libmylibMandel.dylib")
else
LoadLib("libmylibMandel.so")
ok
UseCcalculator = 1 ###<<< True-1. Ring-C-Array draws WRONG direction
decimals(12)
###----------------------------------
### ScreenValues
ScreenX = 100 // 100 ### Where on Screen
ScreenY = 50 // 50
WinSizeX = 920 // 920 ### Window Size. Mona=>800
WinSizeY = 920 + 30 // 950 ### SQUARE Window Area
ButtonY = 5 ### WinSizeY - 35 ### 915 Button Placement on TOP of Window
ButtonW = 90
ButtonH = 30
LabelX = WinSizeX - 20 ### 900 Label Area within Window
LabelY = WinSizeY - 50 ### 900
MonaX = WinSizeX - 20 ### 900 Canvas Size - drawing
MonaY = WinSizeY - 50 ### 900
width = MonaX - 100 ### 800 Mandelbrot Size
height = MonaY - 100 ### 800
iter = 50 ### Iteration of N loops before going into Orbit
offset = 50 ### Draw on MonaLisa 50 pixels from border Width & Height
grid = offset -2 ### Notched grid
aList = newList(width,height) ### Save X-Y Mandelbrot Point Values here
###--------------------------------------------
### Madelbrot Min-Max Ranges:
### I = Imaginary=Vertical R - Real=Horizontal
minI = -2.00
maxI = 2.00
minR = -2.00
maxR = 2.00 # Default limits
###-------------------------------
### Mouse Pressed Points
nX = 0 #= myfilter.getglobalx() ### Screen co-ord, NOT Canvas
ny = 0 #= myfilter.getglobaly() ### Screen co-ord, NOT Canvas
###---------------------------
### Mouse Move OLD Points
oX = 0 #= fX ### Save OLD points
oY = 0 #= fY
###-------------------------------
### Mouse Release Points
fX = 0 #= myfilter.getglobalx() ### Screen co-ord, NOT Canvas
fY = 0 #= myfilter.getglobaly()
###-----------------------------------------
colorBlack = new qcolor() { setrgb(000,000,000,255) }
penUseBk = new qpen() { setcolor(colorBlack ) setwidth(1) }
colorWhite = new qcolor() { setrgb(255,255,255,255) }
colorRed = new qcolor() { setrgb(204,000,000,255) }
colorGreen = new qcolor() { setrgb(000,204,000,255) }
colorBlue = new qcolor() { setrgb(000,000,255,255) }
colorGray = new qcolor() { setrgb(128,128,128,255) }
colorBrown = new qcolor() { setrgb(153,076,000,255) }
colorGrape = new qcolor() { setrgb(255,178,159,255) }
colorOrange = new qcolor() { setrgb(255,128,000,255) }
colorYellow = new qcolor() { setrgb(255,255,000,255) }
colorPurple = new qcolor() { setrgb(153,153,255,255) }
colorPink = new qcolor() { setrgb(255,051,255,255) }
colorLime = new qcolor() { setrgb(128,255,000,255) }
penUseW = new qpen() { setcolor(colorWhite ) setwidth(1) }
penUseR = new qpen() { setcolor(colorRed ) setwidth(1) }
penUseG = new qpen() { setcolor(colorGreen ) setwidth(1) }
penUseB = new qpen() { setcolor(colorBlue ) setwidth(1) }
penUseGr = new qpen() { setcolor(colorGray ) setwidth(1) }
penUseBr = new qpen() { setcolor(colorBrown ) setwidth(1) }
penUseGp = new qpen() { setcolor(colorGrape ) setwidth(1) }
penUseOr = new qpen() { setcolor(colorOrange) setwidth(1) }
penUseYe = new qpen() { setcolor(colorYellow) setwidth(1) }
penUsePu = new qpen() { setcolor(colorPurple) setwidth(1) }
penUsePi = new qpen() { setcolor(colorPink ) setwidth(1) }
penUseLi = new qpen() { setcolor(colorLime ) setwidth(1) }
penArray = [penUseW, penUseR, penUseG, penUseB, PenUseGr, penUseBr, penUseGp, penUseOr, penUseYe, penUsePu, penUsePi, penUseLi]
###===========================================
MyApp = New qapp
{
win1 = new qwidget()
{
setwindowtitle("Draw Mandelbrot: USE MOUSE to ZOOM-IN")
setgeometry(ScreenX, ScreenY, WinSizeX, WinSizeY) ### On Screen
oFont = new qfont("",8,0,0)
setFont(oFont)
###==================================
myfilter = new qallevents(win1)
###------------------------------------------
### Mouse Event
myfilter.setMouseButtonPressEvent("pPress()")
myfilter.setMouseButtonReleaseEvent("pRelease()")
myfilter.setMouseMoveEvent("pMove()")
installeventfilter(myfilter)
###------------------------------------------
### ReSizeEvent ... Call WhereAreWe function
myfilter.setResizeEvent( "WhereAreWe()")
myfilter.setMoveEvent( "WhereMoved()" )
###===================================
new qpushbutton(win1)
{
setgeometry(10,ButtonY, ButtonW, ButtonH)
settext("Draw")
setclickevent("Draw()")
}
###-------------------------------
### Draw Label and lineEdit
label1 = new qlabel(win1)
{
setGeometry(105,ButtonY, 40, ButtonH)
setText("Min-I")
}
lineEdit1 = new qlineedit(win1) {
setGeometry(140,ButtonY, 70, ButtonH)
setText(""+minI)
}
###---------------------
label2 = new qlabel(win1)
{
setGeometry(215,ButtonY, 40, ButtonH)
setText("Max-I")
}
lineEdit2 = new qlineedit(win1) {
setGeometry(250,ButtonY, 70, ButtonH)
setText(""+maxI) ### value = lineedit1.text() ### Read text field
}
###---------------------
label3 = new qlabel(win1)
{
setGeometry(325,ButtonY, 40, ButtonH)
setText("Min-R")
}
lineEdit3 = new qlineedit(win1) {
setGeometry(360,ButtonY, 70, ButtonH)
setText(""+minR)
}
###---------------------
label4 = new qlabel(win1)
{
setGeometry(435,ButtonY, 40, ButtonH)
setText("Max-R")
}
lineEdit4 = new qlineedit(win1) {
setGeometry(470,ButtonY, 70, ButtonH)
setText(""+maxR)
}
###---------------------
label5 = new qlabel(win1)
{
setGeometry(545,ButtonY, 40, ButtonH)
setText("Iter")
}
lineEdit5 = new qlineedit(win1) {
setGeometry(580,ButtonY, 50, ButtonH)
setText(""+iter)
}
###---------------------
label6 = new qlabel(win1)
{
setGeometry(635,ButtonY, 40, ButtonH)
setText("Zoom:")
}
lineEdit6 = new qlineedit(win1) {
setGeometry(670,ButtonY, 180, ButtonH)
setText(""+1)
}
###==================================
Canvas = new qlabel(win1)
{
setgeometry(10,40,LabelX, LabelY) ### In Black Canvas inside Window
MonaLisa = new qPixMap2( MonaX, MonaY)
daVinci = new qpainter()
{
begin(MonaLisa)
setpen(penUseB)
#endpaint() ### This will Stop the Painting
}
setpixmap(MonaLisa)
}
show() ### Will show Painting ONLY after exec
}
exec()
}
###====================================================
### Draw MonaLisa Painting
Func DrawUpdate()
#MonaLisa.fill(colorBlack)
Canvas.setpixmap(MonaLisa) ### Need this setpixmap to display imageLabel
win1.show() ### Need this show to display imageLabel
MyApp.ProcessEvents() ###<<< EXEC the Draw
return
###=============================================================
Func Draw()
MonaLisa.fill(colorBlack)
minI = number( lineEdit1.text() ) ### Get values from edit box on bottom of screen
maxI = number( lineEdit2.text() )
minR = number( lineEdit3.text() )
maxR = number( lineEdit4.text() )
iter = number( lineEdit5.text() )
if ( MaxI - MinI = 0 ) || (MaxR - MinR = 0 )
See "Size of Mandelbrot Area too Small " +nl
return
ok
decimals(0)
zoom = ( 16 / (( maxI - minI) * (maxR - minR))) ### Smaller square = bigger magnify
lineEdit6.setText(""+zoom)
decimals(8)
###-------------------------------------------------------------------------
### Range: Imaginary-Vertical and Real-Horizontal. Limits are +-2
### minI = -2.0 maxI = 2.0 minR = -2.0 maxR = 2.0 # Default limits
### minI = -0.1 maxI = 0.1 minR = -1.9 maxR = -1.7
### minI = -0.03 maxI = 0.03 minR = -1.81 maxR = -1.74
### minI = -0.003 maxI = 0.003 minR = -1.7850 maxR = -1.7820
###----------------------------
### Draw Grid - Notches
daVinci.setpen(penUseW)
daVinci.drawLine(grid, grid, grid+width, grid) ### H
daVinci.drawLine(grid, grid, grid, grid+height) ### V
for i = 0 to width step (width / 100) ### Width 800
notch = 10
if i % (width / 10) = 0
notch = 20
incI = (maxI - minI) / height
incR = (maxR - minR) / width
rI = minI + ( incI * i)
rR = minR + ( incR * i)
daVinci.drawText(grid+i, grid-notch , (""+rR) ) ### H
daVinci.drawText(grid-notch-notch, grid+i , (""+rI) ) ### V
ok
daVinci.drawLine(grid+i, grid, grid+i, grid-notch) ### H
daVinci.drawLine(grid , grid+i, grid-notch, grid+i) ### V
next
decimals(12)
###----------------------------------------------------------
### CALCULATOR Draw X-Y Mandelbrot Points Values
### Imaginary-Vertical and Real-Horizontal. Limits are +-2
### minI = -2.0 maxI = 2.0 minR = -2.0 maxR = 2.0 # Default limits
SEE "Range: "+nl +"MinI:"+ minI +" MinR:"+ minR +nl +"MaxI:"+ maxI +" MaxR:"+ maxR +" W: "+width +" H: "+height +nl
aList = newlist(width, height) ### Save N value here for each Pixel
startCalcClock = clock()
if UseCcalculator = 1
mandel( minI,maxI,minR, maxR,iter,width,height,aList )
else
###---------------------------------------------------------
### RING CALCULATOR
stepR = (maxR - minR) / width ### step-Real-horizontal
stepI = (maxI - minI) / height ### step-Virtual-vertical
for y = 1 to height ### Each vertical point Ring at 1
pointI = minI + stepI * y ### Imaginary + Step
for x = 1 to width ### Each horizontal point Ring at 1
pointR = minR + stepR * x ### Real horizontal + Step
zR = pointR ### Depth - horizontal-real
zI = pointI ### Depth - vertical-imaginary
for n = 0 to iter ### Does it leave Orbit ?
a = zR * zR ### zR^2 - horizontal-real
b = zI * zI ### zI^2 - vertical-imaginary
if a + b > 4 exit ok ### Beyond boudary limts +-2
zI = 2 * zR * zI + pointI ### Vertical-imaginary + Step
zR = a - b + pointR ### Horizontal-real
next
aList[x][y] = N
next
next
ok
? "TimeCalc = " + ((clock()-startCalcClock)/clockspersecond()) + " seconds"
###--------------------------------------------------------
### Draw the aList[x][y] N-values that were calculated
### aList = newList(width,height)
### (1) DrawHSVFList( Ring List of points where each item is a sub list contains x,y,h,s,v,f )
### (2) DrawRGBFList( Ring List of points where each item is a sub list contains x,y,r,g,b,f )
### RGB Divide by 255 for daVinci.DrawRGBFList(FList)
aRGB = [ [255/255, 255/255, 255/255, 1],
[204/255, 000/255, 000/255, 1],
[000/255, 204/255, 000/255, 1],
[000/255, 000/255, 255/255, 1],
[128/255, 128/255, 128/255, 1],
[153/255, 076/255, 000/255, 1],
[255/255, 178/255, 159/255, 1],
[255/255, 128/255, 000/255, 1],
[255/255, 255/255, 000/255, 1],
[153/255, 153/255, 255/255, 1],
[255/255, 051/255, 255/255, 1],
[128/255, 255/255, 000/255, 1]
]
### HVS Divide by 360 for daVinci.DrawHVSFList(FList)
xaRGB = [[ 0, 0.00, 1.00, 1],
[ 0, 1.00, 0.80, 1],
[120/360, 1.00, 0.80, 1],
[240/360, 1.00, 1.00, 1],
[ 0, 0.00, 0.50, 1],
[ 30/360, 1.00, 0.60, 1],
[ 12/360, 0.37, 1.00, 1],
[ 30/360, 1.00, 1.00, 1],
[ 60/360, 1.00, 1.00, 1],
[240/360, 0.40, 1.00, 1],
[300/360, 0.80, 1.00, 1],
[ 90/360, 1.00, 1.00, 1]
]
startDrawClock = clock()
FList = []
nLastPenID = 0
for y = 1 to height // Vertical
for x = 1 to width // Horizontal
N = alist[x][y] // N number in the cell
if N > 0 and N < iter // Color
nPenID = N % 12 + 1
FList + [y+offset, x+offset, aRGB[nPenID][1], aRGB[nPenID][2], aRGB[nPenID][3], aRGB[nPenID][4] ]
ok
next
next
See "Finish FList y-x: "+ y +" "+ x +nl
daVinci.DrawRGBFList(FList) // RGB color array
//daVinci.DrawHSVFList(FList) // HVS color array
? "TimeDraw = " + ((clock()-startDrawClock)/clockspersecond()) + " seconds"
###--------------------------------------------------------
### Draw center lines
daVinci.drawLine(grid, grid+(height/2), grid+width, grid+(height/2)) ### H
daVinci.drawLine(grid+(width/2), grid, grid+(width/2), grid+height) ### V
See "FINISHED: "+ nl
win1.setwindowtitle("FINISHED - Use MOUSE to Select Area to Zoom In ")
DrawUpdate()
return
###===================================================
###===================================================
###===================================================
###--------------------------------------------------------------------
Func pPress
nX = myfilter.getx() -8 ### Screen co-ord, Canvas = myfilter.globalx()
ny = myfilter.gety() -8 -30 ### Screen co-ord, NOT Canvas
win1.setWindowTitle("Press: Top: "+ nX +"-"+ nY +" Bot:"+ fX +"-" +fY )
daVinci.setCompositionMode(26) ### THIS is the MAGIC - Erase Old Line when Redrawn
oX = nX ### Save Pressed Mouse point as OLD points
oY = nY
return
###------------------------------------------------------------------------
Func pMove
fX = myfilter.getx() -8 ### Screen co-ord, NOT Canvas
fY = myfilter.gety() -8 -30
xWidth = fX - nX
yHeight = fY - nY
fX = nX + yHeight ### make square. = height lenght
win1.setWindowTitle("Move: Top:"+ nX +"-"+ nY +" Bot: "+ fX +"-"+ fY +" Width:"+ (xWidth) +" Height:"+ (yHeight) )
pDrawObjects() ### Draw Mouse Square outline
DrawUpdate()
oX = fX ### Save OLD points
oY = fY
return
###------------------------------------------------------------------------
Func pRelease
fX = myfilter.getx() -8 ### Screen co-ord, NOT Canvas
fY = myfilter.gety() -8 -30
xWidth = fX - nX
yHeight = fY - nY
fX = nX + yHeight ### make square. = height length
win1.setWindowTitle("Release: Top: "+ nX +"-"+ nY +" Bot:"+ fX +"-"+ fY +" Width: "+ (xWidth) + " Height:"+ (yHeight) )
pDrawObjects()
DrawUpdate()
CalculateZoom()
return
###--------------------------------------------------------------------
###-----------------------------------------
### FUNCTION Where Are We - Window Resized
###----------------------------------------
Func WhereAreWe()
Rec = win1.framegeometry()
WinWidth = Rec.width() ### Current Values
WinHeight = Rec.height() ###
WinLeft = Rec.left() +8 ### <<< QT FIX because of Win Title
WinTop = Rec.top() +30 ### <<< QT FIX because of Win Title
WinRight = Rec.right()
WinBottom = Rec.bottom()
### win1{ setwindowtitle("Window ReSize: Width:"+ WinWidth +" Height:"+ WinHeight +
### " --- LT "+ WinLeft +"-"+ WinTop +" --- RB "+ WinRight +"-"+ WinBottom +
### " Width: "+ width +" Height: "+ height ) }
return
###---------------------------------------
### Window Moved
Func WhereMoved()
xPos = win1.x() +8 ### <<< QT FIX because of Win Title
yPos = win1.y() +30 ### <<< QT FIX because of Win Title
### win1{ setwindowtitle("Window Moved: HPos: " + xPos +" VPos: "+ yPos ) }
return
###-----------------------
### Draw the Mouse Square
Func pDrawObjects()
### Rectangle
oldLenX = oX - nX ### old - new position
oldLenY = oY - nY
newLenX = fX - nX ### final - new position
newLenY = fY - nY
daVinci.drawRect( nX, nY, oldLenX, oldLenY ) ### ReDraw OLD Line to Erase
daVinci.drawRect( nX, nY, newLenX, newLenY ) ### Draw NEW Line
return
###---------------------------
Func pClear()
daVinci.setCompositionMode(0) ### Put back to default mode 0
MonaLisa.fill(colorBlack) ### Clear painting canvas
daVinci.setCompositionMode(26) ### THIS is the MAGIC - Erase Old Line when Redrawn
DrawUpdate()
return
###-------------------------------------------------
### CalculateZoom - Portion of Mandelbrot to expand
### 378-223 to 515-358 areaW 138 areaH 135
### MandelW 800 MandelH 800
Func CalculateZoom()
nMinR = nX - offset ### 378 Horizontal
nMaxR = fX - offset ### 515
nMinI = nY - offset ### 223 Vertical
nMaxI = fY - offset ### 358
if nMaxI < nMinI ### nMinI smaller than nMaxI
nTemp = nMaxI
nMaxI = nMinI
nMinI = nTemp
ok
if nMaxR < nMinR ### nMinR smaller than nMaxR
nTemp = nMaxR
nMaxR = nMinR
nMinR = nTemp
ok
stepR = fabs(maxR - minR) / (width ) ### step-Real-horizontal
stepI = fabs(maxI - minI) / (height ) ### step-Virtual-vertical
newMinR = minR + (nMinR * stepR )
newMaxR = minR + (nMaxR * stepR )
newMinI = minI + (nMinI * stepI )
newMaxI = minI + (nMaxI * stepI )
See " newMinI:"+ newMinI +" newMinR:"+ newMinR +nl
See " newMaxI:"+ newMaxI +" newMaxR:"+ newMaxR +nl
See nl+nl
lineEdit1.setText(""+ newMinI) ### Put values in edit box on bottom of screen
lineEdit2.setText(""+ newMaxI)
lineEdit3.setText(""+ newMinR)
lineEdit4.setText(""+ newMaxR)
return
###-----------------------------------------