#!/usr/bin/env ruby require 'tk' class BinaryOp def initialize(left,right) @left = left @right = right end def compute end end class Addition < BinaryOp def compute target = Wave.new(nil,@left.points) (0...@left.points).each {|idx| target.data[idx] = @left.data[idx] + @right.data[idx] } target end end class Subtraction < BinaryOp def compute target = Wave.new(nil,@left.points) (0...@left.points).each {|idx| target.data[idx] = @left.data[idx] - @right.data[idx] } target end end class Multiplication < BinaryOp def compute target = Wave.new(nil,@left.points) (0...@left.points).each {|idx| target.data[idx] = @left.data[idx] * @right.data[idx] } target end end class Wave include Enumerable attr_accessor :data , :points def initialize(formula,points = 300) @data = [] points.times {|i| @data << 0.0} @points = points if(formula) (0..points-1).each do |p| x = p*Math::PI*2.0/points @data[p] = eval(formula) end end end def to_s @data.each {|d| print d} end def +(other) x = Addition.new(self,other) x.compute end def *(other) target = Wave.new(nil,@points) if (other.class == 5.class || other.class == 5.0.class) target.data.each_index {|i| target.data[i] = @data[i] * other} target else x = Multiplication.new(self,other) x.compute end end def each @data.each {|pt| yield pt} end def -(other) x = Subtraction.new(self,other) x.compute end def integral ans = 0.0 @data.each {|pt| ans += pt} ans*2.0*Math::PI/@points end def plot(_title="??",pixHeight=200,maxY=1.5,others=[]) pixHeight = @points*(2.0/3.0) if pixHeight pixWidth = @points maxY = [(@data.max),-(@data.min)].max if !maxY offset = pixHeight/2.0 scale = offset/maxY win = TkRoot.new {title _title} canvas = TkCanvas.new("width"=>pixWidth,"height"=>pixHeight) #create zero line TkcLine.new(canvas,0,offset,pixWidth,offset) canvas.pack() self.plotOne(canvas,pixWidth,scale,offset) others.each {|i| i.plotOne(canvas,pixWidth,scale,offset)} Tk.mainloop end def plotOne(canvas,pixWidth,scale,offset) (0..pixWidth-1).each do |x| y1 = offset - @data[x] * scale if x != (pixWidth-1) y = offset - @data[x+1] * scale else y = y1 end TkcLine.new(canvas,x,y1,(x+1),y) if (x && x!=pixWidth-1) end end end if __FILE__ == $0 a = Wave.new("Math.sin(4*x)",400) b = Wave.new("(Math.sin(3*x))/3.0",400) c = Wave.new("(Math.sin(5*x))/5.0",400) d = Wave.new("(Math.sin(7*x))/7.0",400) e = Wave.new("(Math.sin(9*x))/9.0",400) f = Wave.new("(Math.sin(11*x))/11.0",400) g = Wave.new("(Math.sin(13*x))/13.0",400) h = Wave.new("(Math.sin(15*x))/15.0",400) i = Wave.new("(Math.sin(17*x))/17.0",400) j = Wave.new("(Math.sin(19*x))/19.0",400) k = Wave.new("(Math.sin(21*x))/21.0",400) l = Wave.new("(Math.sin(23*x))/23.0",400) m = Wave.new("(Math.sin(25*x))/25.0",400) res= a-c+e*f-g*h-i+j*k*l-m res.each {|x| puts x} res.plot("sin(4x)") end