Domain Coloring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
require 'fox16'
require 'cmath'

module Fox
  FRFT=FRAME_RAISED|FRAME_THICK
  XY=LAYOUT_FIX_X|LAYOUT_FIX_Y
  WH=LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT
end

include Fox
include CMath

class Window <FXMainWindow
	
  def initialize(anApp)
    super(anApp, 'Complex Plot', :opts => DECOR_ALL, :width => 850, :height => 650)
		@buffer=FXBMPImage.new(anApp, nil, :opts => IMAGE_KEEP, :width => 800, :height => 600)
    @buffer.create
    FXDCWindow.new(@buffer) { |dc|
      dc.foreground=0x000000
      dc.fillRectangle(0, 0, 500, 500)
    }
    @canvas=FXCanvas.new(self, :opts => XY|WH, :width => 800, :height => 600, :x => 25, :y => 25)
    @canvas.connect(SEL_PAINT){
      FXDCWindow.new(@canvas) { |dc|
        dc.drawImage(@buffer, 0, 0)
      }
    }
		@canvas.connect(SEL_MOTION) {|sel, sen, e|
			@coord.text="(#{e.win_x},#{e.win_y}) => #{pixToComplex(e.win_x,e.win_y,-2*PI,2*PI,-1.5*PI,1.5*PI,800.0,600.0)}"
		}
		@coord=FXLabel.new(self, '(0,0)', :opts => LAYOUT_FIX_X|LAYOUT_FIX_Y, :x => 25, :y => 3)
		drawDomainColors
		
		#INTERFACE
		FXButton.new(self, "Save Domain Plot", :opts => XY|WH|BUTTON_NORMAL, :x => 350, :y => 3, :width => 100, :height => 20) { |bt|
      bt.connect(SEL_COMMAND) {
          FXFileStream.open("plot.bmp", FXStreamSave) {|outfile|
            @buffer.restore
            @buffer.savePixels(outfile)
          }
      }
    }
		
  end
	
	def f(z)
		#log(z**2/(z**2+1))
		#cos(z)/sin(z**4.0-1.0)
		#sin(z**2-1)/(sin(3*z)+cos(2*z))
		#(z**2-1)*(z-Complex(2.0,1.0))**2/(z**2+Complex(2.0,2.0)) Thanks wiki
		#sin(z)/log(z)
		exp(exp(z**2)/cos(2*z))
	end
	
	def drawDomainColors
		Thread.new {
			color=0
			for x in 0..799
				for y in 0..599
					begin
						zArg = pixToComplex(x,y,-3*PI/8,3*PI/8,-9*PI/32,9*PI/32,800.0,600.0)
						zRes = f(zArg)
						#___________________OLD WAY!____________________________
						#val=zRes.magnitude/144.0
						#val=1 if val>1
						#sat=1-val
						#color = HSVtoRGB(zRes.angle*180.0/PI,1.0-val,val**0.125) #/n is arbitrary--scale mag so it is < 1
						#___________________NEW WAY!____________________________
						hue=zRes.angle*180/PI%360
						r=log(1+zRes.magnitude)
						sat = (1+sin(2*PI*r))*0.25+0.5 #Default /2 + 0
						val = (1+cos(2*PI*r))*0.25+0.5 # Default is /2 +0 not whatever is here
						color=HSVtoRGB(hue,sat,val)
					rescue
					end
					FXDCWindow.new(@buffer) { |dc|
						dc.foreground = color
						dc.drawPoint(x, y)
					}
				end
				@canvas.update
			end
		}
	end
	
	def HSVtoRGB(h, s, v)
		h = h%360.0
		c = v*s
		hp = h/60.0
		x = c*(1.0-(hp%2.0-1.0).abs)
		if 0<=hp and hp<1
			r,g,b=c,x,0.0
		elsif 1<=hp and hp<2
			r,g,b=x,c,0.0
		elsif 2<=hp and hp<3
			r,g,b=0.0,c,x
		elsif 3<=hp and hp<4
			r,g,b=0.0,x,c
		elsif 4<=hp and hp<5
			r,g,b=x,0.0,c
		elsif 5<=hp and hp<=6
			r,g,b=c,0.0,x
		else
			r,g,b=0.0,0.0,0.0
		end
		m=v-c
		r+=m
		g+=m
		b+=m
		return FXRGB((255*r).to_i,(255*g).to_i,(255*b).to_i)
	end
	
	def pixToComplex(x,y,amin,amax,bmin,bmax,width,height)
		Complex(x*(amax-amin)/width+amin, y*(bmin-bmax)/height+bmax)
	end
	
  def create
    super
    show(PLACEMENT_SCREEN)
  end
	
end

if __FILE__==$0
  FXApp.new('win', 'FXRuby') do |theApp|
    Window.new(theApp)
    theApp.create
    theApp.run
  end
end