| 赞 | 15  | 
 
| VIP | 0 | 
 
| 好人卡 | 0 | 
 
| 积分 | 19 | 
 
| 经验 | 16801 | 
 
| 最后登录 | 2024-7-10 | 
 
| 在线时间 | 403 小时 | 
 
 
 
 
 
Lv3.寻梦者 
	- 梦石
 - 0 
 
        - 星屑
 - 1939 
 
        - 在线时间
 - 403 小时
 
        - 注册时间
 - 2015-8-30
 
        - 帖子
 - 395
 
 
 
 | 
	
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员  
 
x
 
 本帖最后由 有丘直方 于 2018-12-2 20:29 编辑  
 
class Vector     include(Enumerable)     attr_accessor :x   attr_accessor :y     def initialize(*args)     case args.size     when 0       @x = 0       @y = 0     when 1       @x = args[0]       @y = args[0]     when 2       @x = args[0]       @y = args[1]     end   end     def +@     self   end     def -@     Vector.new(-@x, -@y)   end     def +(other)     Vector.new(@x + other.x, @y + other.y)   end     def -(other)     self + -other   end     def *(other)     case other     when Numeric       Vector.new(@x * other, @y * other)     when Vector       @x * other.x + @y * other.y     end   end     def dot(other)     self * other   end     def cross(other)     self.x * other.y - other.x * self.y   end     def slope     y / x   end     def square_length     self * self   end     def length     Math.sqrt(square_length)   end     def is_out_of?(other)     @x.abs > other.x.abs || @y.abs > other.y.abs   end     def abs     Vector.new(@x.abs, @y.abs)   end     def each     yield @x     yield @y   end end   module Math     def self.definite_proportion(point1, point2, proportion)     point1 * (1 - proportion) + point2 * proportion   end end   class Rect     alias ulysses201811181949_initialize initialize   def initialize(*args)     args = case args.size     when 0, 4       args     when 2       [args[0].x, args[0].y, args[1].x, args[1].y]     end     ulysses201811181949_initialize(*args)   end     def position     Vector.new(x, y)   end     def position=(position)     self.x = position.x     self.y = position.y   end     def size     Vector.new(width, height)   end     def size=(size)     self.width = size.x     self.height = size.y   end end   module Kernel     def do_by_step(from, to, step)     if block_given?       i = from       until i >= to         yield i         i += step       end     else       to_enum(__method__, from, to, step)     end   end end   class Bitmap     alias ulysses201811181708_initialize initialize   def initialize(*args)     args = if args.size == 2 || args[0].is_a?(String)       args     elsif args.size == 1       [args[0].x, args[0].y]     else       [0, 0]     end     ulysses201811181708_initialize(*args)   end     def fill_circle(center, radius, color)     i_max = (radius * 707) / 1000 + 1     square_distance_max = radius * radius + radius / 2     x = radius     fill_rect(center.x - radius, center.y, 2 * radius, 1, color)     for i in 1..i_max       if Vector.new(center.x, i).square_length > square_distance_max         if x > i_max           fill_rect(center.x - i + 1, center.y + x, 2 * (i - 1), 1, color)           fill_rect(center.x - i + 1, center.y - x, 2 * (i - 1), 1, color)         end         x -= 1       end       fill_rect(center.x - x, center.y + i, 2 * x, 1, color)       fill_rect(center.x - x, center.y - i, 2 * x, 1, color)     end   end     def draw_line(point1, point2, color)     difference = point2 - point1     abs_difference = difference.abs     total_step = abs_difference.max     delta = difference * (1.0 / total_step)     vector = point1     (total_step - 1).to_i.times do       set_pixel(vector, color)       vector += delta     end   end     alias ulysses201811182036_set_pixel set_pixel   def set_pixel(*args)     args = case args.size     when 3       args     when 2       [args[0].x, args[0].y, args[1]]     end     ulysses201811182036_set_pixel(*args)   end     def text_vector(text)     text_size(text).size   end     def size     Vector.new(width, height)   end     def size=(size)     self.rect.size = size   end     alias ulysses201811181952_draw_text draw_text   def draw_text(*args)     args = case args[0]     when Numeric, Rect       args     when Vector       a = [args[0].x, args[0].y, args[1].x, args[1].y, args[2]]       a.push(args[3]) if args.size >= 4       a     end     ulysses201811181952_draw_text(*args)   end end   class Sprite     alias ulysses201811181903_initialize initialize   def initialize(viewport = nil)     ulysses201811181903_initialize(viewport)     self.bitmap = Bitmap.new   end     def position=(position)     self.x = position.x     self.y = position.y   end end   module Graphics     def self.size     Vector.new(width, height)   end end   module Mouse     def self.position     Vector.new(x, y)   end end   module Scene     POINT_RADIUS = 3   POINT_COLOR = Color.new(255, 255, 255, 255)   POINT_Z = 10   CURVE_RADIUS = 2   CURVE_COLOR = Color.new(255, 255, 255, 255)   LINE_COLOR = Color.new(255, 255, 255, 255)   T_BEGINNING = 0.0   T_END = 1.0   T_STEP = 0.001   UPDATE_STEPS = 20     def self.init     Graphics.resize_screen(1024, 768)     @graph_sprite = Sprite.new     @graph_sprite.bitmap = Bitmap.new(Graphics.size)     @line_sprite = Sprite.new     @line_sprite.bitmap = Bitmap.new(Graphics.size)     @points = []     @point_sprites = []     @temp_bitmap = Bitmap.new(32, 32)     @line_visible = true     @point_visible = true     @fast_mode = false     @covering_drawing = 0   end     def self.create_point(point)     sprite = Sprite.new     sprite.visible = @point_visible     radius_vector = Vector.new(POINT_RADIUS)     text_vector = @temp_bitmap.text_vector(@points.size)     radius_text_vector = radius_vector + text_vector     sprite.bitmap = Bitmap.new(radius_text_vector + radius_vector)     flip = (point + radius_text_vector).is_out_of?(Graphics.size)     excursion = flip ? radius_text_vector : radius_vector     sprite.position = point - excursion     sprite.bitmap.fill_circle(excursion, POINT_RADIUS, POINT_COLOR)     text_position = flip ? Vector.new : radius_vector * 2     sprite.bitmap.draw_text(text_position, text_vector, @points.size)     sprite.z = POINT_Z     @points.push(point)     @point_sprites.push(sprite)     refresh_graph   end     def self.delete_point     @points.pop     @point_sprites.pop.dispose     refresh_graph   end     def self.refresh_graph     @covering_drawing += 1     @graph_sprite.bitmap.clear     return if @points.empty?     step_count = 0     will_update = false     do_by_step(T_BEGINNING, T_END, T_STEP) do |t|       will_update = true if !@fast_mode && (step_count += 1) >= UPDATE_STEPS       @line_sprite.bitmap.clear       sequences = [@points]       (@points.size - 1).times do |i|         last_sequence = sequences.last         sequences.push([])         (last_sequence.size - 1).times do |j|           if @line_visible && will_update             @line_sprite.bitmap.draw_line(*last_sequence[j, 2], LINE_COLOR)           end           sequences.last.push(Math.definite_proportion(*last_sequence[j, 2], t))         end       end       @graph_sprite.bitmap.fill_circle(*sequences.last, CURVE_RADIUS, CURVE_COLOR)       if will_update         step_count = 0         will_update = false         last_covering_drawing = @covering_drawing         update         return if @covering_drawing > last_covering_drawing       end     end     (@points.size - 1).times do |i|       @line_sprite.bitmap.draw_line(*@points[i, 2], LINE_COLOR)     end   end     def self.toggle_line_visible     @line_visible = !@line_visible     @line_sprite.visible = @line_visible   end     def self.toggle_point_visible     @point_visible = !@point_visible     @point_sprites.each {|sprite| sprite.visible = @point_visible }   end     def self.toggle_fast_mode     @fast_mode = !@fast_mode   end     def self.update_basic     Graphics.update     Input.update     Mouse.update   end     def self.update     update_basic     if Mouse.click?(:L)       create_point(Mouse.position)     elsif Mouse.click?(:R)       delete_point     elsif Input.trigger?(:A)       toggle_fast_mode     elsif Input.trigger?(:B)       toggle_line_visible     elsif Input.trigger?(:C)       toggle_point_visible     end   end   def self.main     init     loop { update }   end end   Scene.main 
 
 class Vector  
   
  include(Enumerable)  
   
  attr_accessor :x  
  attr_accessor :y  
   
  def initialize(*args)  
    case args.size  
    when 0  
      @x = 0  
      @y = 0  
    when 1  
      @x = args[0]  
      @y = args[0]  
    when 2  
      @x = args[0]  
      @y = args[1]  
    end  
  end  
   
  def +@  
    self  
  end  
   
  def -@  
    Vector.new(-@x, -@y)  
  end  
   
  def +(other)  
    Vector.new(@x + other.x, @y + other.y)  
  end  
   
  def -(other)  
    self + -other  
  end  
   
  def *(other)  
    case other  
    when Numeric  
      Vector.new(@x * other, @y * other)  
    when Vector  
      @x * other.x + @y * other.y  
    end  
  end  
   
  def dot(other)  
    self * other  
  end  
   
  def cross(other)  
    self.x * other.y - other.x * self.y  
  end  
   
  def slope  
    y / x  
  end  
   
  def square_length  
    self * self  
  end  
   
  def length  
    Math.sqrt(square_length)  
  end  
   
  def is_out_of?(other)  
    @x.abs > other.x.abs || @y.abs > other.y.abs  
  end  
   
  def abs  
    Vector.new(@x.abs, @y.abs)  
  end  
   
  def each  
    yield @x  
    yield @y  
  end  
end  
   
module Math  
   
  def self.definite_proportion(point1, point2, proportion)  
    point1 * (1 - proportion) + point2 * proportion  
  end  
end  
   
class Rect  
   
  alias ulysses201811181949_initialize initialize  
  def initialize(*args)  
    args = case args.size  
    when 0, 4  
      args  
    when 2  
      [args[0].x, args[0].y, args[1].x, args[1].y]  
    end  
    ulysses201811181949_initialize(*args)  
  end  
   
  def position  
    Vector.new(x, y)  
  end  
   
  def position=(position)  
    self.x = position.x  
    self.y = position.y  
  end  
   
  def size  
    Vector.new(width, height)  
  end  
   
  def size=(size)  
    self.width = size.x  
    self.height = size.y  
  end  
end  
   
module Kernel  
   
  def do_by_step(from, to, step)  
    if block_given?  
      i = from  
      until i >= to  
        yield i  
        i += step  
      end  
    else  
      to_enum(__method__, from, to, step)  
    end  
  end  
end  
   
class Bitmap  
   
  alias ulysses201811181708_initialize initialize  
  def initialize(*args)  
    args = if args.size == 2 || args[0].is_a?(String)  
      args  
    elsif args.size == 1  
      [args[0].x, args[0].y]  
    else  
      [0, 0]  
    end  
    ulysses201811181708_initialize(*args)  
  end  
   
  def fill_circle(center, radius, color)  
    i_max = (radius * 707) / 1000 + 1  
    square_distance_max = radius * radius + radius / 2  
    x = radius  
    fill_rect(center.x - radius, center.y, 2 * radius, 1, color)  
    for i in 1..i_max  
      if Vector.new(center.x, i).square_length > square_distance_max  
        if x > i_max  
          fill_rect(center.x - i + 1, center.y + x, 2 * (i - 1), 1, color)  
          fill_rect(center.x - i + 1, center.y - x, 2 * (i - 1), 1, color)  
        end  
        x -= 1  
      end  
      fill_rect(center.x - x, center.y + i, 2 * x, 1, color)  
      fill_rect(center.x - x, center.y - i, 2 * x, 1, color)  
    end  
  end  
   
  def draw_line(point1, point2, color)  
    difference = point2 - point1  
    abs_difference = difference.abs  
    total_step = abs_difference.max  
    delta = difference * (1.0 / total_step)  
    vector = point1  
    (total_step - 1).to_i.times do  
      set_pixel(vector, color)  
      vector += delta  
    end  
  end  
   
  alias ulysses201811182036_set_pixel set_pixel  
  def set_pixel(*args)  
    args = case args.size  
    when 3  
      args  
    when 2  
      [args[0].x, args[0].y, args[1]]  
    end  
    ulysses201811182036_set_pixel(*args)  
  end  
   
  def text_vector(text)  
    text_size(text).size  
  end  
   
  def size  
    Vector.new(width, height)  
  end  
   
  def size=(size)  
    self.rect.size = size  
  end  
   
  alias ulysses201811181952_draw_text draw_text  
  def draw_text(*args)  
    args = case args[0]  
    when Numeric, Rect  
      args  
    when Vector  
      a = [args[0].x, args[0].y, args[1].x, args[1].y, args[2]]  
      a.push(args[3]) if args.size >= 4  
      a  
    end  
    ulysses201811181952_draw_text(*args)  
  end  
end  
   
class Sprite  
   
  alias ulysses201811181903_initialize initialize  
  def initialize(viewport = nil)  
    ulysses201811181903_initialize(viewport)  
    self.bitmap = Bitmap.new  
  end  
   
  def position=(position)  
    self.x = position.x  
    self.y = position.y  
  end  
end  
   
module Graphics  
   
  def self.size  
    Vector.new(width, height)  
  end  
end  
   
module Mouse  
   
  def self.position  
    Vector.new(x, y)  
  end  
end  
   
module Scene  
   
  POINT_RADIUS = 3  
  POINT_COLOR = Color.new(255, 255, 255, 255)  
  POINT_Z = 10  
  CURVE_RADIUS = 2  
  CURVE_COLOR = Color.new(255, 255, 255, 255)  
  LINE_COLOR = Color.new(255, 255, 255, 255)  
  T_BEGINNING = 0.0  
  T_END = 1.0  
  T_STEP = 0.001  
  UPDATE_STEPS = 20  
   
  def self.init  
    Graphics.resize_screen(1024, 768)  
    @graph_sprite = Sprite.new  
    @graph_sprite.bitmap = Bitmap.new(Graphics.size)  
    @line_sprite = Sprite.new  
    @line_sprite.bitmap = Bitmap.new(Graphics.size)  
    @points = []  
    @point_sprites = []  
    @temp_bitmap = Bitmap.new(32, 32)  
    @line_visible = true  
    @point_visible = true  
    @fast_mode = false  
    @covering_drawing = 0  
  end  
   
  def self.create_point(point)  
    sprite = Sprite.new  
    sprite.visible = @point_visible  
    radius_vector = Vector.new(POINT_RADIUS)  
    text_vector = @temp_bitmap.text_vector(@points.size)  
    radius_text_vector = radius_vector + text_vector  
    sprite.bitmap = Bitmap.new(radius_text_vector + radius_vector)  
    flip = (point + radius_text_vector).is_out_of?(Graphics.size)  
    excursion = flip ? radius_text_vector : radius_vector  
    sprite.position = point - excursion  
    sprite.bitmap.fill_circle(excursion, POINT_RADIUS, POINT_COLOR)  
    text_position = flip ? Vector.new : radius_vector * 2  
    sprite.bitmap.draw_text(text_position, text_vector, @points.size)  
    sprite.z = POINT_Z  
    @points.push(point)  
    @point_sprites.push(sprite)  
    refresh_graph  
  end  
   
  def self.delete_point  
    @points.pop  
    @point_sprites.pop.dispose  
    refresh_graph  
  end  
   
  def self.refresh_graph  
    @covering_drawing += 1  
    @graph_sprite.bitmap.clear  
    return if @points.empty?  
    step_count = 0  
    will_update = false  
    do_by_step(T_BEGINNING, T_END, T_STEP) do |t|  
      will_update = true if !@fast_mode && (step_count += 1) >= UPDATE_STEPS  
      @line_sprite.bitmap.clear  
      sequences = [@points]  
      (@points.size - 1).times do |i|  
        last_sequence = sequences.last  
        sequences.push([])  
        (last_sequence.size - 1).times do |j|  
          if @line_visible && will_update  
            @line_sprite.bitmap.draw_line(*last_sequence[j, 2], LINE_COLOR)  
          end  
          sequences.last.push(Math.definite_proportion(*last_sequence[j, 2], t))  
        end  
      end  
      @graph_sprite.bitmap.fill_circle(*sequences.last, CURVE_RADIUS, CURVE_COLOR)  
      if will_update  
        step_count = 0  
        will_update = false  
        last_covering_drawing = @covering_drawing  
        update  
        return if @covering_drawing > last_covering_drawing  
      end  
    end  
    (@points.size - 1).times do |i|  
      @line_sprite.bitmap.draw_line(*@points[i, 2], LINE_COLOR)  
    end  
  end  
   
  def self.toggle_line_visible  
    @line_visible = !@line_visible  
    @line_sprite.visible = @line_visible  
  end  
   
  def self.toggle_point_visible  
    @point_visible = !@point_visible  
    @point_sprites.each {|sprite| sprite.visible = @point_visible }  
  end  
   
  def self.toggle_fast_mode  
    @fast_mode = !@fast_mode  
  end  
   
  def self.update_basic  
    Graphics.update  
    Input.update  
    Mouse.update  
  end  
   
  def self.update  
    update_basic  
    if Mouse.click?(:L)  
      create_point(Mouse.position)  
    elsif Mouse.click?(:R)  
      delete_point  
    elsif Input.trigger?(:A)  
      toggle_fast_mode  
    elsif Input.trigger?(:B)  
      toggle_line_visible  
    elsif Input.trigger?(:C)  
      toggle_point_visible  
    end  
  end  
  def self.main  
    init  
    loop { update }  
  end  
end  
   
Scene.main  
 
  马上要睡了,不多说了,看图 
 
 
本来想用shader的,后来还是屈服于Bitmap了…… 
按左键添加节点,按右键去除节点,按A开启快速模式(不显示绘制过程),按B切换线段的显示,按C切换节点的显示(此处ABC不是键盘上的ABC)
 # 二维向量 class Vector     # 可以进行枚举,参见#each   include(Enumerable)     attr_accessor :x # x方向上的分量   attr_accessor :y # y方向上的分量     # 初始化   # 无参数时:(0, 0)   # 有一个参数r时:(r, r)   # 有两个参数x, y时:(x, y)   def initialize(*args)     case args.size     when 0       @x = 0       @y = 0     when 1       @x = args[0]       @y = args[0]     when 2       @x = args[0]       @y = args[1]     end   end     def +@     self   end     # 反向量   def -@     Vector.new(-@x, -@y)   end     # 加法   def +(other)     Vector.new(@x + other.x, @y + other.y)   end     # 减法   def -(other)     self + -other   end     # 点乘或数乘运算   def *(other)     case other     when Numeric       Vector.new(@x * other, @y * other)     when Vector       @x * other.x + @y * other.y     end   end     # 点积   def dot(other)     @x * other.x + @y * other.y   end     # 叉积   def cross(other)     self.x * other.y - other.x * self.y   end     # 斜率   def slope     x =! 0 ? y / x : Float::Infinity   end     # 模的平方   def square_length     self * self   end     # 模   def length     Math.sqrt(square_length)   end     # 超出范围   def is_out_of?(other)     @x.abs > other.x.abs || @y.abs > other.y.abs   end     # 对x和y方向的分量分别取绝对值   def abs     Vector.new(@x.abs, @y.abs)   end     # 切向   def normal     Vector.new(-@y, @x)   end     # 枚举,先对x计算,后对y计算   def each     yield @x     yield @y   end     def inspect     "(#{@x}, #{@y})"   end end   module Math     # 获得两点之间由某个比例决定的分点   def self.definite_proportion(point1, point2, proportion)     point1 * (1 - proportion) + point2 * proportion   end end   class Rect     # 初始化   # 除了原先的参数列表,支持由两个向量来决定其位置大小   # 如果用向量表示,第一个向量是position,第二个向量是size   alias ulysses201811181949_initialize initialize   def initialize(*args)     args = case args.size     when 0, 4       args     when 2       [args[0].x, args[0].y, args[1].x, args[1].y]     end     ulysses201811181949_initialize(*args)   end     def position     Vector.new(x, y)   end     def position=(position)     self.x = position.x     self.y = position.y   end     def size     Vector.new(width, height)   end     def size=(size)     self.width = size.x     self.height = size.y   end end   module Kernel     # 令变量从from到to按照step进行线性变化并传递到块中   def do_by_step(from, to, step)     if block_given?       i = from       until i >= to         yield i         i += step       end     else       to_enum(__method__, from, to, step)     end   end     def gets(*args)     $stdin.gets(*args)   end     def Vector(*args)     Vector.new(*args)   end end   class Bitmap     # 初始化   # 支持向量表示   alias ulysses201811181708_initialize initialize   def initialize(*args)     args = if args.size == 2 || args[0].is_a?(String)       args     elsif args.size == 1       [args[0].x, args[0].y]     else       [0, 0]     end     ulysses201811181708_initialize(*args)   end     # 填充一个圆   def fill_circle(center, radius, color)     i_max = (radius * 707) / 1000 + 1     square_distance_max = radius * radius + radius / 2     x = radius     fill_rect(center.x - radius, center.y, 2 * radius, 1, color)     for i in 1..i_max       if Vector.new(center.x, i).square_length > square_distance_max         if x > i_max           fill_rect(center.x - i + 1, center.y + x, 2 * (i - 1), 1, color)           fill_rect(center.x - i + 1, center.y - x, 2 * (i - 1), 1, color)         end         x -= 1       end       fill_rect(center.x - x, center.y + i, 2 * x, 1, color)       fill_rect(center.x - x, center.y - i, 2 * x, 1, color)     end   end     # 用一条1像素宽的线段联结两点   def draw_line(point1, point2, color)     difference = point2 - point1     abs_difference = difference.abs     total_step = abs_difference.max     delta = difference * (1.0 / total_step)     vector = point1     (total_step.to_i + 1).times do       set_pixel(vector, color)       vector += delta     end   end     alias ulysses201811182036_set_pixel set_pixel   def set_pixel(*args)     args = case args.size     when 3       args     when 2       [args[0].x, args[0].y, args[1]]     end     ulysses201811182036_set_pixel(*args)   end     def text_vector(text)     text_size(text).size   end     def size     Vector.new(width, height)   end     def size=(size)     self.rect.size = size   end     alias ulysses201811181952_draw_text draw_text   def draw_text(*args)     args = case args[0]     when Numeric, Rect       args     when Vector       a = [args[0].x, args[0].y, args[1].x, args[1].y, args[2]]       a.push(args[3]) if args.size >= 4       a     end     ulysses201811181952_draw_text(*args)   end end   class Sprite     def position=(position)     self.x = position.x     self.y = position.y   end end   class Viewport     # 让add_fast_layer接受默认参数blend_type = 0   alias ulysses201812021851_add_fast_layer add_fast_layer   def add_fast_layer(z, blend_type = 0)     ulysses201812021851_add_fast_layer(z, blend_type)   end end   # 重写了Input模块 # 支持全键盘和鼠标按键 # 如果不需要判断鼠标位置的话,可以不update module Input     REPEAT_TIME = 4 # 当key被按超过此数时,repeat?(key) == true   GetKeyState = Win32API.new("user32", "GetAsyncKeyState", ['I'], 'I')     @key_states = {}   @key_repeat_times = {}     def self.press?(key)     key < 0x08 ? Mouse.press?(key) : GetKeyState.call(key) != 0   end     def self.repeat?(key)     if press?(key)       unless @key_repeat_times[key]         @key_repeat_times[key] = 0         return true       end       @key_repeat_times[key] += 1     else       @key_repeat_times[key] = nil       @key_states[key] = 0     end     if !@key_repeat_times[key].nil? && @key_repeat_times[key] > REPEAT_TIME       @key_repeat_times[key] = 0       return true     end     false   end     def self.trigger?(key)     if press?(key)       return false if @key_states[key] == 1       @key_states[key] = 1       true     else       @key_states[key] = 0       false     end   end     def self.update     Mouse.update   end end   class << Graphics     def size     Vector.new(width, height)   end     alias ulysses201811251830_resize_screen resize_screen   def resize_screen(*args)     case args.size     when 2       ulysses201811251830_resize_screen(*args)     when 1       ulysses201811251830_resize_screen(args[0].x, args[0].y)     end   end end   Graphics.resize_screen(1024, 768) # 更改分辨率   module Mouse     def self.position     Vector.new(x, y)   end end   # 封装为模块的场景 module Scene     # 绘制控制点的参数   POINTS_RADIUS = 3   POINTS_COLOR = Color.new(255, 255, 255, 255)   POINTS_Z = 10   # 绘制曲线的参数   CURVE_COLOR = Color.new(255, 255, 255, 255)   CURVE_Z = 0   # 绘制线段的参数   LINES_COLOR = Color.new(255, 255, 255, 127)   LINES_Z = -10   # 用于调整绘制的范围和精度   T_BEGINNING = 0.0   T_END = 1.0   T_STEP = 0.01   UPDATE_STEPS = 5   TEMP_BITMAP = Bitmap.new(32, 32) # 临时位图,用于获取文字大小   # 按键   CREATE_CONTROL_POINT_KEY = 0x01 # left   DELETE_CONTROL_POINT_KEY = 0x02 # right   FAST_MODE_KEY = 0x41 # A   LINES_VISIBLE_KEY = 0x42 # B   CONTROL_POINTS_VISIBLE_KEY = 0x43 # C     # 显示端口   @viewport = Viewport.new   @viewport.add_fast_layer(POINTS_Z)   # 曲线   @curve_sprite = Sprite.new(@viewport)   @curve_sprite.bitmap = Bitmap.new(Graphics.size)   @curve_sprite.z = CURVE_Z   # 线段   @lines_sprite = Sprite.new(@viewport)   @lines_sprite.bitmap = Bitmap.new(Graphics.size)   @lines_sprite.z = LINES_Z   # 控制点   @control_points = []   @control_point_sprites = []   # 模式控制   @lines_visible = true   @control_points_visible = true   @fast_mode = false   # 阻断刷新控制   @covering_drawing = 0     # 创建控制点   def self.create_control_point(point)     sprite = Sprite.new(@viewport)     sprite.visible = @control_points_visible     radius_vector = Vector.new(POINTS_RADIUS)     text_vector = TEMP_BITMAP.text_vector(@control_points.size)     radius_text_vector = radius_vector + text_vector     sprite.bitmap = Bitmap.new(radius_text_vector + radius_vector)     sprite.bitmap.font.color = POINTS_COLOR     x_flip = (point + radius_text_vector).x > Graphics.width     y_flip = (point + radius_text_vector).y > Graphics.height     excursion = Vector.new     excursion.x = x_flip ? radius_text_vector.x : radius_vector.x     excursion.y = y_flip ? radius_text_vector.y : radius_vector.y     sprite.position = point - excursion     sprite.bitmap.fill_circle(excursion, POINTS_RADIUS, POINTS_COLOR)     text_position = Vector.new     text_position.x = x_flip ? 0 : radius_vector.x * 2     text_position.y = y_flip ? 0 : radius_vector.y * 2     sprite.bitmap.draw_text(text_position, text_vector, @control_points.size)     sprite.z = POINTS_Z     @control_point_sprites.push(sprite)     @control_points.push(point)     refresh_graph     point   end     # 删除上一个控制点   def self.delete_control_point     return if @control_points.empty?     point = @control_points.pop     sprite = @control_point_sprites.pop     sprite.bitmap.dispose     sprite.dispose     refresh_graph     point   end     # 刷新图形   # 该方法在非快速模式下会阻塞,但update不会停且可以被打断   def self.refresh_graph     @covering_drawing += 1     @curve_sprite.bitmap.clear     return if @control_points.empty?     graph_points = []     steps_count = 0     do_by_step(T_BEGINNING, T_END, T_STEP) do |t|       will_update = !@fast_mode && (steps_count += 1) >= UPDATE_STEPS       graph_points.push(next_graph_point(t, will_update))       if graph_points.size > 1         @curve_sprite.bitmap.draw_line(*graph_points.last(2), CURVE_COLOR)       end       if will_update         steps_count = 0         last_covering_drawing = @covering_drawing         update         return if @covering_drawing > last_covering_drawing       end     end     connect_control_points_with_lines   end     # 根据t返回曲线上的点坐标   # 若@lines_visible && will_update则会绘制线段   def self.next_graph_point(t, will_update = false)     is_drawing = @lines_visible && will_update     @lines_sprite.bitmap.clear if is_drawing     sequences = [@control_points]     (@control_points.size - 1).times do |i|       last_sequence = sequences.last       sequences.push([])       (last_sequence.size - 1).times do |j|         if is_drawing           @lines_sprite.bitmap.draw_line(*last_sequence[j, 2], LINES_COLOR)         end         sequences.last.push(Math.definite_proportion(*last_sequence[j, 2], t))       end     end     sequences.last.first   end     # 用线段将控制点联结   def self.connect_control_points_with_lines     @lines_sprite.bitmap.clear     (@control_points.size - 1).times do |i|       @lines_sprite.bitmap.draw_line(*@control_points[i, 2], LINES_COLOR)     end     nil   end     # 切换线段可见   def self.toggle_lines_visible     @lines_visible = !@lines_visible     @lines_sprite.visible = @lines_visible   end     # 切换控制点可见   def self.toggle_points_visible     @control_points_visible = !@control_points_visible     @control_point_sprites.each do |sprite|       sprite.visible = @control_points_visible     end   end     # 切换快速模式   def self.toggle_fast_mode     @fast_mode = !@fast_mode   end     # 基础更新,必须每帧调用   def self.update_basic     Graphics.update     Input.update   end     # 更新,需每帧调用   def self.update     update_basic     if Input.trigger?(CREATE_CONTROL_POINT_KEY)       create_control_point(Mouse.position)     elsif Input.trigger?(DELETE_CONTROL_POINT_KEY)       delete_control_point     elsif Input.trigger?(FAST_MODE_KEY)       toggle_fast_mode     elsif Input.trigger?(LINES_VISIBLE_KEY)       toggle_lines_visible     elsif Input.trigger?(CONTROL_POINTS_VISIBLE_KEY)       toggle_points_visible     end   end     # 简单的irb   def self.simple_irb_start     Thread.start do       ans = nil       loop { puts("=> #{(ans = eval(gets)).inspect}") rescue puts($!.message) }     end   end     # 主进程   def self.main     simple_irb_start     loop { update }   end end   # 入口 Scene.main 
 
 # 二维向量  
class Vector  
   
  # 可以进行枚举,参见#each  
  include(Enumerable)  
   
  attr_accessor :x # x方向上的分量  
  attr_accessor :y # y方向上的分量  
   
  # 初始化  
  # 无参数时:(0, 0)  
  # 有一个参数r时:(r, r)  
  # 有两个参数x, y时:(x, y)  
  def initialize(*args)  
    case args.size  
    when 0  
      @x = 0  
      @y = 0  
    when 1  
      @x = args[0]  
      @y = args[0]  
    when 2  
      @x = args[0]  
      @y = args[1]  
    end  
  end  
   
  def +@  
    self  
  end  
   
  # 反向量  
  def -@  
    Vector.new(-@x, -@y)  
  end  
   
  # 加法  
  def +(other)  
    Vector.new(@x + other.x, @y + other.y)  
  end  
   
  # 减法  
  def -(other)  
    self + -other  
  end  
   
  # 点乘或数乘运算  
  def *(other)  
    case other  
    when Numeric  
      Vector.new(@x * other, @y * other)  
    when Vector  
      @x * other.x + @y * other.y  
    end  
  end  
   
  # 点积  
  def dot(other)  
    @x * other.x + @y * other.y  
  end  
   
  # 叉积  
  def cross(other)  
    self.x * other.y - other.x * self.y  
  end  
   
  # 斜率  
  def slope  
    x =! 0 ? y / x : Float::Infinity  
  end  
   
  # 模的平方  
  def square_length  
    self * self  
  end  
   
  # 模  
  def length  
    Math.sqrt(square_length)  
  end  
   
  # 超出范围  
  def is_out_of?(other)  
    @x.abs > other.x.abs || @y.abs > other.y.abs  
  end  
   
  # 对x和y方向的分量分别取绝对值  
  def abs  
    Vector.new(@x.abs, @y.abs)  
  end  
   
  # 切向  
  def normal  
    Vector.new(-@y, @x)  
  end  
   
  # 枚举,先对x计算,后对y计算  
  def each  
    yield @x  
    yield @y  
  end  
   
  def inspect  
    "(#{@x}, #{@y})"  
  end  
end  
   
module Math  
   
  # 获得两点之间由某个比例决定的分点  
  def self.definite_proportion(point1, point2, proportion)  
    point1 * (1 - proportion) + point2 * proportion  
  end  
end  
   
class Rect  
   
  # 初始化  
  # 除了原先的参数列表,支持由两个向量来决定其位置大小  
  # 如果用向量表示,第一个向量是position,第二个向量是size  
  alias ulysses201811181949_initialize initialize  
  def initialize(*args)  
    args = case args.size  
    when 0, 4  
      args  
    when 2  
      [args[0].x, args[0].y, args[1].x, args[1].y]  
    end  
    ulysses201811181949_initialize(*args)  
  end  
   
  def position  
    Vector.new(x, y)  
  end  
   
  def position=(position)  
    self.x = position.x  
    self.y = position.y  
  end  
   
  def size  
    Vector.new(width, height)  
  end  
   
  def size=(size)  
    self.width = size.x  
    self.height = size.y  
  end  
end  
   
module Kernel  
   
  # 令变量从from到to按照step进行线性变化并传递到块中  
  def do_by_step(from, to, step)  
    if block_given?  
      i = from  
      until i >= to  
        yield i  
        i += step  
      end  
    else  
      to_enum(__method__, from, to, step)  
    end  
  end  
   
  def gets(*args)  
    $stdin.gets(*args)  
  end  
   
  def Vector(*args)  
    Vector.new(*args)  
  end  
end  
   
class Bitmap  
   
  # 初始化  
  # 支持向量表示  
  alias ulysses201811181708_initialize initialize  
  def initialize(*args)  
    args = if args.size == 2 || args[0].is_a?(String)  
      args  
    elsif args.size == 1  
      [args[0].x, args[0].y]  
    else  
      [0, 0]  
    end  
    ulysses201811181708_initialize(*args)  
  end  
   
  # 填充一个圆  
  def fill_circle(center, radius, color)  
    i_max = (radius * 707) / 1000 + 1  
    square_distance_max = radius * radius + radius / 2  
    x = radius  
    fill_rect(center.x - radius, center.y, 2 * radius, 1, color)  
    for i in 1..i_max  
      if Vector.new(center.x, i).square_length > square_distance_max  
        if x > i_max  
          fill_rect(center.x - i + 1, center.y + x, 2 * (i - 1), 1, color)  
          fill_rect(center.x - i + 1, center.y - x, 2 * (i - 1), 1, color)  
        end  
        x -= 1  
      end  
      fill_rect(center.x - x, center.y + i, 2 * x, 1, color)  
      fill_rect(center.x - x, center.y - i, 2 * x, 1, color)  
    end  
  end  
   
  # 用一条1像素宽的线段联结两点  
  def draw_line(point1, point2, color)  
    difference = point2 - point1  
    abs_difference = difference.abs  
    total_step = abs_difference.max  
    delta = difference * (1.0 / total_step)  
    vector = point1  
    (total_step.to_i + 1).times do  
      set_pixel(vector, color)  
      vector += delta  
    end  
  end  
   
  alias ulysses201811182036_set_pixel set_pixel  
  def set_pixel(*args)  
    args = case args.size  
    when 3  
      args  
    when 2  
      [args[0].x, args[0].y, args[1]]  
    end  
    ulysses201811182036_set_pixel(*args)  
  end  
   
  def text_vector(text)  
    text_size(text).size  
  end  
   
  def size  
    Vector.new(width, height)  
  end  
   
  def size=(size)  
    self.rect.size = size  
  end  
   
  alias ulysses201811181952_draw_text draw_text  
  def draw_text(*args)  
    args = case args[0]  
    when Numeric, Rect  
      args  
    when Vector  
      a = [args[0].x, args[0].y, args[1].x, args[1].y, args[2]]  
      a.push(args[3]) if args.size >= 4  
      a  
    end  
    ulysses201811181952_draw_text(*args)  
  end  
end  
   
class Sprite  
   
  def position=(position)  
    self.x = position.x  
    self.y = position.y  
  end  
end  
   
class Viewport  
   
  # 让add_fast_layer接受默认参数blend_type = 0  
  alias ulysses201812021851_add_fast_layer add_fast_layer  
  def add_fast_layer(z, blend_type = 0)  
    ulysses201812021851_add_fast_layer(z, blend_type)  
  end  
end  
   
# 重写了Input模块  
# 支持全键盘和鼠标按键  
# 如果不需要判断鼠标位置的话,可以不update  
module Input  
   
  REPEAT_TIME = 4 # 当key被按超过此数时,repeat?(key) == true  
  GetKeyState = Win32API.new("user32", "GetAsyncKeyState", ['I'], 'I')  
   
  @key_states = {}  
  @key_repeat_times = {}  
   
  def self.press?(key)  
    key < 0x08 ? Mouse.press?(key) : GetKeyState.call(key) != 0  
  end  
   
  def self.repeat?(key)  
    if press?(key)  
      unless @key_repeat_times[key]  
        @key_repeat_times[key] = 0  
        return true  
      end  
      @key_repeat_times[key] += 1  
    else  
      @key_repeat_times[key] = nil  
      @key_states[key] = 0  
    end  
    if !@key_repeat_times[key].nil? && @key_repeat_times[key] > REPEAT_TIME  
      @key_repeat_times[key] = 0  
      return true  
    end  
    false  
  end  
   
  def self.trigger?(key)  
    if press?(key)  
      return false if @key_states[key] == 1  
      @key_states[key] = 1  
      true  
    else  
      @key_states[key] = 0  
      false  
    end  
  end  
   
  def self.update  
    Mouse.update  
  end  
end  
   
class << Graphics  
   
  def size  
    Vector.new(width, height)  
  end  
   
  alias ulysses201811251830_resize_screen resize_screen  
  def resize_screen(*args)  
    case args.size  
    when 2  
      ulysses201811251830_resize_screen(*args)  
    when 1  
      ulysses201811251830_resize_screen(args[0].x, args[0].y)  
    end  
  end  
end  
   
Graphics.resize_screen(1024, 768) # 更改分辨率  
   
module Mouse  
   
  def self.position  
    Vector.new(x, y)  
  end  
end  
   
# 封装为模块的场景  
module Scene  
   
  # 绘制控制点的参数  
  POINTS_RADIUS = 3  
  POINTS_COLOR = Color.new(255, 255, 255, 255)  
  POINTS_Z = 10  
  # 绘制曲线的参数  
  CURVE_COLOR = Color.new(255, 255, 255, 255)  
  CURVE_Z = 0  
  # 绘制线段的参数  
  LINES_COLOR = Color.new(255, 255, 255, 127)  
  LINES_Z = -10  
  # 用于调整绘制的范围和精度  
  T_BEGINNING = 0.0  
  T_END = 1.0  
  T_STEP = 0.01  
  UPDATE_STEPS = 5  
  TEMP_BITMAP = Bitmap.new(32, 32) # 临时位图,用于获取文字大小  
  # 按键  
  CREATE_CONTROL_POINT_KEY = 0x01 # left  
  DELETE_CONTROL_POINT_KEY = 0x02 # right  
  FAST_MODE_KEY = 0x41 # A  
  LINES_VISIBLE_KEY = 0x42 # B  
  CONTROL_POINTS_VISIBLE_KEY = 0x43 # C  
   
  # 显示端口  
  @viewport = Viewport.new  
  @viewport.add_fast_layer(POINTS_Z)  
  # 曲线  
  @curve_sprite = Sprite.new(@viewport)  
  @curve_sprite.bitmap = Bitmap.new(Graphics.size)  
  @curve_sprite.z = CURVE_Z  
  # 线段  
  @lines_sprite = Sprite.new(@viewport)  
  @lines_sprite.bitmap = Bitmap.new(Graphics.size)  
  @lines_sprite.z = LINES_Z  
  # 控制点  
  @control_points = []  
  @control_point_sprites = []  
  # 模式控制  
  @lines_visible = true  
  @control_points_visible = true  
  @fast_mode = false  
  # 阻断刷新控制  
  @covering_drawing = 0  
   
  # 创建控制点  
  def self.create_control_point(point)  
    sprite = Sprite.new(@viewport)  
    sprite.visible = @control_points_visible  
    radius_vector = Vector.new(POINTS_RADIUS)  
    text_vector = TEMP_BITMAP.text_vector(@control_points.size)  
    radius_text_vector = radius_vector + text_vector  
    sprite.bitmap = Bitmap.new(radius_text_vector + radius_vector)  
    sprite.bitmap.font.color = POINTS_COLOR  
    x_flip = (point + radius_text_vector).x > Graphics.width  
    y_flip = (point + radius_text_vector).y > Graphics.height  
    excursion = Vector.new  
    excursion.x = x_flip ? radius_text_vector.x : radius_vector.x  
    excursion.y = y_flip ? radius_text_vector.y : radius_vector.y  
    sprite.position = point - excursion  
    sprite.bitmap.fill_circle(excursion, POINTS_RADIUS, POINTS_COLOR)  
    text_position = Vector.new  
    text_position.x = x_flip ? 0 : radius_vector.x * 2  
    text_position.y = y_flip ? 0 : radius_vector.y * 2  
    sprite.bitmap.draw_text(text_position, text_vector, @control_points.size)  
    sprite.z = POINTS_Z  
    @control_point_sprites.push(sprite)  
    @control_points.push(point)  
    refresh_graph  
    point  
  end  
   
  # 删除上一个控制点  
  def self.delete_control_point  
    return if @control_points.empty?  
    point = @control_points.pop  
    sprite = @control_point_sprites.pop  
    sprite.bitmap.dispose  
    sprite.dispose  
    refresh_graph  
    point  
  end  
   
  # 刷新图形  
  # 该方法在非快速模式下会阻塞,但update不会停且可以被打断  
  def self.refresh_graph  
    @covering_drawing += 1  
    @curve_sprite.bitmap.clear  
    return if @control_points.empty?  
    graph_points = []  
    steps_count = 0  
    do_by_step(T_BEGINNING, T_END, T_STEP) do |t|  
      will_update = !@fast_mode && (steps_count += 1) >= UPDATE_STEPS  
      graph_points.push(next_graph_point(t, will_update))  
      if graph_points.size > 1  
        @curve_sprite.bitmap.draw_line(*graph_points.last(2), CURVE_COLOR)  
      end  
      if will_update  
        steps_count = 0  
        last_covering_drawing = @covering_drawing  
        update  
        return if @covering_drawing > last_covering_drawing  
      end  
    end  
    connect_control_points_with_lines  
  end  
   
  # 根据t返回曲线上的点坐标  
  # 若@lines_visible && will_update则会绘制线段  
  def self.next_graph_point(t, will_update = false)  
    is_drawing = @lines_visible && will_update  
    @lines_sprite.bitmap.clear if is_drawing  
    sequences = [@control_points]  
    (@control_points.size - 1).times do |i|  
      last_sequence = sequences.last  
      sequences.push([])  
      (last_sequence.size - 1).times do |j|  
        if is_drawing  
          @lines_sprite.bitmap.draw_line(*last_sequence[j, 2], LINES_COLOR)  
        end  
        sequences.last.push(Math.definite_proportion(*last_sequence[j, 2], t))  
      end  
    end  
    sequences.last.first  
  end  
   
  # 用线段将控制点联结  
  def self.connect_control_points_with_lines  
    @lines_sprite.bitmap.clear  
    (@control_points.size - 1).times do |i|  
      @lines_sprite.bitmap.draw_line(*@control_points[i, 2], LINES_COLOR)  
    end  
    nil  
  end  
   
  # 切换线段可见  
  def self.toggle_lines_visible  
    @lines_visible = !@lines_visible  
    @lines_sprite.visible = @lines_visible  
  end  
   
  # 切换控制点可见  
  def self.toggle_points_visible  
    @control_points_visible = !@control_points_visible  
    @control_point_sprites.each do |sprite|  
      sprite.visible = @control_points_visible  
    end  
  end  
   
  # 切换快速模式  
  def self.toggle_fast_mode  
    @fast_mode = !@fast_mode  
  end  
   
  # 基础更新,必须每帧调用  
  def self.update_basic  
    Graphics.update  
    Input.update  
  end  
   
  # 更新,需每帧调用  
  def self.update  
    update_basic  
    if Input.trigger?(CREATE_CONTROL_POINT_KEY)  
      create_control_point(Mouse.position)  
    elsif Input.trigger?(DELETE_CONTROL_POINT_KEY)  
      delete_control_point  
    elsif Input.trigger?(FAST_MODE_KEY)  
      toggle_fast_mode  
    elsif Input.trigger?(LINES_VISIBLE_KEY)  
      toggle_lines_visible  
    elsif Input.trigger?(CONTROL_POINTS_VISIBLE_KEY)  
      toggle_points_visible  
    end  
  end  
   
  # 简单的irb  
  def self.simple_irb_start  
    Thread.start do  
      ans = nil  
      loop { puts("=> #{(ans = eval(gets)).inspect}") rescue puts($!.message) }  
    end  
  end  
   
  # 主进程  
  def self.main  
    simple_irb_start  
    loop { update }  
  end  
end  
   
# 入口  
Scene.main  
 
  更新了很多地方,懒得说了,依赖这玩意https://rpg.blue/thread-400462-1-1.html |   
 
评分
- 
查看全部评分
 
 
 
 
 
 |