Class: Aims::Volume

Inherits:
Object
  • Object
show all
Extended by:
Vectorize
Defined in:
lib/aims/volume.rb

Overview

A volume is defined by a minimum of four planes that intersect in a minimum of four points. The normals of the planes must all point outward. This is tested

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Vectorize

cross, dot

Constructor Details

#initialize(planes) ⇒ Volume

Returns a new instance of Volume.



72
73
74
75
76
77
78
79
80
# File 'lib/aims/volume.rb', line 72

def initialize(planes)
  
  points = Volume.intersection_points(planes)
  if (4 > points.size)
    raise "Planes do not intersect in a closed volume."
  end
  @points = points
  @planes = planes
end

Class Method Details

.choose(list, num, head = []) ⇒ Object

Quick recursive method for calculating combinations



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/aims/volume.rb', line 14

def Volume.choose(list, num, head = [])

  _head = head.dup
  _list = list.dup
  _num = num

  if _num == 0 
    return [_head]
  end
    
  new_heads = []
  while _list.size > _num-1
      h = _head + [_list.shift]
      new_heads += Volume.choose(_list, num-1, h)
    end
  return new_heads
  
end

.intersection_points(planes) ⇒ Array

Return an array of tuples that define the vertices of intersection of these planes Vertices are removed that lie in front of any plane

Parameters:

  • planes (Array<Plane>)

    An array of Planes that define the boundaries of the volume

Returns:

  • (Array)

    An array of tuples that define the vertices of intersection of these planes



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/aims/volume.rb', line 39

def Volume.intersection_points(planes)
  combos = Volume.choose(planes, 3)
  points = []
  combos.each{|c|
    n1 = c[0].unit_normal
    n2 = c[1].unit_normal
    n3 = c[2].unit_normal
    d = Matrix[n1, n2,n3].transpose.det
    
    # The determinant is zero if any two planes are parallel
    unless (d == 0)
      p1 = c[0].any_point_on_plane
      p2 = c[1].any_point_on_plane
      p3 = c[2].any_point_on_plane
    
      # This defines the point of intersection of three planes.
      points << (cross(n2,n3)*dot(p1, n1) + cross(n3,n1)*dot(p2,n2) + cross(n1,n2)*dot(p3, n3))*(1/d)
    end
  }
  
  # Only keep the points that are behind all planes
  keepers = []
  points.each{|pt|
    keep = true
    planes.each {|pl|
      keep = (pl.distance_to_point(pt[0], pt[1], pt[2]) <= 0)
      break unless keep
    }
    keepers << pt if keep
  }
  return keepers
end

Instance Method Details

#bounding_boxObject

Return the bounding box for this volume



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/aims/volume.rb', line 83

def bounding_box
  unless @bbox
    p = @points[0]
    minX = p[0]
    maxX = p[0]
    minY = p[1]
    maxY = p[1]
    minZ = p[2]
    maxZ = p[2]
    @points.each{|p|
      minX = p[0] if p[0] < minX  
      maxX = p[0] if p[0] > maxX  
      minY = p[1] if p[1] < minY  
      maxY = p[1] if p[1] > maxY  
      minZ = p[2] if p[2] < minZ  
      maxZ = p[2] if p[2] > maxZ  
    }
    @max = Vector[maxX, maxY,maxZ]
    @min = Vector[minX, minY, minZ]
    @bbox = Volume.new([Plane.new(-1,0,0, minX, minY, minZ), 
                       Plane.new(0,-1,0, minX, minY, minZ),
                       Plane.new(0,0,-1, minX, minY, minZ),
                       Plane.new(1,0,0, maxX, maxY, maxZ),
                       Plane.new(0,1,0, maxX, maxY, maxZ), 
                       Plane.new(0,0,1, maxX, maxY, maxZ)])
  end
  @bbox
end

#contains_point(x, y, z) ⇒ Object

A volume contains a point if it lies behind all the planes



131
132
133
134
135
136
137
138
# File 'lib/aims/volume.rb', line 131

def contains_point(x,y,z)
  behind = true
  @planes.each{|p|
    behind = (0 >= p.distance_to_point(x,y,z))
    break if not behind
  }
  return behind
end

#max_pointObject

Return the point on the bounding box that represents the maximum value of any cartesian coordinate (the upper right corner)



114
115
116
117
118
119
# File 'lib/aims/volume.rb', line 114

def max_point
  # generate the bounding box if not already done
  bounding_box
  # return the max
  @max
end

#min_pointObject

Return the point on the bounding box that represents the minimum value of any cartesian coordinate (the lower left corner).



123
124
125
126
127
128
# File 'lib/aims/volume.rb', line 123

def min_point
  # generate the bounding box if not already done
  bounding_box
  # return the min
  @min
end