Class: PerfectShape::Rectangle

Inherits:
Shape
  • Object
show all
Includes:
RectangularShape
Defined in:
lib/perfect_shape/rectangle.rb

Direct Known Subclasses

Square

Constant Summary collapse

OUT_LEFT =

bitmask indicating a point lies to the left

1
OUT_TOP =

bitmask indicating a point lies above

2
OUT_RIGHT =

bitmask indicating a point lies to the right

4
OUT_BOTTOM =

bitmask indicating a point lies below

8
RECT_INTERSECTS =
0x80000000

Instance Attribute Summary

Attributes included from RectangularShape

#height, #width

Attributes included from PointLocation

#x, #y

Instance Method Summary collapse

Methods included from RectangularShape

#initialize, #max_x, #max_y

Methods included from PointLocation

#first_point, #initialize, #min_x, #min_y

Methods inherited from Shape

#==, #bounding_box, #center_point, #center_x, #center_y, #height, #max_x, #max_y, #min_x, #min_y, #width

Instance Method Details

#contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0) ⇒ Boolean

Checks if rectangle contains point (two-number Array or x, y args)

the rectangle, false if the point lies outside of the rectangle’s bounds.

Parameters:

  • x

    The X coordinate of the point to test.

  • y (defaults to: nil)

    The Y coordinate of the point to test.

Returns:

  • (Boolean)

    true if the point lies within the bound of



54
55
56
57
58
59
60
61
62
63
# File 'lib/perfect_shape/rectangle.rb', line 54

def contain?(x_or_point, y = nil, outline: false, distance_tolerance: 0)
  x, y = Point.normalize_point(x_or_point, y)
  return unless x && y
  
  if outline
    edges.any? { |edge| edge.contain?(x, y, distance_tolerance: distance_tolerance) }
  else
    x.between?(self.x, self.x + width) && y.between?(self.y, self.y + height)
  end
end

#edgesObject



65
66
67
68
69
70
71
72
# File 'lib/perfect_shape/rectangle.rb', line 65

def edges
  [
    Line.new(points: [[self.x, self.y], [self.x + width, self.y]]),
    Line.new(points: [[self.x + width, self.y], [self.x + width, self.y + height]]),
    Line.new(points: [[self.x + width, self.y + height], [self.x, self.y + height]]),
    Line.new(points: [[self.x, self.y + height], [self.x, self.y]])
  ]
end

#empty?Boolean

A rectangle is empty if its width or height is 0 (or less)

Returns:

  • (Boolean)


102
103
104
# File 'lib/perfect_shape/rectangle.rb', line 102

def empty?
  width <= 0.0 || height <= 0.0
end

#intersect?(rectangle) ⇒ Boolean

Returns:

  • (Boolean)


106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/perfect_shape/rectangle.rb', line 106

def intersect?(rectangle)
  x = rectangle.x
  y = rectangle.y
  w = rectangle.width
  h = rectangle.height
  return false if empty? || w <= 0 || h <= 0
  x0 = self.x
  y0 = self.y
  (x + w) > x0 &&
    (y + h) > y0 &&
    x < (x0 + self.width) &&
    y < (y0 + self.height)
end

#out_state(x_or_point, y = nil) ⇒ Object

Returns out state for specified point (x,y): (left, right, top, bottom)

It can be 0 meaning not outside the rectangle, or if outside the rectangle, then a bit mask combination of OUT_LEFT, OUT_RIGHT, OUT_TOP, or OUT_BOTTOM



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/perfect_shape/rectangle.rb', line 79

def out_state(x_or_point, y = nil)
  x, y = Point.normalize_point(x_or_point, y)
  return unless x && y
  
  out = 0
  if self.width <= 0
      out |= OUT_LEFT | OUT_RIGHT
  elsif x < self.x
      out |= OUT_LEFT
  elsif x > self.x + self.width
      out |= OUT_RIGHT
  end
  if self.height <= 0
      out |= OUT_TOP | OUT_BOTTOM
  elsif y < self.y
      out |= OUT_TOP
  elsif y > self.y + self.height
      out |= OUT_BOTTOM
  end
  out
end

#to_path_shapesObject

Converts Rectangle into basic Path shapes made up of Points and Lines Used by Path when adding a Rectangle to Path shapes



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/perfect_shape/rectangle.rb', line 122

def to_path_shapes
  path_shapes = []
  x = self.x
  y = self.y
  w = self.width
  h = self.height
  index = 0
  index = 5 if (w < 0 || h < 0)
  max_index = 4
  max_index = 2 if (w == 0 && h > 0) || (w > 0 && h == 0)
  max_index = 1 if (w == 0 && h == 0)
  first_point_x = first_point_y = nil
  
  until index > max_index
    if index == max_index
      path_shapes << Line.new(points: [[first_point_x, first_point_y]])
    else
      coords = []
      coords[0] = x
      coords[1] = y
      coords[0] += w if ([2, 4].include?(max_index) && index == 1) || (max_index == 4 && index == 2)
      coords[1] += h if (max_index == 2 && index == 1) || (max_index == 4 && [2, 3].include?(index))
      if index == 0
        first_point_x = coords[0]
        first_point_y = coords[1]
        path_shapes << Point.new(coords)
      else
        path_shapes << Line.new(points: coords)
      end
    end
    index += 1
  end
  
  path_shapes
end