Давид обнови решението на 22.12.2013 22:37 (преди почти 11 години)
+module Graphics
+ START_HTML="<!DOCTYPE html>
+ <html>
+ <head>
+ <title>Rendered Canvas</title>
+ <style type='text/css'>
+ .canvas {
+ font-size: 1px;
+ line-height: 1px;
+ }
+ .canvas * {
+ display: inline-block;
+ width: 10px;
+ height: 10px;
+ border-radius: 5px;
+ }
+ .canvas i {
+ background-color: #eee;
+ }
+ .canvas b {
+ background-color: #333;
+ }
+ </style>
+ </head>
+ <body>
+ <div class='canvas'>"
+
+ END_HTML="</div>
+ </body>
+ </html>"
+
+ class Canvas
+ attr_reader :width,:height, :matrix
+
+ def initialize(width,height)
+ @width=width
+ @height=height
+ @matrix=Array.new(@height) {Array.new(@width,0)}
+ end
+
+ def set_pixel(x,y)
+ @matrix[y][x]=1
+ end
+
+ def pixel_at?(x,y)
+ @matrix[y][x]==1
+ end
+
+ def draw(figure)
+ if figure.instance_of? Point
+ @matrix[figure.y][figure.x]=1
+ elsif figure.instance_of? Rectangle
+ draw_rectangle(figure)
+ else
+ draw_line(figure.from,figure.to)
+ end
+ end
+
+ def draw_rectangle(figure)
+ draw_line(figure.top_left,figure.top_right)
+ draw_line(figure.bottom_left,figure.bottom_right)
+ draw_line(figure.top_left,figure.bottom_left)
+ draw_line(figure.top_right,figure.bottom_right)
+ end
+
+ def draw_horizontal_line(from,to)
+ 0.upto(width).each { |i| @matrix[from.y][i]=1 if i>=from.x and i<=to.x }
+ end
+
+ def draw_vertical_line(from,to)
+ 0.upto(height).each { |i| @matrix[i][from.x]=1 if i>=from.y and i<=to.y}
+ end
+
+ def draw_line(from,to)
+ if from.y==to.y
+ draw_horizontal_line(from,to)
+ elsif from.x==to.x
+ draw_vertical_line(from,to)
+ else
+ bresenham(from.x,from.y,to.x,to.y)
+ end
+ end
+
+ #ne raboti kat horata
+ def bresenham(x_1,y_1,x_2,y_2)
+ x_1, y_1 ,x_2, y_2= y_1, x_1,y_2, x_2 if steep=(y_2 - y_1).abs > (x_2 - x_1).abs
+ deltax,deltay,error,y = x_2 - x_1,y_2 - y_1,((x_2-x_1) / 2).to_f,y_1
+ x_1.upto(x_2) do |a|
+ steep ? @matrix[a][y]=1 : @matrix[y][a]=1
+ error -= deltay
+ if error < 0 then y,error =y+1,error+deltax end
+ end
+ end
+
+ def render_as(renderer)
+ if renderer.to_s.match(/Ascii/)
+ render_as_ascii
+ else
+ render_as_html
+ end
+ end
+
+ def render_as_html
+ chars, max={0 => "<i></i>",1 => "<b></b>"},height-1
+ html_string=@matrix.each_with_index.map do |row,i|
+ row.map {|e| chars[e]}.push("<br>").join
+ end.join
+ START_HTML+html_string+END_HTML
+ end
+
+ def render_as_ascii
+ char_hash={0 => "-",1 => "@"}
+ @matrix.map {|row| row.map {|e| char_hash[e]}.push("\n").join}.join.chomp
+ end
+ end
+
+ module Renderers
+ class Ascii
+ end
+
+ class Html
+ end
+ end
+
+ class Point
+ attr_reader :x,:y
+ def initialize(x,y)
+ @x=x
+ @y=y
+ end
+
+ def ==(other)
+ x==other.x and y==other.y
+ end
+
+ def eql?(other)
+ x.eql? other.x and y.eql? other.y
+ end
+
+ def hash
+ [x,y].hash
+ end
+ end
+
+
+ class Line
+ attr_reader :from,:to
+ def initialize(from,to)
+ if from.x==to.x
+ @from=from.y<to.y ? from : to
+ @to= @from==from ? to : from
+ else
+ @from=from.x<to.x ? from : to
+ @to= @from==from ? to : from
+ end
+ end
+
+ def ==(other)
+ from==other.from and to==other.to
+ end
+
+ def eql?(other)
+ from.eql? other.from and to.eql? other.to
+ end
+
+ def hash
+ [from,to].hash
+ end
+
+ end
+
+ class Rectangle
+ attr_reader :left,:right
+ def initialize(left,right)
+ if left.x==right.x
+ @left=left.y<right.y ? left : right
+ @right= @left==left ? right : left
+ else
+ @left=left.x<right.x ? left : right
+ @right= @left==left ? right : left
+ end
+ end
+
+ def top_left
+ Point.new([left.x,right.x].min,[left.y,right.y].min)
+ end
+
+ def top_right
+ Point.new(bottom_right.x,top_left.y)
+ end
+
+ def bottom_left
+ Point.new(top_left.x,bottom_right.y)
+ end
+
+ def bottom_right
+ Point.new([left.x,right.x].max,[left.y,right.y].max)
+ end
+
+
+ def ==(other)
+ top_left==other.top_left and bottom_right==other.bottom_right
+ end
+
+ def eql?(other)
+ top_left.eql? other.top_left and bottom_right.eql? other.bottom_right
+ end
+
+ def hash
+ [top_left,bottom_right].hash
+ end
+
+ end
+end