dem-curves 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/core/constraint.rb +79 -0
- data/lib/core/control-point.rb +106 -0
- data/lib/core/path-element.rb +88 -0
- data/lib/core/path.rb +87 -0
- data/lib/core/util.rb +26 -0
- data/lib/dem-curves.rb +19 -0
- data/lib/rubygame-util/control-handles.rb +76 -0
- data/lib/rubygame-util/gfx.rb +15 -0
- metadata +52 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 95c1fab002f919736b30a60e299e82c05a10f1fb
         | 
| 4 | 
            +
              data.tar.gz: 9a9a364baf601ea4c82d302b38cb2fb7b62fa543
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: ce2ca54589e1a097467d565a315383b3269a3cee37f7dbfc8c6e12514ae9ebf38a909721ce7de4c797896f8e16f2b0ea49034bcec57efd2eb7d3def32ffb6757
         | 
| 7 | 
            +
              data.tar.gz: f78075a71096ba4ffc79600ed2ddc28a2667a5d234b86923a85b69295ade8c878823960109b19f07f3846347fabf402e7d07a47dfe15bda70901b31039eba1ba
         | 
| @@ -0,0 +1,79 @@ | |
| 1 | 
            +
            module DemCurves
         | 
| 2 | 
            +
              module BaseConstraint
         | 
| 3 | 
            +
                master_point = nil
         | 
| 4 | 
            +
                slave_points = []
         | 
| 5 | 
            +
                
         | 
| 6 | 
            +
                def notify(src, orig_src, params)
         | 
| 7 | 
            +
                  if src == @master_point
         | 
| 8 | 
            +
                    handle_master src, orig_src, params
         | 
| 9 | 
            +
                  elsif @slave_points.include? src
         | 
| 10 | 
            +
                    handle_slave src, orig_src, params
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def handle_master(master, orig_src, params)
         | 
| 15 | 
            +
                  # This has to be implemented by the class
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                def handle_slave(slave, orig_src, params)
         | 
| 19 | 
            +
                  # This has to be implemented by the class
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              
         | 
| 24 | 
            +
              class LineUpConstraint
         | 
| 25 | 
            +
                include BaseConstraint
         | 
| 26 | 
            +
                def initialize(pivot, p0, p1, mirror_distance=false, follow=:pivot)
         | 
| 27 | 
            +
                  pivot.add_constraint self
         | 
| 28 | 
            +
                  p0.add_constraint self
         | 
| 29 | 
            +
                  p1.add_constraint self
         | 
| 30 | 
            +
                  
         | 
| 31 | 
            +
                  @master_point = pivot
         | 
| 32 | 
            +
                  @slave_points = [p0, p1]
         | 
| 33 | 
            +
                  @mirror_distance = mirror_distance
         | 
| 34 | 
            +
                  @follow = follow
         | 
| 35 | 
            +
                  p1.move_to p1.loc #hacky way to trigger readjustment
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
                
         | 
| 38 | 
            +
                def handle_master(master, orig_src, params)
         | 
| 39 | 
            +
                  if (params.include? :new_pos and params.include? :old_pos) or params.include? :rel
         | 
| 40 | 
            +
                    case @follow
         | 
| 41 | 
            +
                    when :pivot
         | 
| 42 | 
            +
                      unless params.include? :rel
         | 
| 43 | 
            +
                        params[:rel] = params[:new_pos], params[:old_pos]
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
                      
         | 
| 46 | 
            +
                      params.delete(:new_pos)
         | 
| 47 | 
            +
                      params.delete(:old_pos)
         | 
| 48 | 
            +
                      
         | 
| 49 | 
            +
                      @slave_points.each do |slave|
         | 
| 50 | 
            +
                        slave.notify_to_move orig_src, self, params
         | 
| 51 | 
            +
                      end
         | 
| 52 | 
            +
                    when :p0
         | 
| 53 | 
            +
                      direction = (params[:new_pos] - @slave_points[0].loc).unit
         | 
| 54 | 
            +
                      distance = (params[:new_pos] - @slave_points[1].loc).r
         | 
| 55 | 
            +
                      @slave_points[1].notify_to_move orig_src, self, {:new_pos => params[:new_pos] + (distance * direction)}
         | 
| 56 | 
            +
                    when :p1
         | 
| 57 | 
            +
                      direction = (params[:new_pos] - @slave_points[1].loc).unit
         | 
| 58 | 
            +
                      distance = (params[:new_pos] - @slave_points[0].loc).r
         | 
| 59 | 
            +
                      @slave_points[0].notify_to_move orig_src, self, {:new_pos => params[:new_pos] + (distance * direction)}
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
                def handle_slave(slave, orig_src, params)
         | 
| 65 | 
            +
                  if params.include? :new_pos
         | 
| 66 | 
            +
                    other_slave = (@slave_points.select {|s| s!=slave})[0]
         | 
| 67 | 
            +
                    direction = (params[:new_pos] - @master_point.loc).unit
         | 
| 68 | 
            +
                    if @mirror_distance
         | 
| 69 | 
            +
                      distance = (slave.loc - @master_point.loc).r
         | 
| 70 | 
            +
                    else
         | 
| 71 | 
            +
                      distance = (other_slave.loc - @master_point.loc).r
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                    
         | 
| 74 | 
            +
                    new_loc = @master_point.loc + (-1 * direction * distance)
         | 
| 75 | 
            +
                    other_slave.notify_to_move orig_src, self, {:new_pos => new_loc}
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
            end
         | 
| @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            require 'matrix'
         | 
| 2 | 
            +
            require 'core/util.rb'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module DemCurves
         | 
| 5 | 
            +
              class ControlPoint
         | 
| 6 | 
            +
                # this class is necessary to let other curves and path elements modify
         | 
| 7 | 
            +
                # points, it works much better than calling "notify movement" functions
         | 
| 8 | 
            +
                # every time a control point moves, this comes in handy when you want a curve
         | 
| 9 | 
            +
                # to use another curve's end point as a starting point.
         | 
| 10 | 
            +
                attr_reader :loc
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                def initialize(loc)
         | 
| 13 | 
            +
                  @loc = Vector.elements(loc)
         | 
| 14 | 
            +
                  @path_elements = []
         | 
| 15 | 
            +
                  @constraints = []
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                def add_path_element(path_element)
         | 
| 19 | 
            +
                  @path_elements << path_element
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                def replace(other)
         | 
| 23 | 
            +
                  old_pos = @loc
         | 
| 24 | 
            +
                  case other
         | 
| 25 | 
            +
                  when ControlPoint
         | 
| 26 | 
            +
                    @loc = Vector.elements(other.loc)
         | 
| 27 | 
            +
                  when Vector, Array
         | 
| 28 | 
            +
                    unless other.size == 2
         | 
| 29 | 
            +
                      raise "Wrong number of dimensions, must be [x, y]"
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
                    @loc = Vector.elements(other)
         | 
| 32 | 
            +
                  else
         | 
| 33 | 
            +
                    raise "Argument is instance of #{other.class}! Replacement argument must be an instance of Vector, Array or ControlPoint."
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                    
         | 
| 36 | 
            +
                    @path_elements.each do |path_element|
         | 
| 37 | 
            +
                      path_element.generate
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
                
         | 
| 41 | 
            +
                def shift(rel)
         | 
| 42 | 
            +
                  unless rel.size == 2
         | 
| 43 | 
            +
                    raise "Wrong number of dimensions, must be [x, y]"
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                  
         | 
| 46 | 
            +
                  old_pos = @loc
         | 
| 47 | 
            +
                  move_to @loc + Vector.elements(rel)
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                def move_to(destination)
         | 
| 51 | 
            +
                  old_pos = @loc
         | 
| 52 | 
            +
                  replace destination
         | 
| 53 | 
            +
                  
         | 
| 54 | 
            +
                  new_pos = @loc
         | 
| 55 | 
            +
                  rel = new_pos - old_pos
         | 
| 56 | 
            +
                  
         | 
| 57 | 
            +
                  @constraints.each do |constraint|
         | 
| 58 | 
            +
                    constraint.notify self, self, {:new_pos => new_pos, :old_pos => old_pos, :rel => rel}
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                def rotate_around(pivot_ctl, angle)
         | 
| 63 | 
            +
                  offset = @loc - pivot_ctl.loc
         | 
| 64 | 
            +
                  new_offset = Matrix[[Math.cos(angle), -Math.sin(angle)], [Math.sin(angle), Math.cos(angle)]] * offset
         | 
| 65 | 
            +
                  replace new_offset + pivot_ctl.loc
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                def notify_to_move(orig_src, src_constraint, params)
         | 
| 69 | 
            +
                  unless orig_src == self
         | 
| 70 | 
            +
                    # Safety measure, it avoids infinite recursion, but produces weird results
         | 
| 71 | 
            +
                    # with cyclic constraint structures.
         | 
| 72 | 
            +
                    old_pos = @loc
         | 
| 73 | 
            +
                    if params.include? :new_pos
         | 
| 74 | 
            +
                      replace params[:new_pos]
         | 
| 75 | 
            +
                    elsif params.include? :rel
         | 
| 76 | 
            +
                      replace params[:rel] + @loc
         | 
| 77 | 
            +
                    else
         | 
| 78 | 
            +
                      return
         | 
| 79 | 
            +
                    end
         | 
| 80 | 
            +
                    
         | 
| 81 | 
            +
                    new_pos = @loc
         | 
| 82 | 
            +
                    rel = new_pos - old_pos
         | 
| 83 | 
            +
                    
         | 
| 84 | 
            +
                    @constraints.each do |constraint|
         | 
| 85 | 
            +
                      unless constraint == src_constraint
         | 
| 86 | 
            +
                        constraint.notify self, orig_src, {:new_pos => new_pos, :old_pos => old_pos, :rel => rel}
         | 
| 87 | 
            +
                      end
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                def add_constraint(constraint)
         | 
| 93 | 
            +
                  unless @constraints.include? constraint
         | 
| 94 | 
            +
                    @constraints << constraint
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
                
         | 
| 98 | 
            +
                def clear_constraints
         | 
| 99 | 
            +
                  @constraints = []
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
              
         | 
| 103 | 
            +
              def ControlPoint.[](*loc)
         | 
| 104 | 
            +
                return ControlPoint.new loc
         | 
| 105 | 
            +
              end
         | 
| 106 | 
            +
            end
         | 
| @@ -0,0 +1,88 @@ | |
| 1 | 
            +
            require 'core/util.rb'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module DemCurves
         | 
| 4 | 
            +
              class PathElement
         | 
| 5 | 
            +
                # Do not directly instantiate this class
         | 
| 6 | 
            +
                attr_reader :path_points, :control_points
         | 
| 7 | 
            +
                def initialize(control_points)
         | 
| 8 | 
            +
                  @control_points = control_points
         | 
| 9 | 
            +
                  @control_points.each_value do |control_point| 
         | 
| 10 | 
            +
                    control_point.add_path_element self
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                  
         | 
| 13 | 
            +
                  @path_points = []
         | 
| 14 | 
            +
                  generate
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                def generate
         | 
| 18 | 
            +
                  @path_points = @control_points.values.collect {|point| point.loc}
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                def set_control(control_id, loc)
         | 
| 22 | 
            +
                  unless control_id.class == Symbol 
         | 
| 23 | 
            +
                    raise 'control_id must be a symbol' 
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  
         | 
| 26 | 
            +
                  @control_points[control_id].move_to location
         | 
| 27 | 
            +
                  generate
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                
         | 
| 30 | 
            +
                def []=(control_id, loc)
         | 
| 31 | 
            +
                  set_control control_id, loc
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                
         | 
| 34 | 
            +
                def get_control(control_id)
         | 
| 35 | 
            +
                  unless control_id.class == Symbol 
         | 
| 36 | 
            +
                    raise 'control_id must be a symbol' 
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                  
         | 
| 39 | 
            +
                  return @control_points[control_id]
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                def [](control_id)
         | 
| 43 | 
            +
                  get_control control_id
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
              
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
              class CubicBezier < PathElement
         | 
| 49 | 
            +
                def initialize(start_point, start_handle, end_handle, end_point)
         | 
| 50 | 
            +
                  super({
         | 
| 51 | 
            +
                    :start => start_point, 
         | 
| 52 | 
            +
                    :start_handle => start_handle, 
         | 
| 53 | 
            +
                    :end_handle => end_handle, 
         | 
| 54 | 
            +
                    :end => end_point})
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
                
         | 
| 57 | 
            +
                def generate(t_freq=32)
         | 
| 58 | 
            +
                  step = 1.0 / t_freq
         | 
| 59 | 
            +
                  @path_points = (0..t_freq).collect {|i| interpolate(step * i)}
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                def interpolate(t)
         | 
| 63 | 
            +
                  # http://mathworld.wolfram.com/BezierCurve.html
         | 
| 64 | 
            +
                  (0..3).inject(Vector[0, 0]) do |mem, i|
         | 
| 65 | 
            +
                    mem += @control_points.values[i].loc.clone * bernstein_basis(i, 3, t)
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                def get_guides
         | 
| 70 | 
            +
                  # this will be removed soon.
         | 
| 71 | 
            +
                  return [[self[:start].loc, self[:start_handle].loc], [self[:end_handle].loc, self[:end].loc]]
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
              
         | 
| 76 | 
            +
              class Line < PathElement
         | 
| 77 | 
            +
                def initialize(start_point, center_point, end_point)
         | 
| 78 | 
            +
                  super({
         | 
| 79 | 
            +
                    :start => start_point,
         | 
| 80 | 
            +
                    :center => center_point,
         | 
| 81 | 
            +
                    :end => end_point})
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
                
         | 
| 84 | 
            +
                def generate
         | 
| 85 | 
            +
                  @path_points = [self[:start].loc, self[:end].loc]
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
            end
         | 
    
        data/lib/core/path.rb
    ADDED
    
    | @@ -0,0 +1,87 @@ | |
| 1 | 
            +
            require 'core/path-element.rb'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module DemCurves
         | 
| 4 | 
            +
              class Path
         | 
| 5 | 
            +
                include Enumerable
         | 
| 6 | 
            +
                attr_reader :path_points, :path_elements, :control_points
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                def initialize(point)
         | 
| 9 | 
            +
                  @path_elements = []
         | 
| 10 | 
            +
                  
         | 
| 11 | 
            +
                  @start_point = ControlPoint[*point]
         | 
| 12 | 
            +
                  @end_point = @start_point
         | 
| 13 | 
            +
                  
         | 
| 14 | 
            +
                  @path_points = to_a
         | 
| 15 | 
            +
                  @control_points = [@start_point]
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                def add_bezier(start_handle, end_handle, end_point, tangent_lock=true)
         | 
| 19 | 
            +
                  new_bezier = CubicBezier.new(
         | 
| 20 | 
            +
                  @end_point, 
         | 
| 21 | 
            +
                  ControlPoint[*start_handle],
         | 
| 22 | 
            +
                  ControlPoint[*end_handle],
         | 
| 23 | 
            +
                  ControlPoint[*end_point])
         | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  if tangent_lock and @path_elements.last
         | 
| 26 | 
            +
                    start_length = (new_bezier[:start_handle].loc - @end_point.loc).r
         | 
| 27 | 
            +
                    last_element = @path_elements.last
         | 
| 28 | 
            +
                    
         | 
| 29 | 
            +
                    case last_element
         | 
| 30 | 
            +
                    when CubicBezier
         | 
| 31 | 
            +
                      LineUpConstraint.new @end_point, last_element[:end_handle], new_bezier[:start_handle]
         | 
| 32 | 
            +
                    when Line
         | 
| 33 | 
            +
                      LineUpConstraint.new @end_point, last_element[:center], new_bezier[:start_handle], morror_distance=false, follow=:p0
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                  
         | 
| 37 | 
            +
                  @end_point = new_bezier[:end]
         | 
| 38 | 
            +
                  @path_elements << new_bezier
         | 
| 39 | 
            +
                  
         | 
| 40 | 
            +
                  @path_points = to_a
         | 
| 41 | 
            +
                  @control_points += new_bezier.control_points.values[1..-1]
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
                
         | 
| 44 | 
            +
                def add_line(end_point, tangent_lock=true)
         | 
| 45 | 
            +
                  center_point = ControlPoint[*(@end_point.loc + (Vector[*end_point] - @end_point.loc) * 0.5)]
         | 
| 46 | 
            +
                  new_line = Line.new @end_point, center_point, ControlPoint[*end_point]
         | 
| 47 | 
            +
                  LineUpConstraint.new center_point, new_line[:end], @end_point
         | 
| 48 | 
            +
                  
         | 
| 49 | 
            +
                  if tangent_lock and @path_elements.last
         | 
| 50 | 
            +
                    last_element = @path_elements.last
         | 
| 51 | 
            +
                    
         | 
| 52 | 
            +
                    case last_element
         | 
| 53 | 
            +
                    when CubicBezier
         | 
| 54 | 
            +
                      LineUpConstraint.new @end_point, last_element[:end_handle], new_line[:end], morror_distance=false, follow=:p1
         | 
| 55 | 
            +
                    when Line
         | 
| 56 | 
            +
                      @end_point.move_to end_point
         | 
| 57 | 
            +
                      return
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                  @end_point = new_line[:end]
         | 
| 62 | 
            +
                  @path_elements << new_line
         | 
| 63 | 
            +
                  
         | 
| 64 | 
            +
                  @path_points = to_a
         | 
| 65 | 
            +
                  @control_points += new_line.control_points.values[1..-1]
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
                
         | 
| 68 | 
            +
                def each
         | 
| 69 | 
            +
                  yield @start_point.loc
         | 
| 70 | 
            +
                  @path_elements.each do |path_element|
         | 
| 71 | 
            +
                    (1..path_element.path_points.size-1).each do |index|
         | 
| 72 | 
            +
                      yield path_element.path_points[index]
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
                
         | 
| 77 | 
            +
                def size
         | 
| 78 | 
            +
                  return @path_points.size
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                def get_guides
         | 
| 82 | 
            +
                  @path_elements.inject([]) do |mem, element|
         | 
| 83 | 
            +
                    mem += element.get_guides
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
            end
         | 
    
        data/lib/core/util.rb
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            class Integer
         | 
| 2 | 
            +
              def choose(k)
         | 
| 3 | 
            +
                # binominal coefficient
         | 
| 4 | 
            +
                return self.factorial / ((self -k).factorial * k.factorial)
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              def factorial()
         | 
| 8 | 
            +
                # n!
         | 
| 9 | 
            +
                return (1..self).inject(1, &:*)
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            def bernstein_basis(i, n, t)
         | 
| 14 | 
            +
              # http://mathworld.wolfram.com/BernsteinPolynomial.html
         | 
| 15 | 
            +
              return n.choose(i) * t ** i * (1 - t) ** (n - i)
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            class Vector
         | 
| 19 | 
            +
              def unit
         | 
| 20 | 
            +
                return self / self.r
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              def angle(other)
         | 
| 24 | 
            +
                return Math.acos(self.inner_product other / (self.r * other.r))
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
    
        data/lib/dem-curves.rb
    ADDED
    
    | @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            # The backend files
         | 
| 2 | 
            +
            require 'core/control-point'
         | 
| 3 | 
            +
            require 'core/constraint'
         | 
| 4 | 
            +
            require 'core/path-element'
         | 
| 5 | 
            +
            require 'core/path'
         | 
| 6 | 
            +
            require 'core/util'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # These are the utils for integration with rubygame
         | 
| 9 | 
            +
            begin
         | 
| 10 | 
            +
              require 'rubygame'
         | 
| 11 | 
            +
              unless Rubygame::Surface.public_method_defined? :draw_line
         | 
| 12 | 
            +
                raise LoadError, 'Loading the Rubygame utils for DemCurves requires SDL_GFX to be present on the system'
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
              
         | 
| 15 | 
            +
              require 'rubygame-util/control-handles'
         | 
| 16 | 
            +
              require 'rubygame-util/gfx'
         | 
| 17 | 
            +
            rescue LoadError => e
         | 
| 18 | 
            +
              puts 'The Rubygame utils for DemCurves require SDL_GFX and Rubygame.'
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            require 'rubygame'
         | 
| 2 | 
            +
            require 'matrix'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module DemCurves
         | 
| 5 | 
            +
              module RubygameUtils
         | 
| 6 | 
            +
                def self.populate_handles(ctl_points, drag_group)
         | 
| 7 | 
            +
                  ctl_points.each do |control_point|
         | 
| 8 | 
            +
                    new_handle = EditorHandle.new
         | 
| 9 | 
            +
                    new_handle.attach_to control_point
         | 
| 10 | 
            +
                    drag_group << new_handle
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                class DragGroup < Rubygame::Sprites::Group
         | 
| 15 | 
            +
                  dragged_object = nil
         | 
| 16 | 
            +
                  
         | 
| 17 | 
            +
                  def on_press(evt)
         | 
| 18 | 
            +
                    self.each do |sprite|
         | 
| 19 | 
            +
                      if sprite.rect.collide_point? *evt.pos
         | 
| 20 | 
            +
                        @dragged_object = sprite
         | 
| 21 | 
            +
                        break
         | 
| 22 | 
            +
                      end
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  
         | 
| 26 | 
            +
                  def on_release(evt)
         | 
| 27 | 
            +
                    @dragged_object = nil
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                  
         | 
| 30 | 
            +
                  def on_move(evt)
         | 
| 31 | 
            +
                    if @dragged_object
         | 
| 32 | 
            +
                      @dragged_object.move evt.rel
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                
         | 
| 38 | 
            +
                class EditorHandle
         | 
| 39 | 
            +
                  include Rubygame::Sprites::Sprite
         | 
| 40 | 
            +
                  
         | 
| 41 | 
            +
                  def initialize(loc=[50, 50], size=10)
         | 
| 42 | 
            +
                    @groups =[]
         | 
| 43 | 
            +
                    @depth = 0
         | 
| 44 | 
            +
                    
         | 
| 45 | 
            +
                    @rect = Rubygame::Rect.new 0, 0, size, size
         | 
| 46 | 
            +
                    @rect.c = loc
         | 
| 47 | 
            +
                    
         | 
| 48 | 
            +
                    @image = Rubygame::Surface.new [size, size], 0, [Rubygame::HWSURFACE, Rubygame::SRCALPHA]
         | 
| 49 | 
            +
                    @image.fill([180, 180, 180])
         | 
| 50 | 
            +
                    @attached = false
         | 
| 51 | 
            +
                    
         | 
| 52 | 
            +
                    @constraints = []
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                  
         | 
| 55 | 
            +
                  def attach_to(control_point)
         | 
| 56 | 
            +
                    unless @attached
         | 
| 57 | 
            +
                      @attached = true
         | 
| 58 | 
            +
                      @control_point = control_point
         | 
| 59 | 
            +
                      @rect.c = control_point.loc.to_a
         | 
| 60 | 
            +
                    end
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                  
         | 
| 63 | 
            +
                  def move(rel)
         | 
| 64 | 
            +
                    if @attached
         | 
| 65 | 
            +
                      @control_point.shift rel
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  
         | 
| 69 | 
            +
                  def update
         | 
| 70 | 
            +
                    if @attached
         | 
| 71 | 
            +
                      @rect.c = @control_point.loc.to_a
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require 'rubygame'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Rubygame::Surface
         | 
| 4 | 
            +
              def draw_path(path, color)
         | 
| 5 | 
            +
                (0..path.size - 2).each do |index|
         | 
| 6 | 
            +
                  _draw_line path.to_a[index], path.to_a[index + 1], color, false
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              def draw_path_a(path, color)
         | 
| 11 | 
            +
                (0..path.size - 2).each do |index|
         | 
| 12 | 
            +
                  _draw_line path.to_a[index], path.to_a[index + 1], color, true
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: dem-curves
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Huba Nagy
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2015-02-14 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies: []
         | 
| 13 | 
            +
            description: 
         | 
| 14 | 
            +
            email: 12huba@gmail.com
         | 
| 15 | 
            +
            executables: []
         | 
| 16 | 
            +
            extensions: []
         | 
| 17 | 
            +
            extra_rdoc_files: []
         | 
| 18 | 
            +
            files:
         | 
| 19 | 
            +
            - lib/core/constraint.rb
         | 
| 20 | 
            +
            - lib/core/control-point.rb
         | 
| 21 | 
            +
            - lib/core/path-element.rb
         | 
| 22 | 
            +
            - lib/core/path.rb
         | 
| 23 | 
            +
            - lib/core/util.rb
         | 
| 24 | 
            +
            - lib/dem-curves.rb
         | 
| 25 | 
            +
            - lib/rubygame-util/control-handles.rb
         | 
| 26 | 
            +
            - lib/rubygame-util/gfx.rb
         | 
| 27 | 
            +
            homepage: https://github.com/huba/DemCurves
         | 
| 28 | 
            +
            licenses:
         | 
| 29 | 
            +
            - MIT
         | 
| 30 | 
            +
            metadata: {}
         | 
| 31 | 
            +
            post_install_message: 
         | 
| 32 | 
            +
            rdoc_options: []
         | 
| 33 | 
            +
            require_paths:
         | 
| 34 | 
            +
            - lib
         | 
| 35 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 36 | 
            +
              requirements:
         | 
| 37 | 
            +
              - - ">="
         | 
| 38 | 
            +
                - !ruby/object:Gem::Version
         | 
| 39 | 
            +
                  version: '0'
         | 
| 40 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 41 | 
            +
              requirements:
         | 
| 42 | 
            +
              - - ">="
         | 
| 43 | 
            +
                - !ruby/object:Gem::Version
         | 
| 44 | 
            +
                  version: '0'
         | 
| 45 | 
            +
            requirements: []
         | 
| 46 | 
            +
            rubyforge_project: 
         | 
| 47 | 
            +
            rubygems_version: 2.4.5
         | 
| 48 | 
            +
            signing_key: 
         | 
| 49 | 
            +
            specification_version: 4
         | 
| 50 | 
            +
            summary: A library for generating bezier curve based paths from control_points. It
         | 
| 51 | 
            +
              can be used with Rubygame
         | 
| 52 | 
            +
            test_files: []
         |