disp3D 0.2.1 → 1.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.
Files changed (56) hide show
  1. data/Gemfile +1 -1
  2. data/README.md +56 -0
  3. data/VERSION +1 -1
  4. data/disp3D.gemspec +24 -20
  5. data/example/stl_viewer/document_ctrl.rb +2 -2
  6. data/example/stl_viewer/qt_widget_controller.rb +3 -7
  7. data/example/tutorial/03_CameraScene.rb +5 -5
  8. data/example/tutorial/04_Qt.rb +4 -4
  9. data/example/tutorial/05_Pick.rb +13 -13
  10. data/example/tutorial/06_FileParser.rb +3 -3
  11. data/example/tutorial/07_SceneGraph.rb +16 -4
  12. data/example/tutorial/08_SceneGraph2.rb +16 -15
  13. data/example/tutorial/09_Texture.rb +28 -0
  14. data/example/tutorial/10_Animation.rb +27 -0
  15. data/example/tutorial/10_AnimationQt.rb +53 -0
  16. data/example/tutorial/11_MultiView.rb +41 -0
  17. data/example/tutorial/12_Light.rb +65 -0
  18. data/example/tutorial/13_RectPick.rb +38 -0
  19. data/example/tutorial/14_LineRubberband.rb +43 -0
  20. data/example/{test → tutorial}/data/test.png +0 -0
  21. data/example/{test → tutorial}/data/test2.jpg +0 -0
  22. data/lib/camera.rb +8 -0
  23. data/lib/compass.rb +21 -14
  24. data/lib/disp3D.rb +3 -0
  25. data/lib/gl_view.rb +70 -40
  26. data/lib/glut_window.rb +24 -18
  27. data/lib/light.rb +35 -21
  28. data/lib/manipulator.rb +0 -7
  29. data/lib/node/node.rb +100 -105
  30. data/lib/node/node_arrows.rb +1 -1
  31. data/lib/node/node_collection.rb +63 -17
  32. data/lib/node/node_cone.rb +49 -0
  33. data/lib/node/node_coord.rb +26 -11
  34. data/lib/node/node_leaf.rb +17 -11
  35. data/lib/node/node_lines.rb +1 -1
  36. data/lib/node/node_points.rb +2 -1
  37. data/lib/node/node_polylines.rb +1 -1
  38. data/lib/node/node_rectangle.rb +9 -4
  39. data/lib/node/node_sphere.rb +28 -0
  40. data/lib/node/node_tea_pod.rb +4 -4
  41. data/lib/node/node_text.rb +2 -2
  42. data/lib/node/node_tris.rb +1 -1
  43. data/lib/node/node_workplane.rb +33 -1
  44. data/lib/picker.rb +157 -3
  45. data/lib/qt_widget_gl.rb +24 -11
  46. data/lib/scene_graph.rb +3 -3
  47. data/test/node/test_node.rb +230 -0
  48. data/test/node/test_node_collection.rb +99 -79
  49. data/test/test_picker.rb +6 -6
  50. metadata +28 -24
  51. data/README.rdoc +0 -63
  52. data/example/test/capture_test.rb +0 -16
  53. data/example/test/dsl_test.rb +0 -46
  54. data/example/test/texture_test.rb +0 -39
  55. data/test/data/binary_test.stl +0 -0
  56. data/test/data/bunny-flatfoot.stl +0 -0
@@ -0,0 +1,49 @@
1
+ require 'disp3D'
2
+
3
+ module Disp3D
4
+ class NodeCone < NodeLeaf
5
+ attr_for_disp :radius
6
+ attr_for_disp :height
7
+ attr_for_disp :base_point
8
+ attr_for_disp :direction
9
+
10
+ def initialize(geom=nil, name=nil)
11
+ super
12
+ @radius = 1.0
13
+ @height = 3.0
14
+ @slices = 10
15
+ @stacks = 10
16
+ @base_point = Vector3.new()
17
+ @direction = Vector3.new(0,0,1)
18
+ end
19
+
20
+ def box
21
+ rtn_box = Box.new(Vector3.new(-@radius,-@radius,0), Vector3.new(@radius,@radius,@height))
22
+ rtn_box = box_transform(rtn_box)
23
+ rot = calc_rotate_from_direction
24
+ rtn_box = rtn_box.rotate(rot) if(!rot.nil?)
25
+ rtn_box = rtn_box.translate(@base_point)
26
+ return rtn_box
27
+ end
28
+
29
+ protected
30
+ def draw_element
31
+ GL.PushMatrix()
32
+ rot = calc_rotate_from_direction
33
+ GL.Translate(@base_point.x, @base_point.y, @base_point.z) if(@base_point)
34
+ GL.MultMatrix(rot.to_array) if(!rot.nil?)
35
+ draw_color
36
+ GLUT.SolidCone(@radius, @height, @slices, @stacks)
37
+ GL.PopMatrix()
38
+ end
39
+
40
+ private
41
+ def calc_rotate_from_direction
42
+ return nil if(@direction.length < 1e-2)
43
+ base_direction = Vector3.new(0,0,1)
44
+ angle = base_direction.angle(@direction)
45
+ axis = base_direction.cross(@direction)
46
+ rotate = Quat.from_axis(axis, angle)
47
+ end
48
+ end
49
+ end
@@ -2,26 +2,41 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodeCoord < NodeCollection
5
- def initialize(base_position = Vector3.new(), length = 1)
6
- super()
5
+ attr_for_disp :length
6
+ attr_for_disp :base_position
7
+
8
+ def initialize(name = nil, base_position = Vector3.new(), length = 1)
9
+ super(name)
7
10
  @length = length
8
11
  @base_position = base_position
9
12
  @x_color = [1,0,0,1]
10
13
  @y_color = [0,1,0,1]
11
14
  @z_color = [0,0,1,1]
12
15
 
16
+ @x_node = NodeArrows.new(geom[0])
17
+ @y_node = NodeArrows.new(geom[1])
18
+ @z_node = NodeArrows.new(geom[2])
19
+ @x_node.colors = @x_color
20
+ @y_node.colors = @y_color
21
+ @z_node.colors = @z_color
22
+ add(@x_node)
23
+ add(@y_node)
24
+ add(@z_node)
25
+ end
26
+
27
+ def update_for_display
28
+ @x_node.geom = geom[0]
29
+ @y_node.geom = geom[1]
30
+ @z_node.geom = geom[2]
31
+ super
32
+ end
33
+
34
+ private
35
+ def geom
13
36
  x_geom = FiniteLine.new(@base_position, @base_position + Vector3.new(@length,0,0))
14
37
  y_geom = FiniteLine.new(@base_position, @base_position + Vector3.new(0,@length,0))
15
38
  z_geom = FiniteLine.new(@base_position, @base_position + Vector3.new(0,0,@length))
16
- x_node = NodeArrows.new(x_geom)
17
- y_node = NodeArrows.new(y_geom)
18
- z_node = NodeArrows.new(z_geom)
19
- x_node.colors = @x_color
20
- y_node.colors = @y_color
21
- z_node.colors = @z_color
22
- add(x_node)
23
- add(y_node)
24
- add(z_node)
39
+ return [x_geom, y_geom, z_geom]
25
40
  end
26
41
  end
27
42
  end
@@ -3,9 +3,10 @@ require 'disp3D'
3
3
 
4
4
  module Disp3D
5
5
  class NodeLeaf < Node
6
- attr_accessor :material_color
7
- attr_accessor :colors
8
- attr_accessor :shininess
6
+ attr_for_disp :material_color
7
+ attr_for_disp :colors
8
+ attr_for_disp :shininess
9
+ attr_for_disp :geom
9
10
 
10
11
  def initialize(geometry = nil, name = nil)
11
12
  Util3D.check_arg_type(Symbol, name, true)
@@ -17,11 +18,11 @@ module Disp3D
17
18
  @shininess = nil
18
19
  @shininess_default = 32.0
19
20
 
20
- @list_created = false
21
+ @dislay_list_created = nil
21
22
  end
22
23
 
23
- def draw
24
- draw_inner(self.method(:draw_element))
24
+ def draw currnet_view
25
+ draw_inner(self.method(:draw_element), currnet_view)
25
26
  end
26
27
 
27
28
  def box
@@ -38,8 +39,12 @@ module Disp3D
38
39
  return box_transform(rtn_box)
39
40
  end
40
41
 
42
+ def update_for_display
43
+ @dislay_list_created = nil
44
+ end
45
+
41
46
  protected
42
- def draw_inner(draw_element)
47
+ def draw_inner(draw_element, current_view)
43
48
  # colors���ݒ肳��Ă�����A�������D��I�ɕ\������B���̍ہA���C�e�B���O�̓I�t�ɂ���K�v������
44
49
  if(@colors.nil?)
45
50
  GL.Enable(GL::GL_LIGHTING)
@@ -58,15 +63,16 @@ protected
58
63
  GL.Disable(GL::GL_LIGHTING)
59
64
  end
60
65
 
61
- if(@list_created == false)
62
- @list_created = true
63
- GL.NewList(@instance_id, GL::COMPILE_AND_EXECUTE)
66
+ if(@dislay_list_created.nil? || @dislay_list_created[current_view] == nil)
67
+ @dislay_list_created ||= Hash.new()
68
+ @dislay_list_created[current_view] = true
69
+ GL.NewList(self.instance_id, GL::COMPILE_AND_EXECUTE)
64
70
  pre_draw # matrix manipulation
65
71
  draw_element.call
66
72
  post_draw # matrix manipulation
67
73
  GL.EndList()
68
74
  else
69
- GL.CallList(@instance_id)
75
+ GL.CallList(self.instance_id)
70
76
  end
71
77
  end
72
78
 
@@ -2,7 +2,7 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodeLines < NodeLeaf
5
- attr_accessor :width
5
+ attr_for_disp :width
6
6
 
7
7
  def initialize(geom, name = nil)
8
8
  Util3D.check_arg_type(Symbol, name, true)
@@ -2,7 +2,7 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodePoints < NodeLeaf
5
- attr_accessor :size
5
+ attr_for_disp :size
6
6
 
7
7
  def initialize(geom, name = nil)
8
8
  Util3D.check_arg_type(Symbol, name, true)
@@ -16,6 +16,7 @@ protected
16
16
  if(@geom)
17
17
  GL.PointSize(@size)
18
18
  draw_color
19
+ GL.Enable(GL::POINT_SMOOTH)
19
20
  GL.Begin(GL::POINTS)
20
21
  if(@geom.kind_of?(GMath3D::Vector3))
21
22
  GL.Vertex( @geom.x, @geom.y, @geom.z )
@@ -2,7 +2,7 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodePolylines < NodeLeaf
5
- attr_accessor :width
5
+ attr_for_disp :width
6
6
 
7
7
  def initialize(geom, name = nil)
8
8
  Util3D.check_arg_type(Symbol, name, true)
@@ -3,18 +3,23 @@ require 'disp3D'
3
3
  module Disp3D
4
4
  class NodeRectangle < NodeLeaf
5
5
  # texture_image should be rmagick image
6
- def initialize(geom, name = nil, texture_image = nil)
6
+ def initialize(geom, name = nil)
7
7
  Util3D.check_arg_type(Symbol, name, true)
8
8
  Util3D.check_arg_type(GMath3D::Rectangle, geom, false, false) #Array is not allowed
9
- super(geom, name)
10
- @image = texture_image
11
- initialize_texture
9
+ super
12
10
  end
13
11
 
14
12
  def box
15
13
  return @geom.box
16
14
  end
17
15
 
16
+ def image=(texture_image)
17
+ Util3D.check_arg_type(Magick::Image, texture_image, true)
18
+ @image = texture_image
19
+ initialize_texture
20
+ update_for_display
21
+ end
22
+
18
23
  protected
19
24
  def draw_element
20
25
  if(@geom && @geom.kind_of?(GMath3D::Rectangle))
@@ -0,0 +1,28 @@
1
+ require 'disp3D'
2
+
3
+ module Disp3D
4
+ class NodeSphere < NodeLeaf
5
+ attr_for_disp :radius
6
+ attr_for_disp :center
7
+
8
+ def initialize(geom=nil, name=nil)
9
+ super
10
+ @radius = 1.0
11
+ @center = Vector3.new()
12
+ @slices = 10
13
+ @stacks = 10
14
+ end
15
+
16
+ def box
17
+ rtn_box = Box.new(Vector3.new(-@radius,-@radius,-@radius)+@center, Vector3.new(@radius,@radius,@radius)+@center)
18
+ return box_transform(rtn_box)
19
+ end
20
+
21
+ protected
22
+ def draw_element
23
+ draw_color
24
+ GL.Translate(@center.x, @center.y, @center.z) if(@center)
25
+ GLUT.SolidSphere(@radius, @slices, @stacks)
26
+ end
27
+ end
28
+ end
@@ -2,11 +2,11 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodeTeaPod < NodeLeaf
5
- attr_accessor :size
5
+ attr_for_disp :size
6
6
 
7
- def initialize(geom = nil, name = nil, size)
8
- super(geom, name)
9
- @size = size
7
+ def initialize(geom=nil, name=nil)
8
+ super
9
+ @size = 1.0
10
10
  end
11
11
 
12
12
  def box
@@ -2,8 +2,8 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodeText < NodeLeaf
5
- attr_accessor :text
6
- attr_accessor :position
5
+ attr_for_disp :text
6
+ attr_for_disp :position
7
7
 
8
8
  def initialize(position, name = nil, text = nil)
9
9
  Util3D.check_arg_type(Vector3, position)
@@ -2,7 +2,7 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodeTris < NodeLeaf
5
- attr_accessor :normal_mode
5
+ attr_for_disp :normal_mode
6
6
 
7
7
  NORMAL_EACH_FACE = 0
8
8
  NORMAL_EACH_VERTEX = 1
@@ -2,13 +2,15 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class NodeWorkplane < NodeLeaf
5
- attr_accessor :length
5
+ attr_for_disp :length
6
+ attr_for_disp :grid
6
7
 
7
8
  def initialize(geom, name = nil)
8
9
  Util3D.check_arg_type(Symbol, name, true)
9
10
  Util3D.check_arg_type(GMath3D::Plane, geom, false)
10
11
  super
11
12
  @length = 1000
13
+ @grid = nil
12
14
  end
13
15
 
14
16
  def box
@@ -25,12 +27,42 @@ protected
25
27
  GL.Vertex( vertex.x, vertex.y, vertex.z )
26
28
  end
27
29
  GL.End()
30
+
31
+ GL.Color(0,0,0,1)
32
+ GL.LineWidth(3)
33
+ if(!@grid.nil?)
34
+ line_vertices_ary = grid_lines_vertices
35
+ GL.Begin(GL::LINES)
36
+ line_vertices_ary.each do |vertex|
37
+ GL.Vertex( vertex.x, vertex.y, vertex.z )
38
+ end
39
+ GL.End()
40
+ end
28
41
  else
29
42
  raise
30
43
  end
31
44
  end
32
45
 
33
46
  private
47
+ def grid_lines_vertices
48
+ count = (@length/@grid) + 1
49
+ u_vec = @geom.normal
50
+ u_vec = @geom.normal.arbitrary_orthogonal
51
+ v_vec = @geom.normal.cross(u_vec)
52
+ vertices = Array.new(count*4)
53
+ count.times.each do |idx|
54
+ point_tmp = @geom.base_point + u_vec * @grid * (idx - count/2)
55
+ vertices[2*idx] = point_tmp + v_vec * @length/2.0
56
+ vertices[2*idx+1] = point_tmp - v_vec * @length/2.0
57
+ end
58
+ count.times.each do |idx|
59
+ point_tmp = @geom.base_point + v_vec * @grid * (idx - count/2)
60
+ vertices[2*idx+2*count] = point_tmp + u_vec * @length/2.0
61
+ vertices[2*idx+2*count+1] = point_tmp - u_vec * @length/2.0
62
+ end
63
+ return vertices
64
+ end
65
+
34
66
  def calc_vertices
35
67
  tan_vec1 = @geom.normal.arbitrary_orthogonal
36
68
  tan_vec2 = @geom.normal.cross(tan_vec1)
data/lib/picker.rb CHANGED
@@ -2,12 +2,106 @@ require 'disp3D'
2
2
 
3
3
  module Disp3D
4
4
  class Picker
5
+ attr_reader :pick_mode
6
+ attr_accessor :max_select_count
7
+
8
+ # pick modes
9
+ NONE = 0
10
+ POINT_PICK = 1
11
+ LINE_PICK = 2
12
+ RECT_PICK = 3
13
+
5
14
  def initialize(view)
6
15
  @view = view
7
16
  @max_select_count = 100
17
+ @pick_mode = NONE
18
+ end
19
+
20
+ def point_pick(x,y)
21
+ pick(x, y)
22
+ end
23
+
24
+ def post_picked(&block)
25
+ @post_pick_process = block
26
+ end
27
+
28
+ def start_point_pick(&block)
29
+ @pick_mode = POINT_PICK
30
+ post_picked(&block) if(block_given?)
31
+ end
32
+
33
+ def start_line_pick(&block)
34
+ @pick_mode = LINE_PICK
35
+ post_picked(&block) if(block_given?)
36
+ end
37
+
38
+ def start_rect_pick(&block)
39
+ @pick_mode = RECT_PICK
40
+ post_picked(&block) if(block_given?)
41
+ end
42
+
43
+ def end_pick
44
+ @pick_mode = NONE
45
+ end
46
+
47
+ # users donot need to use this.
48
+ def mouse(button,state,x,y)
49
+ return if(@pick_mode == NONE)
50
+ if(button == GLUT::GLUT_LEFT_BUTTON && state == GLUT::GLUT_DOWN)
51
+ if(@pick_mode == POINT_PICK)
52
+ picked_result = point_pick(x,y)
53
+ @post_pick_process.call(picked_result) if(!@post_pick_process.nil?)
54
+ return
55
+ elsif(@pick_mode == LINE_PICK)
56
+ @line_start_result = point_pick(x,y)
57
+ end
58
+ @last_pos = Vector3.new(x, y)
59
+ @rubber_band = false
60
+ elsif(button == GLUT::GLUT_LEFT_BUTTON && state == GLUT::GLUT_UP)
61
+ if(@pick_mode == LINE_PICK)
62
+ draw_rubber_band(FiniteLine.new(@last_pos, @save_pos)) # delete rubber band
63
+ line_end_result = pick(x, y)
64
+ @post_pick_process.call(@line_start_result, line_end_result) if(!@post_pick_process.nil?)
65
+ @line_start_result = nil
66
+ elsif(@pick_mode == RECT_PICK)
67
+ draw_rubber_band(Box.new(@last_pos, @save_pos)) # delete rubber band
68
+ pick_x = (x + @last_pos.x)/2
69
+ pick_y = (y + @last_pos.y)/2
70
+ width = (x - @last_pos.x).abs
71
+ height = (y - @last_pos.y).abs
72
+ picked_result = pick(pick_x, pick_y, width, height)
73
+ @post_pick_process.call(picked_result) if(!@post_pick_process.nil?)
74
+ end
75
+ @save_pos = nil
76
+ @last_pos = nil
77
+ @rubber_band = false
78
+ end
79
+ end
80
+
81
+ # users donot need to use this.
82
+ # return if picking process is in progress?
83
+ def motion(x,y)
84
+ return false if(@pick_mode == NONE || @last_pos.nil?)
85
+ if(@pick_mode == LINE_PICK)
86
+ if(@rubber_band)
87
+ draw_rubber_band([FiniteLine.new(@last_pos, @save_pos), FiniteLine.new(@last_pos, Vector3.new(x,y))])
88
+ else
89
+ draw_rubber_band(FiniteLine.new(@last_pos, Vector3.new(x,y)))
90
+ end
91
+ elsif(@pick_mode == RECT_PICK)
92
+ if(@rubber_band)
93
+ draw_rubber_band([Box.new(@last_pos, @save_pos), Box.new(@last_pos, Vector3.new(x,y))])
94
+ else
95
+ draw_rubber_band(Box.new(@last_pos, Vector3.new(x,y)))
96
+ end
97
+ end
98
+ @save_pos = Vector3.new(x, y)
99
+ @rubber_band=true
100
+ return true
8
101
  end
9
102
 
10
- def pick(x,y)
103
+ private
104
+ def pick(x, y, width = 1, height = 1)
11
105
  vp = GL.GetIntegerv(GL::VIEWPORT)
12
106
 
13
107
  selection = GL.SelectBuffer(@max_select_count)
@@ -19,7 +113,7 @@ module Disp3D
19
113
  GL.PushMatrix()
20
114
  GL.LoadIdentity()
21
115
 
22
- GLU.PickMatrix(x, vp[3] - y - 1, 1, 1, vp)
116
+ GLU.PickMatrix(x, vp[3] - y - 1, width, height, vp)
23
117
  @view.camera.set_screen(vp[2], vp[3])
24
118
 
25
119
  GL.MatrixMode(GL::MODELVIEW)
@@ -47,7 +141,7 @@ module Disp3D
47
141
  node_info = Array.new()
48
142
  count.times do | j |
49
143
  path_id = data[4*i+3 + j]
50
- picked_node = Node.find_node_by_path_id(path_id)
144
+ picked_node = NodePathDB.find_by_path_id(path_id)
51
145
  if (picked_node != nil)
52
146
  parent_node = picked_node.parents.find {|parent| parent.include?(path_id) }
53
147
  picked_node_info = PathInfo.new(picked_node, parent_node, path_id)
@@ -58,5 +152,65 @@ module Disp3D
58
152
  end
59
153
  return picked_result
60
154
  end
155
+
156
+ def pre_rubber_band_process
157
+ dmy,dmy, w,h = GL.GetIntegerv(GL::VIEWPORT)
158
+ @view.camera.set_projection_for_camera_scene
159
+ GL.MatrixMode(GL::GL_MODELVIEW)
160
+ GL.PushMatrix()
161
+ GL.LoadIdentity()
162
+ GLU.LookAt(0, 0, 1, 0, 0, 0, 0, 1, 0)
163
+
164
+ GL.Enable(GL::COLOR_LOGIC_OP)
165
+ GL.LogicOp(GL::INVERT)
166
+ GL.DrawBuffer( GL::FRONT )
167
+
168
+ GL.LineWidth(2)
169
+
170
+ return w,h
171
+ end
172
+
173
+ def post_rubber_band_process
174
+ GL.Flush()
175
+
176
+ GL.Disable(GL::COLOR_LOGIC_OP)
177
+ GL.LogicOp(GL::COPY)
178
+
179
+ GL.PopMatrix()
180
+ end
181
+
182
+ # [Input]
183
+ # _elemnets_ should be FiniteLine or Box or Array of them.
184
+ def draw_rubber_band(elements)
185
+ w,h = pre_rubber_band_process
186
+ draw_rubber_band_lines_inner(elements, w, h)
187
+ post_rubber_band_process
188
+ end
189
+
190
+ def screen_to_rubberband( vec, w , h )
191
+ [-w/2 + vec.x, h/2 - vec.y - 1]
192
+ end
193
+
194
+ def draw_rubber_band_lines_inner(elements, w, h)
195
+ return if(elements.nil?)
196
+ if(elements.kind_of?(FiniteLine))
197
+ GL.Begin(GL::LINES)
198
+ GL.Vertex(screen_to_rubberband( elements.start_point, w, h ))
199
+ GL.Vertex(screen_to_rubberband( elements.end_point, w, h ))
200
+ GL.End()
201
+ elsif(elements.kind_of?(Box))
202
+ box = elements
203
+ lines = Array.new(4)
204
+ lines[0] = FiniteLine.new(Vector3.new(box.min_point.x, box.min_point.y), Vector3.new(box.max_point.x, box.min_point.y))
205
+ lines[1] = FiniteLine.new(Vector3.new(box.max_point.x, box.min_point.y), Vector3.new(box.max_point.x, box.max_point.y))
206
+ lines[2] = FiniteLine.new(Vector3.new(box.max_point.x, box.max_point.y), Vector3.new(box.min_point.x, box.max_point.y))
207
+ lines[3] = FiniteLine.new(Vector3.new(box.min_point.x, box.max_point.y), Vector3.new(box.min_point.x, box.min_point.y))
208
+ draw_rubber_band_lines_inner(lines, w, h)
209
+ elsif(elements.kind_of?(Array))
210
+ elements.each do |item|
211
+ draw_rubber_band_lines_inner(item, w, h)
212
+ end
213
+ end
214
+ end
61
215
  end
62
216
  end