lib/geomotion/cg_rect.rb in geomotion-0.1 vs lib/geomotion/cg_rect.rb in geomotion-0.5

- old
+ new

@@ -1,43 +1,62 @@ class CGRect - # CGRect.make(x: 10, y: 30) + # CGRect.make # default rect: {origin: {x: 0, y: 0}, size: {width:0, height:0}} + # # aka CGRectZero + # CGRect.make(x: 10, y: 30) # default size: [0, 0] # CGRect.make(x: 10, y: 30, width:100, height: 20) + # + # point = CGPoint.make(x: 10, y: 30) + # size = CGSize.make(width: 100, height: 20) + # CGRect.make(origin: point, size: size) def self.make(options = {}) if options[:origin] - options[:x] = options[:origin].x - options[:y] = options[:origin].y + x = options[:origin].x + y = options[:origin].y + else + x = options[:x] || 0 + y = options[:y] || 0 end if options[:size] - options[:width] = options[:size].width - options[:height] = options[:size].height + w = options[:size].width + h = options[:size].height + else + w = options[:width] || 0 + h = options[:height] || 0 end - CGRect.new([options[:x] || 0, options[:y] || 0], [options[:width] || 0, options[:height] || 0]) + self.new([x, y], [w, h]) end def self.empty - # Don't return CGRectZero; can be mutated - CGRect.make + # Don't just return CGRectZero; can be mutated + CGRectZero.dup end def self.null - CGRectNull + # Don't just return CGRectNull; can be mutated + CGRectNull.dup end def self.infinite - self.new([0, 0], CGSize.infinite) + # This actually returns the not-very-infinite value of: + # [[-1.7014114289565e+38, -1.7014114289565e+38], [3.402822857913e+38, 3.402822857913e+38]] + # originally this method returned [[-Infinity, -Infinity], [Infinity, Infinity]], + # but that rect ended up returning `false` for any point in the method + # CGRect.infinite.contains?(point). CGRectInfinite returns `true` for any + # (sensible) point, so we'll go with that instead + CGRectInfinite.dup end # OPTIONS: [:above, :below, :left_of, :right_of, :margins] # :margins is array of [top, right, bottom, left] # EX CGRect.layout(rect1, above: rect2, left_of: rect3, margins: [0, 10, 20, 0]) def self.layout(rect1, options) if options.empty? - p "No options provided in CGRect.layout" + p "No options provided in #{self.class}.layout" return rect1 end - rect = CGRect.new + rect = self.new rect.size = rect1.size options[:margins] ||= [] margins = {} [:top, :right, :bottom, :left].each_with_index do |margin, index| @@ -51,54 +70,73 @@ rect.x = options[:right_of].beside(margins[:left]).x if options[:right_of] rect end + # bounds + def min_x + CGRectGetMinX(self) + end + + def max_x + CGRectGetMaxX(self) + end + + def min_y + CGRectGetMinY(self) + end + + def max_y + CGRectGetMaxY(self) + end + + # getters/setters def x(setter = nil) if setter return CGRect.new([setter, self.y], self.size) end - self.origin.x + min_x end def x=(_x) self.origin.x = _x end def y(setter = nil) if setter return CGRect.new([self.x, setter], self.size) end - self.origin.y + min_y end def y=(_y) self.origin.y = _y end def width(setter = nil) if setter return CGRect.new(self.origin, [setter, self.height]) end - self.size.width + CGRectGetWidth(self) end def width=(_width) self.size.width = _width end def height(setter = nil) if setter return CGRect.new(self.origin, [self.width, setter]) end - self.size.height + CGRectGetHeight(self) end def height=(_height) self.size.height = _height end + # modified rects def left(dist = 0) CGRect.new([self.x - dist, self.y], self.size) end def right(dist = 0) @@ -111,10 +149,27 @@ def down(dist = 0) CGRect.new([self.x, self.y + dist], self.size) end + def wider(dist) + CGRect.new(self.origin, [self.width + dist, self.height]) + end + + def thinner(dist) + CGRect.new(self.origin, [self.width - dist, self.height]) + end + + def taller(dist) + CGRect.new(self.origin, [self.width, self.height + dist]) + end + + def shorter(dist) + CGRect.new(self.origin, [self.width, self.height - dist]) + end + + # adjacent rects def above(margin = 0) self.above(margin, height:self.height) end def above(margin, height:height) @@ -132,28 +187,47 @@ def before(margin, width:width) CGRect.new([self.x - width - margin, self.y], [width, self.height]) end def beside(margin = 0) - CGRect.new([self.x + self.width + margin, self.y], self.size) + self.beside(margin, width: self.width) end - def center(relative = false) - offset_x = relative ? self.x : 0 - offset_y = relative ? self.y : 0 + def beside(margin, width:width) + CGRect.new([self.x + self.width + margin, self.y], [width, self.height]) + end + + # locations + def center(absolute = false) + offset_x = absolute ? self.x : 0 + offset_y = absolute ? self.y : 0 CGPoint.new(offset_x + self.width / 2, offset_y + self.height / 2) end + def top_left + CGPoint.new(CGRectGetMinX(self), CGRectGetMinY(self)) + end + + def top_right + CGPoint.new(CGRectGetMaxX(self), CGRectGetMinY(self)) + end + + def bottom_left + CGPoint.new(CGRectGetMinX(self), CGRectGetMaxY(self)) + end + + def bottom_right + CGPoint.new(CGRectGetMaxX(self), CGRectGetMaxY(self)) + end + + # others def round CGRect.new([self.x.round, self.y.round], [self.width.round, self.height.round]) end - def centered_in(rect, relative = false) - offset_x = relative ? rect.x : 0 - offset_y = relative ? rect.y : 0 - CGRect.new([offset_x + ((rect.width - self.width) / 2), - offset_y + ((rect.height - self.height) / 2)], self.size) + def centered_in(rect, absolute = false) + self.size.centered_in(rect, absolute) end def +(other) case other when CGRect @@ -194,11 +268,11 @@ def empty? CGRectIsEmpty(self) end def infinite? - self.size.infinite? + self.size.infinite? || CGRectEqualToRect(self, CGRectInfinite) end def null? CGRectIsNull(self) end @@ -206,24 +280,37 @@ def intersects?(rect) case rect when CGRect CGRectIntersectsRect(self, rect) else - super + super # raises an error end end def contains?(rect_or_point) case rect_or_point when CGPoint CGRectContainsPoint(self, rect_or_point) when CGRect CGRectContainsRect(self, rect_or_point) else - super + super # raises an error end end def ==(rect) rect.is_a?(CGRect) && CGRectEqualToRect(self, rect) end + + def -@ + CGRect.new(-self.origin, -self.size) + end + + def -(other) + self.+(-other) + end + + def inspect + "#{self.class.name}([#{self.origin.x}, #{self.origin.y}], [#{self.size.width}, #{self.size.height}])" + end + end