Module: Overlap
- Defined in:
- lib/nswtopo/geometry/overlap.rb
Instance Method Summary collapse
Instance Method Details
#overlap?(buffer = 0) ⇒ Boolean
42 43 44 |
# File 'lib/nswtopo/geometry/overlap.rb', line 42 def overlap?(buffer = 0) !separated_by?(buffer) end |
#overlaps(buffer = 0) ⇒ Object
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 71 72 73 74 75 |
# File 'lib/nswtopo/geometry/overlap.rb', line 46 def overlaps(buffer = 0) return [] if empty? axis = flatten(1).transpose.map { |values| values.max - values.min }.map.with_index.max.last events, tops, bots, results = AVLTree.new, [], [], [] margin = [buffer, 0] each.with_index do |hull, index| min, max = hull.map { |point| point.rotate axis }.minmax events << [min.minus(margin), index, :start] events << [max.plus( margin), index, :stop ] end events.each do |point, index, event| top, bot = at(index).transpose[1-axis].minmax case event when :start not_above = bots.select { |bot, other| bot >= top - buffer }.map(&:last) not_below = tops.select { |top, other| top <= bot + buffer }.map(&:last) (not_below & not_above).reject do |other| values_at(index, other).separated_by? buffer end.each do |other| results << [index, other] end tops << [top, index] bots << [bot, index] when :stop tops.delete [top, index] bots.delete [bot, index] end end results end |
#separated_by?(buffer) ⇒ Boolean
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/nswtopo/geometry/overlap.rb', line 2 def separated_by?(buffer) simplex = [map(&:first).inject(&:minus)] perp = simplex[0].perp loop do return false unless case when simplex.one? then simplex[0].norm when simplex.inject(&:minus).dot(simplex[1]) > 0 then simplex[1].norm when simplex.inject(&:minus).dot(simplex[0]) < 0 then simplex[0].norm else simplex.inject(&:cross).abs / simplex.inject(&:minus).norm end > buffer max = self[0].max_by { |point| perp.cross point } min = self[1].min_by { |point| perp.cross point } support = max.minus min return true unless simplex[0].minus(support).cross(perp) > 0 rays = simplex.map { |point| point.minus support } case simplex.length when 1 case when rays[0].dot(support) > 0 simplex, perp = [support], support.perp when rays[0].cross(support) < 0 simplex, perp = [support, *simplex], rays[0] else simplex, perp = [*simplex, support], rays[0].negate end when 2 case when rays[0].cross(support) > 0 && rays[0].dot(support) < 0 simplex, perp = [simplex[0], support], rays[0].negate when rays[1].cross(support) < 0 && rays[1].dot(support) < 0 simplex, perp = [support, simplex[1]], rays[1] when rays[0].cross(support) <= 0 && rays[1].cross(support) >= 0 return false else simplex, perp = [support], support.perp end end end end |