Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env ruby
- require 'tk'
- require 'matrix'
- # need for correct math operations
- require 'mathn'
- # $lastX = 0
- # $lastY = 0
- # adding support for 3D conversion
- class Point
- # attr_reader :x, :y, :z
- attr_accessor :x, :y, :z
- def initialize(x,y,z)
- @x, @y, @z = x, y, z
- @matr = Matrix[[@x, @y, @z, 1]]
- end
- def to_s
- # "x: #{@x}\ny: #{y}\nz: #{z}"
- "(#{@x}, #{@y}, #{z})"
- end
- # transfer to a distance
- def moveTo(a,b,c)
- operMatrix = Matrix[
- [1, 0, 0, 0],
- [0, 1, 0, 0],
- [0, 0, 1, 0],
- [a, b, c, 1]
- ]
- @matr *= operMatrix
- # show 3 ways to get data from matrix by given indexeses
- # @TODO: maybe need to call _parseMatr
- @x = @matr.element(0,0)
- @y = @matr[0,1]
- @z = @matr.component(0,2)
- # returning value, actually needs?
- @matr
- end
- def rotateZ phi
- phi = phi * Math::PI / 180
- operMatrix = Matrix[
- [Math.cos(phi), Math.sin(phi), 0, 0],
- [-Math.sin(phi), Math.cos(phi), 0, 0],
- [0, 0, 1, 0],
- [0, 0, 0, 1]
- ]
- @matr *= operMatrix
- _parseMatr
- @matr
- end
- def rotateX phi
- phi = phi * Math::PI / 180
- operMatrix = Matrix[
- [1, 0, 0, 0],
- [0, Math.cos(phi), Math.sin(phi), 0],
- [0, -Math.sin(phi), Math.cos(phi), 0],
- [0, 0, 0, 1]
- ]
- @matr *= operMatrix
- _parseMatr
- @matr
- end
- def rotateY phi
- phi = phi * Math::PI / 180
- operMatrix = Matrix[
- [Math.cos(phi), 0, -Math.sin(phi), 0],
- [0, 1, 0, 0],
- [Math.sin(phi), 0, Math.cos(phi), 0],
- [0, 0, 0, 1]
- ]
- @matr *= operMatrix
- _parseMatr
- @matr
- end
- def scale(x,y,z)
- operMatrix = Matrix[
- [x, 0, 0, 0],
- [0, y, 0, 0],
- [0, 0, z, 0],
- [0, 0, 0, 1]
- ]
- @matr *= operMatrix
- _parseMatr
- @matr
- end
- # next methods are private declared
- private
- def _parseMatr
- @x = @matr[0,0]
- @y = @matr[0,1]
- @z = @matr[0,2]
- end
- private :_parseMatr
- end
- $cylinder = []
- def $cylinder.generate_skeleton faces, face_lenght, height
- if faces > 1
- # code
- perimetr = face_lenght*faces
- radius = perimetr/(2*Math::PI)
- center = 0
- # phi is degre of start point
- phi = 0
- # round value
- rnd = 3
- # add 1 to faces need to close circuit
- (faces+1).times do |i|
- if i != faces+1
- x = (center + radius*Math::cos(phi+(2*Math::PI*i)/faces)).round(rnd)
- y = (center + radius*Math::sin(phi+(2*Math::PI*i)/faces)).round(rnd)
- # generating next points, to be an array of [Point, Point] and simple drawing
- xn = (center + radius*Math::cos(phi+(2*Math::PI*(i+1))/faces)).round(rnd)
- yn = (center + radius*Math::sin(phi+(2*Math::PI*(i+1))/faces)).round(rnd)
- # pushing into array an array of 2 point to simple draw
- push [Point.new(x, y, 0), Point.new(xn, yn, 0)]
- end
- end
- # pushing higher face of cylinder
- # size.times{ |i|
- # push [Point.new(self[i][0].x, self[i][0].y, height), Point.new(self[i][1].x, self[i][1].y, height)]
- # # print self[i]
- # }
- # adding vertical vertex's
- # offset = size/2
- size.times{ |i|
- push [Point.new(self[i][0].x, self[i][0].y, 0), Point.new(0, 0, height)]
- }
- push [Point.new(0,0,0), Point.new(500,0,0)]
- push [Point.new(0,0,0), Point.new(0,500,0)]
- push [Point.new(0,0,0), Point.new(0,0,500)]
- else
- raise ArgumentError, "Number of faces must be more or = then 2"
- end
- end
- def $cylinder.each_point
- each { |i| yield i[0]; yield i[1]}
- end
- def $cylinder.draw
- $canvas.delete("all")
- of = 0
- # puts self
- for i in 0..length-1
- TkcLine.new($canvas, of+self[i][0].x, of+self[i][0].y, of+self[i][1].x, of+self[i][1].y, 'tags' => 'Line')
- end
- # TkcLine.new($canvas, of+self[-1].x, of+self[-1].y, of+self[0].x, of+self[0].y, 'tags' => 'Line')
- end
- $width = 640
- $height = 480
- def _resize()
- $cylinder.each_point {|i| i.moveTo(-$width/2, -$height/2, 0)}
- # use this to get geometry of main widget
- $width = $root.winfo_width()
- $height = $root.winfo_height()
- $canvas.width $width
- $canvas.height $height
- $cylinder.each_point {|i| i.moveTo($width/2, $height/2, 0)}
- $cylinder.draw
- end
- # initializing main window
- $root = TkRoot.new do
- title "Machine Graphics. lab3"
- geometry("#{$width}x#{$height}-0+20")
- end
- $canvas = TkCanvas.new do
- bg "gray"
- width "#{$width}"
- height "#{$height}"
- bind('Configure', proc { _resize } )
- pack
- end
- $canvas.bind("ButtonPress-1", proc{|x,y| $lastX, $lastY = x, y}, "%x %y") {
- puts "Press"
- $stdout.flush
- }
- $canvas.bind("ButtonRelease-1") {
- }
- $canvas.bind("B1-Motion", proc{|x,y| rotation(x,y)}, "%x %y")
- def rotation (x, y)
- $cylinder.each_point {|i| i.moveTo(-$width/2, -$height/2, 0)}
- dx, dy = x-$lastX, $lastY-y
- dx /= 1.0
- dy /= 1.0
- $cylinder.each_point {|i| i.rotateX dy}
- $cylinder.each_point {|i| i.rotateY dx}
- $cylinder.each_point {|i| i.moveTo($width/2, $height/2, 0)}
- $cylinder.draw
- $lastX, $lastY = x, y
- end
- $cylinder.generate_skeleton(8,90,220)
- $cylinder.each_point {|i| i.moveTo($width/2, $height/2, 0)}
- # $cylinder.each_point {|i| i.rotateX 4 70}
- # $cylinder.each_point {|i| i.rotateY 10}
- # $cylinder.each_point {|i| i.moveTo(200, 150, 0) }
- $cylinder.draw()
- # print $cylinder, "\n"
- # need to output all need's data, because in Tk loop nothing will output
- $stdout.flush
- $root.mainloop
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement